From 42c9c109fe1a794ff959111f6be52d0d2ec17642 Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Sat, 25 Jan 2025 14:25:10 +0800 Subject: [PATCH 001/546] Remove unused trait BoundedSize --- library/core/src/iter/adapters/flatten.rs | 55 ----------------------- 1 file changed, 55 deletions(-) diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 9b9353b800a9..a820045521b9 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -172,61 +172,6 @@ where } } -/// Marker trait for iterators/iterables which have a statically known upper -/// bound of the number of items they can produce. -/// -/// # Safety -/// -/// Implementations must not yield more elements than indicated by UPPER_BOUND if it is `Some`. -/// Used in specializations. Implementations must not be conditional on lifetimes or -/// user-implementable traits. -#[rustc_specialization_trait] -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe trait BoundedSize { - const UPPER_BOUND: Option> = NonZero::new(1); -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for Option {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for option::IntoIter {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for Result {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for result::IntoIter {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for Once {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for OnceWith {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for [T; N] { - const UPPER_BOUND: Option> = NonZero::new(N); -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for array::IntoIter { - const UPPER_BOUND: Option> = NonZero::new(N); -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for Filter { - const UPPER_BOUND: Option> = I::UPPER_BOUND; -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for FilterMap { - const UPPER_BOUND: Option> = I::UPPER_BOUND; -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for Map { - const UPPER_BOUND: Option> = I::UPPER_BOUND; -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for Copied { - const UPPER_BOUND: Option> = I::UPPER_BOUND; -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl BoundedSize for Cloned { - const UPPER_BOUND: Option> = I::UPPER_BOUND; -} - /// An iterator that flattens one level of nesting in an iterator of things /// that can be turned into iterators. /// From f1010442cc650aba832a11b95a2b1a75f23cdf0e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 4 Feb 2025 15:15:28 +0100 Subject: [PATCH 002/546] intrinsics: unify rint, roundeven, nearbyint in a single round_ties_even intrinsic --- src/intrinsics/mod.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 26f14532b458..4d9bed8652cb 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -340,14 +340,10 @@ fn codegen_float_intrinsic_call<'tcx>( sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64, types::F64), sym::truncf32 => ("truncf", 1, fx.tcx.types.f32, types::F32), sym::truncf64 => ("trunc", 1, fx.tcx.types.f64, types::F64), - sym::rintf32 => ("rintf", 1, fx.tcx.types.f32, types::F32), - sym::rintf64 => ("rint", 1, fx.tcx.types.f64, types::F64), + sym::round_ties_even_f32 => ("rintf", 1, fx.tcx.types.f32, types::F32), + sym::round_ties_even_f64 => ("rint", 1, fx.tcx.types.f64, types::F64), sym::roundf32 => ("roundf", 1, fx.tcx.types.f32, types::F32), sym::roundf64 => ("round", 1, fx.tcx.types.f64, types::F64), - sym::roundevenf32 => ("roundevenf", 1, fx.tcx.types.f32, types::F32), - sym::roundevenf64 => ("roundeven", 1, fx.tcx.types.f64, types::F64), - sym::nearbyintf32 => ("nearbyintf", 1, fx.tcx.types.f32, types::F32), - sym::nearbyintf64 => ("nearbyint", 1, fx.tcx.types.f64, types::F64), sym::sinf32 => ("sinf", 1, fx.tcx.types.f32, types::F32), sym::sinf64 => ("sin", 1, fx.tcx.types.f64, types::F64), sym::cosf32 => ("cosf", 1, fx.tcx.types.f32, types::F32), @@ -399,8 +395,8 @@ fn codegen_float_intrinsic_call<'tcx>( | sym::ceilf64 | sym::truncf32 | sym::truncf64 - | sym::nearbyintf32 - | sym::nearbyintf64 + | sym::round_ties_even_f32 + | sym::round_ties_even_f64 | sym::sqrtf32 | sym::sqrtf64 => { let val = match intrinsic { @@ -408,7 +404,9 @@ fn codegen_float_intrinsic_call<'tcx>( sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]), sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]), sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]), - sym::nearbyintf32 | sym::nearbyintf64 => fx.bcx.ins().nearest(args[0]), + sym::round_ties_even_f32 | sym::round_ties_even_f64 => { + fx.bcx.ins().nearest(args[0]) + } sym::sqrtf32 | sym::sqrtf64 => fx.bcx.ins().sqrt(args[0]), _ => unreachable!(), }; From 0b90953a2d35b1886829fb8ec986d59d337f9c3a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Feb 2025 14:13:01 +0000 Subject: [PATCH 003/546] Merge commit '557ed8ebb7e981817d03c87352892c394183dd70' into sync_cg_clif-2025-02-15 --- .github/workflows/main.yml | 4 ++-- rust-toolchain | 2 +- rustfmt.toml | 3 ++- src/abi/pass_mode.rs | 2 +- src/common.rs | 7 ++++++- src/debuginfo/mod.rs | 2 +- src/debuginfo/types.rs | 4 ++-- src/inline_asm.rs | 3 ++- src/value_and_place.rs | 6 +++--- 9 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a8333df77e6e..61a4c1270c99 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -188,8 +188,8 @@ jobs: fail-fast: false matrix: include: - # FIXME update at some point in the future once most distros use a newer glibc - - os: ubuntu-20.04 + # Intentionally using an older ubuntu version to lower the glibc requirements of the distributed cg_clif + - os: ubuntu-22.04 env: TARGET_TRIPLE: x86_64-unknown-linux-gnu - os: macos-latest diff --git a/rust-toolchain b/rust-toolchain index 8d423319fa97..481903c6afb2 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-02-07" +channel = "nightly-2025-02-15" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/rustfmt.toml b/rustfmt.toml index d9e6ac3d543c..f31fa9c76abc 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -3,8 +3,9 @@ ignore = [ ] # Matches rustfmt.toml of rustc -version = "Two" +style_edition = "2024" use_small_heuristics = "Max" merge_derives = false group_imports = "StdExternalCrate" imports_granularity = "Module" +use_field_init_shorthand = true diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 7594a53fc758..b28c4c9539ce 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -195,7 +195,7 @@ pub(super) fn from_casted_value<'tcx>( // It may also be smaller for example when the type is a wrapper around an integer with a // larger alignment than the integer. std::cmp::max(abi_param_size, layout_size), - u32::try_from(layout.align.pref.bytes()).unwrap(), + u32::try_from(layout.align.abi.bytes()).unwrap(), ); let mut offset = 0; let mut block_params_iter = block_params.iter().copied(); diff --git a/src/common.rs b/src/common.rs index 534557fcd41b..766278d87183 100644 --- a/src/common.rs +++ b/src/common.rs @@ -382,6 +382,11 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { } pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer { + assert!( + size % align == 0, + "size must be a multiple of alignment (size={size}, align={align})" + ); + let abi_align = if self.tcx.sess.target.arch == "s390x" { 8 } else { 16 }; if align <= abi_align { let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData { @@ -403,7 +408,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { align_shift: 4, }); let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0); - let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align)); + let misalign_offset = self.bcx.ins().band_imm(base_ptr, i64::from(align - 1)); let realign_offset = self.bcx.ins().irsub_imm(misalign_offset, i64::from(align)); Pointer::new(self.bcx.ins().iadd(base_ptr, realign_offset)) } diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index f3a8623e2161..bba6567774d7 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -304,7 +304,7 @@ impl DebugContext { entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); - entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.pref.bytes())); + entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.abi.bytes())); let mut expr = Expression::new(); expr.op_addr(address_for_data(data_id)); diff --git a/src/debuginfo/types.rs b/src/debuginfo/types.rs index a2f6691cdd23..017d7784dc03 100644 --- a/src/debuginfo/types.rs +++ b/src/debuginfo/types.rs @@ -166,7 +166,7 @@ impl DebugContext { let tuple_entry = self.dwarf.unit.get_mut(tuple_type_id); tuple_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); tuple_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes())); - tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.pref.bytes())); + tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.abi.bytes())); for (i, (ty, dw_ty)) in components.into_iter().enumerate() { let member_id = self.dwarf.unit.add(tuple_type_id, gimli::DW_TAG_member); @@ -179,7 +179,7 @@ impl DebugContext { member_entry.set( gimli::DW_AT_alignment, AttributeValue::Udata( - FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.pref.bytes(), + FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.abi.bytes(), ), ); member_entry.set( diff --git a/src/inline_asm.rs b/src/inline_asm.rs index f2b0ec977c63..310b226814d4 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -871,7 +871,8 @@ fn call_inline_asm<'tcx>( inputs: Vec<(Size, Value)>, outputs: Vec<(Size, CPlace<'tcx>)>, ) { - let stack_slot = fx.create_stack_slot(u32::try_from(slot_size.bytes()).unwrap(), 16); + let stack_slot = + fx.create_stack_slot(u32::try_from(slot_size.bytes().next_multiple_of(16)).unwrap(), 16); let inline_asm_func = fx .module diff --git a/src/value_and_place.rs b/src/value_and_place.rs index c17d1f30fbe3..a9b8e1bd3935 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -101,7 +101,7 @@ impl<'tcx> CValue<'tcx> { /// The is represented by a dangling pointer of suitable alignment. pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> { assert!(layout.is_zst()); - CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout) + CValue::by_ref(crate::Pointer::dangling(layout.align.abi), layout) } pub(crate) fn layout(&self) -> TyAndLayout<'tcx> { @@ -392,7 +392,7 @@ impl<'tcx> CPlace<'tcx> { assert!(layout.is_sized()); if layout.size.bytes() == 0 { return CPlace { - inner: CPlaceInner::Addr(Pointer::dangling(layout.align.pref), None), + inner: CPlaceInner::Addr(Pointer::dangling(layout.align.abi), None), layout, }; } @@ -405,7 +405,7 @@ impl<'tcx> CPlace<'tcx> { let stack_slot = fx.create_stack_slot( u32::try_from(layout.size.bytes()).unwrap(), - u32::try_from(layout.align.pref.bytes()).unwrap(), + u32::try_from(layout.align.abi.bytes()).unwrap(), ); CPlace { inner: CPlaceInner::Addr(stack_slot, None), layout } } From b141440f8621e238941f1b79a4e9ea7bcd9c38bc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 3 Feb 2025 10:45:49 +1100 Subject: [PATCH 004/546] Move some `Map` methods onto `TyCtxt`. The end goal is to eliminate `Map` altogether. I added a `hir_` prefix to all of them, that seemed simplest. The exceptions are `module_items` which became `hir_module_free_items` because there was already a `hir_module_items`, and `items` which became `hir_free_items` for consistency with `hir_module_free_items`. --- src/driver/jit.rs | 2 +- src/global_asm.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 2e713171ae06..57c88f4b0f9f 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -124,7 +124,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec< crate::constant::codegen_static(tcx, &mut jit_module, def_id); } MonoItem::GlobalAsm(item_id) => { - let item = tcx.hir().item(item_id); + let item = tcx.hir_item(item_id); tcx.dcx().span_fatal(item.span, "Global asm is not supported in JIT mode"); } } diff --git a/src/global_asm.rs b/src/global_asm.rs index c0a3ce84d529..54745b0d8c10 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -15,7 +15,7 @@ use rustc_target::asm::InlineAsmArch; use crate::prelude::*; pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { - let item = tcx.hir().item(item_id); + let item = tcx.hir_item(item_id); if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind { let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); From 44af9d30ff49f0d9fa360222a5a8f68c1a42877b Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 11 Feb 2025 22:33:18 -0800 Subject: [PATCH 005/546] cg_clif: use exclusively ABI alignment --- src/abi/comments.rs | 5 ++--- src/constant.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/abi/comments.rs b/src/abi/comments.rs index 521a250ab82c..e2c9f40d1479 100644 --- a/src/abi/comments.rs +++ b/src/abi/comments.rs @@ -65,7 +65,7 @@ pub(super) fn add_locals_header_comment(fx: &mut FunctionCx<'_, '_, '_>) { if fx.clif_comments.enabled() { fx.add_global_comment(String::new()); fx.add_global_comment( - "kind local ty size align (abi,pref)".to_string(), + "kind local ty size align (abi)".to_string(), ); } } @@ -84,13 +84,12 @@ pub(super) fn add_local_place_comments<'tcx>( let (kind, extra) = place.debug_comment(); fx.add_global_comment(format!( - "{:<5} {:5} {:30} {:4}b {}, {}{}{}", + "{:<5} {:5} {:30} {:4}b {}, {}{}", kind, format!("{:?}", local), format!("{:?}", ty), size.bytes(), align.abi.bytes(), - align.pref.bytes(), if extra.is_empty() { "" } else { " " }, extra, )); diff --git a/src/constant.rs b/src/constant.rs index 425b2adf32a3..bcc70f4567fb 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -272,7 +272,7 @@ fn data_id_for_static( .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .unwrap() .align - .pref + .abi .bytes(); let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak From 616fe134c258e0aa4e139a2caf3280a4249a66b4 Mon Sep 17 00:00:00 2001 From: Jubilee Date: Tue, 18 Feb 2025 01:29:23 -0800 Subject: [PATCH 006/546] cg_clif: Tweak formatting of global comments Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- src/abi/comments.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/abi/comments.rs b/src/abi/comments.rs index e2c9f40d1479..c74efeb59f3f 100644 --- a/src/abi/comments.rs +++ b/src/abi/comments.rs @@ -84,13 +84,13 @@ pub(super) fn add_local_place_comments<'tcx>( let (kind, extra) = place.debug_comment(); fx.add_global_comment(format!( - "{:<5} {:5} {:30} {:4}b {}, {}{}", + "{:<5} {:5} {:30} {:4}b {}{}{}", kind, format!("{:?}", local), format!("{:?}", ty), size.bytes(), align.abi.bytes(), - if extra.is_empty() { "" } else { " " }, + if extra.is_empty() { "" } else { " " }, extra, )); } From 3fc1a5852193e6be4d9ef3d05f70ac167eb31091 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 19 Feb 2025 09:25:24 +0000 Subject: [PATCH 007/546] Rustup to rustc 1.87.0-nightly (827a0d638 2025-02-18) --- patches/coretests-lock.toml | 75 +++++++++++++++++++++++++++++++++---- rust-toolchain | 2 +- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/patches/coretests-lock.toml b/patches/coretests-lock.toml index af8f28a193bc..bb7f519f7a7c 100644 --- a/patches/coretests-lock.toml +++ b/patches/coretests-lock.toml @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "coretests" @@ -11,25 +11,84 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.8.5" +name = "proc-macro2" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_core", + "zerocopy", ] [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" +dependencies = [ + "zerocopy", +] [[package]] name = "rand_xorshift" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ "rand_core", ] + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" + +[[package]] +name = "zerocopy" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/rust-toolchain b/rust-toolchain index 481903c6afb2..854ca5db8011 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-02-15" +channel = "nightly-2025-02-19" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 410a68a907b14db7eaa2152eccbbcef9ae357f7c Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 25 Jan 2025 20:15:24 -0600 Subject: [PATCH 008/546] Remove `BackendRepr::Uninhabited`, replaced with an `uninhabited: bool` field in `LayoutData`. Also update comments that refered to BackendRepr::Uninhabited. --- src/value_and_place.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index a9b8e1bd3935..1b3f86c8405d 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -638,9 +638,7 @@ impl<'tcx> CPlace<'tcx> { } CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self), CPlaceInner::Addr(to_ptr, None) => { - if dst_layout.size == Size::ZERO - || dst_layout.backend_repr == BackendRepr::Uninhabited - { + if dst_layout.size == Size::ZERO { return; } From 8622c818e2474b1973cce49b11c4826c2d3f93d9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 22:25:23 +0000 Subject: [PATCH 009/546] Use `public-dependencies` in all sysroot crates In [1], most dependencies of `std` and other sysroot crates were marked private, but this did not happen for `alloc` and `test`. Update these here, marking public standard library crates as the only non-private dependencies. [1]: https://github.com/rust-lang/rust/pull/111076 --- .../0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index e3a9512dda9c..eb1fc4b0ad59 100644 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -15,7 +15,7 @@ index 7165c3e48af..968552ad435 100644 edition = "2021" [dependencies] - core = { path = "../core" } + core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std', 'no-f16-f128'] } From 9dd86e64cc19d24d5e62a028cae4515a1fbe95c2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 17 Feb 2025 05:33:06 +0000 Subject: [PATCH 010/546] Make asm a named field --- src/global_asm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/global_asm.rs b/src/global_asm.rs index 54745b0d8c10..0a23f63d6ba9 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -16,7 +16,7 @@ use crate::prelude::*; pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { let item = tcx.hir_item(item_id); - if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind { + if let rustc_hir::ItemKind::GlobalAsm { asm } = item.kind { let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); From ea760dd09911d5bd73fd8a4321f319620e0cc53a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 17 Feb 2025 16:09:46 +0000 Subject: [PATCH 011/546] Make a fake body to store typeck results for global_asm --- src/global_asm.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/global_asm.rs b/src/global_asm.rs index 0a23f63d6ba9..9ea92c300f89 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -16,7 +16,7 @@ use crate::prelude::*; pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { let item = tcx.hir_item(item_id); - if let rustc_hir::ItemKind::GlobalAsm { asm } = item.kind { + if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind { let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); @@ -55,7 +55,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, } } } - InlineAsmOperand::SymFn { anon_const } => { + InlineAsmOperand::SymFn { expr } => { if cfg!(not(feature = "inline_asm_sym")) { tcx.dcx().span_err( item.span, @@ -63,7 +63,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, ); } - let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); + let ty = tcx.typeck(item_id.owner_id).expr_ty(expr); let instance = match ty.kind() { &ty::FnDef(def_id, args) => Instance::new(def_id, args), _ => span_bug!(op_sp, "asm sym is not a function"), From 5ff55a4783e09ce3eda33e0db0a419c15a7f8b00 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 11:42:10 +0000 Subject: [PATCH 012/546] Rustup to rustc 1.87.0-nightly (794c12416 2025-02-21) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 854ca5db8011..1017b9550d03 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-02-19" +channel = "nightly-2025-02-22" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From c7b251e09e097a9b33bcaf5ae677ac641da9a360 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Feb 2025 20:17:02 -0500 Subject: [PATCH 013/546] Update `compiler-builtins` to 0.1.147 Removes an ABI hack that used `<2 x i64>` to return `i128` in `xmm0` on Windows [1]. [1]: https://github.com/rust-lang/compiler-builtins/pull/759 Link: https://github.com/rust-lang/rust/issues/116558 Link: https://github.com/rust-lang/compiler-builtins/issues/758 --- ...029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index eb1fc4b0ad59..364a6a035ab8 100644 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644 [dependencies] core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std', 'no-f16-f128'] } +-compiler_builtins = { version = "=0.1.147", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.147", features = ['rustc-dep-of-std', 'no-f16-f128'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } From 447d85845de2dc68ec366c27cb1d1b65a1ba6e75 Mon Sep 17 00:00:00 2001 From: DianQK Date: Sun, 17 Nov 2024 14:21:23 +0800 Subject: [PATCH 014/546] The embedded bitcode should always be prepared for LTO/ThinLTO --- src/driver/aot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index a52b18573b15..366e83853e51 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -210,7 +210,7 @@ fn produce_final_output_artifacts( // to get rid of it. for output_type in crate_output.outputs.keys() { match *output_type { - OutputType::Bitcode | OutputType::ThinLinkBitcode => { + OutputType::Bitcode | OutputType::ThinLinkBitcode | OutputType::ThinBitcode => { // Cranelift doesn't have bitcode // user_wants_bitcode = true; // // Copy to .bc, but always keep the .0.bc. There is a later From 016f429c56992f2d62717fe2b6554ca4c4dd1f4a Mon Sep 17 00:00:00 2001 From: DianQK Date: Thu, 6 Feb 2025 22:01:08 +0800 Subject: [PATCH 015/546] Remove unused `OutputType::ThinLinkBitcode` --- src/driver/aot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 366e83853e51..a52b18573b15 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -210,7 +210,7 @@ fn produce_final_output_artifacts( // to get rid of it. for output_type in crate_output.outputs.keys() { match *output_type { - OutputType::Bitcode | OutputType::ThinLinkBitcode | OutputType::ThinBitcode => { + OutputType::Bitcode | OutputType::ThinLinkBitcode => { // Cranelift doesn't have bitcode // user_wants_bitcode = true; // // Copy to .bc, but always keep the .0.bc. There is a later From 63a3ab4fae27ffc6af807598a5634546f9c05a9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 02:47:59 +0000 Subject: [PATCH 016/546] Add a span to `CompilerBuiltinsCannotCall` Currently, this error emit a diagnostic with no context like: error: `compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from ` as core::fmt::LowerHex>::fmt` to `core::fmt::num::::fmt` With this change, it at least usually points to the problematic function: error: `compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from ` as core::fmt::LowerHex>::fmt` to `core::fmt::num::::fmt` --> src/../libm/src/math/support/hex_float.rs:270:5 | 270 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | --- src/abi/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 756a2226753f..e8076ce77abc 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -402,9 +402,13 @@ pub(crate) fn codegen_terminator_call<'tcx>( if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) { if target.is_some() { - let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id())); - let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)); - fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee }); + let caller_def = fx.instance.def_id(); + let e = CompilerBuiltinsCannotCall { + span: fx.tcx.def_span(caller_def), + caller: with_no_trimmed_paths!(fx.tcx.def_path_str(caller_def)), + callee: with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)), + }; + fx.tcx.dcx().emit_err(e); } else { fx.bcx.ins().trap(TrapCode::user(2).unwrap()); return; From 957389c196d744a68c51dd265e6ec63f984f80a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2025 17:34:50 +0100 Subject: [PATCH 017/546] remove support for rustc_intrinsic_must_be_overridden from the compiler --- example/mini_core.rs | 65 +++++++++----------------------------------- 1 file changed, 13 insertions(+), 52 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 79820232496a..72c9df59d833 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -620,70 +620,31 @@ pub union MaybeUninit { pub mod intrinsics { #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn size_of() -> usize { - loop {} - } + pub fn size_of() -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn size_of_val(_val: *const T) -> usize { - loop {} - } + pub unsafe fn size_of_val(_val: *const T) -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn min_align_of() -> usize { - loop {} - } + pub fn min_align_of() -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn min_align_of_val(_val: *const T) -> usize { - loop {} - } + pub unsafe fn min_align_of_val(_val: *const T) -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize) { - loop {} - } + pub unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize); #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn transmute(_e: T) -> U { - loop {} - } + pub unsafe fn transmute(_e: T) -> U; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn ctlz_nonzero(_x: T) -> u32 { - loop {} - } + pub unsafe fn ctlz_nonzero(_x: T) -> u32; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn needs_drop() -> bool { - loop {} - } + pub fn needs_drop() -> bool; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn bitreverse(_x: T) -> T { - loop {} - } + pub fn bitreverse(_x: T) -> T; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn bswap(_x: T) -> T { - loop {} - } + pub fn bswap(_x: T) -> T; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize) { - loop {} - } + pub unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize); #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn unreachable() -> ! { - loop {} - } + pub unsafe fn unreachable() -> !; } pub mod libc { From be4eb9a3aa976e864d69f7c361cca8779c8d09f7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 07:46:55 +0000 Subject: [PATCH 018/546] Update `compiler-builtins` to 0.1.148 Includes `f16` symbols on MIPS [1], updates for `libm` [2], and reapplies the patch that drops the `public_test_deps!` macro [3]. [1]: https://github.com/rust-lang/compiler-builtins/pull/762 [2]: https://github.com/rust-lang/compiler-builtins/pull/765 [3]: https://github.com/rust-lang/compiler-builtins/pull/766 --- ...029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index 364a6a035ab8..bedc6ca11b3f 100644 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644 [dependencies] core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.147", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.147", features = ['rustc-dep-of-std', 'no-f16-f128'] } +-compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std', 'no-f16-f128'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } From fb85ef70fc599827ed520df32eb486b0d80ce29e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 24 Feb 2025 14:21:50 +0000 Subject: [PATCH 019/546] Rustup to rustc 1.87.0-nightly (f8a913b13 2025-02-23) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 1017b9550d03..94b1403e47c1 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-02-22" +channel = "nightly-2025-02-24" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From ae5f2c2d5cd7734d77c9b87de272b96783e5e18b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 24 Feb 2025 14:35:19 +0000 Subject: [PATCH 020/546] Fix rustc test suite --- scripts/test_rustc_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 55230a0b5988..599ce63bab56 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -57,7 +57,6 @@ rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes rm -r tests/run-make/embed-source-dwarf # embedding sources in debuginfo -rm tests/ui/simd-abi-checks.rs # vector types >128bits not yet supported # requires LTO rm -r tests/run-make/cdylib @@ -120,6 +119,7 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift +rm tests/ui/abi/simd-abi-checks-avx.rs # attempts to declare function with two different signatures # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended From a91db48ecf32f3e4c188679aee9897e107d31295 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2025 19:10:55 +0100 Subject: [PATCH 021/546] =?UTF-8?q?rename=20simd=5Fshuffle=5Fgeneric=20?= =?UTF-8?q?=E2=86=92=20simd=5Fshuffle=5Fconst=5Fgeneric?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/intrinsics/simd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index fcccda62355c..0929218ea2b2 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -116,8 +116,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - // simd_shuffle_generic(x: T, y: T) -> U - sym::simd_shuffle_generic => { + // simd_shuffle_const_generic(x: T, y: T) -> U + sym::simd_shuffle_const_generic => { let [x, y] = args else { bug!("wrong number of args for intrinsic {intrinsic}"); }; From cae7c76d509386ea29a90c4001bb8dbc59c79d22 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 28 Jul 2024 16:54:14 -0400 Subject: [PATCH 022/546] Avoid no-op unlink+link dances in incr comp --- .../rustc_codegen_cranelift/src/driver/aot.rs | 8 ++++- compiler/rustc_codegen_ssa/src/back/write.rs | 21 ++++++++---- compiler/rustc_codegen_ssa/src/base.rs | 1 + compiler/rustc_codegen_ssa/src/lib.rs | 2 ++ compiler/rustc_fs_util/src/lib.rs | 32 +++++++++++-------- .../src/persist/work_product.rs | 7 +++- 6 files changed, 50 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index a52b18573b15..d1843f90a07d 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -103,12 +103,14 @@ impl OngoingCodegen { ("o", &module_regular.object.as_ref().unwrap()), ("asm.o", &module_global_asm.object.as_ref().unwrap()), ], + &[], ) } else { rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( sess, &module_regular.name, &[("o", &module_regular.object.as_ref().unwrap())], + &[], ) }; if let Some((work_product_id, work_product)) = work_product { @@ -381,6 +383,7 @@ fn emit_cgu( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), }), existing_work_product: None, }) @@ -437,6 +440,7 @@ fn emit_module( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), }) } @@ -487,6 +491,7 @@ fn reuse_workproduct_for_cgu( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), }, module_global_asm: has_global_asm.then(|| CompiledModule { name: cgu.name().to_string(), @@ -496,6 +501,7 @@ fn reuse_workproduct_for_cgu( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), }), existing_work_product: Some((cgu.work_product_id(), work_product)), }) @@ -637,6 +643,7 @@ fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> Compiled bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), } } @@ -745,7 +752,6 @@ pub(crate) fn run_aot( let metadata_module = if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None }; - Box::new(OngoingCodegen { modules, allocator_module, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index f008bd12ed8f..b8dc6f93349b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -540,9 +540,12 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( if let Some(path) = &module.bytecode { files.push((OutputType::Bitcode.extension(), path.as_path())); } - if let Some((id, product)) = - copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice()) - { + if let Some((id, product)) = copy_cgu_workproduct_to_incr_comp_cache_dir( + sess, + &module.name, + files.as_slice(), + &module.links_from_incr_cache, + ) { work_products.insert(id, product); } } @@ -934,7 +937,9 @@ fn execute_copy_from_cache_work_item( ) -> WorkItemResult { let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); - let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| { + let mut links_from_incr_cache = Vec::new(); + + let mut load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| { let source_file = in_incr_comp_dir(incr_comp_session_dir, saved_path); debug!( "copying preexisting module `{}` from {:?} to {}", @@ -943,7 +948,10 @@ fn execute_copy_from_cache_work_item( output_path.display() ); match link_or_copy(&source_file, &output_path) { - Ok(_) => Some(output_path), + Ok(_) => { + links_from_incr_cache.push(source_file); + Some(output_path) + } Err(error) => { cgcx.create_dcx().handle().emit_err(errors::CopyPathBuf { source_file, @@ -966,7 +974,7 @@ fn execute_copy_from_cache_work_item( load_from_incr_comp_dir(dwarf_obj_out, saved_dwarf_object_file) }); - let load_from_incr_cache = |perform, output_type: OutputType| { + let mut load_from_incr_cache = |perform, output_type: OutputType| { if perform { let saved_file = module.source.saved_files.get(output_type.extension())?; let output_path = cgcx.output_filenames.temp_path(output_type, Some(&module.name)); @@ -986,6 +994,7 @@ fn execute_copy_from_cache_work_item( } WorkItemResult::Finished(CompiledModule { + links_from_incr_cache, name: module.name, kind: ModuleKind::Regular, object, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 40238f4b4915..e4db2bed9e8d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -656,6 +656,7 @@ pub fn codegen_crate( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), } }) }); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 9d2ac219d592..7ff97f127e03 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -102,6 +102,7 @@ impl ModuleCodegen { bytecode, assembly, llvm_ir, + links_from_incr_cache: Vec::new(), } } } @@ -115,6 +116,7 @@ pub struct CompiledModule { pub bytecode: Option, pub assembly: Option, // --emit=asm pub llvm_ir: Option, // --emit=llvm-ir, llvm-bc is in bytecode + pub links_from_incr_cache: Vec, } impl CompiledModule { diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 4e9d21c900df..0df1b243d697 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -55,25 +55,31 @@ pub enum LinkOrCopy { Copy, } -/// Copies `p` into `q`, preferring to use hard-linking if possible. If -/// `q` already exists, it is removed first. +/// Copies `p` into `q`, preferring to use hard-linking if possible. /// The result indicates which of the two operations has been performed. pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result { + // Creating a hard-link will fail if the destination path already exists. We could defensively + // call remove_file in this function, but that pessimizes callers who can avoid such calls. + // Incremental compilation calls this function a lot, and is able to avoid calls that + // would fail the first hard_link attempt. + let p = p.as_ref(); let q = q.as_ref(); - match fs::remove_file(q) { - Ok(()) => (), - Err(err) if err.kind() == io::ErrorKind::NotFound => (), - Err(err) => return Err(err), + + let err = match fs::hard_link(p, q) { + Ok(()) => return Ok(LinkOrCopy::Link), + Err(err) => err, + }; + + if err.kind() == io::ErrorKind::AlreadyExists { + fs::remove_file(q)?; + if fs::hard_link(p, q).is_ok() { + return Ok(LinkOrCopy::Link); + } } - match fs::hard_link(p, q) { - Ok(()) => Ok(LinkOrCopy::Link), - Err(_) => match fs::copy(p, q) { - Ok(_) => Ok(LinkOrCopy::Copy), - Err(e) => Err(e), - }, - } + // Hard linking failed, fall back to copying. + fs::copy(p, q).map(|_| LinkOrCopy::Copy) } #[cfg(any(unix, all(target_os = "wasi", target_env = "p1")))] diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs index 048981f0d5ce..7b1eb0a82e39 100644 --- a/compiler/rustc_incremental/src/persist/work_product.rs +++ b/compiler/rustc_incremental/src/persist/work_product.rs @@ -3,7 +3,7 @@ //! [work products]: WorkProduct use std::fs as std_fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use rustc_data_structures::unord::UnordMap; use rustc_fs_util::link_or_copy; @@ -20,6 +20,7 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir( sess: &Session, cgu_name: &str, files: &[(&'static str, &Path)], + known_links: &[PathBuf], ) -> Option<(WorkProductId, WorkProduct)> { debug!(?cgu_name, ?files); sess.opts.incremental.as_ref()?; @@ -28,6 +29,10 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir( for (ext, path) in files { let file_name = format!("{cgu_name}.{ext}"); let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name); + if known_links.contains(&path_in_incr_dir) { + let _ = saved_files.insert(ext.to_string(), file_name); + continue; + } match link_or_copy(path, &path_in_incr_dir) { Ok(_) => { let _ = saved_files.insert(ext.to_string(), file_name); From 12f7ae1ebbfcbe9ab38c92b95b9306312fbef720 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 28 Jul 2024 16:54:14 -0400 Subject: [PATCH 023/546] Avoid no-op unlink+link dances in incr comp --- src/driver/aot.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index a52b18573b15..d1843f90a07d 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -103,12 +103,14 @@ impl OngoingCodegen { ("o", &module_regular.object.as_ref().unwrap()), ("asm.o", &module_global_asm.object.as_ref().unwrap()), ], + &[], ) } else { rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( sess, &module_regular.name, &[("o", &module_regular.object.as_ref().unwrap())], + &[], ) }; if let Some((work_product_id, work_product)) = work_product { @@ -381,6 +383,7 @@ fn emit_cgu( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), }), existing_work_product: None, }) @@ -437,6 +440,7 @@ fn emit_module( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), }) } @@ -487,6 +491,7 @@ fn reuse_workproduct_for_cgu( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), }, module_global_asm: has_global_asm.then(|| CompiledModule { name: cgu.name().to_string(), @@ -496,6 +501,7 @@ fn reuse_workproduct_for_cgu( bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), }), existing_work_product: Some((cgu.work_product_id(), work_product)), }) @@ -637,6 +643,7 @@ fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> Compiled bytecode: None, assembly: None, llvm_ir: None, + links_from_incr_cache: Vec::new(), } } @@ -745,7 +752,6 @@ pub(crate) fn run_aot( let metadata_module = if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None }; - Box::new(OngoingCodegen { modules, allocator_module, From 143cf8da3dbf7d3a7d5a16766d48058bec8a299d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 25 Feb 2025 09:20:10 +0100 Subject: [PATCH 024/546] remove `simd_fpow` and `simd_fpowi` --- src/intrinsics/simd.rs | 58 ------------------------------------------ 1 file changed, 58 deletions(-) diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index fcccda62355c..0c13fa91f7a7 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -460,64 +460,6 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - sym::simd_fpow => { - intrinsic_args!(fx, args => (a, b); intrinsic); - - if !a.layout().ty.is_simd() { - report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); - return; - } - - simd_pair_for_each_lane(fx, a, b, ret, &|fx, lane_ty, _ret_lane_ty, a_lane, b_lane| { - match lane_ty.kind() { - ty::Float(FloatTy::F32) => fx.lib_call( - "powf", - vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], - vec![AbiParam::new(types::F32)], - &[a_lane, b_lane], - )[0], - ty::Float(FloatTy::F64) => fx.lib_call( - "pow", - vec![AbiParam::new(types::F64), AbiParam::new(types::F64)], - vec![AbiParam::new(types::F64)], - &[a_lane, b_lane], - )[0], - _ => unreachable!("{:?}", lane_ty), - } - }); - } - - sym::simd_fpowi => { - intrinsic_args!(fx, args => (a, exp); intrinsic); - let exp = exp.load_scalar(fx); - - if !a.layout().ty.is_simd() { - report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); - return; - } - - simd_for_each_lane( - fx, - a, - ret, - &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() { - ty::Float(FloatTy::F32) => fx.lib_call( - "__powisf2", // compiler-builtins - vec![AbiParam::new(types::F32), AbiParam::new(types::I32)], - vec![AbiParam::new(types::F32)], - &[lane, exp], - )[0], - ty::Float(FloatTy::F64) => fx.lib_call( - "__powidf2", // compiler-builtins - vec![AbiParam::new(types::F64), AbiParam::new(types::I32)], - vec![AbiParam::new(types::F64)], - &[lane, exp], - )[0], - _ => unreachable!("{:?}", lane_ty), - }, - ); - } - sym::simd_fsin | sym::simd_fcos | sym::simd_fexp From 94ac6e557f5ea35aee52089f66a20f3ae9230bc8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:07:50 +0000 Subject: [PATCH 025/546] Update to Cranelift 0.117 --- Cargo.lock | 89 ++++++++++++++++++++++++++++++------------------------ Cargo.toml | 24 +++++++-------- 2 files changed, 62 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca66ec5c6e93..011e291cd203 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,27 +42,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cranelift-bforest" -version = "0.116.1" +name = "cranelift-assembler-x64" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +checksum = "d2b83fcf2fc1c8954561490d02079b496fd0c757da88129981e15bfe3a548229" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.117.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7496a6e92b5cee48c5d772b0443df58816dee30fed6ba19b2a28e78037ecedf" + +[[package]] +name = "cranelift-bforest" +version = "0.117.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73a9dc0a8d3d49ee772101924968830f1c1937d650c571d3c2dd69dc36a68f41" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" +checksum = "573c641174c40ef31021ae4a5a3ad78974e280633502d0dfc6e362385e0c100f" [[package]] name = "cranelift-codegen" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +checksum = "2d7c94d572615156f2db682181cadbd96342892c31e08cc26a757344319a9220" dependencies = [ "bumpalo", + "cranelift-assembler-x64", "cranelift-bforest", "cranelift-bitset", "cranelift-codegen-meta", @@ -71,7 +87,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.14.5", + "hashbrown", "log", "regalloc2", "rustc-hash", @@ -82,42 +98,43 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +checksum = "beecd9fcf2c3e06da436d565de61a42676097ea6eb6b4499346ac6264b6bb9ce" dependencies = [ + "cranelift-assembler-x64", "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" +checksum = "0f4ff8d2e1235f2d6e7fc3c6738be6954ba972cd295f09079ebffeca2f864e22" [[package]] name = "cranelift-control" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +checksum = "001312e9fbc7d9ca9517474d6fe71e29d07e52997fd7efe18f19e8836446ceb2" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +checksum = "eb0fd6d4aae680275fcbceb08683416b744e65c8b607352043d3f0951d72b3b2" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fac41e16729107393174b0c9e3730fb072866100e1e64e80a1a963b2e484d57" +checksum = "9fd44e7e5dcea20ca104d45894748205c51365ce4cdb18f4418e3ba955971d1b" dependencies = [ "cranelift-codegen", "log", @@ -127,15 +144,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" +checksum = "f900e0a3847d51eed0321f0777947fb852ccfce0da7fb070100357f69a2f37fc" [[package]] name = "cranelift-jit" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e65c42755a719b09662b00c700daaf76cc35d5ace1f5c002ad404b591ff1978" +checksum = "55e37088dec72b7819f980558faaba9215d248fec4a2c3b89357b474f9e46f21" dependencies = [ "anyhow", "cranelift-codegen", @@ -153,9 +170,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d55612bebcf16ff7306c8a6f5bdb6d45662b8aa1ee058ecce8807ad87db719b" +checksum = "e9c3d728819ff644e8613d808378cbfed54fef464790f32e62079e638639eeff" dependencies = [ "anyhow", "cranelift-codegen", @@ -164,9 +181,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7" +checksum = "7617f13f392ebb63c5126258aca8b8eca739636ca7e4eeee301d3eff68489a6a" dependencies = [ "cranelift-codegen", "libc", @@ -175,9 +192,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.116.1" +version = "0.117.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad5a6d3e379493c3f8b35dc61c93d0bf5f27003bbe20614e0200b0ec372ef52" +checksum = "60fc9092f7d9bba17c96ce51de5d91461f7905f3e1c43d1ba965df4b884d16ce" dependencies = [ "anyhow", "cranelift-codegen", @@ -226,12 +243,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashbrown" version = "0.15.2" @@ -248,7 +259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown", ] [[package]] @@ -295,7 +306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", - "hashbrown 0.15.2", + "hashbrown", "indexmap", "memchr", ] @@ -326,7 +337,7 @@ checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.2", + "hashbrown", "log", "rustc-hash", "smallvec", @@ -425,9 +436,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" -version = "29.0.1" +version = "30.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5e8552e01692e6c2e5293171704fed8abdec79d1a6995a0870ab190e5747d1" +checksum = "3f180cc0d2745e3a5df5d02231cd3046f49c75512eaa987b8202363b112e125d" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 670d6f4eef5c..fa3037e77a0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.116.0", default-features = false, features = ["std", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.116.0" } -cranelift-module = { version = "0.116.0" } -cranelift-native = { version = "0.116.0" } -cranelift-jit = { version = "0.116.0", optional = true } -cranelift-object = { version = "0.116.0" } +cranelift-codegen = { version = "0.117.2", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.117.2" } +cranelift-module = { version = "0.117.2" } +cranelift-native = { version = "0.117.2" } +cranelift-jit = { version = "0.117.2", optional = true } +cranelift-object = { version = "0.117.2" } target-lexicon = "0.13" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } From 439062052e9103a6286a4da462303ce56189eaa3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 16 Jan 2025 18:02:21 +0000 Subject: [PATCH 026/546] Test and dist for arm64 linux on CI --- .github/workflows/abi-cafe.yml | 3 +++ .github/workflows/main.yml | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/abi-cafe.yml b/.github/workflows/abi-cafe.yml index 30dc5cb16154..a32a275a027a 100644 --- a/.github/workflows/abi-cafe.yml +++ b/.github/workflows/abi-cafe.yml @@ -25,6 +25,9 @@ jobs: - os: ubuntu-latest env: TARGET_TRIPLE: x86_64-unknown-linux-gnu + - os: ubuntu-24.04-arm + env: + TARGET_TRIPLE: aarch64-unknown-linux-gnu - os: macos-latest env: TARGET_TRIPLE: x86_64-apple-darwin diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 61a4c1270c99..da0f95c77bb8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -53,13 +53,12 @@ jobs: - os: ubuntu-latest env: TARGET_TRIPLE: x86_64-unknown-linux-gnu + - os: ubuntu-24.04-arm + env: + TARGET_TRIPLE: aarch64-unknown-linux-gnu - os: macos-latest env: TARGET_TRIPLE: x86_64-apple-darwin - - os: ubuntu-latest - env: - TARGET_TRIPLE: aarch64-unknown-linux-gnu - apt_deps: gcc-aarch64-linux-gnu qemu-user - os: macos-latest env: TARGET_TRIPLE: aarch64-apple-darwin @@ -192,6 +191,9 @@ jobs: - os: ubuntu-22.04 env: TARGET_TRIPLE: x86_64-unknown-linux-gnu + - os: ubuntu-24.04-arm + env: + TARGET_TRIPLE: aarch64-unknown-linux-gnu - os: macos-latest env: TARGET_TRIPLE: x86_64-apple-darwin From bdcd07466b14db4965536b565c2b6ea5cf4d09d9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:10:43 +0000 Subject: [PATCH 027/546] Use native x86_64 macOS runners for x86_64 builds Rather than running in Rosetta 2. This should make testing on CI faster. --- .github/workflows/main.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index da0f95c77bb8..137504bc0aaa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,7 +56,7 @@ jobs: - os: ubuntu-24.04-arm env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - - os: macos-latest + - os: macos-13 env: TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest @@ -94,10 +94,6 @@ jobs: if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Use x86_64 compiler on macOS - if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' - run: rustup set default-host x86_64-apple-darwin - - name: Install toolchain and emulator if: matrix.apt_deps != null run: | @@ -194,7 +190,7 @@ jobs: - os: ubuntu-24.04-arm env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - - os: macos-latest + - os: macos-13 env: TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest @@ -220,10 +216,6 @@ jobs: if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Use x86_64 compiler on macOS - if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' - run: rustup set default-host x86_64-apple-darwin - - name: Prepare dependencies run: ./y.sh prepare From 2695a19fb0fee087899616fe2f5b87e701732520 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:35:27 +0000 Subject: [PATCH 028/546] Use native x86_64 runners for macOS abi-cafe tests too --- .github/workflows/abi-cafe.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/abi-cafe.yml b/.github/workflows/abi-cafe.yml index a32a275a027a..23e15866f52d 100644 --- a/.github/workflows/abi-cafe.yml +++ b/.github/workflows/abi-cafe.yml @@ -28,7 +28,7 @@ jobs: - os: ubuntu-24.04-arm env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - - os: macos-latest + - os: macos-13 env: TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest @@ -59,10 +59,6 @@ jobs: if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Use x86_64 compiler on macOS - if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' - run: rustup set default-host x86_64-apple-darwin - - name: Prepare dependencies run: ./y.sh prepare From 4698eb627647fe6fb78293024585ef27383e6f5a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:52:47 +0000 Subject: [PATCH 029/546] Rustup to rustc 1.87.0-nightly (85abb2763 2025-02-25) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 94b1403e47c1..86052b4df764 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-02-24" +channel = "nightly-2025-02-26" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From e173b714aa4307d136871025b1ef6e2a409d06ca Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:05:26 +0000 Subject: [PATCH 030/546] You don't need y.sh prepare to build, only to test Also improve the error message when trying to test without having run y.sh prepare first. --- Readme.md | 2 +- build_system/prepare.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 18a840f8a50e..28edb5795ce3 100644 --- a/Readme.md +++ b/Readme.md @@ -49,13 +49,13 @@ If you want to build the backend manually, you can download it from GitHub and b ```bash $ git clone https://github.com/rust-lang/rustc_codegen_cranelift $ cd rustc_codegen_cranelift -$ ./y.sh prepare $ ./y.sh build ``` To run the test suite replace the last command with: ```bash +$ ./y.sh prepare # only needs to be run the first time $ ./test.sh ``` diff --git a/build_system/prepare.rs b/build_system/prepare.rs index 11f73bdb61f9..ba5cc9a29f59 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -91,6 +91,13 @@ impl GitRepo { fn verify_checksum(&self, dirs: &Dirs) { let download_dir = self.download_dir(dirs); + if !download_dir.exists() { + eprintln!( + "Missing directory {download_dir}: Please run ./y.sh prepare to download.", + download_dir = download_dir.display(), + ); + std::process::exit(1); + } let actual_hash = format!("{:016x}", hash_dir(&download_dir)); if actual_hash != self.content_hash { eprintln!( From 994c8cfaf6c3e717365d5484a43bb20090e85460 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:11:44 +0000 Subject: [PATCH 031/546] Skip downloading test crates in CI jobs that don't need them --- .github/workflows/abi-cafe.yml | 3 --- .github/workflows/main.yml | 6 ------ .github/workflows/rustc.yml | 6 ------ 3 files changed, 15 deletions(-) diff --git a/.github/workflows/abi-cafe.yml b/.github/workflows/abi-cafe.yml index 23e15866f52d..6ad041a796c9 100644 --- a/.github/workflows/abi-cafe.yml +++ b/.github/workflows/abi-cafe.yml @@ -59,9 +59,6 @@ jobs: if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Prepare dependencies - run: ./y.sh prepare - - name: Build run: ./y.sh build --sysroot none diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 137504bc0aaa..7d941887100d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -165,9 +165,6 @@ jobs: sudo apt update sudo apt install -y hyperfine - - name: Prepare dependencies - run: ./y.sh prepare - - name: Build run: ./y.sh build --sysroot none @@ -216,9 +213,6 @@ jobs: if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Prepare dependencies - run: ./y.sh prepare - - name: Build backend run: ./y.sh build --sysroot none diff --git a/.github/workflows/rustc.yml b/.github/workflows/rustc.yml index 70c214ce8b14..9253ab96353c 100644 --- a/.github/workflows/rustc.yml +++ b/.github/workflows/rustc.yml @@ -22,9 +22,6 @@ jobs: path: build/cg_clif key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }} - - name: Prepare dependencies - run: ./y.sh prepare - - name: Test run: ./scripts/test_bootstrap.sh @@ -50,8 +47,5 @@ jobs: sudo apt update sudo apt install -y ripgrep - - name: Prepare dependencies - run: ./y.sh prepare - - name: Test run: ./scripts/test_rustc_tests.sh From d27c67c941a0fa14dabfed98b475c8e84ffcc958 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:24:41 +0000 Subject: [PATCH 032/546] Fix FIXME about unversioned macOS target names --- src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a3f437448757..2c019e754460 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,6 @@ use std::sync::Arc; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; use rustc_codegen_ssa::CodegenResults; -use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -247,9 +246,7 @@ fn enable_verifier(sess: &Session) -> bool { } fn target_triple(sess: &Session) -> target_lexicon::Triple { - // FIXME(madsmtm): Use `sess.target.llvm_target` once target-lexicon supports unversioned macOS. - // See - match versioned_llvm_target(sess).parse() { + match sess.target.llvm_target.parse() { Ok(triple) => triple, Err(err) => sess.dcx().fatal(format!("target not recognized: {}", err)), } From 30ece8da06882b9cbca9f7e73f6804c669449a17 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 26 Feb 2025 13:06:01 +0000 Subject: [PATCH 033/546] Make tiny-skia work on arm64 --- src/intrinsics/llvm.rs | 8 +++ src/intrinsics/llvm_aarch64.rs | 119 +++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index 720a0d8fbf59..eb0dfbb69c3b 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -54,6 +54,14 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( ); } + "llvm.fptosi.sat.v4i32.v4f32" => { + intrinsic_args!(fx, args => (a); intrinsic); + + simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| { + fx.bcx.ins().fcvt_to_sint_sat(types::I32, lane) + }); + } + _ => { fx.tcx .dcx() diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index 4c59c81296ba..b77c99fa2896 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -1,5 +1,9 @@ //! Emulate AArch64 LLVM intrinsics +use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_target::asm::*; + +use crate::inline_asm::{CInlineAsmOperand, codegen_inline_asm_inner}; use crate::intrinsics::*; use crate::prelude::*; @@ -49,6 +53,121 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( }); } + "llvm.aarch64.neon.fcvtns.v4i32.v4f32" => { + intrinsic_args!(fx, args => (a); intrinsic); + + // Note: Using inline asm instead of fcvt_to_sint as the latter rounds to zero rather than to nearest + + let a_ptr = a.force_stack(fx).0.get_addr(fx); + let res_place = CPlace::new_stack_slot(fx, ret.layout()); + let res_ptr = res_place.to_ptr().get_addr(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String( + "ldr q0, [x0] + fcvtns v0.4s, v0.4s + str q0, [x1]" + .into(), + )], + &[ + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x0, + )), + value: a_ptr, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x1, + )), + value: res_ptr, + }, + ], + InlineAsmOptions::NOSTACK, + ); + let res = res_place.to_cvalue(fx); + ret.write_cvalue_transmute(fx, res); + } + + "llvm.aarch64.neon.frecpe.v4f32" => { + intrinsic_args!(fx, args => (a); intrinsic); + + let a_ptr = a.force_stack(fx).0.get_addr(fx); + let res_place = CPlace::new_stack_slot(fx, ret.layout()); + let res_ptr = res_place.to_ptr().get_addr(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String( + "ldr q0, [x0] + frecpe v0.4s, v0.4s + str q0, [x1]" + .into(), + )], + &[ + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x0, + )), + value: a_ptr, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x1, + )), + value: res_ptr, + }, + ], + InlineAsmOptions::NOSTACK, + ); + let res = res_place.to_cvalue(fx); + ret.write_cvalue_transmute(fx, res); + } + + "llvm.aarch64.neon.frecps.v4f32" => { + intrinsic_args!(fx, args => (a, b); intrinsic); + + let a_ptr = a.force_stack(fx).0.get_addr(fx); + let b_ptr = b.force_stack(fx).0.get_addr(fx); + let res_place = CPlace::new_stack_slot(fx, ret.layout()); + let res_ptr = res_place.to_ptr().get_addr(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String( + "ldr q0, [x0] + ldr q1, [x1] + frecps v0.4s, v0.4s, v1.4s + str q0, [x2]" + .into(), + )], + &[ + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x0, + )), + value: a_ptr, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x1, + )), + value: b_ptr, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x2, + )), + value: res_ptr, + }, + ], + InlineAsmOptions::NOSTACK, + ); + let res = res_place.to_cvalue(fx); + ret.write_cvalue_transmute(fx, res); + } + _ if intrinsic.starts_with("llvm.aarch64.neon.sqadd.v") || intrinsic.starts_with("llvm.aarch64.neon.uqadd.v") => { From e21502cf9ed247bbf879132b8c62e423d959bd38 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 25 Feb 2025 18:41:49 -0500 Subject: [PATCH 034/546] Fill out links_from_incr_cache in cg_clif --- .../rustc_codegen_cranelift/src/driver/aot.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index d1843f90a07d..fb7864ae6124 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -464,22 +464,23 @@ fn reuse_workproduct_for_cgu( err )); } + let obj_out_global_asm = crate::global_asm::add_file_stem_postfix(obj_out_regular.clone(), ".asm"); - let has_global_asm = if let Some(asm_o) = work_product.saved_files.get("asm.o") { + let source_file_global_asm = if let Some(asm_o) = work_product.saved_files.get("asm.o") { let source_file_global_asm = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, asm_o); if let Err(err) = rustc_fs_util::link_or_copy(&source_file_global_asm, &obj_out_global_asm) { return Err(format!( "unable to copy {} to {}: {}", - source_file_regular.display(), - obj_out_regular.display(), + source_file_global_asm.display(), + obj_out_global_asm.display(), err )); } - true + Some(source_file_global_asm) } else { - false + None }; Ok(ModuleCodegenResult { @@ -491,9 +492,9 @@ fn reuse_workproduct_for_cgu( bytecode: None, assembly: None, llvm_ir: None, - links_from_incr_cache: Vec::new(), + links_from_incr_cache: vec![source_file_regular], }, - module_global_asm: has_global_asm.then(|| CompiledModule { + module_global_asm: source_file_global_asm.map(|source_file| CompiledModule { name: cgu.name().to_string(), kind: ModuleKind::Regular, object: Some(obj_out_global_asm), @@ -501,7 +502,7 @@ fn reuse_workproduct_for_cgu( bytecode: None, assembly: None, llvm_ir: None, - links_from_incr_cache: Vec::new(), + links_from_incr_cache: vec![source_file], }), existing_work_product: Some((cgu.work_product_id(), work_product)), }) @@ -752,6 +753,7 @@ pub(crate) fn run_aot( let metadata_module = if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None }; + Box::new(OngoingCodegen { modules, allocator_module, From af9f91696bb3f504a6fc7c235e7eb1999d064acb Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 25 Feb 2025 18:41:49 -0500 Subject: [PATCH 035/546] Fill out links_from_incr_cache in cg_clif --- src/driver/aot.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index d1843f90a07d..fb7864ae6124 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -464,22 +464,23 @@ fn reuse_workproduct_for_cgu( err )); } + let obj_out_global_asm = crate::global_asm::add_file_stem_postfix(obj_out_regular.clone(), ".asm"); - let has_global_asm = if let Some(asm_o) = work_product.saved_files.get("asm.o") { + let source_file_global_asm = if let Some(asm_o) = work_product.saved_files.get("asm.o") { let source_file_global_asm = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, asm_o); if let Err(err) = rustc_fs_util::link_or_copy(&source_file_global_asm, &obj_out_global_asm) { return Err(format!( "unable to copy {} to {}: {}", - source_file_regular.display(), - obj_out_regular.display(), + source_file_global_asm.display(), + obj_out_global_asm.display(), err )); } - true + Some(source_file_global_asm) } else { - false + None }; Ok(ModuleCodegenResult { @@ -491,9 +492,9 @@ fn reuse_workproduct_for_cgu( bytecode: None, assembly: None, llvm_ir: None, - links_from_incr_cache: Vec::new(), + links_from_incr_cache: vec![source_file_regular], }, - module_global_asm: has_global_asm.then(|| CompiledModule { + module_global_asm: source_file_global_asm.map(|source_file| CompiledModule { name: cgu.name().to_string(), kind: ModuleKind::Regular, object: Some(obj_out_global_asm), @@ -501,7 +502,7 @@ fn reuse_workproduct_for_cgu( bytecode: None, assembly: None, llvm_ir: None, - links_from_incr_cache: Vec::new(), + links_from_incr_cache: vec![source_file], }), existing_work_product: Some((cgu.work_product_id(), work_product)), }) @@ -752,6 +753,7 @@ pub(crate) fn run_aot( let metadata_module = if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None }; + Box::new(OngoingCodegen { modules, allocator_module, From b9ca52582bb6a5b73fc633539b267579e82be422 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Feb 2025 16:29:07 +0100 Subject: [PATCH 036/546] =?UTF-8?q?rename=20BackendRepr::Vector=20?= =?UTF-8?q?=E2=86=92=20SimdVector?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/abi/pass_mode.rs | 4 ++-- src/intrinsics/mod.rs | 2 +- src/value_and_place.rs | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index b28c4c9539ce..06d89bc9ea7d 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -84,7 +84,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { AbiParam::new(scalar_to_clif_type(tcx, scalar)), attrs )], - BackendRepr::Vector { .. } => { + BackendRepr::SimdVector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); smallvec![AbiParam::new(vector_ty)] } @@ -135,7 +135,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { BackendRepr::Scalar(scalar) => { (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))]) } - BackendRepr::Vector { .. } => { + BackendRepr::SimdVector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); (None, vec![AbiParam::new(vector_ty)]) } diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 4d9bed8652cb..6735ae024d1c 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -53,7 +53,7 @@ fn report_atomic_type_validation_error<'tcx>( pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Type { let (element, count) = match layout.backend_repr { - BackendRepr::Vector { element, count } => (element, count), + BackendRepr::SimdVector { element, count } => (element, count), _ => unreachable!(), }; diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 1b3f86c8405d..cc739fefcd06 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -173,9 +173,11 @@ impl<'tcx> CValue<'tcx> { CValueInner::ByRef(ptr, None) => { let clif_ty = match layout.backend_repr { BackendRepr::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar), - BackendRepr::Vector { element, count } => scalar_to_clif_type(fx.tcx, element) - .by(u32::try_from(count).unwrap()) - .unwrap(), + BackendRepr::SimdVector { element, count } => { + scalar_to_clif_type(fx.tcx, element) + .by(u32::try_from(count).unwrap()) + .unwrap() + } _ => unreachable!("{:?}", layout.ty), }; let mut flags = MemFlags::new(); From c4d642616d8fb74d9884bdc0b8df270d13739de3 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 1 Mar 2025 04:47:36 +0100 Subject: [PATCH 037/546] Set target_vendor = "openwrt" On mips64-openwrt-linux-musl target. --- .../rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs | 1 + tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr | 2 +- tests/ui/check-cfg/exhaustive-names-values.feature.stderr | 2 +- tests/ui/check-cfg/exhaustive-names-values.full.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs index 1300280e35b0..71b3fbe00b2f 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64".into(), options: TargetOptions { + vendor: "openwrt".into(), abi: "abi64".into(), endian: Endian::Big, mcount: "_mcount".into(), diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr index e7b8f3550576..b07d630e5f5d 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr @@ -14,7 +14,7 @@ warning: unexpected `cfg` condition value: `value` LL | #[cfg(target_vendor = "value")] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` + = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `openwrt`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `feature` diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr index 95af0a909299..80f8f36c23f7 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr @@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `value` LL | #[cfg(target_vendor = "value")] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` + = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `openwrt`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `unk` diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr index 95af0a909299..80f8f36c23f7 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr @@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `value` LL | #[cfg(target_vendor = "value")] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` + = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `openwrt`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `unk` diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index ba1900fcddb2..4636b6945d06 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -230,7 +230,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_vendor = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` + = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `openwrt`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From 5328983b077f98a41d6dc3c3af303ae4f3ecccf2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Feb 2025 19:08:03 +0000 Subject: [PATCH 038/546] Update `compiler-builtins` to 0.1.150 Includes a change to make a subset of math symbols available on all platforms [1], and disables `f16` on aarch64 without neon [2]. [1]: https://github.com/rust-lang/compiler-builtins/pull/763 [2]: https://github.com/rust-lang/compiler-builtins/pull/775 --- ...029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index bedc6ca11b3f..d8db7d63f2dd 100644 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644 [dependencies] core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std', 'no-f16-f128'] } +-compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std', 'no-f16-f128'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } From 4508f5f8628c2869f153b59aba6d90411d831e33 Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Sun, 2 Mar 2025 23:21:43 +0800 Subject: [PATCH 039/546] update outdated doc with new example --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d72cf00293f0..e81d753f3e7d 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -218,10 +218,10 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua /// definition itself. For example, this definition would be illegal: /// /// ```rust -/// struct Ref<'a, T> { x: &'a T } +/// struct StaticRef { x: &'static T } /// ``` /// -/// because the type did not declare that `T:'a`. +/// because the type did not declare that `T: 'static`. /// /// We do this check as a pre-pass before checking fn bodies because if these constraints are /// not included it frequently leads to confusing errors in fn bodies. So it's better to check From e31bb45e47d78798f6b6d31316f525316bfcaecf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Mar 2025 10:53:58 +0100 Subject: [PATCH 040/546] stabilize const_cell --- library/core/src/cell.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index cbf00106c517..79051588f443 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -495,7 +495,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "move_cell", since = "1.17.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] #[rustc_confusables("swap")] pub const fn replace(&self, val: T) -> T { // SAFETY: This can cause data races if called from a separate thread, @@ -537,7 +537,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] pub const fn get(&self) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. @@ -617,7 +617,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] pub const fn get_mut(&mut self) -> &mut T { self.value.get_mut() } @@ -637,7 +637,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "as_cell", since = "1.37.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] pub const fn from_mut(t: &mut T) -> &Cell { // SAFETY: `&mut` ensures unique access. unsafe { &*(t as *mut T as *const Cell) } @@ -695,7 +695,7 @@ impl Cell<[T]> { /// assert_eq!(slice_cell.len(), 3); /// ``` #[stable(feature = "as_cell", since = "1.37.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] pub const fn as_slice_of_cells(&self) -> &[Cell] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T]> as *const [Cell]) } From 57767d6d998c9998049df14e9c4ccc903396f013 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:35:10 +0000 Subject: [PATCH 041/546] Rustup to rustc 1.87.0-nightly (f4a216d28 2025-03-02) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 86052b4df764..d9b4f2fc6743 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-02-26" +channel = "nightly-2025-03-03" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 0f9c09fb3a64ff11ea81446a96907cd5e86490c2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:43:05 +0000 Subject: [PATCH 042/546] Remoe has_ptr_meta in favor of tcx.type_has_metadata() --- src/base.rs | 6 ++++-- src/common.rs | 18 ++---------------- src/debuginfo/types.rs | 4 ++-- src/num.rs | 8 ++++++-- src/value_and_place.rs | 6 +++--- 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/base.rs b/src/base.rs index 125a9201831c..adaa754491e5 100644 --- a/src/base.rs +++ b/src/base.rs @@ -729,8 +729,10 @@ fn codegen_stmt<'tcx>( let to_ty = fx.monomorphize(to_ty); fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.builtin_deref(true) - .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty)) + ty.builtin_deref(true).is_some_and(|pointee_ty| { + fx.tcx + .type_has_metadata(pointee_ty, ty::TypingEnv::fully_monomorphized()) + }) } if is_wide_ptr(fx, from_ty) { diff --git a/src/common.rs b/src/common.rs index 766278d87183..abe2972ba0cb 100644 --- a/src/common.rs +++ b/src/common.rs @@ -71,7 +71,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option pointer_ty(tcx), ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => { - if has_ptr_meta(tcx, *pointee_ty) { + if tcx.type_has_metadata(*pointee_ty, ty::TypingEnv::fully_monomorphized()) { return None; } else { pointer_ty(tcx) @@ -91,7 +91,7 @@ fn clif_pair_type_from_ty<'tcx>( (clif_type_from_ty(tcx, types[0])?, clif_type_from_ty(tcx, types[1])?) } ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => { - if has_ptr_meta(tcx, *pointee_ty) { + if tcx.type_has_metadata(*pointee_ty, ty::TypingEnv::fully_monomorphized()) { (pointer_ty(tcx), pointer_ty(tcx)) } else { return None; @@ -101,20 +101,6 @@ fn clif_pair_type_from_ty<'tcx>( }) } -/// Is a pointer to this type a wide ptr? -pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - if ty.is_sized(tcx, ty::TypingEnv::fully_monomorphized()) { - return false; - } - - let tail = tcx.struct_tail_for_codegen(ty, ty::TypingEnv::fully_monomorphized()); - match tail.kind() { - ty::Foreign(..) => false, - ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail), - } -} - pub(crate) fn codegen_icmp_imm( fx: &mut FunctionCx<'_, '_, '_>, intcc: IntCC, diff --git a/src/debuginfo/types.rs b/src/debuginfo/types.rs index 017d7784dc03..25b922c8be4c 100644 --- a/src/debuginfo/types.rs +++ b/src/debuginfo/types.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; -use crate::{DebugContext, FullyMonomorphizedLayoutCx, has_ptr_meta}; +use crate::{DebugContext, FullyMonomorphizedLayoutCx}; #[derive(Default)] pub(crate) struct TypeDebugContext<'tcx> { @@ -129,7 +129,7 @@ impl DebugContext { let name = type_names::compute_debuginfo_type_name(tcx, ptr_type, true); - if !has_ptr_meta(tcx, ptr_type) { + if !tcx.type_has_metadata(ptr_type, ty::TypingEnv::fully_monomorphized()) { let pointer_type_id = self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_pointer_type); let pointer_entry = self.dwarf.unit.get_mut(pointer_type_id); diff --git a/src/num.rs b/src/num.rs index f44e2459a784..2a4d1e3ae571 100644 --- a/src/num.rs +++ b/src/num.rs @@ -395,8 +395,12 @@ pub(crate) fn codegen_ptr_binop<'tcx>( in_lhs: CValue<'tcx>, in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { - let is_thin_ptr = - in_lhs.layout().ty.builtin_deref(true).map(|ty| !has_ptr_meta(fx.tcx, ty)).unwrap_or(true); + let is_thin_ptr = in_lhs + .layout() + .ty + .builtin_deref(true) + .map(|ty| !fx.tcx.type_has_metadata(ty, ty::TypingEnv::fully_monomorphized())) + .unwrap_or(true); if is_thin_ptr { match bin_op { diff --git a/src/value_and_place.rs b/src/value_and_place.rs index cc739fefcd06..f8a19589fdd7 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -746,7 +746,7 @@ impl<'tcx> CPlace<'tcx> { }; let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field); - if has_ptr_meta(fx.tcx, field_layout.ty) { + if fx.tcx.type_has_metadata(field_layout.ty, ty::TypingEnv::fully_monomorphized()) { CPlace::for_ptr_with_extra(field_ptr, extra.unwrap(), field_layout) } else { CPlace::for_ptr(field_ptr, field_layout) @@ -832,7 +832,7 @@ impl<'tcx> CPlace<'tcx> { pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> { let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap()); - if has_ptr_meta(fx.tcx, inner_layout.ty) { + if fx.tcx.type_has_metadata(inner_layout.ty, ty::TypingEnv::fully_monomorphized()) { let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx); CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout) } else { @@ -845,7 +845,7 @@ impl<'tcx> CPlace<'tcx> { fx: &mut FunctionCx<'_, '_, 'tcx>, layout: TyAndLayout<'tcx>, ) -> CValue<'tcx> { - if has_ptr_meta(fx.tcx, self.layout().ty) { + if fx.tcx.type_has_metadata(self.layout().ty, ty::TypingEnv::fully_monomorphized()) { let (ptr, extra) = self.to_ptr_unsized(); CValue::by_val_pair(ptr.get_addr(fx), extra, layout) } else { From 157137a64aeba7fb6e6571bcc046c97d63d368a7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Feb 2025 15:25:54 +1100 Subject: [PATCH 043/546] Change signature of `target_features_cfg`. Currently it is called twice, once with `allow_unstable` set to true and once with it set to false. This results in some duplicated work. Most notably, for the LLVM backend, `LLVMRustHasFeature` is called twice for every feature, and it's moderately slow. For very short running compilations on platforms with many features (e.g. a `check` build of hello-world on x86) this is a significant fraction of runtime. This commit changes `target_features_cfg` so it is only called once, and it now returns a pair of feature sets. This halves the number of `LLVMRustHasFeature` calls. --- src/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a3f437448757..06939beb3742 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -176,13 +176,9 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features_cfg( - &self, - sess: &Session, - _allow_unstable: bool, - ) -> Vec { + fn target_features_cfg(&self, sess: &Session) -> (Vec, Vec) { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] - if sess.target.arch == "x86_64" && sess.target.os != "none" { + let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" { // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")] } else if sess.target.arch == "aarch64" { @@ -196,7 +192,10 @@ impl CodegenBackend for CraneliftCodegenBackend { } } else { vec![] - } + }; + // FIXME do `unstable_target_features` properly + let unstable_target_features = target_features.clone(); + (target_features, unstable_target_features) } fn print_version(&self) { From 0ec1d460bb898a22de37bcc040f86449371bdbdb Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 4 Mar 2025 20:07:25 +0530 Subject: [PATCH 044/546] Add the new `amx` target features --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 6 ++++++ compiler/rustc_target/src/target_features.rs | 5 +++++ tests/ui/check-cfg/target_feature.stderr | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 5cc4f4ab9e67..e3e2e8f2c0be 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -298,6 +298,12 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("v9")), ("sparc", "v8plus") if get_version().0 < 19 => None, ("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")), + // These new `amx` variants and `movrs` were introduced in LLVM20 + ("x86", "amx-avx512" | "amx-fp8" | "amx-movrs" | "amx-tf32" | "amx-transpose") + if get_version().0 < 20 => + { + None + } (_, s) => Some(LLVMFeature::new(s)), } } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index d05466bb4843..1a4903cdbfa3 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -380,11 +380,16 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("adx", Stable, &[]), ("aes", Stable, &["sse2"]), + ("amx-avx512", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-fp8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-movrs", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-tf32", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]), + ("amx-transpose", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("avx", Stable, &["sse4.2"]), ("avx2", Stable, &["avx"]), ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]), diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 5b82d3f539fe..2060dcc61600 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -17,11 +17,16 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `aes` `altivec` `alu32` +`amx-avx512` `amx-bf16` `amx-complex` `amx-fp16` +`amx-fp8` `amx-int8` +`amx-movrs` +`amx-tf32` `amx-tile` +`amx-transpose` `atomics` `avx` `avx2` From 7c2434c52caf1fc4269dd2e376fb332d0dd78143 Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 4 Mar 2025 20:08:28 +0530 Subject: [PATCH 045/546] Add the `movrs` target feature and `movrs_target_feature` feature gate --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 1 + compiler/rustc_feature/src/unstable.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/target_features.rs | 1 + tests/ui/check-cfg/target_feature.stderr | 1 + .../feature-gate-movrs_target_feature.rs | 6 ++++++ .../feature-gate-movrs_target_feature.stderr | 13 +++++++++++++ 7 files changed, 24 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-movrs_target_feature.rs create mode 100644 tests/ui/feature-gates/feature-gate-movrs_target_feature.stderr diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e3e2e8f2c0be..7e244e0b2680 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -304,6 +304,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, (_, s) => Some(LLVMFeature::new(s)), } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 841d30841856..4248cac5812b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -323,6 +323,7 @@ declare_features! ( (unstable, loongarch_target_feature, "1.73.0", Some(44839)), (unstable, m68k_target_feature, "1.85.0", Some(134328)), (unstable, mips_target_feature, "1.27.0", Some(44839)), + (unstable, movrs_target_feature, "CURRENT_RUSTC_VERSION", Some(137976)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), (unstable, prfchw_target_feature, "1.78.0", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1dc84150cbe5..b932b525aea5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1348,6 +1348,7 @@ symbols! { movbe_target_feature, move_ref_pattern, move_size_limit, + movrs_target_feature, mul, mul_assign, mul_with_overflow, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 1a4903cdbfa3..e46da2359b97 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -423,6 +423,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), ("lzcnt", Stable, &[]), ("movbe", Stable, &[]), + ("movrs", Unstable(sym::movrs_target_feature), &[]), ("pclmulqdq", Stable, &["sse2"]), ("popcnt", Stable, &[]), ("prfchw", Unstable(sym::prfchw_target_feature), &[]), diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 2060dcc61600..e3133b0af3c5 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -153,6 +153,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `mclass` `mops` `movbe` +`movrs` `mp` `mp1e2` `msa` diff --git a/tests/ui/feature-gates/feature-gate-movrs_target_feature.rs b/tests/ui/feature-gates/feature-gate-movrs_target_feature.rs new file mode 100644 index 000000000000..738cab5a06d6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-movrs_target_feature.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "movrs")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-movrs_target_feature.stderr b/tests/ui/feature-gates/feature-gate-movrs_target_feature.stderr new file mode 100644 index 000000000000..16fe7aaead5c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-movrs_target_feature.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `movrs` is currently unstable + --> $DIR/feature-gate-movrs_target_feature.rs:2:18 + | +LL | #[target_feature(enable = "movrs")] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #137976 for more information + = help: add `#![feature(movrs_target_feature)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 75485a2c093304e93831e6789b38d7aa0024ff3b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Mar 2025 01:35:02 -0500 Subject: [PATCH 046/546] Update `compiler-builtins` to 0.1.151 This enables `f16` builtins for loongarch [1] and adds support for Cygwin [2]. [1]: https://github.com/rust-lang/compiler-builtins/pull/770 [2]: https://github.com/rust-lang/compiler-builtins/pull/774 --- ...029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index d8db7d63f2dd..c2027863b00b 100644 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644 [dependencies] core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std', 'no-f16-f128'] } +-compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } From 0fcd068bec1aab1a596f23328769a26f253dfee2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:12:57 +0000 Subject: [PATCH 047/546] Refactor the cli of cg_clif --- docs/usage.md | 4 ++-- scripts/cargo-clif.rs | 5 +++-- scripts/filter_profile.rs | 2 +- src/config.rs | 41 +++++++++++++-------------------------- src/driver/jit.rs | 19 ++++++++---------- src/lib.rs | 15 +++++++------- 6 files changed, 34 insertions(+), 52 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 135a51ce392b..785adbbdf9a8 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -38,7 +38,7 @@ $ $cg_clif_dir/dist/cargo-clif jit or ```bash -$ $cg_clif_dir/dist/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs +$ $cg_clif_dir/dist/rustc-clif -Cllvm-args=jit-mode -Cprefer-dynamic my_crate.rs ``` There is also an experimental lazy jit mode. In this mode functions are only compiled once they are @@ -54,7 +54,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic + echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode -Cllvm-args=jit-lazy -Cprefer-dynamic } function jit() { diff --git a/scripts/cargo-clif.rs b/scripts/cargo-clif.rs index ebbb68796105..1ca02bc6a2ce 100644 --- a/scripts/cargo-clif.rs +++ b/scripts/cargo-clif.rs @@ -50,7 +50,7 @@ fn main() { .chain([ "--".to_string(), "-Zunstable-options".to_string(), - "-Cllvm-args=mode=jit".to_string(), + "-Cllvm-args=jit-mode".to_string(), ]) .collect() } @@ -62,7 +62,8 @@ fn main() { .chain([ "--".to_string(), "-Zunstable-options".to_string(), - "-Cllvm-args=mode=jit-lazy".to_string(), + "-Cllvm-args=jit-mode".to_string(), + "-Cllvm-args=jit-lazy".to_string(), ]) .collect() } diff --git a/scripts/filter_profile.rs b/scripts/filter_profile.rs index 0252d5b33403..4595063c032d 100755 --- a/scripts/filter_profile.rs +++ b/scripts/filter_profile.rs @@ -4,7 +4,7 @@ pushd $(dirname "$0")/../ RUSTC="$(pwd)/dist/rustc-clif" popd -PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0 +PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=jit-mode -Cprefer-dynamic $0 #*/ //! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse diff --git a/src/config.rs b/src/config.rs index d784f6e9d9eb..30b48786cdc4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,21 +1,15 @@ -/// The mode to use for compilation. -#[derive(Copy, Clone, Debug)] -pub enum CodegenMode { - /// AOT compile the crate. This is the default. - Aot, - /// JIT compile and execute the crate. - Jit, - /// JIT compile and execute the crate, but only compile functions the first time they are used. - JitLazy, -} - /// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars. #[derive(Clone, Debug)] pub struct BackendConfig { /// Should the crate be AOT compiled or JIT executed. /// - /// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`. - pub codegen_mode: CodegenMode, + /// Defaults to AOT compilation. Can be set using `-Cllvm-args=jit-mode`. + pub jit_mode: bool, + + /// When JIT executing should the lazy JIT mode be used. + /// + /// Defaults to false. Can be set using `-Cllvm-args=jit-lazy`. + pub lazy_jit: bool, /// When JIT mode is enable pass these arguments to the program. /// @@ -27,7 +21,8 @@ impl BackendConfig { /// Parse the configuration passed in using `-Cllvm-args`. pub fn from_opts(opts: &[String]) -> Result { let mut config = BackendConfig { - codegen_mode: CodegenMode::Aot, + jit_mode: false, + lazy_jit: false, jit_args: match std::env::var("CG_CLIF_JIT_ARGS") { Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(), Err(std::env::VarError::NotPresent) => vec![], @@ -43,20 +38,10 @@ impl BackendConfig { // testing cg_clif. continue; } - if let Some((name, value)) = opt.split_once('=') { - match name { - "mode" => { - config.codegen_mode = match value { - "aot" => CodegenMode::Aot, - "jit" => CodegenMode::Jit, - "jit-lazy" => CodegenMode::JitLazy, - _ => return Err(format!("Unknown codegen mode `{}`", value)), - }; - } - _ => return Err(format!("Unknown option `{}`", name)), - } - } else { - return Err(format!("Invalid option `{}`", opt)); + match &**opt { + "jit-mode" => config.jit_mode = true, + "jit-lazy" => config.lazy_jit = true, + _ => return Err(format!("Unknown option `{}`", opt)), } } diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 57c88f4b0f9f..17d55a82e8b5 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -13,10 +13,10 @@ use rustc_middle::mir::mono::MonoItem; use rustc_session::Session; use rustc_span::sym; +use crate::CodegenCx; use crate::debuginfo::TypeDebugContext; use crate::prelude::*; use crate::unwind_module::UnwindModule; -use crate::{CodegenCx, CodegenMode}; struct JitState { jit_module: UnwindModule, @@ -79,7 +79,7 @@ fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule (jit_module, cx) } -pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec) -> ! { +pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec) -> ! { if !tcx.sess.opts.output_types.should_codegen() { tcx.dcx().fatal("JIT mode doesn't work with `cargo check`"); } @@ -88,8 +88,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec< tcx.dcx().fatal("can't jit non-executable crate"); } - let (mut jit_module, mut cx) = - create_jit_module(tcx, matches!(codegen_mode, CodegenMode::JitLazy)); + let (mut jit_module, mut cx) = create_jit_module(tcx, jit_lazy); let mut cached_context = Context::new(); let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; @@ -105,9 +104,10 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec< super::predefine_mono_items(tcx, &mut jit_module, &mono_items); for (mono_item, _) in mono_items { match mono_item { - MonoItem::Fn(inst) => match codegen_mode { - CodegenMode::Aot => unreachable!(), - CodegenMode::Jit => { + MonoItem::Fn(inst) => { + if jit_lazy { + codegen_shim(tcx, &mut cached_context, &mut jit_module, inst) + } else { codegen_and_compile_fn( tcx, &mut cx, @@ -116,10 +116,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec< inst, ); } - CodegenMode::JitLazy => { - codegen_shim(tcx, &mut cached_context, &mut jit_module, inst) - } - }, + } MonoItem::Static(def_id) => { crate::constant::codegen_static(tcx, &mut jit_module, def_id); } diff --git a/src/lib.rs b/src/lib.rs index 2c019e754460..c5ca6565a86b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -213,15 +213,14 @@ impl CodegenBackend for CraneliftCodegenBackend { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) .unwrap_or_else(|err| tcx.sess.dcx().fatal(err)) }); - match config.codegen_mode { - CodegenMode::Aot => driver::aot::run_aot(tcx, metadata, need_metadata_module), - CodegenMode::Jit | CodegenMode::JitLazy => { - #[cfg(feature = "jit")] - driver::jit::run_jit(tcx, config.codegen_mode, config.jit_args); + if config.jit_mode { + #[cfg(feature = "jit")] + driver::jit::run_jit(tcx, config.lazy_jit, config.jit_args); - #[cfg(not(feature = "jit"))] - tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); - } + #[cfg(not(feature = "jit"))] + tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); + } else { + driver::aot::run_aot(tcx, metadata, need_metadata_module) } } From 5d03df9431833ad992c1507fedc7daee3e232443 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:35:51 +0000 Subject: [PATCH 048/546] Remove support for the lazy jit mode I might re-implement it in the future, but would probably do so by replacing cranelift-jit. cranelift-jit's api doesn't quite work well for lazy jitting. And even so it adds complexity to cranelift-jit and breaks cranelift-jit outside of x86_64. --- build_system/tests.rs | 14 --- docs/usage.md | 9 +- scripts/cargo-clif.rs | 13 --- src/config.rs | 7 -- src/driver/jit.rs | 214 ++++-------------------------------------- src/lib.rs | 2 +- 6 files changed, 18 insertions(+), 241 deletions(-) diff --git a/build_system/tests.rs b/build_system/tests.rs index ea7e94c345ad..1b1f0f483a33 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -384,20 +384,6 @@ impl<'a> TestRunner<'a> { jit_cmd.env("CG_CLIF_JIT_ARGS", args); } spawn_and_wait(jit_cmd); - - eprintln!("[JIT-lazy] {testname}"); - let mut jit_cmd = self.rustc_command([ - "-Zunstable-options", - "-Cllvm-args=mode=jit-lazy", - "-Cprefer-dynamic", - source, - "--cfg", - "jit", - ]); - if !args.is_empty() { - jit_cmd.env("CG_CLIF_JIT_ARGS", args); - } - spawn_and_wait(jit_cmd); } } } diff --git a/docs/usage.md b/docs/usage.md index 785adbbdf9a8..dbe36109f83e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -41,20 +41,13 @@ or $ $cg_clif_dir/dist/rustc-clif -Cllvm-args=jit-mode -Cprefer-dynamic my_crate.rs ``` -There is also an experimental lazy jit mode. In this mode functions are only compiled once they are -first called. - -```bash -$ $cg_clif_dir/dist/cargo-clif lazy-jit -``` - ## Shell These are a few functions that allow you to easily run rust code from the shell using cg_clif as jit. ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode -Cllvm-args=jit-lazy -Cprefer-dynamic + echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode-Cprefer-dynamic } function jit() { diff --git a/scripts/cargo-clif.rs b/scripts/cargo-clif.rs index 1ca02bc6a2ce..e6c63bf5e650 100644 --- a/scripts/cargo-clif.rs +++ b/scripts/cargo-clif.rs @@ -54,19 +54,6 @@ fn main() { ]) .collect() } - Some("lazy-jit") => { - rustflags.push("-Cprefer-dynamic".to_owned()); - args.remove(0); - IntoIterator::into_iter(["rustc".to_string()]) - .chain(args) - .chain([ - "--".to_string(), - "-Zunstable-options".to_string(), - "-Cllvm-args=jit-mode".to_string(), - "-Cllvm-args=jit-lazy".to_string(), - ]) - .collect() - } _ => args, }; diff --git a/src/config.rs b/src/config.rs index 30b48786cdc4..d328b33a704f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,11 +6,6 @@ pub struct BackendConfig { /// Defaults to AOT compilation. Can be set using `-Cllvm-args=jit-mode`. pub jit_mode: bool, - /// When JIT executing should the lazy JIT mode be used. - /// - /// Defaults to false. Can be set using `-Cllvm-args=jit-lazy`. - pub lazy_jit: bool, - /// When JIT mode is enable pass these arguments to the program. /// /// Defaults to the value of `CG_CLIF_JIT_ARGS`. @@ -22,7 +17,6 @@ impl BackendConfig { pub fn from_opts(opts: &[String]) -> Result { let mut config = BackendConfig { jit_mode: false, - lazy_jit: false, jit_args: match std::env::var("CG_CLIF_JIT_ARGS") { Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(), Err(std::env::VarError::NotPresent) => vec![], @@ -40,7 +34,6 @@ impl BackendConfig { } match &**opt { "jit-mode" => config.jit_mode = true, - "jit-lazy" => config.lazy_jit = true, _ => return Err(format!("Unknown option `{}`", opt)), } } diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 17d55a82e8b5..4a08937f4aa9 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -1,12 +1,9 @@ //! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object //! files. -use std::cell::RefCell; use std::ffi::CString; use std::os::raw::{c_char, c_int}; -use std::sync::{Mutex, OnceLock, mpsc}; -use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_jit::{JITBuilder, JITModule}; use rustc_codegen_ssa::CrateInfo; use rustc_middle::mir::mono::MonoItem; @@ -18,58 +15,13 @@ use crate::debuginfo::TypeDebugContext; use crate::prelude::*; use crate::unwind_module::UnwindModule; -struct JitState { - jit_module: UnwindModule, -} - -thread_local! { - static LAZY_JIT_STATE: RefCell> = const { RefCell::new(None) }; -} - -/// The Sender owned by the rustc thread -static GLOBAL_MESSAGE_SENDER: OnceLock>> = OnceLock::new(); - -/// A message that is sent from the jitted runtime to the rustc thread. -/// Senders are responsible for upholding `Send` semantics. -enum UnsafeMessage { - /// Request that the specified `Instance` be lazily jitted. - /// - /// Nothing accessible through `instance_ptr` may be moved or mutated by the sender after - /// this message is sent. - JitFn { - instance_ptr: *const Instance<'static>, - trampoline_ptr: *const u8, - tx: mpsc::Sender<*const u8>, - }, -} -unsafe impl Send for UnsafeMessage {} - -impl UnsafeMessage { - /// Send the message. - fn send(self) { - thread_local! { - /// The Sender owned by the local thread - static LOCAL_MESSAGE_SENDER: mpsc::Sender = - GLOBAL_MESSAGE_SENDER - .get().unwrap() - .lock().unwrap() - .clone(); - } - LOCAL_MESSAGE_SENDER.with(|sender| { - sender.send(self).expect("rustc thread hung up before lazy JIT request was sent") - }) - } -} - -fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule, CodegenCx) { +fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule, CodegenCx) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); let isa = crate::build_isa(tcx.sess); let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); - jit_builder.hotswap(hotswap); crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info)); - jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8); let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false); let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name); @@ -79,7 +31,7 @@ fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule (jit_module, cx) } -pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec) -> ! { +pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { if !tcx.sess.opts.output_types.should_codegen() { tcx.dcx().fatal("JIT mode doesn't work with `cargo check`"); } @@ -88,7 +40,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec) -> tcx.dcx().fatal("can't jit non-executable crate"); } - let (mut jit_module, mut cx) = create_jit_module(tcx, jit_lazy); + let (mut jit_module, mut cx) = create_jit_module(tcx); let mut cached_context = Context::new(); let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; @@ -105,17 +57,13 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec) -> for (mono_item, _) in mono_items { match mono_item { MonoItem::Fn(inst) => { - if jit_lazy { - codegen_shim(tcx, &mut cached_context, &mut jit_module, inst) - } else { - codegen_and_compile_fn( - tcx, - &mut cx, - &mut cached_context, - &mut jit_module, - inst, - ); - } + codegen_and_compile_fn( + tcx, + &mut cx, + &mut cached_context, + &mut jit_module, + inst, + ); } MonoItem::Static(def_id) => { crate::constant::codegen_static(tcx, &mut jit_module, def_id); @@ -158,41 +106,17 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec) -> let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); let finalized_start: *const u8 = jit_module.module.get_finalized_function(start_func_id); - LAZY_JIT_STATE.with(|lazy_jit_state| { - let mut lazy_jit_state = lazy_jit_state.borrow_mut(); - assert!(lazy_jit_state.is_none()); - *lazy_jit_state = Some(JitState { jit_module }); - }); - let f: extern "C" fn(c_int, *const *const c_char) -> c_int = unsafe { ::std::mem::transmute(finalized_start) }; - let (tx, rx) = mpsc::channel(); - GLOBAL_MESSAGE_SENDER.set(Mutex::new(tx)).unwrap(); + let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); - // Spawn the jitted runtime in a new thread so that this rustc thread can handle messages - // (eg to lazily JIT further functions as required) - std::thread::spawn(move || { - let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); + // Push a null pointer as a terminating argument. This is required by POSIX and + // useful as some dynamic linkers use it as a marker to jump over. + argv.push(std::ptr::null()); - // Push a null pointer as a terminating argument. This is required by POSIX and - // useful as some dynamic linkers use it as a marker to jump over. - argv.push(std::ptr::null()); - - let ret = f(args.len() as c_int, argv.as_ptr()); - std::process::exit(ret); - }); - - // Handle messages - loop { - match rx.recv().unwrap() { - // lazy JIT compilation request - compile requested instance and return pointer to result - UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx } => { - tx.send(jit_fn(instance_ptr, trampoline_ptr)) - .expect("jitted runtime hung up before response to lazy JIT request was sent"); - } - } - } + let ret = f(args.len() as c_int, argv.as_ptr()); + std::process::exit(ret); } pub(crate) fn codegen_and_compile_fn<'tcx>( @@ -224,58 +148,6 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( }); } -extern "C" fn clif_jit_fn( - instance_ptr: *const Instance<'static>, - trampoline_ptr: *const u8, -) -> *const u8 { - // send the JIT request to the rustc thread, with a channel for the response - let (tx, rx) = mpsc::channel(); - UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx }.send(); - - // block on JIT compilation result - rx.recv().expect("rustc thread hung up before responding to sent lazy JIT request") -} - -fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> *const u8 { - rustc_middle::ty::tls::with(|tcx| { - // lift is used to ensure the correct lifetime for instance. - let instance = tcx.lift(unsafe { *instance_ptr }).unwrap(); - - LAZY_JIT_STATE.with(|lazy_jit_state| { - let mut lazy_jit_state = lazy_jit_state.borrow_mut(); - let lazy_jit_state = lazy_jit_state.as_mut().unwrap(); - let jit_module = &mut lazy_jit_state.jit_module; - - let name = tcx.symbol_name(instance).name; - let sig = crate::abi::get_function_sig( - tcx, - jit_module.target_config().default_call_conv, - instance, - ); - let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap(); - - let current_ptr = jit_module.module.read_got_entry(func_id); - - // If the function's GOT entry has already been updated to point at something other - // than the shim trampoline, don't re-jit but just return the new pointer instead. - // This does not need synchronization as this code is executed only by a sole rustc - // thread. - if current_ptr != trampoline_ptr { - return current_ptr; - } - - jit_module.module.prepare_for_function_redefine(func_id).unwrap(); - - let mut cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name); - codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance); - - assert!(cx.global_asm.is_empty()); - jit_module.finalize_definitions(); - jit_module.module.get_finalized_function(func_id) - }) - }) -} - fn dep_symbol_lookup_fn( sess: &Session, crate_info: CrateInfo, @@ -323,57 +195,3 @@ fn dep_symbol_lookup_fn( None }) } - -fn codegen_shim<'tcx>( - tcx: TyCtxt<'tcx>, - cached_context: &mut Context, - module: &mut UnwindModule, - inst: Instance<'tcx>, -) { - let pointer_type = module.target_config().pointer_type(); - - let name = tcx.symbol_name(inst).name; - let sig = crate::abi::get_function_sig(tcx, module.target_config().default_call_conv, inst); - let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap(); - - let instance_ptr = Box::into_raw(Box::new(inst)); - - let jit_fn = module - .declare_function( - "__clif_jit_fn", - Linkage::Import, - &Signature { - call_conv: module.target_config().default_call_conv, - params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)], - returns: vec![AbiParam::new(pointer_type)], - }, - ) - .unwrap(); - - let context = cached_context; - context.clear(); - let trampoline = &mut context.func; - trampoline.signature = sig.clone(); - - let mut builder_ctx = FunctionBuilderContext::new(); - let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx); - - let trampoline_fn = module.declare_func_in_func(func_id, trampoline_builder.func); - let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func); - let sig_ref = trampoline_builder.func.import_signature(sig); - - let entry_block = trampoline_builder.create_block(); - trampoline_builder.append_block_params_for_function_params(entry_block); - let fn_args = trampoline_builder.func.dfg.block_params(entry_block).to_vec(); - - trampoline_builder.switch_to_block(entry_block); - let instance_ptr = trampoline_builder.ins().iconst(pointer_type, instance_ptr as u64 as i64); - let trampoline_ptr = trampoline_builder.ins().func_addr(pointer_type, trampoline_fn); - let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr, trampoline_ptr]); - let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0]; - let call_inst = trampoline_builder.ins().call_indirect(sig_ref, jitted_fn, &fn_args); - let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec(); - trampoline_builder.ins().return_(&ret_vals); - - module.define_function(func_id, context).unwrap(); -} diff --git a/src/lib.rs b/src/lib.rs index c5ca6565a86b..4d97c3ae6048 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,7 +215,7 @@ impl CodegenBackend for CraneliftCodegenBackend { }); if config.jit_mode { #[cfg(feature = "jit")] - driver::jit::run_jit(tcx, config.lazy_jit, config.jit_args); + driver::jit::run_jit(tcx, config.jit_args); #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); From 5cdb8663563fa1fc47a869d790e5cd06eaf1de3e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:51:35 +0000 Subject: [PATCH 049/546] Update rust-analyzer config mod_bench no longer exists and there is no benefit to not having a sysroot available for mini_core and mini_core_hello_world. --- .vscode/settings.json | 33 ++++++++++++++++----------------- .zed/settings.json | 25 ++++++++++--------------- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 491646ce59bb..68bd93aea890 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,41 +1,40 @@ { "editor.formatOnSave": true, - // in case rustc.source is disabled for performance reasons; disable the errors about this - "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], + "rust-analyzer.diagnostics.disabled": [ + "unresolved-extern-crate", + "unresolved-macro-call" + ], "rust-analyzer.rustc.source": "discover", "rust-analyzer.imports.granularity.enforce": true, "rust-analyzer.imports.granularity.group": "module", "rust-analyzer.imports.prefix": "crate", - "rust-analyzer.cargo.features": ["unstable-features"], + "rust-analyzer.cargo.features": [ + "unstable-features" + ], "rust-analyzer.linkedProjects": [ "./Cargo.toml", "./build_system/Cargo.toml", { + "sysroot_src": "./build/stdlib/library", "crates": [ { "root_module": "./example/mini_core.rs", - "edition": "2018", + "edition": "2015", "deps": [], "cfg": [], }, { "root_module": "./example/mini_core_hello_world.rs", - "edition": "2018", - "deps": [{ "crate": 0, "name": "mini_core" }], + "edition": "2015", + "deps": [ + { + "crate": 0, + "name": "mini_core" + } + ], "cfg": [], }, - { - "root_module": "./example/mod_bench.rs", - "edition": "2018", - "deps": [], - "cfg": [], - }, - ] - }, - { - "sysroot_src": "./build/stdlib/library", - "crates": [ { "root_module": "./example/std_example.rs", "edition": "2015", diff --git a/.zed/settings.json b/.zed/settings.json index e93bed369492..4338a3473311 100644 --- a/.zed/settings.json +++ b/.zed/settings.json @@ -5,7 +5,10 @@ "initialization_options": { "diagnostics": { // in case rustc.source is disabled for performance reasons; disable the errors about this - "disabled": ["unresolved-extern-crate", "unresolved-macro-call"] + "disabled": [ + "unresolved-extern-crate", + "unresolved-macro-call" + ] }, "rustc": { "source": "discover" @@ -18,22 +21,25 @@ "prefix": "crate" }, "cargo": { - "features": ["unstable-features"] + "features": [ + "unstable-features" + ] }, "linkedProjects": [ "./Cargo.toml", "./build_system/Cargo.toml", { + "sysroot_src": "./build/stdlib/library", "crates": [ { "root_module": "./example/mini_core.rs", - "edition": "2018", + "edition": "2015", "deps": [], "cfg": [] }, { "root_module": "./example/mini_core_hello_world.rs", - "edition": "2018", + "edition": "2015", "deps": [ { "crate": 0, @@ -42,17 +48,6 @@ ], "cfg": [] }, - { - "root_module": "./example/mod_bench.rs", - "edition": "2018", - "deps": [], - "cfg": [] - } - ] - }, - { - "sysroot_src": "./build/stdlib/library", - "crates": [ { "root_module": "./example/std_example.rs", "edition": "2015", From 7eb0a99fc9ff5ee3870a07926d5137d434ee22ab Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:55:41 +0000 Subject: [PATCH 050/546] Fix jit mode testing --- build_system/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_system/tests.rs b/build_system/tests.rs index 1b1f0f483a33..9ec0d3850f11 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -374,7 +374,7 @@ impl<'a> TestRunner<'a> { TestCaseCmd::JitBin { source, args } => { let mut jit_cmd = self.rustc_command([ "-Zunstable-options", - "-Cllvm-args=mode=jit", + "-Cllvm-args=jit-mode", "-Cprefer-dynamic", source, "--cfg", From f048c4501839701e27443abe68407f2824197137 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 12:40:11 +0000 Subject: [PATCH 051/546] Rustup to rustc 1.87.0-nightly (30f168ef8 2025-03-05) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index d9b4f2fc6743..4a566552322a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-03" +channel = "nightly-2025-03-06" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 75109ec1ba2fe1b5182f2accab3e31a1b6e810f7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 12:46:54 +0000 Subject: [PATCH 052/546] FIx rustc test suite --- scripts/test_rustc_tests.sh | 40 +++++++------------------------------ 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 599ce63bab56..63f3c8b05036 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -152,46 +152,20 @@ rm tests/ui/process/process-panic-after-fork.rs # same cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist cp $(../dist/rustc-clif --print target-libdir)/libstd-*.so ../dist/lib/ -# prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by -# rustdoc-clif cat < Self { - #[track_caller] - pub fn new() -> Self { - let mut cmd = setup_common(); -- cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR")); - Self { cmd } - } - diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index e7ae773ffa1d3..04bc2d7787da7 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs -@@ -329,7 +329,6 @@ impl TestCx<'_> { +@@ -117,7 +117,6 @@ impl TestCx<'_> { .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) .arg("--edition=2021") - .arg(&self.testpaths.file.join("rmake.rs")) -- .arg("-Cprefer-dynamic") - // Provide necessary library search paths for rustc. - .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); +- .arg(&self.testpaths.file.join("rmake.rs")) +- .arg("-Cprefer-dynamic"); ++ .arg(&self.testpaths.file.join("rmake.rs")); + // In test code we want to be very pedantic about values being silently discarded that are + // annotated with \`#[must_use]\`. diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index 30387af428c..f7895b12961 100644 --- a/tests/run-make/linker-warning/rmake.rs @@ -205,7 +179,7 @@ index 30387af428c..f7895b12961 100644 regex::escape(run_make_support::build_root().to_str().unwrap()), "/build-root", ) - .run(); + .normalize(r#""[^"]*\/symbols.o""#, "\\"/symbols.o\\"") EOF echo "[TEST] rustc test suite" From aa31d42b39cf9a7c216736392aa522a94794c071 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 12:51:22 +0000 Subject: [PATCH 053/546] Remove no longer necessary disabling of dylib usage for run-make tests Run-make tests are now fully compiled using the bootstrap compiler. --- scripts/test_rustc_tests.sh | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 63f3c8b05036..005e87c2b2ad 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -150,22 +150,8 @@ rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same rm tests/ui/process/process-panic-after-fork.rs # same cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist -cp $(../dist/rustc-clif --print target-libdir)/libstd-*.so ../dist/lib/ cat < { - .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) - .arg("--edition=2021") -- .arg(&self.testpaths.file.join("rmake.rs")) -- .arg("-Cprefer-dynamic"); -+ .arg(&self.testpaths.file.join("rmake.rs")); - - // In test code we want to be very pedantic about values being silently discarded that are - // annotated with \`#[must_use]\`. diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index 30387af428c..f7895b12961 100644 --- a/tests/run-make/linker-warning/rmake.rs From 58c10c66c1d5ec2e47e35a4ff31f3758448f20f4 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 6 Dec 2024 23:16:06 +0100 Subject: [PATCH 054/546] Lower BinOp::Cmp to llvm.{s,u}cmp.* intrinsics Lowers `mir::BinOp::Cmp` (`three_way_compare` intrinsic) to the corresponding LLVM `llvm.{s,u}cmp.i8.*` intrinsics, added in LLVM 19. --- compiler/rustc_codegen_llvm/src/builder.rs | 30 ++++++++++++ compiler/rustc_codegen_llvm/src/context.rs | 12 +++++ compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 3 ++ .../rustc_codegen_ssa/src/traits/builder.rs | 12 +++++ tests/assembly/x86_64-cmp.rs | 46 ++++++++++++------- tests/codegen/comparison-operators-2-tuple.rs | 1 - tests/codegen/integer-cmp.rs | 35 ++++++++++++-- tests/codegen/intrinsics/three_way_compare.rs | 27 ++--------- 8 files changed, 124 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 3f20350d0efd..04b9ed02aab2 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -14,6 +14,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers, @@ -1119,6 +1120,35 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED) } } + fn three_way_compare( + &mut self, + ty: Ty<'tcx>, + lhs: Self::Value, + rhs: Self::Value, + ) -> Option { + // FIXME: See comment on the definition of `three_way_compare`. + if crate::llvm_util::get_version() < (20, 0, 0) { + return None; + } + + let name = match (ty.is_signed(), ty.primitive_size(self.tcx).bits()) { + (true, 8) => "llvm.scmp.i8.i8", + (true, 16) => "llvm.scmp.i8.i16", + (true, 32) => "llvm.scmp.i8.i32", + (true, 64) => "llvm.scmp.i8.i64", + (true, 128) => "llvm.scmp.i8.i128", + + (false, 8) => "llvm.ucmp.i8.i8", + (false, 16) => "llvm.ucmp.i8.i16", + (false, 32) => "llvm.ucmp.i8.i32", + (false, 64) => "llvm.ucmp.i8.i64", + (false, 128) => "llvm.ucmp.i8.i128", + + _ => bug!("three-way compare unsupported for type {ty:?}"), + }; + Some(self.call_intrinsic(name, &[lhs, rhs])) + } + /* Miscellaneous instructions */ fn memcpy( &mut self, diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ed8426ae1974..e367cf90eee6 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1108,6 +1108,18 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64); ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128); + ifn!("llvm.scmp.i8.i8", fn(t_i8, t_i8) -> t_i8); + ifn!("llvm.scmp.i8.i16", fn(t_i16, t_i16) -> t_i8); + ifn!("llvm.scmp.i8.i32", fn(t_i32, t_i32) -> t_i8); + ifn!("llvm.scmp.i8.i64", fn(t_i64, t_i64) -> t_i8); + ifn!("llvm.scmp.i8.i128", fn(t_i128, t_i128) -> t_i8); + + ifn!("llvm.ucmp.i8.i8", fn(t_i8, t_i8) -> t_i8); + ifn!("llvm.ucmp.i8.i16", fn(t_i16, t_i16) -> t_i8); + ifn!("llvm.ucmp.i8.i32", fn(t_i32, t_i32) -> t_i8); + ifn!("llvm.ucmp.i8.i64", fn(t_i64, t_i64) -> t_i8); + ifn!("llvm.ucmp.i8.i128", fn(t_i128, t_i128) -> t_i8); + ifn!("llvm.lifetime.start.p0i8", fn(t_i64, ptr) -> void); ifn!("llvm.lifetime.end.p0i8", fn(t_i64, ptr) -> void); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d24e48b37a46..992a23442e2f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1005,6 +1005,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::Cmp => { use std::cmp::Ordering; assert!(!is_float); + if let Some(value) = bx.three_way_compare(lhs_ty, lhs, rhs) { + return value; + } let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed); if bx.cx().tcx().sess.opts.optimize == OptLevel::No { // FIXME: This actually generates tighter assembly, and is a classic trick diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 99fd6b6510ff..070b680e540a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -397,6 +397,18 @@ pub trait BuilderMethods<'a, 'tcx>: fn icmp(&mut self, op: IntPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + /// Returns `-1` if `lhs < rhs`, `0` if `lhs == rhs`, and `1` if `lhs > rhs`. + // FIXME: Move the default implementation from `codegen_scalar_binop` into this method and + // remove the `Option` return once LLVM 20 is the minimum version. + fn three_way_compare( + &mut self, + _ty: Ty<'tcx>, + _lhs: Self::Value, + _rhs: Self::Value, + ) -> Option { + None + } + fn memcpy( &mut self, dst: Self::Value, diff --git a/tests/assembly/x86_64-cmp.rs b/tests/assembly/x86_64-cmp.rs index 8cccab7d40da..26c9013d96fc 100644 --- a/tests/assembly/x86_64-cmp.rs +++ b/tests/assembly/x86_64-cmp.rs @@ -1,5 +1,8 @@ -//@ revisions: DEBUG LLVM-PRE-20-OPTIM LLVM-20-OPTIM -//@ [DEBUG] compile-flags: -C opt-level=0 +//@ revisions: LLVM-PRE-20-DEBUG LLVM-20-DEBUG LLVM-PRE-20-OPTIM LLVM-20-OPTIM +//@ [LLVM-PRE-20-DEBUG] compile-flags: -C opt-level=0 +//@ [LLVM-PRE-20-DEBUG] max-llvm-major-version: 19 +//@ [LLVM-20-DEBUG] compile-flags: -C opt-level=0 +//@ [LLVM-20-DEBUG] min-llvm-version: 20 //@ [LLVM-PRE-20-OPTIM] compile-flags: -C opt-level=3 //@ [LLVM-PRE-20-OPTIM] max-llvm-major-version: 19 //@ [LLVM-20-OPTIM] compile-flags: -C opt-level=3 @@ -16,13 +19,19 @@ use std::intrinsics::three_way_compare; #[no_mangle] // CHECK-LABEL: signed_cmp: pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { - // DEBUG: cmp - // DEBUG: setg - // DEBUG: and - // DEBUG: cmp - // DEBUG: setl - // DEBUG: and - // DEBUG: sub + // LLVM-PRE-20-DEBUG: cmp + // LLVM-PRE-20-DEBUG: setg + // LLVM-PRE-20-DEBUG: and + // LLVM-PRE-20-DEBUG: cmp + // LLVM-PRE-20-DEBUG: setl + // LLVM-PRE-20-DEBUG: and + // LLVM-PRE-20-DEBUG: sub + // + // LLVM-20-DEBUG: sub + // LLVM-20-DEBUG: setl + // LLVM-20-DEBUG: setg + // LLVM-20-DEBUG: sub + // LLVM-20-DEBUG: ret // LLVM-PRE-20-OPTIM: xor // LLVM-PRE-20-OPTIM: cmp @@ -42,13 +51,18 @@ pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { #[no_mangle] // CHECK-LABEL: unsigned_cmp: pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { - // DEBUG: cmp - // DEBUG: seta - // DEBUG: and - // DEBUG: cmp - // DEBUG: setb - // DEBUG: and - // DEBUG: sub + // LLVM-PRE-20-DEBUG: cmp + // LLVM-PRE-20-DEBUG: seta + // LLVM-PRE-20-DEBUG: and + // LLVM-PRE-20-DEBUG: cmp + // LLVM-PRE-20-DEBUG: setb + // LLVM-PRE-20-DEBUG: and + // LLVM-PRE-20-DEBUG: sub + // + // LLVM-20-DEBUG: sub + // LLVM-20-DEBUG: seta + // LLVM-20-DEBUG: sbb + // LLVM-20-DEBUG: ret // LLVM-PRE-20-OPTIM: xor // LLVM-PRE-20-OPTIM: cmp diff --git a/tests/codegen/comparison-operators-2-tuple.rs b/tests/codegen/comparison-operators-2-tuple.rs index 91a99f9b91f9..6a7e489c82dd 100644 --- a/tests/codegen/comparison-operators-2-tuple.rs +++ b/tests/codegen/comparison-operators-2-tuple.rs @@ -1,5 +1,4 @@ //@ compile-flags: -C opt-level=1 -Z merge-functions=disabled -//@ only-x86_64 //@ min-llvm-version: 20 #![crate_type = "lib"] diff --git a/tests/codegen/integer-cmp.rs b/tests/codegen/integer-cmp.rs index 9bbf243946d1..812fa8e4a424 100644 --- a/tests/codegen/integer-cmp.rs +++ b/tests/codegen/integer-cmp.rs @@ -4,7 +4,7 @@ //@ revisions: llvm-pre-20 llvm-20 //@ [llvm-20] min-llvm-version: 20 //@ [llvm-pre-20] max-llvm-major-version: 19 -//@ compile-flags: -C opt-level=3 +//@ compile-flags: -C opt-level=3 -Zmerge-functions=disabled #![crate_type = "lib"] @@ -13,7 +13,7 @@ use std::cmp::Ordering; // CHECK-LABEL: @cmp_signed #[no_mangle] pub fn cmp_signed(a: i64, b: i64) -> Ordering { - // llvm-20: @llvm.scmp.i8.i64 + // llvm-20: call{{.*}} i8 @llvm.scmp.i8.i64 // llvm-pre-20: icmp slt // llvm-pre-20: icmp ne // llvm-pre-20: zext i1 @@ -24,10 +24,39 @@ pub fn cmp_signed(a: i64, b: i64) -> Ordering { // CHECK-LABEL: @cmp_unsigned #[no_mangle] pub fn cmp_unsigned(a: u32, b: u32) -> Ordering { - // llvm-20: @llvm.ucmp.i8.i32 + // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32 // llvm-pre-20: icmp ult // llvm-pre-20: icmp ne // llvm-pre-20: zext i1 // llvm-pre-20: select i1 a.cmp(&b) } + +// CHECK-LABEL: @cmp_char +#[no_mangle] +pub fn cmp_char(a: char, b: char) -> Ordering { + // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32 + // llvm-pre-20: icmp ult + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 + a.cmp(&b) +} + +// CHECK-LABEL: @cmp_tuple +#[no_mangle] +pub fn cmp_tuple(a: (i16, u16), b: (i16, u16)) -> Ordering { + // llvm-20-DAG: call{{.*}} i8 @llvm.ucmp.i8.i16 + // llvm-20-DAG: call{{.*}} i8 @llvm.scmp.i8.i16 + // llvm-20: ret i8 + // llvm-pre-20: icmp slt + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 + // llvm-pre-20: icmp ult + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 + // llvm-pre-20: select i1 + a.cmp(&b) +} diff --git a/tests/codegen/intrinsics/three_way_compare.rs b/tests/codegen/intrinsics/three_way_compare.rs index 9a476abe8914..95fcb636f7ca 100644 --- a/tests/codegen/intrinsics/three_way_compare.rs +++ b/tests/codegen/intrinsics/three_way_compare.rs @@ -2,6 +2,7 @@ //@ [DEBUG] compile-flags: -C opt-level=0 //@ [OPTIM] compile-flags: -C opt-level=3 //@ compile-flags: -C no-prepopulate-passes +//@ min-llvm-version: 20 #![crate_type = "lib"] #![feature(core_intrinsics)] @@ -12,17 +13,8 @@ use std::intrinsics::three_way_compare; // CHECK-LABEL: @signed_cmp // CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { - // DEBUG: %[[GT:.+]] = icmp sgt i16 %a, %b - // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8 - // DEBUG: %[[LT:.+]] = icmp slt i16 %a, %b - // DEBUG: %[[ZLT:.+]] = zext i1 %[[LT]] to i8 - // DEBUG: %[[R:.+]] = sub nsw i8 %[[ZGT]], %[[ZLT]] - - // OPTIM: %[[LT:.+]] = icmp slt i16 %a, %b - // OPTIM: %[[NE:.+]] = icmp ne i16 %a, %b - // OPTIM: %[[CGE:.+]] = select i1 %[[NE]], i8 1, i8 0 - // OPTIM: %[[CGEL:.+]] = select i1 %[[LT]], i8 -1, i8 %[[CGE]] - // OPTIM: ret i8 %[[CGEL]] + // CHECK: %[[CMP:.+]] = call i8 @llvm.scmp.i8.i16(i16 %a, i16 %b) + // CHECK-NEXT: ret i8 %[[CMP]] three_way_compare(a, b) } @@ -30,16 +22,7 @@ pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { // CHECK-LABEL: @unsigned_cmp // CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { - // DEBUG: %[[GT:.+]] = icmp ugt i16 %a, %b - // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8 - // DEBUG: %[[LT:.+]] = icmp ult i16 %a, %b - // DEBUG: %[[ZLT:.+]] = zext i1 %[[LT]] to i8 - // DEBUG: %[[R:.+]] = sub nsw i8 %[[ZGT]], %[[ZLT]] - - // OPTIM: %[[LT:.+]] = icmp ult i16 %a, %b - // OPTIM: %[[NE:.+]] = icmp ne i16 %a, %b - // OPTIM: %[[CGE:.+]] = select i1 %[[NE]], i8 1, i8 0 - // OPTIM: %[[CGEL:.+]] = select i1 %[[LT]], i8 -1, i8 %[[CGE]] - // OPTIM: ret i8 %[[CGEL]] + // CHECK: %[[CMP:.+]] = call i8 @llvm.ucmp.i8.i16(i16 %a, i16 %b) + // CHECK-NEXT: ret i8 %[[CMP]] three_way_compare(a, b) } From 4b7bcdbf9fcfa4972a97e7cc47b105d7b3711b19 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 14:16:09 +0000 Subject: [PATCH 055/546] Use the github cli to publish dev releases This removes a whole bunch of complicated javascript with two lines of bash. Fixes rust-lang/rustc_codegen_cranelift#1562 --- .github/actions/github-release/README.md | 18 - .github/actions/github-release/action.yml | 13 - .github/actions/github-release/main.js | 162 ----- .../actions/github-release/package-lock.json | 571 ------------------ .github/actions/github-release/package.json | 11 - .github/workflows/main.yml | 15 +- 6 files changed, 6 insertions(+), 784 deletions(-) delete mode 100644 .github/actions/github-release/README.md delete mode 100644 .github/actions/github-release/action.yml delete mode 100644 .github/actions/github-release/main.js delete mode 100644 .github/actions/github-release/package-lock.json delete mode 100644 .github/actions/github-release/package.json diff --git a/.github/actions/github-release/README.md b/.github/actions/github-release/README.md deleted file mode 100644 index c70ba8f49538..000000000000 --- a/.github/actions/github-release/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# github-release - -An action used to publish GitHub releases for `wasmtime`. - -As of the time of this writing there's a few actions floating around which -perform github releases but they all tend to have their set of drawbacks. -Additionally nothing handles deleting releases which we need for our rolling -`dev` release. - -To handle all this this action rolls-its-own implementation using the -actions/toolkit repository and packages published there. These run in a Docker -container and take various inputs to orchestrate the release from the build. - -More comments can be found in `main.js`. - -Testing this is really hard. If you want to try though run `npm install` and -then `node main.js`. You'll have to configure a bunch of env vars though to get -anything reasonably working. diff --git a/.github/actions/github-release/action.yml b/.github/actions/github-release/action.yml deleted file mode 100644 index 36e5209f50c3..000000000000 --- a/.github/actions/github-release/action.yml +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -name: 'rustc_codegen_cranelift github releases' -description: 'rustc_codegen_cranelift github releases' -inputs: - token: - description: '' - required: true - files: - description: '' - required: true -runs: - using: 'node16' - main: 'main.js' diff --git a/.github/actions/github-release/main.js b/.github/actions/github-release/main.js deleted file mode 100644 index 1eb2b7f23b26..000000000000 --- a/.github/actions/github-release/main.js +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -const core = require('@actions/core'); -const path = require("path"); -const fs = require("fs"); -const github = require('@actions/github'); -const glob = require('glob'); - -function sleep(milliseconds) { - return new Promise(resolve => setTimeout(resolve, milliseconds)) -} - -async function runOnce() { - // Load all our inputs and env vars. Note that `getInput` reads from `INPUT_*` - const files = core.getInput('files'); - const token = core.getInput('token'); - const slug = process.env.GITHUB_REPOSITORY; - const owner = slug.split('/')[0]; - const repo = slug.split('/')[1]; - const sha = process.env.GITHUB_SHA; - let name = 'dev'; - if (process.env.GITHUB_REF.startsWith('refs/tags/v')) { - name = process.env.GITHUB_REF.substring(10); - } - - core.info(`files: ${files}`); - core.info(`name: ${name}`); - core.info(`token: ${token}`); - - const octokit = github.getOctokit(token); - - // For the `dev` release we may need to update the tag to point to the new - // commit on this branch. All other names should already have tags associated - // with them. - if (name == 'dev') { - let tag = null; - try { - tag = await octokit.request("GET /repos/:owner/:repo/git/refs/tags/:name", { owner, repo, name }); - core.info(`found existing tag`); - console.log("tag: ", JSON.stringify(tag.data, null, 2)); - } catch (e) { - // ignore if this tag doesn't exist - core.info(`no existing tag found`); - } - - if (tag === null || tag.data.object.sha !== sha) { - core.info(`updating existing tag or creating new one`); - - try { - core.info(`updating dev tag`); - await octokit.rest.git.updateRef({ - owner, - repo, - ref: 'tags/dev', - sha, - force: true, - }); - } catch (e) { - console.log("ERROR: ", JSON.stringify(e.response, null, 2)); - core.info(`creating dev tag`); - try { - await octokit.rest.git.createRef({ - owner, - repo, - ref: 'refs/tags/dev', - sha, - }); - } catch (e) { - // we might race with others, so assume someone else has created the - // tag by this point. - console.log("failed to create tag: ", JSON.stringify(e.response, null, 2)); - } - } - - console.log("double-checking tag is correct"); - tag = await octokit.request("GET /repos/:owner/:repo/git/refs/tags/:name", { owner, repo, name }); - if (tag.data.object.sha !== sha) { - console.log("tag: ", JSON.stringify(tag.data, null, 2)); - throw new Error("tag didn't work"); - } - } else { - core.info(`existing tag works`); - } - } - - // Delete a previous release - try { - core.info(`fetching release`); - let release = await octokit.rest.repos.getReleaseByTag({ owner, repo, tag: name }); - console.log("found release: ", JSON.stringify(release.data, null, 2)); - await octokit.rest.repos.deleteRelease({ - owner, - repo, - release_id: release.data.id, - }); - console.log("deleted release"); - } catch (e) { - console.log("ERROR: ", JSON.stringify(e, null, 2)); - } - - console.log("creating a release"); - let release = await octokit.rest.repos.createRelease({ - owner, - repo, - tag_name: name, - prerelease: name === 'dev', - }); - - // Delete all assets from a previous run - for (const asset of release.data.assets) { - console.log(`deleting prior asset ${asset.id}`); - await octokit.rest.repos.deleteReleaseAsset({ - owner, - repo, - asset_id: asset.id, - }); - } - - // Upload all the relevant assets for this release as just general blobs. - for (const file of glob.sync(files)) { - const size = fs.statSync(file).size; - const name = path.basename(file); - core.info(`upload ${file}`); - await octokit.rest.repos.uploadReleaseAsset({ - data: fs.createReadStream(file), - headers: { 'content-length': size, 'content-type': 'application/octet-stream' }, - name, - url: release.data.upload_url, - }); - } -} - -async function run() { - const retries = 10; - for (let i = 0; i < retries; i++) { - try { - await runOnce(); - break; - } catch (e) { - if (i === retries - 1) - throw e; - logError(e); - console.log("RETRYING after 10s"); - await sleep(10000) - } - } -} - -function logError(e) { - console.log("ERROR: ", e.message); - try { - console.log(JSON.stringify(e, null, 2)); - } catch (e) { - // ignore json errors for now - } - console.log(e.stack); -} - -run().catch(err => { - logError(err); - core.setFailed(err.message); -}); diff --git a/.github/actions/github-release/package-lock.json b/.github/actions/github-release/package-lock.json deleted file mode 100644 index dd3b2a048f09..000000000000 --- a/.github/actions/github-release/package-lock.json +++ /dev/null @@ -1,571 +0,0 @@ -{ - "name": "rustc_codegen_cranelift-github-release", - "version": "0.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "rustc_codegen_cranelift-github-release", - "version": "0.0.0", - "dependencies": { - "@actions/core": "^1.9.1", - "@actions/github": "^5.1.0", - "glob": "^7.1.5" - } - }, - "node_modules/@actions/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", - "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", - "dependencies": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" - } - }, - "node_modules/@actions/github": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz", - "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==", - "dependencies": { - "@actions/http-client": "^2.0.1", - "@octokit/core": "^3.6.0", - "@octokit/plugin-paginate-rest": "^2.17.0", - "@octokit/plugin-rest-endpoint-methods": "^5.13.0" - } - }, - "node_modules/@actions/http-client": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", - "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", - "dependencies": { - "tunnel": "^0.0.6" - } - }, - "node_modules/@octokit/auth-token": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", - "dependencies": { - "@octokit/types": "^6.0.3" - } - }, - "node_modules/@octokit/core": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", - "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", - "dependencies": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.3", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/endpoint": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", - "dependencies": { - "@octokit/types": "^6.0.3", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/graphql": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", - "dependencies": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "12.11.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", - "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "2.21.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", - "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", - "dependencies": { - "@octokit/types": "^6.40.0" - }, - "peerDependencies": { - "@octokit/core": ">=2" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.16.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", - "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", - "dependencies": { - "@octokit/types": "^6.39.0", - "deprecation": "^2.3.1" - }, - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/request": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", - "dependencies": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/request-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", - "dependencies": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "node_modules/@octokit/types": { - "version": "6.41.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", - "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", - "dependencies": { - "@octokit/openapi-types": "^12.11.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - } - }, - "dependencies": { - "@actions/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", - "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", - "requires": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" - } - }, - "@actions/github": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz", - "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==", - "requires": { - "@actions/http-client": "^2.0.1", - "@octokit/core": "^3.6.0", - "@octokit/plugin-paginate-rest": "^2.17.0", - "@octokit/plugin-rest-endpoint-methods": "^5.13.0" - } - }, - "@actions/http-client": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", - "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", - "requires": { - "tunnel": "^0.0.6" - } - }, - "@octokit/auth-token": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", - "requires": { - "@octokit/types": "^6.0.3" - } - }, - "@octokit/core": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", - "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", - "requires": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.3", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/endpoint": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", - "requires": { - "@octokit/types": "^6.0.3", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/graphql": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", - "requires": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/openapi-types": { - "version": "12.11.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", - "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" - }, - "@octokit/plugin-paginate-rest": { - "version": "2.21.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", - "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", - "requires": { - "@octokit/types": "^6.40.0" - } - }, - "@octokit/plugin-rest-endpoint-methods": { - "version": "5.16.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", - "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", - "requires": { - "@octokit/types": "^6.39.0", - "deprecation": "^2.3.1" - } - }, - "@octokit/request": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", - "requires": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/request-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", - "requires": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "@octokit/types": { - "version": "6.41.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", - "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", - "requires": { - "@octokit/openapi-types": "^12.11.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" - }, - "universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - } - } -} diff --git a/.github/actions/github-release/package.json b/.github/actions/github-release/package.json deleted file mode 100644 index d9c23f8873ec..000000000000 --- a/.github/actions/github-release/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "rustc_codegen_cranelift-github-release", - "version": "0.0.0", - "license": "Apache-2.0 WITH LLVM-exception", - "main": "main.js", - "dependencies": { - "@actions/core": "^1.9.1", - "@actions/github": "^5.1.0", - "glob": "^7.1.5" - } -} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7d941887100d..6fd288d195c0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -261,12 +261,9 @@ jobs: rmdir artifacts/ # verify all artifacts are represented in release/ ls -R release/ - - run: npm install --production - working-directory: .github/actions/github-release - - - name: Publish Release - uses: ./.github/actions/github-release - with: - files: "release/*" - token: ${{ github.token }} - continue-on-error: true + - name: Publish release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release delete --cleanup-tag -y dev || true + gh release create --target $GITHUB_SHA --prerelease dev release/* From fd3fb2cf46a155682eee50ef8d6f84cac4ef154d Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Wed, 5 Mar 2025 18:14:07 -0800 Subject: [PATCH 056/546] Remove #[cfg(not(test))] gates in core These gates are unnecessary now that unit tests for `core` are in a separate package, `coretests`, instead of in the same files as the source code. They previously prevented the two `core` versions from conflicting with each other. --- ...0027-stdlib-128bit-atomic-operations.patch | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/patches/0027-stdlib-128bit-atomic-operations.patch b/patches/0027-stdlib-128bit-atomic-operations.patch index 3c81b04c0ead..d7e3b11127c4 100644 --- a/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/patches/0027-stdlib-128bit-atomic-operations.patch @@ -1,4 +1,4 @@ -From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001 +From 5d7c709608b01301d4628d2159265936d4440b67 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 18 Feb 2021 18:45:28 +0100 Subject: [PATCH] Disable 128bit atomic operations @@ -7,11 +7,10 @@ Cranelift doesn't support them yet --- library/core/src/panic/unwind_safe.rs | 6 ----- library/core/src/sync/atomic.rs | 38 --------------------------- - library/core/tests/atomic.rs | 4 --- - 4 files changed, 4 insertions(+), 50 deletions(-) + 2 files changed, 44 deletions(-) diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs -index 092b7cf..158cf71 100644 +index a60f0799c0e..af056fbf41f 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -216,9 +216,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {} @@ -21,7 +20,7 @@ index 092b7cf..158cf71 100644 -#[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "99069")] -impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {} - + #[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] @@ -235,9 +232,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {} @@ -31,14 +30,14 @@ index 092b7cf..158cf71 100644 -#[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "99069")] -impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {} - + #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs -index d9de37e..8293fce 100644 +index bf2b6d59f88..d5ccce03bbf 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -2996,44 +2996,6 @@ atomic_int! { +@@ -3585,44 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type { 8, u64 AtomicU64 } @@ -54,7 +53,7 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), -- cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), +- rustc_diagnostic_item = "AtomicI128", - "i128", - "#![feature(integer_atomics)]\n\n", - atomic_min, atomic_max, @@ -73,7 +72,7 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), -- cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), +- rustc_diagnostic_item = "AtomicU128", - "u128", - "#![feature(integer_atomics)]\n\n", - atomic_umin, atomic_umax, @@ -83,7 +82,6 @@ index d9de37e..8293fce 100644 #[cfg(target_has_atomic_load_store = "ptr")] macro_rules! atomic_int_ptr_sized { - ( $($target_pointer_width:literal $align:literal)* ) => { $( --- -2.26.2.7.g19db9cfb68 +-- +2.48.1 From 540565e5b97b4669cd84ecd57f3d7affd00e83a1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:46:33 +0000 Subject: [PATCH 057/546] Fully test the alloc crate through alloctests For the tests that make use of internal implementation details, we include the module to test using #[path] in alloctests now. --- ...9-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index c2027863b00b..754025ff49db 100644 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -12,15 +12,15 @@ index 7165c3e48af..968552ad435 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -11,7 +11,7 @@ test = { path = "../test" } - edition = "2021" + bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } - [dev-dependencies] - rand = { version = "0.8.5", default-features = false, features = ["alloc"] } + [features] + compiler-builtins-mem = ['compiler_builtins/mem'] -- 2.34.1 From f86a71dfbf35b36b1ce439f65dfe51f591688393 Mon Sep 17 00:00:00 2001 From: Amy Kwan Date: Sat, 8 Mar 2025 00:23:46 -0500 Subject: [PATCH 058/546] [AIX] Ignore linting on repr(C) structs with repr(packed) or repr(align(n)) This PR updates the lint added in 9b40bd7 to ignore repr(C) structs that also have repr(packed) or repr(align(n)). As these representations can be modifiers on repr(C), it is assumed that users that add these should know what they are doing, and thus the the lint should not warn on the respective structs. For example, for the time being, using repr(packed) and manually padding a repr(C) struct can be done to correctly align struct members on AIX. --- compiler/rustc_lint/src/types.rs | 6 ++++++ tests/ui/layout/reprc-power-alignment.rs | 26 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fcadbfc3c4a7..71116d0bfe42 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1638,6 +1638,9 @@ impl ImproperCTypesDefinitions { return true; } else if let Adt(adt_def, _) = ty.kind() && adt_def.is_struct() + && adt_def.repr().c() + && !adt_def.repr().packed() + && adt_def.repr().align.is_none() { let struct_variant = adt_def.variant(VariantIdx::ZERO); // Within a nested struct, all fields are examined to correctly @@ -1659,8 +1662,11 @@ impl ImproperCTypesDefinitions { item: &'tcx hir::Item<'tcx>, ) { let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id()); + // repr(C) structs also with packed or aligned representation + // should be ignored. if adt_def.repr().c() && !adt_def.repr().packed() + && adt_def.repr().align.is_none() && cx.tcx.sess.target.os == "aix" && !adt_def.all_fields().next().is_none() { diff --git a/tests/ui/layout/reprc-power-alignment.rs b/tests/ui/layout/reprc-power-alignment.rs index f6c1df55988b..f144094d43fb 100644 --- a/tests/ui/layout/reprc-power-alignment.rs +++ b/tests/ui/layout/reprc-power-alignment.rs @@ -148,5 +148,29 @@ pub struct I { d: f32, e: f64, } - +#[repr(C)] +pub struct J { + a: u8, + b: I, +} +// The lint also ignores diagnosing #[repr(align(n))]. +#[repr(C, align(8))] +pub struct K { + a: u8, + b: u8, + c: f64, + d: f32, + e: f64, +} +#[repr(C)] +pub struct L { + a: u8, + b: K, +} +#[repr(C, align(8))] +pub struct M { + a: u8, + b: K, + c: L, +} fn main() { } From 28bd22c3d9a477ff9b7b85782fb517c29b58ed88 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 9 Mar 2025 23:42:48 +0000 Subject: [PATCH 059/546] rustdoc: Gate unstable `doc(cfg())` predicates --- src/librustdoc/clean/cfg.rs | 14 ++++---------- src/librustdoc/clean/types.rs | 7 +++++++ src/librustdoc/doctest/rust.rs | 2 +- tests/rustdoc-ui/doc-cfg-unstable.rs | 10 ++++++++++ tests/rustdoc-ui/doc-cfg-unstable.stderr | 23 +++++++++++++++++++++++ 5 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 tests/rustdoc-ui/doc-cfg-unstable.rs create mode 100644 tests/rustdoc-ui/doc-cfg-unstable.stderr diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index ab169f3c2a4d..1541e7201cef 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -8,7 +8,6 @@ use std::{mem, ops}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::FxHashSet; -use rustc_feature::Features; use rustc_session::parse::ParseSess; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; @@ -132,18 +131,13 @@ impl Cfg { /// Checks whether the given configuration can be matched in the current session. /// /// Equivalent to `attr::cfg_matches`. - // FIXME: Actually make use of `features`. - pub(crate) fn matches(&self, psess: &ParseSess, features: Option<&Features>) -> bool { + pub(crate) fn matches(&self, psess: &ParseSess) -> bool { match *self { Cfg::False => false, Cfg::True => true, - Cfg::Not(ref child) => !child.matches(psess, features), - Cfg::All(ref sub_cfgs) => { - sub_cfgs.iter().all(|sub_cfg| sub_cfg.matches(psess, features)) - } - Cfg::Any(ref sub_cfgs) => { - sub_cfgs.iter().any(|sub_cfg| sub_cfg.matches(psess, features)) - } + Cfg::Not(ref child) => !child.matches(psess), + Cfg::All(ref sub_cfgs) => sub_cfgs.iter().all(|sub_cfg| sub_cfg.matches(psess)), + Cfg::Any(ref sub_cfgs) => sub_cfgs.iter().any(|sub_cfg| sub_cfg.matches(psess)), Cfg::Cfg(name, value) => psess.config.contains(&(name, value)), } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9e9cd5288349..e70511a798a3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1056,6 +1056,13 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator .meta_item() .and_then(|item| rustc_expand::config::parse_cfg(item, sess)) { + // The result is unused here but we can gate unstable predicates + rustc_attr_parsing::cfg_matches( + cfg_mi, + tcx.sess, + rustc_ast::CRATE_NODE_ID, + Some(tcx.features()), + ); match Cfg::parse(cfg_mi) { Ok(new_cfg) => cfg &= new_cfg, Err(e) => { diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 907e2a3eb2fc..b12c516a827d 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -98,7 +98,7 @@ impl HirCollector<'_> { let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); if let Some(ref cfg) = extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default()) - && !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features())) + && !cfg.matches(&self.tcx.sess.psess) { return; } diff --git a/tests/rustdoc-ui/doc-cfg-unstable.rs b/tests/rustdoc-ui/doc-cfg-unstable.rs new file mode 100644 index 000000000000..14c2e83ec854 --- /dev/null +++ b/tests/rustdoc-ui/doc-cfg-unstable.rs @@ -0,0 +1,10 @@ +// #138113: rustdoc didn't gate unstable predicates inside `doc(cfg(..))` +#![feature(doc_cfg)] + +// `cfg_boolean_literals` +#[doc(cfg(false))] //~ ERROR `cfg(false)` is experimental and subject to change +pub fn cfg_boolean_literals() {} + +// `cfg_version` +#[doc(cfg(sanitize = "thread"))] //~ ERROR `cfg(sanitize)` is experimental and subject to change +pub fn cfg_sanitize() {} diff --git a/tests/rustdoc-ui/doc-cfg-unstable.stderr b/tests/rustdoc-ui/doc-cfg-unstable.stderr new file mode 100644 index 000000000000..54de3b178edb --- /dev/null +++ b/tests/rustdoc-ui/doc-cfg-unstable.stderr @@ -0,0 +1,23 @@ +error[E0658]: `cfg(false)` is experimental and subject to change + --> $DIR/doc-cfg-unstable.rs:5:11 + | +LL | #[doc(cfg(false))] + | ^^^^^ + | + = note: see issue #131204 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(sanitize)` is experimental and subject to change + --> $DIR/doc-cfg-unstable.rs:9:11 + | +LL | #[doc(cfg(sanitize = "thread"))] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #39699 for more information + = help: add `#![feature(cfg_sanitize)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From 9e5c942286f8d2367987daac856300447ee43776 Mon Sep 17 00:00:00 2001 From: Paul Menage Date: Mon, 10 Mar 2025 08:31:06 -0700 Subject: [PATCH 060/546] Mark some std tests as requiring `panic = "unwind"` This allows these test modules to pass on builds/targets without unwinding support, where `panic = "abort"` - the ignored tests are for functionality that's not supported on those targets. --- library/std/src/thread/tests.rs | 5 +++++ library/std/tests/sync/mutex.rs | 10 ++++++++++ library/std/tests/sync/once.rs | 4 ++++ library/std/tests/sync/once_lock.rs | 6 ++++-- library/std/tests/sync/rwlock.rs | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 06c347af1819..59ec48a57d1c 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -108,6 +108,7 @@ fn test_is_finished() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_join_panic() { match thread::spawn(move || panic!()).join() { result::Result::Err(_) => (), @@ -210,6 +211,7 @@ fn test_simple_newsched_spawn() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_try_panic_message_string_literal() { match thread::spawn(move || { panic!("static string"); @@ -226,6 +228,7 @@ fn test_try_panic_message_string_literal() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_try_panic_any_message_owned_str() { match thread::spawn(move || { panic_any("owned string".to_string()); @@ -242,6 +245,7 @@ fn test_try_panic_any_message_owned_str() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_try_panic_any_message_any() { match thread::spawn(move || { panic_any(Box::new(413u16) as Box); @@ -260,6 +264,7 @@ fn test_try_panic_any_message_any() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_try_panic_any_message_unit_struct() { struct Juju; diff --git a/library/std/tests/sync/mutex.rs b/library/std/tests/sync/mutex.rs index 74c627201073..88fb448d1ebf 100644 --- a/library/std/tests/sync/mutex.rs +++ b/library/std/tests/sync/mutex.rs @@ -118,6 +118,7 @@ fn test_into_inner_drop() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_into_inner_poison() { let m = new_poisoned_mutex(NonCopy(10)); @@ -135,6 +136,7 @@ fn test_get_cloned() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_get_cloned_poison() { let m = new_poisoned_mutex(Cloneable(10)); @@ -152,6 +154,7 @@ fn test_get_mut() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_get_mut_poison() { let mut m = new_poisoned_mutex(NonCopy(10)); @@ -179,6 +182,7 @@ fn test_set() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_set_poison() { fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) where @@ -217,6 +221,7 @@ fn test_replace() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_replace_poison() { fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) where @@ -261,6 +266,7 @@ fn test_mutex_arc_condvar() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_arc_condvar_poison() { let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); let packet2 = Packet(packet.0.clone()); @@ -290,6 +296,7 @@ fn test_arc_condvar_poison() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_mutex_arc_poison() { let arc = Arc::new(Mutex::new(1)); assert!(!arc.is_poisoned()); @@ -304,6 +311,7 @@ fn test_mutex_arc_poison() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_mutex_arc_poison_mapped() { let arc = Arc::new(Mutex::new(1)); assert!(!arc.is_poisoned()); @@ -335,6 +343,7 @@ fn test_mutex_arc_nested() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_mutex_arc_access_in_unwind() { let arc = Arc::new(Mutex::new(1)); let arc2 = arc.clone(); @@ -381,6 +390,7 @@ fn test_mapping_mapped_guard() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn panic_while_mapping_unlocked_poison() { let lock = Mutex::new(()); diff --git a/library/std/tests/sync/once.rs b/library/std/tests/sync/once.rs index a3ffc73fe06b..1b43831df3a4 100644 --- a/library/std/tests/sync/once.rs +++ b/library/std/tests/sync/once.rs @@ -52,6 +52,7 @@ fn stampede_once() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn poison_bad() { static O: Once = Once::new(); @@ -80,6 +81,7 @@ fn poison_bad() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn wait_for_force_to_finish() { static O: Once = Once::new(); @@ -137,6 +139,7 @@ fn wait() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn wait_on_poisoned() { let once = Once::new(); @@ -145,6 +148,7 @@ fn wait_on_poisoned() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn wait_force_on_poisoned() { let once = Once::new(); diff --git a/library/std/tests/sync/once_lock.rs b/library/std/tests/sync/once_lock.rs index ac9aaa8892ef..922fd7da3d44 100644 --- a/library/std/tests/sync/once_lock.rs +++ b/library/std/tests/sync/once_lock.rs @@ -77,8 +77,10 @@ fn get_or_try_init() { let cell: OnceLock = OnceLock::new(); assert!(cell.get().is_none()); - let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); - assert!(res.is_err()); + if cfg!(panic = "unwind") { + let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); + assert!(res.is_err()); + } assert!(cell.get().is_none()); assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); diff --git a/library/std/tests/sync/rwlock.rs b/library/std/tests/sync/rwlock.rs index 49f260648c6a..d2c784aefcf6 100644 --- a/library/std/tests/sync/rwlock.rs +++ b/library/std/tests/sync/rwlock.rs @@ -73,6 +73,7 @@ fn frob() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_poison_wr() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -85,6 +86,7 @@ fn test_rw_arc_poison_wr() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_poison_mapped_w_r() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -98,6 +100,7 @@ fn test_rw_arc_poison_mapped_w_r() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_poison_ww() { let arc = Arc::new(RwLock::new(1)); assert!(!arc.is_poisoned()); @@ -112,6 +115,7 @@ fn test_rw_arc_poison_ww() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_poison_mapped_w_w() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -126,6 +130,7 @@ fn test_rw_arc_poison_mapped_w_w() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_no_poison_rr() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -139,6 +144,7 @@ fn test_rw_arc_no_poison_rr() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_no_poison_mapped_r_r() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -153,6 +159,7 @@ fn test_rw_arc_no_poison_mapped_r_r() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_no_poison_rw() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -166,6 +173,7 @@ fn test_rw_arc_no_poison_rw() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_no_poison_mapped_r_w() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -218,6 +226,7 @@ fn test_rw_arc() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_rw_arc_access_in_unwind() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -316,6 +325,7 @@ fn test_into_inner_drop() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_into_inner_poison() { let m = new_poisoned_rwlock(NonCopy(10)); @@ -333,6 +343,7 @@ fn test_get_cloned() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_get_cloned_poison() { let m = new_poisoned_rwlock(Cloneable(10)); @@ -350,6 +361,7 @@ fn test_get_mut() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_get_mut_poison() { let mut m = new_poisoned_rwlock(NonCopy(10)); @@ -377,6 +389,7 @@ fn test_set() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_set_poison() { fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) where @@ -415,6 +428,7 @@ fn test_replace() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_replace_poison() { fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) where @@ -482,6 +496,7 @@ fn test_mapping_mapped_guard() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn panic_while_mapping_read_unlocked_no_poison() { let lock = RwLock::new(()); @@ -551,6 +566,7 @@ fn panic_while_mapping_read_unlocked_no_poison() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn panic_while_mapping_write_unlocked_poison() { let lock = RwLock::new(()); From d9de94001a25d33d4ba77cfa686c65f49264264c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 26 Jul 2024 10:04:02 +0000 Subject: [PATCH 061/546] Implement `#[define_opaque]` attribute for functions. --- example/issue-72793.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/example/issue-72793.rs b/example/issue-72793.rs index 2e08fbca8ef2..95d58b90e798 100644 --- a/example/issue-72793.rs +++ b/example/issue-72793.rs @@ -2,23 +2,21 @@ #![feature(type_alias_impl_trait)] -mod helper { - pub trait T { - type Item; - } - - pub type Alias<'a> = impl T; - - struct S; - impl<'a> T for &'a S { - type Item = &'a (); - } - - pub fn filter_positive<'a>() -> Alias<'a> { - &S - } +pub trait T { + type Item; +} + +pub type Alias<'a> = impl T; + +struct S; +impl<'a> T for &'a S { + type Item = &'a (); +} + +#[define_opaque(Alias)] +pub fn filter_positive<'a>() -> Alias<'a> { + &S } -use helper::*; fn with_positive(fun: impl Fn(Alias<'_>)) { fun(filter_positive()); From 85b1116a18595794da07c53642eefd81ff775faf Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 10 Mar 2025 15:58:41 +0000 Subject: [PATCH 062/546] rustdoc: Add FIXME test for `doc_cfg` interaction with `check_cfg` --- tests/rustdoc-ui/doc-cfg-check-cfg.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/rustdoc-ui/doc-cfg-check-cfg.rs diff --git a/tests/rustdoc-ui/doc-cfg-check-cfg.rs b/tests/rustdoc-ui/doc-cfg-check-cfg.rs new file mode 100644 index 000000000000..e3420dc07897 --- /dev/null +++ b/tests/rustdoc-ui/doc-cfg-check-cfg.rs @@ -0,0 +1,16 @@ +// Ensure that `doc(cfg())` respects `check-cfg` +// Currently not properly working +#![feature(doc_cfg)] +#![deny(unexpected_cfgs)] + +//@revisions: no_check cfg_empty cfg_foo +//@[cfg_empty] compile-flags: --check-cfg cfg() +//@[cfg_foo] compile-flags: --check-cfg cfg(foo) + +//@[no_check] check-pass +//@[cfg_empty] check-pass +//@[cfg_empty] known-bug: #138358 +//@[cfg_foo] check-pass + +#[doc(cfg(foo))] +pub fn foo() {} From 60805dc7e48171164af2e311a160bbbfa3baf6cb Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 8 Feb 2025 17:45:05 -0800 Subject: [PATCH 063/546] Deduplicate platform stdio types --- library/std/src/sys/stdio/solid.rs | 59 ++++-------------------- library/std/src/sys/stdio/teeos.rs | 55 ++++++---------------- library/std/src/sys/stdio/unsupported.rs | 18 +------- library/std/src/sys/stdio/xous.rs | 27 ++++------- 4 files changed, 32 insertions(+), 127 deletions(-) diff --git a/library/std/src/sys/stdio/solid.rs b/library/std/src/sys/stdio/solid.rs index a2ff4bb212ff..55daf0b54b92 100644 --- a/library/std/src/sys/stdio/solid.rs +++ b/library/std/src/sys/stdio/solid.rs @@ -1,22 +1,13 @@ +#[expect(dead_code)] +#[path = "unsupported.rs"] +mod unsupported_stdio; + use crate::io; use crate::sys::pal::abi; -pub struct Stdin; +pub type Stdin = unsupported_stdio::Stdin; pub struct Stdout; -pub struct Stderr; -struct PanicOutput; - -impl Stdin { - pub const fn new() -> Stdin { - Stdin - } -} - -impl io::Read for Stdin { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Ok(0) - } -} +pub type Stderr = Stdout; impl Stdout { pub const fn new() -> Stdout { @@ -35,46 +26,12 @@ impl io::Write for Stdout { } } -impl Stderr { - pub const fn new() -> Stderr { - Stderr - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl PanicOutput { - pub const fn new() -> PanicOutput { - PanicOutput - } -} - -impl io::Write for PanicOutput { - fn write(&mut self, buf: &[u8]) -> io::Result { - unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub const STDIN_BUF_SIZE: usize = 0; +pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE; pub fn is_ebadf(_err: &io::Error) -> bool { true } pub fn panic_output() -> Option { - Some(PanicOutput::new()) + Some(Stderr::new()) } diff --git a/library/std/src/sys/stdio/teeos.rs b/library/std/src/sys/stdio/teeos.rs index 67e251812da7..27b3292bf8f0 100644 --- a/library/std/src/sys/stdio/teeos.rs +++ b/library/std/src/sys/stdio/teeos.rs @@ -1,12 +1,16 @@ #![deny(unsafe_op_in_unsafe_fn)] +#[expect(dead_code)] +#[path = "unsupported.rs"] +mod unsupported_stdio; + use core::arch::asm; use crate::io; -pub struct Stdin; +pub type Stdin = unsupported_stdio::Stdin; pub struct Stdout; -pub struct Stderr; +pub type Stderr = Stdout; const KCALL_DEBUG_CMD_PUT_BYTES: i64 = 2; @@ -25,27 +29,6 @@ unsafe fn debug_call(cap_ref: u64, call_no: i64, arg1: u64, arg2: u64) -> i32 { ret as i32 } -fn print_buf(s: &[u8]) -> io::Result { - // Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`. - const MAX_LEN: usize = 512; - let len = if s.len() > MAX_LEN { MAX_LEN } else { s.len() }; - let result = unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, s.as_ptr() as u64, len as u64) }; - - if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) } -} - -impl Stdin { - pub const fn new() -> Stdin { - Stdin - } -} - -impl io::Read for Stdin { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Ok(0) - } -} - impl Stdout { pub const fn new() -> Stdout { Stdout @@ -54,7 +37,13 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - print_buf(buf) + // Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`. + const MAX_LEN: usize = 512; + let len = buf.len().min(MAX_LEN); + let result = + unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, buf.as_ptr() as u64, len as u64) }; + + if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) } } fn flush(&mut self) -> io::Result<()> { @@ -62,23 +51,7 @@ impl io::Write for Stdout { } } -impl Stderr { - pub const fn new() -> Stderr { - Stderr - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - print_buf(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub const STDIN_BUF_SIZE: usize = 0; +pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { err.raw_os_error() == Some(libc::EBADF as i32) diff --git a/library/std/src/sys/stdio/unsupported.rs b/library/std/src/sys/stdio/unsupported.rs index b5e3f5be9885..67f7c1b7efb9 100644 --- a/library/std/src/sys/stdio/unsupported.rs +++ b/library/std/src/sys/stdio/unsupported.rs @@ -2,7 +2,7 @@ use crate::io; pub struct Stdin; pub struct Stdout; -pub struct Stderr; +pub type Stderr = Stdout; impl Stdin { pub const fn new() -> Stdin { @@ -32,22 +32,6 @@ impl io::Write for Stdout { } } -impl Stderr { - pub const fn new() -> Stderr { - Stderr - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - pub const STDIN_BUF_SIZE: usize = 0; pub fn is_ebadf(_err: &io::Error) -> bool { diff --git a/library/std/src/sys/stdio/xous.rs b/library/std/src/sys/stdio/xous.rs index 717361452213..a92167642b70 100644 --- a/library/std/src/sys/stdio/xous.rs +++ b/library/std/src/sys/stdio/xous.rs @@ -1,27 +1,18 @@ +#[expect(dead_code)] +#[path = "unsupported.rs"] +mod unsupported_stdio; + use crate::io; - -pub struct Stdin; -pub struct Stdout {} -pub struct Stderr; - use crate::os::xous::ffi::{Connection, lend, try_lend, try_scalar}; use crate::os::xous::services::{LogLend, LogScalar, log_server, try_connect}; -impl Stdin { - pub const fn new() -> Stdin { - Stdin - } -} - -impl io::Read for Stdin { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Ok(0) - } -} +pub type Stdin = unsupported_stdio::Stdin; +pub struct Stdout; +pub struct Stderr; impl Stdout { pub const fn new() -> Stdout { - Stdout {} + Stdout } } @@ -73,7 +64,7 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = 0; +pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE; pub fn is_ebadf(_err: &io::Error) -> bool { true From 56715d986483f17af09dc2d73c99d20f7def7ab4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Mar 2025 08:03:54 +0100 Subject: [PATCH 064/546] intrinsics: remove unnecessary leading underscore from argument names --- example/mini_core.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 72c9df59d833..6e345b2a6fdf 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -624,25 +624,25 @@ pub mod intrinsics { #[rustc_intrinsic] pub fn size_of() -> usize; #[rustc_intrinsic] - pub unsafe fn size_of_val(_val: *const T) -> usize; + pub unsafe fn size_of_val(val: *const T) -> usize; #[rustc_intrinsic] pub fn min_align_of() -> usize; #[rustc_intrinsic] - pub unsafe fn min_align_of_val(_val: *const T) -> usize; + pub unsafe fn min_align_of_val(val: *const T) -> usize; #[rustc_intrinsic] - pub unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize); + pub unsafe fn copy(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic] - pub unsafe fn transmute(_e: T) -> U; + pub unsafe fn transmute(e: T) -> U; #[rustc_intrinsic] - pub unsafe fn ctlz_nonzero(_x: T) -> u32; + pub unsafe fn ctlz_nonzero(x: T) -> u32; #[rustc_intrinsic] pub fn needs_drop() -> bool; #[rustc_intrinsic] - pub fn bitreverse(_x: T) -> T; + pub fn bitreverse(x: T) -> T; #[rustc_intrinsic] - pub fn bswap(_x: T) -> T; + pub fn bswap(x: T) -> T; #[rustc_intrinsic] - pub unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize); + pub unsafe fn write_bytes(dst: *mut T, val: u8, count: usize); #[rustc_intrinsic] pub unsafe fn unreachable() -> !; } From 4ca551cf41d8273a2829f19a8e802fb557f14d6f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:08:42 +0000 Subject: [PATCH 065/546] Rustup to rustc 1.87.0-nightly (665025243 2025-03-11) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 4a566552322a..ec730a4402cf 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-06" +channel = "nightly-2025-03-12" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From d2b328e6b3a4cd42b85a289ce3285ca0ac461e7c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:08:50 +0000 Subject: [PATCH 066/546] Reduce verbosity of ./scripts/rustup.sh pull --- scripts/rustup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/rustup.sh b/scripts/rustup.sh index 355282911c25..152c243aa6ad 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -64,7 +64,7 @@ case $1 in cg_clif=$(pwd) pushd ../rust git fetch origin master - git checkout "$RUST_VERS" + git -c advice.detachedHead=false checkout "$RUST_VERS" "$cg_clif/git-fixed-subtree.sh" push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust popd git merge sync_from_rust -m "Sync from rust $RUST_VERS" From eea0db2590a79b58d1354c86954382e2952f7749 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:18:52 +0000 Subject: [PATCH 067/546] Fix rustc test suite --- scripts/test_rustc_tests.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 005e87c2b2ad..5e96210d8589 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -166,6 +166,18 @@ index 30387af428c..f7895b12961 100644 "/build-root", ) .normalize(r#""[^"]*\/symbols.o""#, "\\"/symbols.o\\"") +diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs +index 073116933bd..c3e4578204d 100644 +--- a/src/tools/compiletest/src/runtest/run_make.rs ++++ b/src/tools/compiletest/src/runtest/run_make.rs +@@ -109,7 +109,6 @@ pub(super) fn run_rmake_test(&self) { + // library or compiler features. Here, we force the stage 0 rustc to consider itself as + // a stable-channel compiler via \`RUSTC_BOOTSTRAP=-1\` to prevent *any* unstable + // library/compiler usages, even if stage 0 rustc is *actually* a nightly rustc. +- .env("RUSTC_BOOTSTRAP", "-1") + .arg("-o") + .arg(&recipe_bin) + // Specify library search paths for \`run_make_support\`. EOF echo "[TEST] rustc test suite" From 90645c187c9d640893a8b5d1cf61c4d29dfabde8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 12 Mar 2025 16:32:00 +0100 Subject: [PATCH 068/546] Reduce FormattingOptions to 64 bits. --- compiler/rustc_ast_lowering/src/expr.rs | 5 - compiler/rustc_ast_lowering/src/format.rs | 40 +-- compiler/rustc_hir/src/lang_items.rs | 1 - compiler/rustc_span/src/symbol.rs | 1 - library/core/src/fmt/float.rs | 6 +- library/core/src/fmt/mod.rs | 392 ++++++++++++---------- library/core/src/fmt/rt.rs | 21 +- 7 files changed, 253 insertions(+), 213 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5bb6704dde45..6e32f8bc28fa 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2150,11 +2150,6 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr_uint(sp, ast::UintTy::U16, value as u128) } - pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Char(value) }); - self.expr(sp, hir::ExprKind::Lit(lit)) - } - pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { let lit = self .arena diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index faa47274f96c..343895984ca4 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -361,24 +361,26 @@ fn make_format_spec<'hir>( zero_pad, debug_hex, } = &placeholder.format_options; - let fill = ctx.expr_char(sp, fill.unwrap_or(' ')); - let align = ctx.expr_lang_item_type_relative( - sp, - hir::LangItem::FormatAlignment, - match alignment { - Some(FormatAlignment::Left) => sym::Left, - Some(FormatAlignment::Right) => sym::Right, - Some(FormatAlignment::Center) => sym::Center, - None => sym::Unknown, - }, - ); - // This needs to match `Flag` in library/core/src/fmt/rt.rs. - let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) - | ((sign == Some(FormatSign::Minus)) as u32) << 1 - | (alternate as u32) << 2 - | (zero_pad as u32) << 3 - | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4 - | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5; + let fill = fill.unwrap_or(' '); + // These need to match the constants in library/core/src/fmt/rt.rs. + let align = match alignment { + Some(FormatAlignment::Left) => 0, + Some(FormatAlignment::Right) => 1, + Some(FormatAlignment::Center) => 2, + None => 3, + }; + // This needs to match the constants in library/core/src/fmt/rt.rs. + let flags: u32 = fill as u32 + | ((sign == Some(FormatSign::Plus)) as u32) << 21 + | ((sign == Some(FormatSign::Minus)) as u32) << 22 + | (alternate as u32) << 23 + | (zero_pad as u32) << 24 + | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25 + | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26 + | (width.is_some() as u32) << 27 + | (precision.is_some() as u32) << 28 + | align << 29 + | 1 << 31; // Highest bit always set. let flags = ctx.expr_u32(sp, flags); let precision = make_count(ctx, sp, precision, argmap); let width = make_count(ctx, sp, width, argmap); @@ -387,7 +389,7 @@ fn make_format_spec<'hir>( hir::LangItem::FormatPlaceholder, sym::new, )); - let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]); + let args = ctx.arena.alloc_from_iter([position, flags, precision, width]); ctx.expr_call_mut(sp, format_placeholder_new, args) } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 29f4d5b80769..e625514e9ffa 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -322,7 +322,6 @@ language_item_table! { BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; // Lang items needed for `format_args!()`. - FormatAlignment, sym::format_alignment, format_alignment, Target::Enum, GenericRequirement::None; FormatArgument, sym::format_argument, format_argument, Target::Struct, GenericRequirement::None; FormatArguments, sym::format_arguments, format_arguments, Target::Struct, GenericRequirement::None; FormatCount, sym::format_count, format_count, Target::Enum, GenericRequirement::None; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a8bec35d819..e6b305d2ffd3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1002,7 +1002,6 @@ symbols! { forbid, forget, format, - format_alignment, format_args, format_args_capture, format_args_macro, diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 4a43c12be9aa..870ad9df4fd3 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -86,7 +86,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { float_to_decimal_common_exact(fmt, num, sign, precision) } else { let min_precision = 0; @@ -162,7 +162,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { // 1 integral digit + `precision` fractional digits = `precision + 1` total digits float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper) } else { @@ -180,7 +180,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { // this behavior of {:.PREC?} predates exponential formatting for {:?} float_to_decimal_common_exact(fmt, num, sign, precision) } else { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e0dc632df705..e46424700087 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -33,19 +33,6 @@ pub enum Alignment { Center, } -#[doc(hidden)] -#[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] -impl From for Option { - fn from(value: rt::Alignment) -> Self { - match value { - rt::Alignment::Left => Some(Alignment::Left), - rt::Alignment::Right => Some(Alignment::Right), - rt::Alignment::Center => Some(Alignment::Center), - rt::Alignment::Unknown => None, - } - } -} - #[stable(feature = "debug_builders", since = "1.2.0")] pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[unstable(feature = "debug_closure_helpers", issue = "117729")] @@ -291,11 +278,50 @@ pub enum DebugAsHex { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "formatting_options", issue = "118117")] pub struct FormattingOptions { + /// Flags, with the following bit fields: + /// + /// ```text + /// 31 30 29 28 27 26 25 24 23 22 21 20 0 + /// ┌───┬───────┬───┬───┬───┬───┬───┬───┬───┬───┬──────────────────────────────────┐ + /// │ 1 │ align │ p │ w │ X?│ x?│'0'│ # │ - │ + │ fill │ + /// └───┴───────┴───┴───┴───┴───┴───┴───┴───┴───┴──────────────────────────────────┘ + /// │ │ │ │ └─┬───────────────────┘ └─┬──────────────────────────────┘ + /// │ │ │ │ │ └─ The fill character (21 bits char). + /// │ │ │ │ └─ The debug upper/lower hex, zero pad, alternate, and plus/minus flags. + /// │ │ │ └─ Whether a width is set. (The value is stored separately.) + /// │ │ └─ Whether a precision is set. (The value is stored separately.) + /// │ ├─ 0: Align left. (<) + /// │ ├─ 1: Align right. (>) + /// │ ├─ 2: Align center. (^) + /// │ └─ 3: Alignment not set. (default) + /// └─ Always set. + /// This makes it possible to distinguish formatting flags from + /// a &str size when stored in (the upper bits of) the same field. + /// (fmt::Arguments will make use of this property in the future.) + /// ``` flags: u32, - fill: char, - align: Option, - width: Option, - precision: Option, + /// Width if width flag (bit 27) above is set. Otherwise, always 0. + width: u16, + /// Precision if precision flag (bit 28) above is set. Otherwise, always 0. + precision: u16, +} + +// This needs to match with compiler/rustc_ast_lowering/src/format.rs. +mod flags { + pub(super) const SIGN_PLUS_FLAG: u32 = 1 << 21; + pub(super) const SIGN_MINUS_FLAG: u32 = 1 << 22; + pub(super) const ALTERNATE_FLAG: u32 = 1 << 23; + pub(super) const SIGN_AWARE_ZERO_PAD_FLAG: u32 = 1 << 24; + pub(super) const DEBUG_LOWER_HEX_FLAG: u32 = 1 << 25; + pub(super) const DEBUG_UPPER_HEX_FLAG: u32 = 1 << 26; + pub(super) const WIDTH_FLAG: u32 = 1 << 27; + pub(super) const PRECISION_FLAG: u32 = 1 << 28; + pub(super) const ALIGN_BITS: u32 = 0b11 << 29; + pub(super) const ALIGN_LEFT: u32 = 0 << 29; + pub(super) const ALIGN_RIGHT: u32 = 1 << 29; + pub(super) const ALIGN_CENTER: u32 = 2 << 29; + pub(super) const ALIGN_UNKNOWN: u32 = 3 << 29; + pub(super) const ALWAYS_SET: u32 = 1 << 31; } impl FormattingOptions { @@ -311,7 +337,11 @@ impl FormattingOptions { /// - no [`DebugAsHex`] output mode. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn new() -> Self { - Self { flags: 0, fill: ' ', align: None, width: None, precision: None } + Self { + flags: ' ' as u32 | flags::ALIGN_UNKNOWN | flags::ALWAYS_SET, + width: 0, + precision: 0, + } } /// Sets or removes the sign (the `+` or the `-` flag). @@ -324,13 +354,12 @@ impl FormattingOptions { /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] pub fn sign(&mut self, sign: Option) -> &mut Self { - self.flags = - self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); - match sign { - None => {} - Some(Sign::Plus) => self.flags |= 1 << rt::Flag::SignPlus as u32, - Some(Sign::Minus) => self.flags |= 1 << rt::Flag::SignMinus as u32, - } + let sign = match sign { + None => 0, + Some(Sign::Plus) => flags::SIGN_PLUS_FLAG, + Some(Sign::Minus) => flags::SIGN_MINUS_FLAG, + }; + self.flags = self.flags & !(flags::SIGN_PLUS_FLAG | flags::SIGN_MINUS_FLAG) | sign; self } /// Sets or unsets the `0` flag. @@ -339,9 +368,9 @@ impl FormattingOptions { #[unstable(feature = "formatting_options", issue = "118117")] pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { if sign_aware_zero_pad { - self.flags |= 1 << rt::Flag::SignAwareZeroPad as u32 + self.flags |= flags::SIGN_AWARE_ZERO_PAD_FLAG; } else { - self.flags &= !(1 << rt::Flag::SignAwareZeroPad as u32) + self.flags &= !flags::SIGN_AWARE_ZERO_PAD_FLAG; } self } @@ -356,9 +385,9 @@ impl FormattingOptions { #[unstable(feature = "formatting_options", issue = "118117")] pub fn alternate(&mut self, alternate: bool) -> &mut Self { if alternate { - self.flags |= 1 << rt::Flag::Alternate as u32 + self.flags |= flags::ALTERNATE_FLAG; } else { - self.flags &= !(1 << rt::Flag::Alternate as u32) + self.flags &= !flags::ALTERNATE_FLAG; } self } @@ -370,7 +399,7 @@ impl FormattingOptions { /// printed around it. #[unstable(feature = "formatting_options", issue = "118117")] pub fn fill(&mut self, fill: char) -> &mut Self { - self.fill = fill; + self.flags = self.flags & (u32::MAX << 21) | fill as u32; self } /// Sets or removes the alignment. @@ -379,7 +408,13 @@ impl FormattingOptions { /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] pub fn align(&mut self, align: Option) -> &mut Self { - self.align = align; + let align: u32 = match align { + Some(Alignment::Left) => flags::ALIGN_LEFT, + Some(Alignment::Right) => flags::ALIGN_RIGHT, + Some(Alignment::Center) => flags::ALIGN_CENTER, + None => flags::ALIGN_UNKNOWN, + }; + self.flags = self.flags & !flags::ALIGN_BITS | align; self } /// Sets or removes the width. @@ -390,7 +425,13 @@ impl FormattingOptions { /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] pub fn width(&mut self, width: Option) -> &mut Self { - self.width = width; + if let Some(width) = width { + self.flags |= flags::WIDTH_FLAG; + self.width = width; + } else { + self.flags &= !flags::WIDTH_FLAG; + self.width = 0; + } self } /// Sets or removes the precision. @@ -404,77 +445,85 @@ impl FormattingOptions { /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] pub fn precision(&mut self, precision: Option) -> &mut Self { - self.precision = precision; + if let Some(precision) = precision { + self.flags |= flags::PRECISION_FLAG; + self.precision = precision; + } else { + self.flags &= !flags::PRECISION_FLAG; + self.precision = 0; + } self } /// Specifies whether the [`Debug`] trait should use lower-/upper-case /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] pub fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { - self.flags = self.flags - & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); - match debug_as_hex { - None => {} - Some(DebugAsHex::Upper) => self.flags |= 1 << rt::Flag::DebugUpperHex as u32, - Some(DebugAsHex::Lower) => self.flags |= 1 << rt::Flag::DebugLowerHex as u32, - } + let debug_as_hex = match debug_as_hex { + None => 0, + Some(DebugAsHex::Lower) => flags::DEBUG_LOWER_HEX_FLAG, + Some(DebugAsHex::Upper) => flags::DEBUG_UPPER_HEX_FLAG, + }; + self.flags = self.flags & !(flags::DEBUG_LOWER_HEX_FLAG | flags::DEBUG_UPPER_HEX_FLAG) + | debug_as_hex; self } /// Returns the current sign (the `+` or the `-` flag). #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign(&self) -> Option { - const SIGN_PLUS_BITFIELD: u32 = 1 << rt::Flag::SignPlus as u32; - const SIGN_MINUS_BITFIELD: u32 = 1 << rt::Flag::SignMinus as u32; - match self.flags & ((1 << rt::Flag::SignPlus as u32) | (1 << rt::Flag::SignMinus as u32)) { - SIGN_PLUS_BITFIELD => Some(Sign::Plus), - SIGN_MINUS_BITFIELD => Some(Sign::Minus), - 0 => None, - _ => panic!("Invalid sign bits set in flags"), + if self.flags & flags::SIGN_PLUS_FLAG != 0 { + Some(Sign::Plus) + } else if self.flags & flags::SIGN_MINUS_FLAG != 0 { + Some(Sign::Minus) + } else { + None } } /// Returns the current `0` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign_aware_zero_pad(&self) -> bool { - self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 + self.flags & flags::SIGN_AWARE_ZERO_PAD_FLAG != 0 } /// Returns the current `#` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_alternate(&self) -> bool { - self.flags & (1 << rt::Flag::Alternate as u32) != 0 + self.flags & flags::ALTERNATE_FLAG != 0 } /// Returns the current fill character. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_fill(&self) -> char { - self.fill + // SAFETY: We only ever put a valid `char` in the lower 21 bits of the flags field. + unsafe { char::from_u32_unchecked(self.flags & 0x1FFFFF) } } /// Returns the current alignment. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_align(&self) -> Option { - self.align + match self.flags & flags::ALIGN_BITS { + flags::ALIGN_LEFT => Some(Alignment::Left), + flags::ALIGN_RIGHT => Some(Alignment::Right), + flags::ALIGN_CENTER => Some(Alignment::Center), + _ => None, + } } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_width(&self) -> Option { - self.width + if self.flags & flags::WIDTH_FLAG != 0 { Some(self.width) } else { None } } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_precision(&self) -> Option { - self.precision + if self.flags & flags::PRECISION_FLAG != 0 { Some(self.precision) } else { None } } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_debug_as_hex(&self) -> Option { - const DEBUG_UPPER_BITFIELD: u32 = 1 << rt::Flag::DebugUpperHex as u32; - const DEBUG_LOWER_BITFIELD: u32 = 1 << rt::Flag::DebugLowerHex as u32; - match self.flags - & ((1 << rt::Flag::DebugUpperHex as u32) | (1 << rt::Flag::DebugLowerHex as u32)) - { - DEBUG_UPPER_BITFIELD => Some(DebugAsHex::Upper), - DEBUG_LOWER_BITFIELD => Some(DebugAsHex::Lower), - 0 => None, - _ => panic!("Invalid hex debug bits set in flags"), + if self.flags & flags::DEBUG_LOWER_HEX_FLAG != 0 { + Some(DebugAsHex::Lower) + } else if self.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 { + Some(DebugAsHex::Upper) + } else { + None } } @@ -485,27 +534,6 @@ impl FormattingOptions { pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { options: self, buf: write } } - - #[doc(hidden)] - #[unstable( - feature = "fmt_internals", - reason = "internal routines only exposed for testing", - issue = "none" - )] - /// Flags for formatting - pub fn flags(&mut self, flags: u32) { - self.flags = flags - } - #[doc(hidden)] - #[unstable( - feature = "fmt_internals", - reason = "internal routines only exposed for testing", - issue = "none" - )] - /// Flags for formatting - pub fn get_flags(&self) -> u32 { - self.flags - } } #[unstable(feature = "formatting_options", issue = "118117")] @@ -1478,15 +1506,25 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { } unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { - fmt.options.fill = arg.fill; - fmt.options.align = arg.align.into(); - fmt.options.flags = arg.flags; - // SAFETY: arg and args come from the same Arguments, - // which guarantees the indexes are always within bounds. - unsafe { - fmt.options.width = getcount(args, &arg.width); - fmt.options.precision = getcount(args, &arg.precision); - } + let (width, precision) = + // SAFETY: arg and args come from the same Arguments, + // which guarantees the indexes are always within bounds. + unsafe { (getcount(args, &arg.width), getcount(args, &arg.precision)) }; + + #[cfg(bootstrap)] + let options = + *FormattingOptions { flags: flags::ALWAYS_SET | arg.flags << 21, width: 0, precision: 0 } + .align(match arg.align { + rt::Alignment::Left => Some(Alignment::Left), + rt::Alignment::Right => Some(Alignment::Right), + rt::Alignment::Center => Some(Alignment::Center), + rt::Alignment::Unknown => None, + }) + .fill(arg.fill) + .width(width) + .precision(precision); + #[cfg(not(bootstrap))] + let options = FormattingOptions { flags: arg.flags, width, precision }; // Extract the correct argument debug_assert!(arg.position < args.len()); @@ -1494,17 +1532,18 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume // which guarantees its index is always within bounds. let value = unsafe { args.get_unchecked(arg.position) }; + // Set all the formatting options. + fmt.options = options; + // Then actually do some printing // SAFETY: this is a placeholder argument. unsafe { value.fmt(fmt) } } +#[cfg(bootstrap)] unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { match *cnt { - #[cfg(bootstrap)] rt::Count::Is(n) => Some(n as u16), - #[cfg(not(bootstrap))] - rt::Count::Is(n) => Some(n), rt::Count::Implied => None, rt::Count::Param(i) => { debug_assert!(i < args.len()); @@ -1515,6 +1554,20 @@ unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { } } +#[cfg(not(bootstrap))] +unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> u16 { + match *cnt { + rt::Count::Is(n) => n, + rt::Count::Implied => 0, + rt::Count::Param(i) => { + debug_assert!(i < args.len()); + // SAFETY: cnt and args come from the same Arguments, + // which guarantees this index is always within bounds. + unsafe { args.get_unchecked(i).as_u16().unwrap_unchecked() } + } + } +} + /// Padding after the end of something. Returned by `Formatter::padding`. #[must_use = "don't forget to write the post padding"] pub(crate) struct PostPadding { @@ -1628,40 +1681,28 @@ impl<'a> Formatter<'a> { } // The `width` field is more of a `min-width` parameter at this point. - match self.options.width { - // If there's no minimum length requirements then we can just - // write the bytes. - None => { - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf) - } - // Check if we're over the minimum width, if so then we can also - // just write the bytes. - Some(min) if width >= usize::from(min) => { - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf) - } + let min = self.options.width; + if width >= usize::from(min) { + // We're over the minimum width, so then we can just write the bytes. + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf) + } else if self.sign_aware_zero_pad() { // The sign and prefix goes before the padding if the fill character // is zero - Some(min) if self.sign_aware_zero_pad() => { - let old_fill = crate::mem::replace(&mut self.options.fill, '0'); - let old_align = - crate::mem::replace(&mut self.options.align, Some(Alignment::Right)); - write_prefix(self, sign, prefix)?; - let post_padding = self.padding(min - width as u16, Alignment::Right)?; - self.buf.write_str(buf)?; - post_padding.write(self)?; - self.options.fill = old_fill; - self.options.align = old_align; - Ok(()) - } + let old_options = self.options; + self.options.fill('0').align(Some(Alignment::Right)); + write_prefix(self, sign, prefix)?; + let post_padding = self.padding(min - width as u16, Alignment::Right)?; + self.buf.write_str(buf)?; + post_padding.write(self)?; + self.options = old_options; + Ok(()) + } else { // Otherwise, the sign and prefix goes after the padding - Some(min) => { - let post_padding = self.padding(min - width as u16, Alignment::Right)?; - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf)?; - post_padding.write(self) - } + let post_padding = self.padding(min - width as u16, Alignment::Right)?; + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf)?; + post_padding.write(self) } } @@ -1697,13 +1738,13 @@ impl<'a> Formatter<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front. - if self.options.width.is_none() && self.options.precision.is_none() { + if self.options.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { return self.buf.write_str(s); } // The `precision` field can be interpreted as a maximum width for the // string being formatted. - let (s, char_count) = if let Some(max_char_count) = self.options.precision { + let (s, char_count) = if let Some(max_char_count) = self.options.get_precision() { let mut iter = s.char_indices(); let remaining = match iter.advance_by(usize::from(max_char_count)) { Ok(()) => 0, @@ -1719,12 +1760,11 @@ impl<'a> Formatter<'a> { }; // The `width` field is more of a minimum width parameter at this point. - if let Some(width) = self.options.width - && char_count < usize::from(width) - { + if char_count < usize::from(self.options.width) { // If we're under the minimum width, then fill up the minimum width // with the specified string + some alignment. - let post_padding = self.padding(width - char_count as u16, Alignment::Left)?; + let post_padding = + self.padding(self.options.width - char_count as u16, Alignment::Left)?; self.buf.write_str(s)?; post_padding.write(self) } else { @@ -1743,19 +1783,20 @@ impl<'a> Formatter<'a> { padding: u16, default: Alignment, ) -> result::Result { - let align = self.align().unwrap_or(default); + let align = self.options.get_align().unwrap_or(default); + let fill = self.options.get_fill(); - let (pre_pad, post_pad) = match align { - Alignment::Left => (0, padding), - Alignment::Right => (padding, 0), - Alignment::Center => (padding / 2, (padding + 1) / 2), + let padding_left = match align { + Alignment::Left => 0, + Alignment::Right => padding, + Alignment::Center => padding / 2, }; - for _ in 0..pre_pad { - self.buf.write_char(self.options.fill)?; + for _ in 0..padding_left { + self.buf.write_char(fill)?; } - Ok(PostPadding::new(self.options.fill, post_pad)) + Ok(PostPadding::new(fill, padding - padding_left)) } /// Takes the formatted parts and applies the padding. @@ -1767,12 +1808,16 @@ impl<'a> Formatter<'a> { /// /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { - if let Some(mut width) = self.options.width { + if self.options.width == 0 { + // this is the common case and we take a shortcut + // SAFETY: Per the precondition. + unsafe { self.write_formatted_parts(formatted) } + } else { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. let mut formatted = formatted.clone(); - let old_fill = self.options.fill; - let old_align = self.options.align; + let mut width = self.options.width; + let old_options = self.options; if self.sign_aware_zero_pad() { // a sign always goes first let sign = formatted.sign; @@ -1781,8 +1826,7 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; width = width.saturating_sub(sign.len() as u16); - self.options.fill = '0'; - self.options.align = Some(Alignment::Right); + self.options.fill('0').align(Some(Alignment::Right)); } // remaining parts go through the ordinary padding process. @@ -1799,13 +1843,8 @@ impl<'a> Formatter<'a> { } post_padding.write(self) }; - self.options.fill = old_fill; - self.options.align = old_align; + self.options = old_options; ret - } else { - // this is the common case and we take a shortcut - // SAFETY: Per the precondition. - unsafe { self.write_formatted_parts(formatted) } } } @@ -1926,7 +1965,9 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead" )] pub fn flags(&self) -> u32 { - self.options.flags + // Extract the debug upper/lower hex, zero pad, alternate, and plus/minus flags + // to stay compatible with older versions of Rust. + self.options.flags >> 21 & 0x3F } /// Returns the character used as 'fill' whenever there is alignment. @@ -1959,7 +2000,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { - self.options.fill + self.options.get_fill() } /// Returns a flag indicating what form of alignment was requested. @@ -1994,7 +2035,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { - self.options.align + self.options.get_align() } /// Returns the optionally specified integer width that the output should be. @@ -2024,7 +2065,11 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.options.width.map(|x| x as usize) + if self.options.flags & flags::WIDTH_FLAG == 0 { + None + } else { + Some(self.options.width as usize) + } } /// Returns the optionally specified precision for numeric types. @@ -2055,7 +2100,11 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.options.precision.map(|x| x as usize) + if self.options.flags & flags::PRECISION_FLAG == 0 { + None + } else { + Some(self.options.precision as usize) + } } /// Determines if the `+` flag was specified. @@ -2087,7 +2136,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignPlus as u32) != 0 + self.options.flags & flags::SIGN_PLUS_FLAG != 0 } /// Determines if the `-` flag was specified. @@ -2116,7 +2165,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignMinus as u32) != 0 + self.options.flags & flags::SIGN_MINUS_FLAG != 0 } /// Determines if the `#` flag was specified. @@ -2144,7 +2193,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.options.flags & (1 << rt::Flag::Alternate as u32) != 0 + self.options.flags & flags::ALTERNATE_FLAG != 0 } /// Determines if the `0` flag was specified. @@ -2170,17 +2219,16 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 + self.options.flags & flags::SIGN_AWARE_ZERO_PAD_FLAG != 0 } // FIXME: Decide what public API we want for these two flags. // https://github.com/rust-lang/rust/issues/48584 fn debug_lower_hex(&self) -> bool { - self.options.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 + self.options.flags & flags::DEBUG_LOWER_HEX_FLAG != 0 } - fn debug_upper_hex(&self) -> bool { - self.options.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 + self.options.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 } /// Creates a [`DebugStruct`] builder designed to assist with creation of @@ -2760,7 +2808,7 @@ impl Debug for char { #[stable(feature = "rust1", since = "1.0.0")] impl Display for char { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - if f.options.width.is_none() && f.options.precision.is_none() { + if f.options.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; MAX_LEN_UTF8])) @@ -2784,26 +2832,24 @@ impl Pointer for *const T { /// /// [problematic]: https://github.com/rust-lang/rust/issues/95489 pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result { - let old_width = f.options.width; - let old_flags = f.options.flags; + let old_options = f.options; // The alternate flag is already treated by LowerHex as being special- // it denotes whether to prefix with 0x. We use it to work out whether // or not to zero extend, and then unconditionally set it to get the // prefix. - if f.alternate() { - f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); + if f.options.get_alternate() { + f.options.sign_aware_zero_pad(true); - if f.options.width.is_none() { - f.options.width = Some((usize::BITS / 4) as u16 + 2); + if f.options.get_width().is_none() { + f.options.width(Some((usize::BITS / 4) as u16 + 2)); } } - f.options.flags |= 1 << (rt::Flag::Alternate as u32); + f.options.alternate(true); let ret = LowerHex::fmt(&ptr_addr, f); - f.options.width = old_width; - f.options.flags = old_flags; + f.options = old_options; ret } diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 080fc6ddfc9b..d27f7e6e0d8e 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -11,7 +11,9 @@ use crate::ptr::NonNull; #[derive(Copy, Clone)] pub struct Placeholder { pub position: usize, + #[cfg(bootstrap)] pub fill: char, + #[cfg(bootstrap)] pub align: Alignment, pub flags: u32, pub precision: Count, @@ -19,6 +21,7 @@ pub struct Placeholder { } impl Placeholder { + #[cfg(bootstrap)] #[inline] pub const fn new( position: usize, @@ -30,8 +33,15 @@ impl Placeholder { ) -> Self { Self { position, fill, align, flags, precision, width } } + + #[cfg(not(bootstrap))] + #[inline] + pub const fn new(position: usize, flags: u32, precision: Count, width: Count) -> Self { + Self { position, flags, precision, width } + } } +#[cfg(bootstrap)] #[lang = "format_alignment"] #[derive(Copy, Clone, PartialEq, Eq)] pub enum Alignment { @@ -58,17 +68,6 @@ pub enum Count { Implied, } -// This needs to match the order of flags in compiler/rustc_ast_lowering/src/format.rs. -#[derive(Copy, Clone)] -pub(super) enum Flag { - SignPlus, - SignMinus, - Alternate, - SignAwareZeroPad, - DebugLowerHex, - DebugUpperHex, -} - #[derive(Copy, Clone)] enum ArgumentType<'a> { Placeholder { From ba2809e08574c608b6b2cd146649af83d7c354ed Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 12 Mar 2025 16:32:11 +0100 Subject: [PATCH 069/546] Update tests. --- ...onential_common.GVN.32bit.panic-abort.diff | 49 +++++++++---------- ...nential_common.GVN.32bit.panic-unwind.diff | 49 +++++++++---------- ...onential_common.GVN.64bit.panic-abort.diff | 49 +++++++++---------- ...nential_common.GVN.64bit.panic-unwind.diff | 49 +++++++++---------- 4 files changed, 88 insertions(+), 108 deletions(-) diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff index 45fc7365d8d6..6baa902b6f4b 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff @@ -29,16 +29,10 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { - let mut _22: std::option::Option; - scope 6 (inlined Option::::map::::precision::{closure#0}}>) { - let mut _23: isize; - let _24: u16; - let mut _25: usize; - scope 7 { - scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { - } - } - } + let mut _22: u32; + let mut _23: u32; + let mut _24: usize; + let mut _25: u16; } } } @@ -53,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const 1_u32); + _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -75,12 +69,12 @@ bb3: { StorageLive(_6); - StorageLive(_24); StorageLive(_22); - _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); StorageLive(_23); - _23 = discriminant(_22); - switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + StorageDead(_23); + switchInt(move _22) -> [0: bb10, otherwise: bb11]; } bb4: { @@ -148,30 +142,31 @@ } bb9: { - StorageDead(_23); - StorageDead(_22); - StorageDead(_24); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12]; } bb10: { - unreachable; - } - - bb11: { + StorageDead(_22); _6 = const Option::::None; goto -> bb9; } - bb12: { - _24 = move ((_22 as Some).0: u16); + bb11: { + StorageDead(_22); + StorageLive(_24); StorageLive(_25); - _25 = copy _24 as usize (IntToInt); - _6 = Option::::Some(move _25); + _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16); + _24 = move _25 as usize (IntToInt); StorageDead(_25); + _6 = Option::::Some(move _24); + StorageDead(_24); goto -> bb9; } + + bb12: { + unreachable; + } } ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff index 578d2c2194b0..36540e038654 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff @@ -29,16 +29,10 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { - let mut _22: std::option::Option; - scope 6 (inlined Option::::map::::precision::{closure#0}}>) { - let mut _23: isize; - let _24: u16; - let mut _25: usize; - scope 7 { - scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { - } - } - } + let mut _22: u32; + let mut _23: u32; + let mut _24: usize; + let mut _25: u16; } } } @@ -53,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const 1_u32); + _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -75,12 +69,12 @@ bb3: { StorageLive(_6); - StorageLive(_24); StorageLive(_22); - _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); StorageLive(_23); - _23 = discriminant(_22); - switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + StorageDead(_23); + switchInt(move _22) -> [0: bb10, otherwise: bb11]; } bb4: { @@ -148,30 +142,31 @@ } bb9: { - StorageDead(_23); - StorageDead(_22); - StorageDead(_24); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12]; } bb10: { - unreachable; - } - - bb11: { + StorageDead(_22); _6 = const Option::::None; goto -> bb9; } - bb12: { - _24 = move ((_22 as Some).0: u16); + bb11: { + StorageDead(_22); + StorageLive(_24); StorageLive(_25); - _25 = copy _24 as usize (IntToInt); - _6 = Option::::Some(move _25); + _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16); + _24 = move _25 as usize (IntToInt); StorageDead(_25); + _6 = Option::::Some(move _24); + StorageDead(_24); goto -> bb9; } + + bb12: { + unreachable; + } } ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff index 5f0f7d6cc74f..41c350f3eaeb 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff @@ -29,16 +29,10 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { - let mut _22: std::option::Option; - scope 6 (inlined Option::::map::::precision::{closure#0}}>) { - let mut _23: isize; - let _24: u16; - let mut _25: usize; - scope 7 { - scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { - } - } - } + let mut _22: u32; + let mut _23: u32; + let mut _24: usize; + let mut _25: u16; } } } @@ -53,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const 1_u32); + _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -75,12 +69,12 @@ bb3: { StorageLive(_6); - StorageLive(_24); StorageLive(_22); - _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); StorageLive(_23); - _23 = discriminant(_22); - switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + StorageDead(_23); + switchInt(move _22) -> [0: bb10, otherwise: bb11]; } bb4: { @@ -148,30 +142,31 @@ } bb9: { - StorageDead(_23); - StorageDead(_22); - StorageDead(_24); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12]; } bb10: { - unreachable; - } - - bb11: { + StorageDead(_22); _6 = const Option::::None; goto -> bb9; } - bb12: { - _24 = move ((_22 as Some).0: u16); + bb11: { + StorageDead(_22); + StorageLive(_24); StorageLive(_25); - _25 = copy _24 as usize (IntToInt); - _6 = Option::::Some(move _25); + _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16); + _24 = move _25 as usize (IntToInt); StorageDead(_25); + _6 = Option::::Some(move _24); + StorageDead(_24); goto -> bb9; } + + bb12: { + unreachable; + } } ALLOC0 (size: 16, align: 8) { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff index 10cc46a8b828..b839bf81eaf4 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff @@ -29,16 +29,10 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { - let mut _22: std::option::Option; - scope 6 (inlined Option::::map::::precision::{closure#0}}>) { - let mut _23: isize; - let _24: u16; - let mut _25: usize; - scope 7 { - scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { - } - } - } + let mut _22: u32; + let mut _23: u32; + let mut _24: usize; + let mut _25: u16; } } } @@ -53,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const 1_u32); + _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -75,12 +69,12 @@ bb3: { StorageLive(_6); - StorageLive(_24); StorageLive(_22); - _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); StorageLive(_23); - _23 = discriminant(_22); - switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + StorageDead(_23); + switchInt(move _22) -> [0: bb10, otherwise: bb11]; } bb4: { @@ -148,30 +142,31 @@ } bb9: { - StorageDead(_23); - StorageDead(_22); - StorageDead(_24); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12]; } bb10: { - unreachable; - } - - bb11: { + StorageDead(_22); _6 = const Option::::None; goto -> bb9; } - bb12: { - _24 = move ((_22 as Some).0: u16); + bb11: { + StorageDead(_22); + StorageLive(_24); StorageLive(_25); - _25 = copy _24 as usize (IntToInt); - _6 = Option::::Some(move _25); + _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16); + _24 = move _25 as usize (IntToInt); StorageDead(_25); + _6 = Option::::Some(move _24); + StorageDead(_24); goto -> bb9; } + + bb12: { + unreachable; + } } ALLOC0 (size: 16, align: 8) { From 65bd61d2fbef50d28caed626ce601a908d5be77f Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 12 Mar 2025 09:47:11 +0100 Subject: [PATCH 070/546] Fix armv7-sony-vita-newlibeabihf LLVM target triple It was previously normalized by LLVM to `thumbv7a-vita-unknown-eabihf`, which is probably wrong, as Vita is the OS. --- .../src/spec/targets/armv7_sony_vita_newlibeabihf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs index 5d292bbf8adf..6a83835059ee 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { ); Target { - llvm_target: "thumbv7a-vita-eabihf".into(), + llvm_target: "thumbv7a-sony-vita-eabihf".into(), metadata: TargetMetadata { description: Some( "Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)".into(), From eab700a0aa4ad3079ad043a9cb4fb89edab3b4b7 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 12 Mar 2025 23:37:35 +0100 Subject: [PATCH 071/546] Fix uclibc LLVM target triples `uclibc` is not an environment understood by LLVM, it is only a concept in Clang that can be selected with `-muclibc` (it affects which dynamic linker is passed to the static linker's `-dynamic-linker` flag). In fact, using `uclibcgnueabi`/`uclibc` is actively harmful, as it prevents LLVM from seeing that the target is gnu-like; we should use `gnueabi`/`gnu` directly instead. --- .../src/spec/targets/armv5te_unknown_linux_uclibceabi.rs | 2 +- .../rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs | 2 +- .../src/spec/targets/mipsel_unknown_linux_uclibc.rs | 2 +- .../rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs index dbe1540364ad..860629b08e19 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs @@ -2,7 +2,7 @@ use crate::spec::{FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { - llvm_target: "armv5te-unknown-linux-uclibcgnueabi".into(), + llvm_target: "armv5te-unknown-linux-gnueabi".into(), metadata: TargetMetadata { description: Some("Armv5TE Linux with uClibc".into()), tier: Some(3), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs index 0955b3debea0..c14bfbf46d21 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs @@ -4,7 +4,7 @@ use crate::spec::{Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { - llvm_target: "mips-unknown-linux-uclibc".into(), + llvm_target: "mips-unknown-linux-gnu".into(), metadata: TargetMetadata { description: Some("MIPS Linux with uClibc".into()), tier: Some(3), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs index 08c4347fe014..f0056799d66f 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs @@ -2,7 +2,7 @@ use crate::spec::{Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { - llvm_target: "mipsel-unknown-linux-uclibc".into(), + llvm_target: "mipsel-unknown-linux-gnu".into(), metadata: TargetMetadata { description: Some("MIPS (LE) Linux with uClibc".into()), tier: Some(3), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs index a034a9fb2445..4107249dcf1e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs @@ -8,7 +8,7 @@ pub(crate) fn target() -> Target { base.panic_strategy = PanicStrategy::Abort; Target { - llvm_target: "x86_64-unknown-l4re-uclibc".into(), + llvm_target: "x86_64-unknown-l4re-gnu".into(), metadata: TargetMetadata { description: None, tier: Some(3), From 025eecc3e7e36bb60bdd4e30ae05b9fa3876d14f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Mar 2025 12:36:40 +0100 Subject: [PATCH 072/546] atomic intrinsics: clarify which types are supported and (if applicable) what happens with provenance --- src/intrinsics/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 6735ae024d1c..75f3a3c19724 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -1031,7 +1031,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1052,7 +1052,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1073,7 +1073,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1094,7 +1094,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); From c58c06a6f51f2de7a869e278d08438c34a6ea86f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:33:37 +0100 Subject: [PATCH 073/546] Return blocks from DropTree::build_mir Rather than requiring the user to pass in a correctly sized blocks map. --- compiler/rustc_mir_build/src/builder/scope.rs | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 27ff01b48034..e56c0ae92cac 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -305,27 +305,25 @@ impl DropTree { } /// Builds the MIR for a given drop tree. - /// - /// `blocks` should have the same length as `self.drops`, and may have its - /// first value set to some already existing block. fn build_mir<'tcx, T: DropTreeBuilder<'tcx>>( &mut self, cfg: &mut CFG<'tcx>, - blocks: &mut IndexVec>, - ) { + root_node: Option, + ) -> IndexVec> { debug!("DropTree::build_mir(drops = {:#?})", self); - assert_eq!(blocks.len(), self.drops.len()); - self.assign_blocks::(cfg, blocks); - self.link_blocks(cfg, blocks) + let mut blocks = self.assign_blocks::(cfg, root_node); + self.link_blocks(cfg, &mut blocks); + + blocks } /// Assign blocks for all of the drops in the drop tree that need them. fn assign_blocks<'tcx, T: DropTreeBuilder<'tcx>>( &mut self, cfg: &mut CFG<'tcx>, - blocks: &mut IndexVec>, - ) { + root_node: Option, + ) -> IndexVec> { // StorageDead statements can share blocks with each other and also with // a Drop terminator. We iterate through the drops to find which drops // need their own block. @@ -342,8 +340,11 @@ impl DropTree { Own, } + let mut blocks = IndexVec::from_elem(None, &self.drops); + blocks[ROOT_NODE] = root_node; + let mut needs_block = IndexVec::from_elem(Block::None, &self.drops); - if blocks[ROOT_NODE].is_some() { + if root_node.is_some() { // In some cases (such as drops for `continue`) the root node // already has a block. In this case, make sure that we don't // override it. @@ -385,6 +386,8 @@ impl DropTree { debug!("assign_blocks: blocks = {:#?}", blocks); assert!(entry_points.is_empty()); + + blocks } fn link_blocks<'tcx>( @@ -1574,10 +1577,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { span: Span, continue_block: Option, ) -> Option> { - let mut blocks = IndexVec::from_elem(None, &drops.drops); - blocks[ROOT_NODE] = continue_block; - - drops.build_mir::(&mut self.cfg, &mut blocks); + let blocks = drops.build_mir::(&mut self.cfg, continue_block); let is_coroutine = self.coroutine.is_some(); // Link the exit drop tree to unwind drop tree. @@ -1633,8 +1633,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { let drops = &mut self.scopes.coroutine_drops; let cfg = &mut self.cfg; let fn_span = self.fn_span; - let mut blocks = IndexVec::from_elem(None, &drops.drops); - drops.build_mir::(cfg, &mut blocks); + let blocks = drops.build_mir::(cfg, None); if let Some(root_block) = blocks[ROOT_NODE] { cfg.terminate( root_block, @@ -1670,9 +1669,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { fn_span: Span, resume_block: &mut Option, ) { - let mut blocks = IndexVec::from_elem(None, &drops.drops); - blocks[ROOT_NODE] = *resume_block; - drops.build_mir::(cfg, &mut blocks); + let blocks = drops.build_mir::(cfg, *resume_block); if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) { cfg.terminate(resume, SourceInfo::outermost(fn_span), TerminatorKind::UnwindResume); From 8dc0c0ece93164da4d10a020a79201c95341bc9f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:39:26 +0100 Subject: [PATCH 074/546] Simplify lit_to_mir_constant a bit --- .../src/builder/expr/as_constant.rs | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index f743ea60a456..64d092e03545 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -105,23 +105,19 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)); } - let trunc = |n, width: ty::UintTy| { - let width = width - .normalize(tcx.data_layout.pointer_size.bits().try_into().unwrap()) - .bit_width() - .unwrap(); - let width = Size::from_bits(width); + let lit_ty = match *ty.kind() { + ty::Pat(base, _) => base, + _ => ty, + }; + + let trunc = |n| { + let width = lit_ty.primitive_size(tcx); trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); ConstValue::Scalar(Scalar::from_uint(result, width)) }; - let lit_ty = match *ty.kind() { - ty::Pat(base, _) => base, - _ => ty, - }; - let value = match (lit, lit_ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); @@ -149,11 +145,10 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) } - (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => trunc(n.get(), *ui), - (ast::LitKind::Int(n, _), ty::Int(i)) => trunc( - if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }, - i.to_unsigned(), - ), + (ast::LitKind::Int(n, _), ty::Uint(_)) if !neg => trunc(n.get()), + (ast::LitKind::Int(n, _), ty::Int(_)) => { + trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }) + } (ast::LitKind::Float(n, _), ty::Float(fty)) => { parse_float_into_constval(*n, *fty, neg).unwrap() } From f9696dda6e9d88a88c057e93fbc854104996bc33 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 7 Mar 2025 17:52:17 +0000 Subject: [PATCH 075/546] Prefer built-in sized impls for rigid types always --- compiler/rustc_middle/src/traits/select.rs | 5 +++- .../src/traits/select/candidate_assembly.rs | 24 +++++++++++++++---- .../src/traits/select/confirmation.rs | 5 ++++ .../src/traits/select/mod.rs | 13 +++++++++- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 811bd8fb4588..749f3c31bf8d 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -95,10 +95,13 @@ pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>), /// parameter environment. #[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)] pub enum SelectionCandidate<'tcx> { + /// UwU + SizedCandidate, + /// A builtin implementation for some specific traits, used in cases /// where we cannot rely an ordinary library implementations. /// - /// The most notable examples are `sized`, `Copy` and `Clone`. This is also + /// The most notable examples are `Copy` and `Clone`. This is also /// used for the `DiscriminantKind` and `Pointee` trait, both of which have /// an associated type. BuiltinCandidate { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a8d8003ead6e..9c0efec2e6cf 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -86,10 +86,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Pointee` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); } else if tcx.is_lang_item(def_id, LangItem::Sized) { - // Sized is never implementable by end-users, it is - // always automatically computed. - let sized_conditions = self.sized_conditions(obligation); - self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); + self.assemble_builtin_sized_candidate(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::Unsize) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::Destruct) { @@ -1059,6 +1056,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Assembles the trait which are built-in to the language itself: /// `Copy`, `Clone` and `Sized`. #[instrument(level = "debug", skip(self, candidates))] + fn assemble_builtin_sized_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match self.sized_conditions(obligation) { + BuiltinImplConditions::Where(_) => { + candidates.vec.push(SizedCandidate); + } + BuiltinImplConditions::None => {} + BuiltinImplConditions::Ambiguous => { + candidates.ambiguous = true; + } + } + } + + /// Assembles the trait which are built-in to the language itself: + /// e.g. `Copy` and `Clone`. + #[instrument(level = "debug", skip(self, candidates))] fn assemble_builtin_bound_candidates( &mut self, conditions: BuiltinImplConditions<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4cd6781ab890..349eab2cbe39 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -40,6 +40,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate: SelectionCandidate<'tcx>, ) -> Result, SelectionError<'tcx>> { let mut impl_src = match candidate { + SizedCandidate => { + let data = self.confirm_builtin_candidate(obligation, true); + ImplSource::Builtin(BuiltinImplSource::Misc, data) + } + BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); ImplSource::Builtin(BuiltinImplSource::Misc, data) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e1adabbeaa66..674ff30786bc 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1801,6 +1801,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> { return Some(candidates.pop().unwrap().candidate); } + // We prefer `Sized` candidates over everything. + let mut sized_candidates = + candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate)); + if let Some(_sized_candidate) = sized_candidates.next() { + // There should only ever be a single sized candidate + // as they would otherwise overlap. + debug_assert_eq!(sized_candidates.next(), None); + return Some(SizedCandidate); + } + // We prefer trivial builtin candidates, i.e. builtin impls without any nested // requirements, over all others. This is a fix for #53123 and prevents winnowing // from accidentally extending the lifetime of a variable. @@ -1940,7 +1950,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // Don't use impl candidates which overlap with other candidates. // This should pretty much only ever happen with malformed impls. if candidates.iter().all(|c| match c.candidate { - BuiltinCandidate { has_nested: _ } + SizedCandidate + | BuiltinCandidate { has_nested: _ } | TransmutabilityCandidate | AutoImplCandidate | ClosureCandidate { .. } From aebbd424607b7797f231bc09f44226fcd3040d7e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 10 Mar 2025 16:50:29 +0000 Subject: [PATCH 076/546] Only prefer Sized candidates, and only if they certainly hold --- compiler/rustc_middle/src/traits/select.rs | 7 +++-- .../src/traits/select/candidate_assembly.rs | 6 ++-- .../src/traits/select/confirmation.rs | 4 +-- .../src/traits/select/mod.rs | 28 ++++++++----------- .../dont-incompletely-prefer-built-in.rs | 21 ++++++++++++++ ...incomplete-prefer-sized-builtin-over-wc.rs | 19 +++++++++++++ ...mplete-prefer-sized-builtin-over-wc.stderr | 27 ++++++++++++++++++ 7 files changed, 89 insertions(+), 23 deletions(-) create mode 100644 tests/ui/sized/dont-incompletely-prefer-built-in.rs create mode 100644 tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs create mode 100644 tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.stderr diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 749f3c31bf8d..aa2ee756bc50 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -95,8 +95,11 @@ pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>), /// parameter environment. #[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)] pub enum SelectionCandidate<'tcx> { - /// UwU - SizedCandidate, + /// A built-in implementation for the `Sized` trait. This is preferred + /// over all other candidates. + SizedCandidate { + has_nested: bool, + }, /// A builtin implementation for some specific traits, used in cases /// where we cannot rely an ordinary library implementations. diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 9c0efec2e6cf..316198f9e012 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -1062,8 +1062,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) { match self.sized_conditions(obligation) { - BuiltinImplConditions::Where(_) => { - candidates.vec.push(SizedCandidate); + BuiltinImplConditions::Where(nested) => { + candidates + .vec + .push(SizedCandidate { has_nested: !nested.skip_binder().is_empty() }); } BuiltinImplConditions::None => {} BuiltinImplConditions::Ambiguous => { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 349eab2cbe39..29e0b833665b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -40,8 +40,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate: SelectionCandidate<'tcx>, ) -> Result, SelectionError<'tcx>> { let mut impl_src = match candidate { - SizedCandidate => { - let data = self.confirm_builtin_candidate(obligation, true); + SizedCandidate { has_nested } => { + let data = self.confirm_builtin_candidate(obligation, has_nested); ImplSource::Builtin(BuiltinImplSource::Misc, data) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 674ff30786bc..956417b122c6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1803,25 +1803,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // We prefer `Sized` candidates over everything. let mut sized_candidates = - candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate)); - if let Some(_sized_candidate) = sized_candidates.next() { + candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate { has_nested: _ })); + if let Some(sized_candidate) = sized_candidates.next() { // There should only ever be a single sized candidate // as they would otherwise overlap. debug_assert_eq!(sized_candidates.next(), None); - return Some(SizedCandidate); - } - - // We prefer trivial builtin candidates, i.e. builtin impls without any nested - // requirements, over all others. This is a fix for #53123 and prevents winnowing - // from accidentally extending the lifetime of a variable. - let mut trivial_builtin = candidates - .iter() - .filter(|c| matches!(c.candidate, BuiltinCandidate { has_nested: false })); - if let Some(_trivial) = trivial_builtin.next() { - // There should only ever be a single trivial builtin candidate - // as they would otherwise overlap. - debug_assert_eq!(trivial_builtin.next(), None); - return Some(BuiltinCandidate { has_nested: false }); + // Only prefer the built-in `Sized` candidate if its nested goals are certain. + // Otherwise, we may encounter failure later on if inference causes this candidate + // to not hold, but a where clause would've applied instead. + if sized_candidate.evaluation.must_apply_modulo_regions() { + return Some(sized_candidate.candidate.clone()); + } else { + return None; + } } // Before we consider where-bounds, we have to deduplicate them here and also @@ -1950,7 +1944,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // Don't use impl candidates which overlap with other candidates. // This should pretty much only ever happen with malformed impls. if candidates.iter().all(|c| match c.candidate { - SizedCandidate + SizedCandidate { has_nested: _ } | BuiltinCandidate { has_nested: _ } | TransmutabilityCandidate | AutoImplCandidate diff --git a/tests/ui/sized/dont-incompletely-prefer-built-in.rs b/tests/ui/sized/dont-incompletely-prefer-built-in.rs new file mode 100644 index 000000000000..f5bf0c8915e7 --- /dev/null +++ b/tests/ui/sized/dont-incompletely-prefer-built-in.rs @@ -0,0 +1,21 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +struct W(T); + +fn is_sized(x: *const T) {} + +fn dummy() -> *const T { todo!() } + +fn non_param_where_bound() +where + W: Sized, +{ + let x: *const W<_> = dummy(); + is_sized::>(x); + let _: *const W = x; +} + +fn main() {} diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs new file mode 100644 index 000000000000..cc3303dccd57 --- /dev/null +++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs @@ -0,0 +1,19 @@ +struct MyType<'a, T: ?Sized>(&'a (), T); + +fn is_sized() {} + +fn foo<'a, T: ?Sized>() +where + (MyType<'a, T>,): Sized, + //~^ ERROR mismatched types + MyType<'static, T>: Sized, +{ + // Preferring the builtin `Sized` impl of tuples + // requires proving `MyType<'a, T>: Sized` which + // can only be proven by using the where-clause, + // adding an unnecessary `'static` constraint. + is_sized::<(MyType<'a, T>,)>(); + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.stderr b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.stderr new file mode 100644 index 000000000000..a54574f743f8 --- /dev/null +++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:7:23 + | +LL | (MyType<'a, T>,): Sized, + | ^^^^^ lifetime mismatch + | + = note: expected trait ` as Sized>` + found trait ` as Sized>` +note: the lifetime `'a` as defined here... + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:5:8 + | +LL | fn foo<'a, T: ?Sized>() + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error: lifetime may not live long enough + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:15:5 + | +LL | fn foo<'a, T: ?Sized>() + | -- lifetime `'a` defined here +... +LL | is_sized::<(MyType<'a, T>,)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From c0230f4a2904e968f4afd833e44db1f4ebe29b21 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 13 Mar 2025 21:17:46 +0000 Subject: [PATCH 077/546] Flesh out tests --- ...complete-infer-via-sized-wc.current.stderr | 9 ++++++ .../incomplete-infer-via-sized-wc.next.stderr | 9 ++++++ .../traits/incomplete-infer-via-sized-wc.rs | 19 +++++++++++++ ...complete-prefer-sized-builtin-over-wc-2.rs | 28 +++++++++++++++++++ ...efer-sized-builtin-over-wc.current.stderr} | 6 ++-- ...e-prefer-sized-builtin-over-wc.next.stderr | 25 +++++++++++++++++ ...incomplete-prefer-sized-builtin-over-wc.rs | 9 +++++- 7 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 tests/ui/traits/incomplete-infer-via-sized-wc.current.stderr create mode 100644 tests/ui/traits/incomplete-infer-via-sized-wc.next.stderr create mode 100644 tests/ui/traits/incomplete-infer-via-sized-wc.rs create mode 100644 tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc-2.rs rename tests/ui/traits/{lifetime-incomplete-prefer-sized-builtin-over-wc.stderr => lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr} (85%) create mode 100644 tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr diff --git a/tests/ui/traits/incomplete-infer-via-sized-wc.current.stderr b/tests/ui/traits/incomplete-infer-via-sized-wc.current.stderr new file mode 100644 index 000000000000..f4930bf890c2 --- /dev/null +++ b/tests/ui/traits/incomplete-infer-via-sized-wc.current.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/incomplete-infer-via-sized-wc.rs:15:5 + | +LL | is_sized::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `is_sized` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/incomplete-infer-via-sized-wc.next.stderr b/tests/ui/traits/incomplete-infer-via-sized-wc.next.stderr new file mode 100644 index 000000000000..f4930bf890c2 --- /dev/null +++ b/tests/ui/traits/incomplete-infer-via-sized-wc.next.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/incomplete-infer-via-sized-wc.rs:15:5 + | +LL | is_sized::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `is_sized` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/incomplete-infer-via-sized-wc.rs b/tests/ui/traits/incomplete-infer-via-sized-wc.rs new file mode 100644 index 000000000000..9dcddea3551d --- /dev/null +++ b/tests/ui/traits/incomplete-infer-via-sized-wc.rs @@ -0,0 +1,19 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Exercises change in . + +struct MaybeSized(T); + +fn is_sized() -> Box { todo!() } + +fn foo() +where + MaybeSized: Sized, +{ + is_sized::>(); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc-2.rs b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc-2.rs new file mode 100644 index 000000000000..8a8f7b933b53 --- /dev/null +++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc-2.rs @@ -0,0 +1,28 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Exercises change in . + +trait Trait: Sized {} +impl Trait for T {} + +fn is_sized() {} + +fn normal_ref<'a, 'b, T>() +where + &'a u32: Trait, +{ + is_sized::<&'b u32>(); +} + +struct MyRef<'a, U: ?Sized = ()>(&'a u32, U); +fn my_ref<'a, 'b, T>() +where + MyRef<'a>: Trait, +{ + is_sized::>(); +} + +fn main() {} diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.stderr b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr similarity index 85% rename from tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.stderr rename to tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr index a54574f743f8..dd9393fae853 100644 --- a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.stderr +++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:7:23 + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:13:23 | LL | (MyType<'a, T>,): Sized, | ^^^^^ lifetime mismatch @@ -7,14 +7,14 @@ LL | (MyType<'a, T>,): Sized, = note: expected trait ` as Sized>` found trait ` as Sized>` note: the lifetime `'a` as defined here... - --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:5:8 + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:11:8 | LL | fn foo<'a, T: ?Sized>() | ^^ = note: ...does not necessarily outlive the static lifetime error: lifetime may not live long enough - --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:15:5 + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:22:5 | LL | fn foo<'a, T: ?Sized>() | -- lifetime `'a` defined here diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr new file mode 100644 index 000000000000..05861877d413 --- /dev/null +++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr @@ -0,0 +1,25 @@ +error[E0478]: lifetime bound not satisfied + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:13:23 + | +LL | (MyType<'a, T>,): Sized, + | ^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined here + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:11:8 + | +LL | fn foo<'a, T: ?Sized>() + | ^^ + = note: but lifetime parameter must outlive the static lifetime + +error: lifetime may not live long enough + --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:22:5 + | +LL | fn foo<'a, T: ?Sized>() + | -- lifetime `'a` defined here +... +LL | is_sized::<(MyType<'a, T>,)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0478`. diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs index cc3303dccd57..ae7a6c9bba33 100644 --- a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs +++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs @@ -1,3 +1,9 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Exercises change in . + struct MyType<'a, T: ?Sized>(&'a (), T); fn is_sized() {} @@ -5,7 +11,8 @@ fn is_sized() {} fn foo<'a, T: ?Sized>() where (MyType<'a, T>,): Sized, - //~^ ERROR mismatched types + //[current]~^ ERROR mismatched types + //[next]~^^ ERROR lifetime bound not satisfied MyType<'static, T>: Sized, { // Preferring the builtin `Sized` impl of tuples From bdaf23b4cd13dd39cebf1756686f581d6040df37 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 14 Mar 2025 12:19:04 +0100 Subject: [PATCH 078/546] Forward `stream_position` in `Arc` as well It was missed in #137165. --- library/std/src/fs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index f9a360585e85..7fc010d2ec3f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1343,6 +1343,9 @@ impl Seek for Arc { fn seek(&mut self, pos: SeekFrom) -> io::Result { (&**self).seek(pos) } + fn stream_position(&mut self) -> io::Result { + (&**self).stream_position() + } } impl OpenOptions { From 409510c0885ba41b5bceec8406d246260baee38d Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 13 Mar 2025 14:56:43 -0500 Subject: [PATCH 079/546] rustdoc js: add nonnull helper and typecheck src-script.js --- src/librustdoc/html/static/js/rustdoc.d.ts | 29 +++++++++++++++++++++ src/librustdoc/html/static/js/src-script.js | 28 +++++++++++++------- src/librustdoc/html/static/js/storage.js | 22 ++++++++++++++++ 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 4b43c00730d4..e94c6beabea3 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -4,6 +4,10 @@ /* eslint-disable */ declare global { + /** Map from crate name to directory structure, for source view */ + declare var srcIndex: Map; + /** Defined and documented in `main.js` */ + declare function nonnull(x: T|null, msg: string|undefined); interface Window { /** Make the current theme easy to find */ currentTheme: HTMLLinkElement|null; @@ -40,6 +44,23 @@ declare global { * or if this is a docs page, this function does nothing. */ rustdocShowSourceSidebar: function(), + /** + * Close the sidebar in source code view + */ + rustdocCloseSourceSidebar?: function(), + /** + * Shows the sidebar in source code view + */ + rustdocShowSourceSidebar?: function(), + /** + * Toggles the sidebar in source code view + */ + rustdocToggleSrcSidebar?: function(), + /** + * create's the sidebar in source code view. + * called in generated `src-files.js`. + */ + createSrcSidebar?: function(), /** * Set up event listeners for a scraped source example. */ @@ -438,4 +459,12 @@ declare namespace rustdoc { type TypeImpls = { [cratename: string]: Array> } + + /** + * Directory structure for source code view, + * defined in generated `src-files.js`. + * + * is a tuple of (filename, subdirs, filenames). + */ + type Dir = [string, rustdoc.Dir[], string[]] } diff --git a/src/librustdoc/html/static/js/src-script.js b/src/librustdoc/html/static/js/src-script.js index fc27241334bf..b9ab6e85603b 100644 --- a/src/librustdoc/html/static/js/src-script.js +++ b/src/librustdoc/html/static/js/src-script.js @@ -3,10 +3,8 @@ // Local js definitions: /* global addClass, onEachLazy, removeClass, browserSupportsHistoryApi */ -/* global updateLocalStorage, getVar */ +/* global updateLocalStorage, getVar, nonnull */ -// Eventually fix this. -// @ts-nocheck "use strict"; @@ -29,6 +27,14 @@ function closeSidebarIfMobile() { } } +/** + * @param {rustdoc.Dir} elem + * @param {HTMLElement} parent + * @param {string} fullPath + * @param {boolean} hasFoundFile + * + * @returns {boolean} - new value for hasFoundFile + */ function createDirEntry(elem, parent, fullPath, hasFoundFile) { const dirEntry = document.createElement("details"); const summary = document.createElement("summary"); @@ -95,7 +101,7 @@ window.rustdocToggleSrcSidebar = () => { // This function is called from "src-files.js", generated in `html/render/write_shared.rs`. // eslint-disable-next-line no-unused-vars function createSrcSidebar() { - const container = document.querySelector("nav.sidebar"); + const container = nonnull(document.querySelector("nav.sidebar")); const sidebar = document.createElement("div"); sidebar.id = "src-sidebar"; @@ -111,6 +117,7 @@ function createSrcSidebar() { // Focus on the current file in the source files sidebar. const selected_elem = sidebar.getElementsByClassName("selected")[0]; if (typeof selected_elem !== "undefined") { + // @ts-expect-error selected_elem.focus(); } } @@ -130,11 +137,12 @@ function highlightSrcLines() { to = from; from = tmp; } - let elem = document.getElementById(from); + const from_s = "" + from; + let elem = document.getElementById(from_s); if (!elem) { return; } - const x = document.getElementById(from); + const x = document.getElementById(from_s); if (x) { x.scrollIntoView(); } @@ -142,7 +150,7 @@ function highlightSrcLines() { removeClass(e, "line-highlighted"); }); for (let i = from; i <= to; ++i) { - elem = document.getElementById(i); + elem = document.getElementById("" + i); if (!elem) { break; } @@ -153,11 +161,12 @@ function highlightSrcLines() { const handleSrcHighlight = (function() { let prev_line_id = 0; + /** @type {function(string): void} */ const set_fragment = name => { const x = window.scrollX, y = window.scrollY; if (browserSupportsHistoryApi()) { - history.replaceState(null, null, "#" + name); + history.replaceState(null, "", "#" + name); highlightSrcLines(); } else { location.replace("#" + name); @@ -166,6 +175,7 @@ const handleSrcHighlight = (function() { window.scrollTo(x, y); }; + // @ts-expect-error return ev => { let cur_line_id = parseInt(ev.target.id, 10); // This event handler is attached to the entire line number column, but it should only @@ -191,7 +201,7 @@ const handleSrcHighlight = (function() { } else { prev_line_id = cur_line_id; - set_fragment(cur_line_id); + set_fragment("" + cur_line_id); } }; }()); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 425b915b5f94..748d2ef33c32 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -21,6 +21,28 @@ const settingsDataset = (function() { return settingsElement && settingsElement.dataset ? settingsElement.dataset : null; })(); +/** + * Assert that the passed value is nonnull, then return it. + * + * Takes an optional error message argument. + * + * Must be defined in this file, as it is loaded before all others. + * + * @template T + * @param {T|null} x + * @param {string=} msg + * @returns T + */ +// used in other files, not yet used in this one. +// eslint-disable-next-line no-unused-vars +function nonnull(x, msg) { + if (x === null) { + throw (msg || "unexpected null value!"); + } else { + return x; + } +} + /** * Get a configuration value. If it's not set, get the default. * From eca391fbd4544e3f200f0ee08ef8d6f0a469542e Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 15 Mar 2025 12:31:36 +0000 Subject: [PATCH 080/546] Cleanup `LangString::parse` Flatten some `if`s into match patterns Use `str::strip_prefix` instead of `starts_with`+indexing Avoid redundant tests for `extra.is_some()` --- src/librustdoc/html/markdown.rs | 85 ++++++++++++++++----------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 079651e86031..e516b498c189 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1200,11 +1200,12 @@ impl LangString { data.ignore = Ignore::All; seen_rust_tags = !seen_other_tags; } - LangStringToken::LangToken(x) if x.starts_with("ignore-") => { - if enable_per_target_ignores { - ignores.push(x.trim_start_matches("ignore-").to_owned()); - seen_rust_tags = !seen_other_tags; - } + LangStringToken::LangToken(x) + if let Some(ignore) = x.strip_prefix("ignore-") + && enable_per_target_ignores => + { + ignores.push(ignore.to_owned()); + seen_rust_tags = !seen_other_tags; } LangStringToken::LangToken("rust") => { data.rust = true; @@ -1226,37 +1227,39 @@ impl LangString { data.standalone_crate = true; seen_rust_tags = !seen_other_tags || seen_rust_tags; } - LangStringToken::LangToken(x) if x.starts_with("edition") => { - data.edition = x[7..].parse::().ok(); + LangStringToken::LangToken(x) + if let Some(edition) = x.strip_prefix("edition") => + { + data.edition = edition.parse::().ok(); } LangStringToken::LangToken(x) - if x.starts_with("rust") && x[4..].parse::().is_ok() => + if let Some(edition) = x.strip_prefix("rust") + && edition.parse::().is_ok() + && let Some(extra) = extra => { - if let Some(extra) = extra { - extra.error_invalid_codeblock_attr_with_help( - format!("unknown attribute `{x}`"), - |lint| { - lint.help(format!( - "there is an attribute with a similar name: `edition{}`", - &x[4..], - )); - }, - ); - } + extra.error_invalid_codeblock_attr_with_help( + format!("unknown attribute `{x}`"), + |lint| { + lint.help(format!( + "there is an attribute with a similar name: `edition{edition}`" + )); + }, + ); } LangStringToken::LangToken(x) - if allow_error_code_check && x.starts_with('E') && x.len() == 5 => + if allow_error_code_check + && let Some(error_code) = x.strip_prefix('E') + && error_code.len() == 4 => { - if x[1..].parse::().is_ok() { + if error_code.parse::().is_ok() { data.error_codes.push(x.to_owned()); seen_rust_tags = !seen_other_tags || seen_rust_tags; } else { seen_other_tags = true; } } - LangStringToken::LangToken(x) if extra.is_some() => { - let s = x.to_lowercase(); - if let Some(help) = match s.as_str() { + LangStringToken::LangToken(x) if let Some(extra) = extra => { + if let Some(help) = match x.to_lowercase().as_str() { "compile-fail" | "compile_fail" | "compilefail" => Some( "use `compile_fail` to invert the results of this test, so that it \ passes if it cannot be compiled and fails if it can", @@ -1273,33 +1276,27 @@ impl LangString { "use `test_harness` to run functions marked `#[test]` instead of a \ potentially-implicit `main` function", ), - "standalone" | "standalone_crate" | "standalone-crate" => { - if let Some(extra) = extra - && extra.sp.at_least_rust_2024() - { - Some( - "use `standalone_crate` to compile this code block \ + "standalone" | "standalone_crate" | "standalone-crate" + if extra.sp.at_least_rust_2024() => + { + Some( + "use `standalone_crate` to compile this code block \ separately", - ) - } else { - None - } + ) } _ => None, } { - if let Some(extra) = extra { - extra.error_invalid_codeblock_attr_with_help( - format!("unknown attribute `{x}`"), - |lint| { - lint.help(help).help( - "this code block may be skipped during testing, \ + extra.error_invalid_codeblock_attr_with_help( + format!("unknown attribute `{x}`"), + |lint| { + lint.help(help).help( + "this code block may be skipped during testing, \ because unknown attributes are treated as markers for \ code samples written in other programming languages, \ unless it is also explicitly marked as `rust`", - ); - }, - ); - } + ); + }, + ); } seen_other_tags = true; data.unknown.push(x.to_owned()); From 360a87d51df99df2c2d2cbec0e5b30dbd9c03e59 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 13 Sep 2024 16:19:38 +0300 Subject: [PATCH 081/546] hygiene: Asserts, comments, code cleanup --- compiler/rustc_span/src/hygiene.rs | 144 ++++++++++++++++++----------- 1 file changed, 91 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 62027caa3537..b872f5e9d38f 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -27,9 +27,9 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::collections::hash_set::Entry as SetEntry; -use std::fmt; use std::hash::Hash; use std::sync::Arc; +use std::{fmt, iter, mem}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -57,7 +57,11 @@ pub struct SyntaxContext(u32); impl !Ord for SyntaxContext {} impl !PartialOrd for SyntaxContext {} -#[derive(Debug, Encodable, Decodable, Clone)] +/// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal. +/// The other fields are only for caching. +type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); + +#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable)] pub struct SyntaxContextData { outer_expn: ExpnId, outer_transparency: Transparency, @@ -70,6 +74,27 @@ pub struct SyntaxContextData { dollar_crate_name: Symbol, } +impl SyntaxContextData { + fn root() -> SyntaxContextData { + SyntaxContextData { + outer_expn: ExpnId::root(), + outer_transparency: Transparency::Opaque, + parent: SyntaxContext::root(), + opaque: SyntaxContext::root(), + opaque_and_semitransparent: SyntaxContext::root(), + dollar_crate_name: kw::DollarCrate, + } + } + + fn decode_placeholder() -> SyntaxContextData { + SyntaxContextData { dollar_crate_name: kw::Empty, ..SyntaxContextData::root() } + } + + fn is_decode_placeholder(&self) -> bool { + self.dollar_crate_name == kw::Empty + } +} + rustc_index::newtype_index! { /// A unique ID associated with a macro invocation and expansion. #[orderable] @@ -342,7 +367,7 @@ pub(crate) struct HygieneData { foreign_expn_hashes: FxHashMap, expn_hash_to_expn_id: UnhashMap, syntax_context_data: Vec, - syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>, + syntax_context_map: FxHashMap, /// Maps the `local_hash` of an `ExpnData` to the next disambiguator value. /// This is used by `update_disambiguator` to keep track of which `ExpnData`s /// would have collisions without a disambiguator. @@ -361,21 +386,15 @@ impl HygieneData { None, ); + let root_ctxt_data = SyntaxContextData::root(); HygieneData { local_expn_data: IndexVec::from_elem_n(Some(root_data), 1), local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1), foreign_expn_data: FxHashMap::default(), foreign_expn_hashes: FxHashMap::default(), - expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) + expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) .collect(), - syntax_context_data: vec![SyntaxContextData { - outer_expn: ExpnId::root(), - outer_transparency: Transparency::Opaque, - parent: SyntaxContext(0), - opaque: SyntaxContext(0), - opaque_and_semitransparent: SyntaxContext(0), - dollar_crate_name: kw::DollarCrate, - }], + syntax_context_data: vec![root_ctxt_data], syntax_context_map: FxHashMap::default(), expn_data_disambiguators: UnhashMap::default(), } @@ -425,23 +444,28 @@ impl HygieneData { } fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext { + debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); self.syntax_context_data[ctxt.0 as usize].opaque } fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { + debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent } fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { + debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); self.syntax_context_data[ctxt.0 as usize].outer_expn } fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { + debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); let data = &self.syntax_context_data[ctxt.0 as usize]; (data.outer_expn, data.outer_transparency) } fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext { + debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); self.syntax_context_data[ctxt.0 as usize].parent } @@ -551,6 +575,7 @@ impl HygieneData { transparency: Transparency, ) -> SyntaxContext { let syntax_context_data = &mut self.syntax_context_data; + debug_assert!(!syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); let mut opaque = syntax_context_data[ctxt.0 as usize].opaque; let mut opaque_and_semitransparent = syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent; @@ -561,7 +586,7 @@ impl HygieneData { .syntax_context_map .entry((parent, expn_id, transparency)) .or_insert_with(|| { - let new_opaque = SyntaxContext(syntax_context_data.len() as u32); + let new_opaque = SyntaxContext::from_usize(syntax_context_data.len()); syntax_context_data.push(SyntaxContextData { outer_expn: expn_id, outer_transparency: transparency, @@ -581,7 +606,7 @@ impl HygieneData { .entry((parent, expn_id, transparency)) .or_insert_with(|| { let new_opaque_and_semitransparent = - SyntaxContext(syntax_context_data.len() as u32); + SyntaxContext::from_usize(syntax_context_data.len()); syntax_context_data.push(SyntaxContextData { outer_expn: expn_id, outer_transparency: transparency, @@ -596,8 +621,6 @@ impl HygieneData { let parent = ctxt; *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| { - let new_opaque_and_semitransparent_and_transparent = - SyntaxContext(syntax_context_data.len() as u32); syntax_context_data.push(SyntaxContextData { outer_expn: expn_id, outer_transparency: transparency, @@ -606,7 +629,7 @@ impl HygieneData { opaque_and_semitransparent, dollar_crate_name: kw::DollarCrate, }); - new_opaque_and_semitransparent_and_transparent + SyntaxContext::from_usize(syntax_context_data.len() - 1) }) } } @@ -713,6 +736,10 @@ impl SyntaxContext { SyntaxContext(raw as u32) } + fn from_usize(raw: usize) -> SyntaxContext { + SyntaxContext(u32::try_from(raw).unwrap()) + } + /// Extend a syntax context with a given expansion and transparency. pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) @@ -893,7 +920,10 @@ impl SyntaxContext { } pub(crate) fn dollar_crate_name(self) -> Symbol { - HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) + HygieneData::with(|data| { + debug_assert!(!data.syntax_context_data[self.0 as usize].is_decode_placeholder()); + data.syntax_context_data[self.0 as usize].dollar_crate_name + }) } pub fn edition(self) -> Edition { @@ -1244,7 +1274,7 @@ impl HygieneEncodeContext { // Consume the current round of SyntaxContexts. // Drop the lock() temporary early - let latest_ctxts = { std::mem::take(&mut *self.latest_ctxts.lock()) }; + let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) }; // It's fine to iterate over a HashMap, because the serialization // of the table that we insert data into doesn't depend on insertion @@ -1256,7 +1286,7 @@ impl HygieneEncodeContext { } }); - let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) }; + let latest_expns = { mem::take(&mut *self.latest_expns.lock()) }; // Same as above, this is fine as we are inserting into a order-independent hashset #[allow(rustc::potential_query_instability)] @@ -1373,9 +1403,11 @@ pub fn decode_syntax_context SyntaxContext return SyntaxContext::root(); } - let ctxt = { + let pending_ctxt = { let mut inner = context.inner.lock(); + // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between + // raw ids from different crate metadatas. if let Some(ctxt) = inner.remapped_ctxts.get(raw_id as usize).copied().flatten() { // This has already been decoded. return ctxt; @@ -1383,18 +1415,21 @@ pub fn decode_syntax_context SyntaxContext match inner.decoding.entry(raw_id) { Entry::Occupied(ctxt_entry) => { + let pending_ctxt = *ctxt_entry.get(); match context.local_in_progress.borrow_mut().entry(raw_id) { - SetEntry::Occupied(..) => { - // We're decoding this already on the current thread. Return here - // and let the function higher up the stack finish decoding to handle - // recursive cases. - return *ctxt_entry.get(); - } + // We're decoding this already on the current thread. Return here and let the + // function higher up the stack finish decoding to handle recursive cases. + // Hopefully having a `SyntaxContext` that refers to an incorrect data is ok + // during reminder of the decoding process, it's certainly not ok after the + // top level decoding function returns. + SetEntry::Occupied(..) => return pending_ctxt, + // Some other thread is currently decoding this. + // Race with it (alternatively we could wait here). + // We cannot return this value, unlike in the recursive case above, because it + // may expose a `SyntaxContext` pointing to incorrect data to arbitrary code. SetEntry::Vacant(entry) => { entry.insert(); - - // Some other thread is current decoding this. Race with it. - *ctxt_entry.get() + pending_ctxt } } } @@ -1405,18 +1440,10 @@ pub fn decode_syntax_context SyntaxContext // Allocate and store SyntaxContext id *before* calling the decoder function, // as the SyntaxContextData may reference itself. let new_ctxt = HygieneData::with(|hygiene_data| { - let new_ctxt = SyntaxContext(hygiene_data.syntax_context_data.len() as u32); // Push a dummy SyntaxContextData to ensure that nobody else can get the - // same ID as us. This will be overwritten after call `decode_Data` - hygiene_data.syntax_context_data.push(SyntaxContextData { - outer_expn: ExpnId::root(), - outer_transparency: Transparency::Transparent, - parent: SyntaxContext::root(), - opaque: SyntaxContext::root(), - opaque_and_semitransparent: SyntaxContext::root(), - dollar_crate_name: kw::Empty, - }); - new_ctxt + // same ID as us. This will be overwritten after call `decode_data`. + hygiene_data.syntax_context_data.push(SyntaxContextData::decode_placeholder()); + SyntaxContext::from_usize(hygiene_data.syntax_context_data.len() - 1) }); entry.insert(new_ctxt); new_ctxt @@ -1426,27 +1453,38 @@ pub fn decode_syntax_context SyntaxContext // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let mut ctxt_data = decode_data(d, raw_id); - // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names` - // We don't care what the encoding crate set this to - we want to resolve it - // from the perspective of the current compilation session - ctxt_data.dollar_crate_name = kw::DollarCrate; + let ctxt_data = decode_data(d, raw_id); - // Overwrite the dummy data with our decoded SyntaxContextData - HygieneData::with(|hygiene_data| { - if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize) + let ctxt = HygieneData::with(|hygiene_data| { + let old = if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize) && old.outer_expn == ctxt_data.outer_expn && old.outer_transparency == ctxt_data.outer_transparency && old.parent == ctxt_data.parent { - ctxt_data = old.clone(); + Some(old.clone()) + } else { + None + }; + // Overwrite its placeholder data with our decoded data. + let ctxt_data_ref = &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize]; + let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data); + // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`. + // We don't care what the encoding crate set this to - we want to resolve it + // from the perspective of the current compilation session + ctxt_data_ref.dollar_crate_name = kw::DollarCrate; + if let Some(old) = old { + *ctxt_data_ref = old; } - - hygiene_data.syntax_context_data[ctxt.as_u32() as usize] = ctxt_data; + // Make sure nothing weird happened while `decode_data` was running. + if !prev_ctxt_data.is_decode_placeholder() { + // Another thread may have already inserted the decoded data, + // but the decoded data should match. + assert_eq!(prev_ctxt_data, *ctxt_data_ref); + } + pending_ctxt }); // Mark the context as completed - context.local_in_progress.borrow_mut().remove(&raw_id); let mut inner = context.inner.lock(); From 6e1effe948525538427b2a6932f1619d74776cef Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 13 Sep 2024 23:08:37 +0300 Subject: [PATCH 082/546] hygiene: Ensure uniqueness of `SyntaxContextData`s --- compiler/rustc_span/src/hygiene.rs | 60 +++++++++++++++++------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index b872f5e9d38f..36ecbe1cb78c 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -93,6 +93,10 @@ impl SyntaxContextData { fn is_decode_placeholder(&self) -> bool { self.dollar_crate_name == kw::Empty } + + fn key(&self) -> SyntaxContextKey { + (self.parent, self.outer_expn, self.outer_transparency) + } } rustc_index::newtype_index! { @@ -395,7 +399,7 @@ impl HygieneData { expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) .collect(), syntax_context_data: vec![root_ctxt_data], - syntax_context_map: FxHashMap::default(), + syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(), expn_data_disambiguators: UnhashMap::default(), } } @@ -1454,34 +1458,38 @@ pub fn decode_syntax_context SyntaxContext // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext let ctxt_data = decode_data(d, raw_id); + let ctxt_key = ctxt_data.key(); let ctxt = HygieneData::with(|hygiene_data| { - let old = if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize) - && old.outer_expn == ctxt_data.outer_expn - && old.outer_transparency == ctxt_data.outer_transparency - && old.parent == ctxt_data.parent - { - Some(old.clone()) - } else { - None - }; - // Overwrite its placeholder data with our decoded data. - let ctxt_data_ref = &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize]; - let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data); - // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`. - // We don't care what the encoding crate set this to - we want to resolve it - // from the perspective of the current compilation session - ctxt_data_ref.dollar_crate_name = kw::DollarCrate; - if let Some(old) = old { - *ctxt_data_ref = old; + match hygiene_data.syntax_context_map.get(&ctxt_key) { + // Ensure that syntax contexts are unique. + // If syntax contexts with the given key already exists, reuse it instead of + // using `pending_ctxt`. + // `pending_ctxt` will leave an unused hole in the vector of syntax contexts. + // Hopefully its value isn't stored anywhere during decoding and its dummy data + // is never accessed later. The `is_decode_placeholder` asserts on all + // accesses to syntax context data attempt to ensure it. + Some(&ctxt) => ctxt, + // This is a completely new context. + // Overwrite its placeholder data with our decoded data. + None => { + let ctxt_data_ref = + &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize]; + let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data); + // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`. + // We don't care what the encoding crate set this to - we want to resolve it + // from the perspective of the current compilation session. + ctxt_data_ref.dollar_crate_name = kw::DollarCrate; + // Make sure nothing weird happened while `decode_data` was running. + if !prev_ctxt_data.is_decode_placeholder() { + // Another thread may have already inserted the decoded data, + // but the decoded data should match. + assert_eq!(prev_ctxt_data, *ctxt_data_ref); + } + hygiene_data.syntax_context_map.insert(ctxt_key, pending_ctxt); + pending_ctxt + } } - // Make sure nothing weird happened while `decode_data` was running. - if !prev_ctxt_data.is_decode_placeholder() { - // Another thread may have already inserted the decoded data, - // but the decoded data should match. - assert_eq!(prev_ctxt_data, *ctxt_data_ref); - } - pending_ctxt }); // Mark the context as completed From 07328d5d408f707f92c4208cb5d4042af981ff43 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 15 Mar 2025 02:54:53 +0300 Subject: [PATCH 083/546] hygiene: Update `$crate` pretty-printing to account for holes in syntax contexts --- compiler/rustc_span/src/hygiene.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 36ecbe1cb78c..4390085cd049 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -653,25 +653,26 @@ pub fn walk_chain_collapsed(span: Span, to: Span) -> Span { pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) { // The new contexts that need updating are at the end of the list and have `$crate` as a name. - let (len, to_update) = HygieneData::with(|data| { - ( - data.syntax_context_data.len(), - data.syntax_context_data - .iter() - .rev() - .take_while(|scdata| scdata.dollar_crate_name == kw::DollarCrate) - .count(), - ) + // Also decoding placeholders can be encountered among both old and new contexts. + let mut to_update = vec![]; + HygieneData::with(|data| { + for (idx, scdata) in data.syntax_context_data.iter().enumerate().rev() { + if scdata.dollar_crate_name == kw::DollarCrate { + to_update.push((idx, kw::DollarCrate)); + } else if !scdata.is_decode_placeholder() { + break; + } + } }); // The callback must be called from outside of the `HygieneData` lock, // since it will try to acquire it too. - let range_to_update = len - to_update..len; - let names: Vec<_> = - range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect(); + for (idx, name) in &mut to_update { + *name = get_name(SyntaxContext::from_usize(*idx)); + } HygieneData::with(|data| { - range_to_update.zip(names).for_each(|(idx, name)| { + for (idx, name) in to_update { data.syntax_context_data[idx].dollar_crate_name = name; - }) + } }) } From 1cdddd67a333fd8e70334395ad33694a575037b4 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 26 Feb 2025 17:40:06 -0800 Subject: [PATCH 084/546] Add MIR pre-codegen tests to track 138544 --- tests/mir-opt/pre-codegen/checked_ops.rs | 39 ++++++++++- ...b_at_home.PreCodegen.after.panic-abort.mir | 48 +++++++++++++ ..._at_home.PreCodegen.after.panic-unwind.mir | 48 +++++++++++++ ...ecked_sub.PreCodegen.after.panic-abort.mir | 44 ++++++++++++ ...cked_sub.PreCodegen.after.panic-unwind.mir | 44 ++++++++++++ ...mple_option_map.ezmap.PreCodegen.after.mir | 2 +- ...map_via_question_mark.PreCodegen.after.mir | 70 +++++++++++++++++++ .../mir-opt/pre-codegen/simple_option_map.rs | 24 ++++++- 8 files changed, 315 insertions(+), 4 deletions(-) create mode 100644 tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir create mode 100644 tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir create mode 100644 tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-abort.mir create mode 100644 tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-unwind.mir create mode 100644 tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir diff --git a/tests/mir-opt/pre-codegen/checked_ops.rs b/tests/mir-opt/pre-codegen/checked_ops.rs index 56f8e3f83384..8fd340503f54 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.rs +++ b/tests/mir-opt/pre-codegen/checked_ops.rs @@ -1,4 +1,3 @@ -// skip-filecheck //@ compile-flags: -O -Zmir-opt-level=2 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY @@ -8,10 +7,48 @@ // EMIT_MIR checked_ops.step_forward.PreCodegen.after.mir pub fn step_forward(x: u16, n: usize) -> u16 { // This uses `u16` so that the conversion to usize is always widening. + + // CHECK-LABEL: fn step_forward + // CHECK: inlined{{.+}}forward std::iter::Step::forward(x, n) } // EMIT_MIR checked_ops.checked_shl.PreCodegen.after.mir pub fn checked_shl(x: u32, rhs: u32) -> Option { + // CHECK-LABEL: fn checked_shl + // CHECK: [[TEMP:_[0-9]+]] = ShlUnchecked(copy _1, copy _2) + // CHECK: _0 = Option::::Some({{move|copy}} [[TEMP]]) x.checked_shl(rhs) } + +// EMIT_MIR checked_ops.use_checked_sub.PreCodegen.after.mir +pub fn use_checked_sub(x: u32, rhs: u32) { + // We want this to be equivalent to open-coding it, leaving no `Option`s around. + // FIXME(#138544): It's not yet. + + // CHECK-LABEL: fn use_checked_sub + // CHECK: inlined{{.+}}u32{{.+}}checked_sub + // CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2) + // CHECK: [[TEMP1:_.+]] = Option::::Some(move [[DELTA]]); + // CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32); + // CHECK: do_something({{move|copy}} [[TEMP2]]) + if let Some(delta) = x.checked_sub(rhs) { + do_something(delta); + } +} + +// EMIT_MIR checked_ops.saturating_sub_at_home.PreCodegen.after.mir +pub fn saturating_sub_at_home(lhs: u32, rhs: u32) -> u32 { + // FIXME(#138544): Similarly here, the `Option` ought to optimize away + + // CHECK-LABEL: fn saturating_sub_at_home + // CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2) + // CHECK: [[TEMP1:_.+]] = Option::::Some({{move|copy}} [[DELTA]]); + // CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32); + // CHECK: _0 = {{move|copy}} [[TEMP2]]; + u32::checked_sub(lhs, rhs).unwrap_or(0) +} + +unsafe extern "Rust" { + safe fn do_something(_: u32); +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir new file mode 100644 index 000000000000..5b4fdeda8573 --- /dev/null +++ b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir @@ -0,0 +1,48 @@ +// MIR for `saturating_sub_at_home` after PreCodegen + +fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 { + debug lhs => _1; + debug rhs => _2; + let mut _0: u32; + let mut _5: std::option::Option; + scope 1 (inlined core::num::::checked_sub) { + let mut _3: bool; + let mut _4: u32; + } + scope 2 (inlined Option::::unwrap_or) { + let _6: u32; + scope 3 { + } + } + + bb0: { + StorageLive(_5); + StorageLive(_3); + _3 = Lt(copy _1, copy _2); + switchInt(move _3) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_4); + _4 = SubUnchecked(copy _1, copy _2); + _5 = Option::::Some(move _4); + StorageDead(_4); + StorageDead(_3); + StorageLive(_6); + _6 = move ((_5 as Some).0: u32); + _0 = move _6; + StorageDead(_6); + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_5); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir new file mode 100644 index 000000000000..5b4fdeda8573 --- /dev/null +++ b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,48 @@ +// MIR for `saturating_sub_at_home` after PreCodegen + +fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 { + debug lhs => _1; + debug rhs => _2; + let mut _0: u32; + let mut _5: std::option::Option; + scope 1 (inlined core::num::::checked_sub) { + let mut _3: bool; + let mut _4: u32; + } + scope 2 (inlined Option::::unwrap_or) { + let _6: u32; + scope 3 { + } + } + + bb0: { + StorageLive(_5); + StorageLive(_3); + _3 = Lt(copy _1, copy _2); + switchInt(move _3) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_4); + _4 = SubUnchecked(copy _1, copy _2); + _5 = Option::::Some(move _4); + StorageDead(_4); + StorageDead(_3); + StorageLive(_6); + _6 = move ((_5 as Some).0: u32); + _0 = move _6; + StorageDead(_6); + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_5); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-abort.mir new file mode 100644 index 000000000000..3c475cd40309 --- /dev/null +++ b/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-abort.mir @@ -0,0 +1,44 @@ +// MIR for `use_checked_sub` after PreCodegen + +fn use_checked_sub(_1: u32, _2: u32) -> () { + debug x => _1; + debug rhs => _2; + let mut _0: (); + let mut _5: std::option::Option; + let _7: (); + scope 1 { + debug delta => _6; + let _6: u32; + scope 2 (inlined core::num::::checked_sub) { + let mut _3: bool; + let mut _4: u32; + } + } + + bb0: { + StorageLive(_5); + StorageLive(_3); + _3 = Lt(copy _1, copy _2); + switchInt(move _3) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_4); + _4 = SubUnchecked(copy _1, copy _2); + _5 = Option::::Some(move _4); + StorageDead(_4); + StorageDead(_3); + _6 = copy ((_5 as Some).0: u32); + _7 = do_something(move _6) -> [return: bb3, unwind unreachable]; + } + + bb2: { + StorageDead(_3); + goto -> bb3; + } + + bb3: { + StorageDead(_5); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-unwind.mir new file mode 100644 index 000000000000..3ef09764b1c5 --- /dev/null +++ b/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,44 @@ +// MIR for `use_checked_sub` after PreCodegen + +fn use_checked_sub(_1: u32, _2: u32) -> () { + debug x => _1; + debug rhs => _2; + let mut _0: (); + let mut _5: std::option::Option; + let _7: (); + scope 1 { + debug delta => _6; + let _6: u32; + scope 2 (inlined core::num::::checked_sub) { + let mut _3: bool; + let mut _4: u32; + } + } + + bb0: { + StorageLive(_5); + StorageLive(_3); + _3 = Lt(copy _1, copy _2); + switchInt(move _3) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_4); + _4 = SubUnchecked(copy _1, copy _2); + _5 = Option::::Some(move _4); + StorageDead(_4); + StorageDead(_3); + _6 = copy ((_5 as Some).0: u32); + _7 = do_something(move _6) -> [return: bb3, unwind continue]; + } + + bb2: { + StorageDead(_3); + goto -> bb3; + } + + bb3: { + StorageDead(_5); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir index cbfc58194cc1..7595ad88d9df 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir @@ -3,7 +3,7 @@ fn ezmap(_1: Option) -> Option { debug x => _1; let mut _0: std::option::Option; - scope 1 (inlined map::) { + scope 1 (inlined map::) { let mut _2: isize; let _3: i32; let mut _4: i32; diff --git a/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir new file mode 100644 index 000000000000..b921b96966b2 --- /dev/null +++ b/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir @@ -0,0 +1,70 @@ +// MIR for `map_via_question_mark` after PreCodegen + +fn map_via_question_mark(_1: Option) -> Option { + debug x => _1; + let mut _0: std::option::Option; + let mut _4: std::ops::ControlFlow, i32>; + let _5: i32; + let mut _6: i32; + scope 1 { + debug residual => const Option::::None; + scope 2 { + scope 7 (inlined as FromResidual>>::from_residual) { + } + } + } + scope 3 { + debug val => _5; + scope 4 { + } + } + scope 5 (inlined as Try>::branch) { + let mut _2: isize; + let _3: i32; + scope 6 { + } + } + + bb0: { + StorageLive(_6); + StorageLive(_4); + StorageLive(_2); + StorageLive(_3); + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); + _0 = const Option::::None; + StorageDead(_6); + StorageDead(_4); + goto -> bb3; + } + + bb2: { + _3 = copy ((_1 as Some).0: i32); + _4 = ControlFlow::, i32>::Continue(copy _3); + StorageDead(_3); + StorageDead(_2); + _5 = copy ((_4 as Continue).0: i32); + _6 = Add(copy _5, const 1_i32); + _0 = Option::::Some(move _6); + StorageDead(_6); + StorageDead(_4); + goto -> bb3; + } + + bb3: { + return; + } + + bb4: { + unreachable; + } +} + +ALLOC0 (size: 8, align: 4) { + 00 00 00 00 __ __ __ __ │ ....░░░░ +} diff --git a/tests/mir-opt/pre-codegen/simple_option_map.rs b/tests/mir-opt/pre-codegen/simple_option_map.rs index 0c432be0419b..f0d7b51a6439 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.rs +++ b/tests/mir-opt/pre-codegen/simple_option_map.rs @@ -1,7 +1,6 @@ -// skip-filecheck //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -#[inline(always)] +#[inline] fn map(slf: Option, f: F) -> Option where F: FnOnce(T) -> U, @@ -14,9 +13,30 @@ where // EMIT_MIR simple_option_map.ezmap.PreCodegen.after.mir pub fn ezmap(x: Option) -> Option { + // We expect this to all be inlined, as though it was written without the + // combinator and without the closure, using just a plain match. + + // CHECK-LABEL: fn ezmap + // CHECK: [[INNER:_.+]] = copy ((_1 as Some).0: i32); + // CHECK: [[SUCC:_.+]] = Add({{copy|move}} [[INNER]], const 1_i32); + // CHECK: _0 = Option::::Some({{copy|move}} [[SUCC]]); map(x, |n| n + 1) } +// EMIT_MIR simple_option_map.map_via_question_mark.PreCodegen.after.mir +pub fn map_via_question_mark(x: Option) -> Option { + // FIXME(#138544): Ideally this would optimize out the `ControlFlow` local. + + // CHECK-LABEL: fn map_via_question_mark + // CHECK: [[INNER:_.+]] = copy ((_1 as Some).0: i32); + // CHECK: [[TEMP1:_.+]] = ControlFlow::, i32>::Continue(copy [[INNER]]); + // CHECK: [[TEMP2:_.+]] = copy (([[TEMP1]] as Continue).0: i32); + // CHECK: [[SUCC:_.+]] = Add({{copy|move}} [[TEMP2]], const 1_i32); + // CHECK: _0 = Option::::Some({{copy|move}} [[SUCC]]); + Some(x? + 1) +} + fn main() { assert_eq!(None, ezmap(None)); + assert_eq!(None, map_via_question_mark(None)); } From 5bb37b7580aaab8578cb7bb30cf1a62cbfb85a27 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Mar 2025 14:55:32 +0000 Subject: [PATCH 085/546] Fix usage of vector registers in inline asm on arm64 --- src/inline_asm.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 310b226814d4..59d109341311 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -652,6 +652,20 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) .unwrap(), }, + InlineAsmArch::AArch64 => match reg { + InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => { + // rustc emits v0 rather than q0 + reg.emit( + &mut generated_asm, + InlineAsmArch::AArch64, + Some(modifier.unwrap_or('q')), + ) + .unwrap() + } + _ => reg + .emit(&mut generated_asm, InlineAsmArch::AArch64, *modifier) + .unwrap(), + }, _ => reg.emit(&mut generated_asm, self.arch, *modifier).unwrap(), } } @@ -809,7 +823,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } InlineAsmArch::AArch64 => { generated_asm.push_str(" str "); - reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); + match reg { + InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => { + // rustc emits v0 rather than q0 + reg.emit(generated_asm, InlineAsmArch::AArch64, Some('q')).unwrap() + } + _ => reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(), + } writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } InlineAsmArch::RiscV64 => { @@ -851,7 +871,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } InlineAsmArch::AArch64 => { generated_asm.push_str(" ldr "); - reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); + match reg { + InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => { + // rustc emits v0 rather than q0 + reg.emit(generated_asm, InlineAsmArch::AArch64, Some('q')).unwrap() + } + _ => reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(), + } writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } InlineAsmArch::RiscV64 => { From aa2c24b03b893f7e65e1755a237ffe0387509b25 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 9 Mar 2025 01:03:11 +0530 Subject: [PATCH 086/546] uefi: Add OwnedEvent abstraction - Events are going to become quite important for Networking, so needed owned abstractions. - Switch to OwnedEvent abstraction for Exit boot services event. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/helpers.rs | 86 +++++++++++++++---------- library/std/src/sys/pal/uefi/mod.rs | 10 +-- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 0a2a8f5ef67b..a0433ddfd967 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -120,39 +120,6 @@ pub(crate) fn open_protocol( } } -pub(crate) fn create_event( - signal: u32, - tpl: efi::Tpl, - handler: Option, - context: *mut crate::ffi::c_void, -) -> io::Result> { - let boot_services: NonNull = - boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast(); - let mut event: r_efi::efi::Event = crate::ptr::null_mut(); - let r = unsafe { - let create_event = (*boot_services.as_ptr()).create_event; - (create_event)(signal, tpl, handler, context, &mut event) - }; - if r.is_error() { - Err(crate::io::Error::from_raw_os_error(r.as_usize())) - } else { - NonNull::new(event).ok_or(const_error!(io::ErrorKind::Other, "null protocol")) - } -} - -/// # SAFETY -/// - The supplied event must be valid -pub(crate) unsafe fn close_event(evt: NonNull) -> io::Result<()> { - let boot_services: NonNull = - boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast(); - let r = unsafe { - let close_event = (*boot_services.as_ptr()).close_event; - (close_event)(evt.as_ptr()) - }; - - if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } -} - /// Gets the Protocol for current system handle. /// /// Note: Some protocols need to be manually freed. It is the caller's responsibility to do so. @@ -559,3 +526,56 @@ impl Drop for ServiceProtocol { } } } + +#[repr(transparent)] +pub(crate) struct OwnedEvent(NonNull); + +impl OwnedEvent { + pub(crate) fn new( + signal: u32, + tpl: efi::Tpl, + handler: Option, + context: Option>, + ) -> io::Result { + let boot_services: NonNull = + boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast(); + let mut event: r_efi::efi::Event = crate::ptr::null_mut(); + let context = context.map(NonNull::as_ptr).unwrap_or(crate::ptr::null_mut()); + + let r = unsafe { + let create_event = (*boot_services.as_ptr()).create_event; + (create_event)(signal, tpl, handler, context, &mut event) + }; + + if r.is_error() { + Err(crate::io::Error::from_raw_os_error(r.as_usize())) + } else { + NonNull::new(event) + .ok_or(const_error!(io::ErrorKind::Other, "failed to create event")) + .map(Self) + } + } + + pub(crate) fn into_raw(self) -> *mut crate::ffi::c_void { + let r = self.0.as_ptr(); + crate::mem::forget(self); + r + } + + /// SAFETY: Assumes that ptr is a non-null valid UEFI event + pub(crate) unsafe fn from_raw(ptr: *mut crate::ffi::c_void) -> Self { + Self(unsafe { NonNull::new_unchecked(ptr) }) + } +} + +impl Drop for OwnedEvent { + fn drop(&mut self) { + if let Some(boot_services) = boot_services() { + let bt: NonNull = boot_services.cast(); + unsafe { + let close_event = (*bt.as_ptr()).close_event; + (close_event)(self.0.as_ptr()) + }; + } + } +} diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 6a03e240c6bd..ed39130ab41b 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -49,17 +49,17 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { unsafe { uefi::env::init_globals(image_handle, system_table) }; // Register exit boot services handler - match helpers::create_event( + match helpers::OwnedEvent::new( r_efi::efi::EVT_SIGNAL_EXIT_BOOT_SERVICES, r_efi::efi::TPL_NOTIFY, Some(exit_boot_service_handler), - crate::ptr::null_mut(), + None, ) { Ok(x) => { if EXIT_BOOT_SERVICE_EVENT .compare_exchange( crate::ptr::null_mut(), - x.as_ptr(), + x.into_raw(), Ordering::Release, Ordering::Acquire, ) @@ -79,7 +79,7 @@ pub unsafe fn cleanup() { if let Some(exit_boot_service_event) = NonNull::new(EXIT_BOOT_SERVICE_EVENT.swap(crate::ptr::null_mut(), Ordering::Acquire)) { - let _ = unsafe { helpers::close_event(exit_boot_service_event) }; + let _ = unsafe { helpers::OwnedEvent::from_raw(exit_boot_service_event.as_ptr()) }; } } @@ -145,7 +145,7 @@ pub fn abort_internal() -> ! { if let Some(exit_boot_service_event) = NonNull::new(EXIT_BOOT_SERVICE_EVENT.load(Ordering::Acquire)) { - let _ = unsafe { helpers::close_event(exit_boot_service_event) }; + let _ = unsafe { helpers::OwnedEvent::from_raw(exit_boot_service_event.as_ptr()) }; } if let (Some(boot_services), Some(handle)) = From c26142697c417010fe338dddd2b771af872d02ba Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 16 Mar 2025 21:14:41 +0100 Subject: [PATCH 087/546] add `naked_functions_target_feature` unstable feature --- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_passes/src/check_attr.rs | 16 +++++++++++++- compiler/rustc_span/src/symbol.rs | 1 + .../ui/asm/naked-functions-target-feature.rs | 21 +++++++++++++++++++ tests/ui/asm/naked-functions.rs | 7 ------- ...ure-gate-naked_functions_target_feature.rs | 15 +++++++++++++ ...gate-naked_functions_target_feature.stderr | 13 ++++++++++++ 7 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 tests/ui/asm/naked-functions-target-feature.rs create mode 100644 tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs create mode 100644 tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3c61bfd1c93f..736d18217b47 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -568,6 +568,8 @@ declare_features! ( (incomplete, mut_ref, "1.79.0", Some(123076)), /// Allows using `#[naked]` on functions. (unstable, naked_functions, "1.9.0", Some(90957)), + /// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions. + (unstable, naked_functions_target_feature, "1.86.0", Some(138568)), /// Allows specifying the as-needed link modifier (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490)), /// Allow negative trait implementations. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ece5a53aaa9c..7f624747a468 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -598,7 +598,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::repr, // code generation sym::cold, - sym::target_feature, // documentation sym::doc, ]; @@ -624,6 +623,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => {} } + if other_attr.has_name(sym::target_feature) { + if !self.tcx.features().naked_functions_target_feature() { + feature_err( + &self.tcx.sess, + sym::naked_functions_target_feature, + other_attr.span(), + "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions", + ).emit(); + + return; + } else { + continue; + } + } + if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: other_attr.span(), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a8bec35d819..9770e315b15c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1375,6 +1375,7 @@ symbols! { naked, naked_asm, naked_functions, + naked_functions_target_feature, name, names, native_link_modifiers, diff --git a/tests/ui/asm/naked-functions-target-feature.rs b/tests/ui/asm/naked-functions-target-feature.rs new file mode 100644 index 000000000000..afe1a3891472 --- /dev/null +++ b/tests/ui/asm/naked-functions-target-feature.rs @@ -0,0 +1,21 @@ +//@ build-pass +//@ needs-asm-support + +#![feature(naked_functions, naked_functions_target_feature)] +#![crate_type = "lib"] + +use std::arch::{asm, naked_asm}; + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse2")] +#[naked] +pub unsafe extern "C" fn compatible_target_feature() { + naked_asm!(""); +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "neon")] +#[naked] +pub unsafe extern "C" fn compatible_target_feature() { + naked_asm!(""); +} diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index e7e5d84f2a5d..3d4d414539c1 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -230,13 +230,6 @@ pub unsafe extern "C" fn compatible_codegen_attributes() { naked_asm!("", options(raw)); } -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -#[naked] -pub unsafe extern "C" fn compatible_target_feature() { - naked_asm!(""); -} - #[doc = "foo bar baz"] /// a doc comment // a normal comment diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs new file mode 100644 index 000000000000..0d3af4c5fe0a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs @@ -0,0 +1,15 @@ +//@ needs-asm-support +//@ only-x86_64 + +#![feature(naked_functions)] + +use std::arch::naked_asm; + +#[naked] +#[target_feature(enable = "avx2")] +//~^ ERROR: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions +extern "C" fn naked() { + unsafe { naked_asm!("") } +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr new file mode 100644 index 000000000000..b0592d08046f --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr @@ -0,0 +1,13 @@ +error[E0658]: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions + --> $DIR/feature-gate-naked_functions_target_feature.rs:9:1 + | +LL | #[target_feature(enable = "avx2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138568 for more information + = help: add `#![feature(naked_functions_target_feature)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 6ccaea19895cc8c0861f3a8707f888a15f8be3a1 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Fri, 7 Mar 2025 05:34:12 +0700 Subject: [PATCH 088/546] Target modifiers fix for bool flags without value --- compiler/rustc_metadata/messages.ftl | 17 ++++- compiler/rustc_metadata/src/creader.rs | 69 ++++++++++++++----- compiler/rustc_metadata/src/errors.rs | 36 +++++++++- compiler/rustc_session/src/options.rs | 52 +++++++------- .../auxiliary/enabled_reg_struct_return.rs | 7 ++ .../defaults_check.error.stderr | 4 +- .../no_value_bool.error.stderr | 13 ++++ .../no_value_bool.error_explicit.stderr | 13 ++++ tests/ui/target_modifiers/no_value_bool.rs | 22 ++++++ 9 files changed, 184 insertions(+), 49 deletions(-) create mode 100644 tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs create mode 100644 tests/ui/target_modifiers/no_value_bool.error.stderr create mode 100644 tests/ui/target_modifiers/no_value_bool.error_explicit.stderr create mode 100644 tests/ui/target_modifiers/no_value_bool.rs diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 20f66fae5c01..9adbcabcf450 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -118,12 +118,23 @@ metadata_incompatible_rustc = metadata_incompatible_target_modifiers = mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}` - .note = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}` + .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$extern_value}` in dependency `{$extern_crate}` .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely - metadata_incompatible_target_modifiers_help_allow = if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error -metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$flag_extern_value}` in this crate or `{$flag_name_prefixed}={$flag_local_value}` in `{$extern_crate}` +metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$extern_value}` in this crate or `{$flag_name_prefixed}={$local_value}` in `{$extern_crate}` +metadata_incompatible_target_modifiers_help_fix_l_missed = set `{$flag_name_prefixed}={$extern_value}` in this crate or unset `{$flag_name_prefixed}` in `{$extern_crate}` + +metadata_incompatible_target_modifiers_help_fix_r_missed = unset `{$flag_name_prefixed}` in this crate or set `{$flag_name_prefixed}={$local_value}` in `{$extern_crate}` + +metadata_incompatible_target_modifiers_l_missed = + mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}` + .note = unset `{$flag_name_prefixed}` in this crate is incompatible with `{$flag_name_prefixed}={$extern_value}` in dependency `{$extern_crate}` + .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely +metadata_incompatible_target_modifiers_r_missed = + mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}` + .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with unset `{$flag_name_prefixed}` in dependency `{$extern_crate}` + .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely metadata_incompatible_wasm_link = `wasm_import_module` is incompatible with other arguments in `#[link]` attributes diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 12503ffd1a67..b7f13e0afdcd 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -358,30 +358,58 @@ impl CStore { ) { let span = krate.spans.inner_span.shrink_to_lo(); let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch; - let name = tcx.crate_name(LOCAL_CRATE); + let local_crate = tcx.crate_name(LOCAL_CRATE); let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone()); let report_diff = |prefix: &String, opt_name: &String, - flag_local_value: &String, - flag_extern_value: &String| { + flag_local_value: Option<&String>, + flag_extern_value: Option<&String>| { if allowed_flag_mismatches.contains(&opt_name) { return; } - tcx.dcx().emit_err(errors::IncompatibleTargetModifiers { - span, - extern_crate: data.name(), - local_crate: name, - flag_name: opt_name.clone(), - flag_name_prefixed: format!("-{}{}", prefix, opt_name), - flag_local_value: flag_local_value.to_string(), - flag_extern_value: flag_extern_value.to_string(), - }); + let extern_crate = data.name(); + let flag_name = opt_name.clone(); + let flag_name_prefixed = format!("-{}{}", prefix, opt_name); + + match (flag_local_value, flag_extern_value) { + (Some(local_value), Some(extern_value)) => { + tcx.dcx().emit_err(errors::IncompatibleTargetModifiers { + span, + extern_crate, + local_crate, + flag_name, + flag_name_prefixed, + local_value: local_value.to_string(), + extern_value: extern_value.to_string(), + }) + } + (None, Some(extern_value)) => { + tcx.dcx().emit_err(errors::IncompatibleTargetModifiersLMissed { + span, + extern_crate, + local_crate, + flag_name, + flag_name_prefixed, + extern_value: extern_value.to_string(), + }) + } + (Some(local_value), None) => { + tcx.dcx().emit_err(errors::IncompatibleTargetModifiersRMissed { + span, + extern_crate, + local_crate, + flag_name, + flag_name_prefixed, + local_value: local_value.to_string(), + }) + } + (None, None) => panic!("Incorrect target modifiers report_diff(None, None)"), + }; }; let mut it1 = mods.iter().map(tmod_extender); let mut it2 = dep_mods.iter().map(tmod_extender); let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None; let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None; - let no_val = "*".to_string(); loop { left_name_val = left_name_val.or_else(|| it1.next()); right_name_val = right_name_val.or_else(|| it2.next()); @@ -389,26 +417,31 @@ impl CStore { (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) { cmp::Ordering::Equal => { if l.0.tech_value != r.0.tech_value { - report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &r.1.value_name); + report_diff( + &l.0.prefix, + &l.0.name, + Some(&l.1.value_name), + Some(&r.1.value_name), + ); } left_name_val = None; right_name_val = None; } cmp::Ordering::Greater => { - report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name); + report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name)); right_name_val = None; } cmp::Ordering::Less => { - report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val); + report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None); left_name_val = None; } }, (Some(l), None) => { - report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val); + report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None); left_name_val = None; } (None, Some(r)) => { - report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name); + report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name)); right_name_val = None; } (None, None) => break, diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 2ad6389c0b4a..0c54628598c4 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -759,8 +759,40 @@ pub struct IncompatibleTargetModifiers { pub local_crate: Symbol, pub flag_name: String, pub flag_name_prefixed: String, - pub flag_local_value: String, - pub flag_extern_value: String, + pub local_value: String, + pub extern_value: String, +} + +#[derive(Diagnostic)] +#[diag(metadata_incompatible_target_modifiers_l_missed)] +#[help] +#[note] +#[help(metadata_incompatible_target_modifiers_help_fix_l_missed)] +#[help(metadata_incompatible_target_modifiers_help_allow)] +pub struct IncompatibleTargetModifiersLMissed { + #[primary_span] + pub span: Span, + pub extern_crate: Symbol, + pub local_crate: Symbol, + pub flag_name: String, + pub flag_name_prefixed: String, + pub extern_value: String, +} + +#[derive(Diagnostic)] +#[diag(metadata_incompatible_target_modifiers_r_missed)] +#[help] +#[note] +#[help(metadata_incompatible_target_modifiers_help_fix_r_missed)] +#[help(metadata_incompatible_target_modifiers_help_allow)] +pub struct IncompatibleTargetModifiersRMissed { + #[primary_span] + pub span: Span, + pub extern_crate: Symbol, + pub local_crate: Symbol, + pub flag_name: String, + pub flag_name_prefixed: String, + pub local_value: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8977365ee73d..599b4fa91090 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -94,45 +94,49 @@ fn tmod_push_impl( tmod_vals: &BTreeMap, tmods: &mut Vec, ) { - tmods.push(TargetModifier { opt, value_name: tmod_vals.get(&opt).cloned().unwrap_or_default() }) + if let Some(v) = tmod_vals.get(&opt) { + tmods.push(TargetModifier { opt, value_name: v.clone() }) + } } macro_rules! tmod_push { - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $mods:expr, $tmod_vals:expr) => { - tmod_push_impl( - OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name), - $tmod_vals, - $mods, - ); + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr) => { + if *$opt_expr != $init { + tmod_push_impl( + OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name), + $tmod_vals, + $mods, + ); + } }; } macro_rules! gather_tmods { - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [SUBSTRUCT], [TARGET_MODIFIER]) => { compile_error!("SUBSTRUCT can't be target modifier"); }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [UNTRACKED], [TARGET_MODIFIER]) => { - tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals) }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [TRACKED], [TARGET_MODIFIER]) => { - tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals) }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [TRACKED_NO_CRATE_HASH], [TARGET_MODIFIER]) => { - tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals) }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [SUBSTRUCT], []) => { $opt_expr.gather_target_modifiers($mods, $tmod_vals); }; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [UNTRACKED], []) => {{}}; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [TRACKED], []) => {{}}; - ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr, [TRACKED_NO_CRATE_HASH], []) => {{}}; } @@ -474,7 +478,8 @@ macro_rules! tmod_enum { $($pout)* Self::$opt => { let mut parsed : $t = Default::default(); - parse::$parse(&mut parsed, Some($puser_value)); + let val = if $puser_value.is_empty() { None } else { Some($puser_value) }; + parse::$parse(&mut parsed, val); ExtendedTargetModifierInfo { prefix: $prefix.to_string(), name: stringify!($opt).to_string().replace('_', "-"), @@ -569,7 +574,7 @@ macro_rules! options { _tmod_vals: &BTreeMap, ) { $({ - gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, _mods, _tmod_vals, + gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, $init, _mods, _tmod_vals, [$dep_tracking_marker], [$($tmod),*]); })* } @@ -681,10 +686,9 @@ fn build_options( ), } } - if let Some(tmod) = *tmod - && let Some(value) = value - { - target_modifiers.insert(tmod, value.to_string()); + if let Some(tmod) = *tmod { + let v = value.map_or(String::new(), ToOwned::to_owned); + target_modifiers.insert(tmod, v); } } None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")), diff --git a/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs b/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs new file mode 100644 index 000000000000..4bda4ba24c54 --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +//@ compile-flags: --target i686-unknown-linux-gnu -Zreg-struct-return=true +//@ needs-llvm-components: x86 + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/defaults_check.error.stderr b/tests/ui/target_modifiers/defaults_check.error.stderr index 4833fe906775..936fbbc94d6d 100644 --- a/tests/ui/target_modifiers/defaults_check.error.stderr +++ b/tests/ui/target_modifiers/defaults_check.error.stderr @@ -5,8 +5,8 @@ LL | #![feature(no_core)] | ^ | = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely - = note: `-Zreg-struct-return=true` in this crate is incompatible with `-Zreg-struct-return=` in dependency `default_reg_struct_return` - = help: set `-Zreg-struct-return=` in this crate or `-Zreg-struct-return=true` in `default_reg_struct_return` + = note: `-Zreg-struct-return=true` in this crate is incompatible with unset `-Zreg-struct-return` in dependency `default_reg_struct_return` + = help: unset `-Zreg-struct-return` in this crate or set `-Zreg-struct-return=true` in `default_reg_struct_return` = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error error: aborting due to 1 previous error diff --git a/tests/ui/target_modifiers/no_value_bool.error.stderr b/tests/ui/target_modifiers/no_value_bool.error.stderr new file mode 100644 index 000000000000..0484960dc62d --- /dev/null +++ b/tests/ui/target_modifiers/no_value_bool.error.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool` + --> $DIR/no_value_bool.rs:16:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zreg-struct-return` in this crate is incompatible with `-Zreg-struct-return=true` in dependency `enabled_reg_struct_return` + = help: set `-Zreg-struct-return=true` in this crate or unset `-Zreg-struct-return` in `enabled_reg_struct_return` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr b/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr new file mode 100644 index 000000000000..0484960dc62d --- /dev/null +++ b/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool` + --> $DIR/no_value_bool.rs:16:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zreg-struct-return` in this crate is incompatible with `-Zreg-struct-return=true` in dependency `enabled_reg_struct_return` + = help: set `-Zreg-struct-return=true` in this crate or unset `-Zreg-struct-return` in `enabled_reg_struct_return` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/no_value_bool.rs b/tests/ui/target_modifiers/no_value_bool.rs new file mode 100644 index 000000000000..ceba40afa896 --- /dev/null +++ b/tests/ui/target_modifiers/no_value_bool.rs @@ -0,0 +1,22 @@ +// Tests that bool target modifier value (true) in dependency crate is ok linked +// with the -Zflag specified without value (-Zflag=true is consistent with -Zflag) + +//@ aux-build:enabled_reg_struct_return.rs +//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort +//@ needs-llvm-components: x86 + +//@ revisions: ok ok_explicit error error_explicit +//@[ok] compile-flags: -Zreg-struct-return +//@[ok_explicit] compile-flags: -Zreg-struct-return=true +//@[error] compile-flags: +//@[error_explicit] compile-flags: -Zreg-struct-return=false +//@[ok] check-pass +//@[ok_explicit] check-pass + +#![feature(no_core)] +//[error]~^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool` +//[error_explicit]~^^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool` +#![crate_type = "rlib"] +#![no_core] + +extern crate enabled_reg_struct_return; From a56b1d2a1378d0559a6174b4392fe49b245268df Mon Sep 17 00:00:00 2001 From: Giang Dao Date: Mon, 7 Oct 2024 19:07:57 +0800 Subject: [PATCH 089/546] fix missing rustfmt and clippy for msi --- src/bootstrap/src/core/build_steps/dist.rs | 31 +++++++++++++++- src/etc/installer/msi/rust.wxs | 41 +++++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 2354fe1ebafb..177696b922e0 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1627,6 +1627,8 @@ impl Step for Extended { "rust-analyzer-preview".to_string() } else if name == "clippy" { "clippy-preview".to_string() + } else if name == "rustfmt" { + "rustfmt-preview".to_string() } else if name == "miri" { "miri-preview".to_string() } else if name == "rustc-codegen-cranelift" { @@ -1646,7 +1648,7 @@ impl Step for Extended { prepare("cargo"); prepare("rust-analysis"); prepare("rust-std"); - for tool in &["clippy", "rust-analyzer", "rust-docs", "miri"] { + for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] { if built_tools.contains(tool) { prepare(tool); } @@ -1764,6 +1766,24 @@ impl Step for Extended { .arg(etc.join("msi/remove-duplicates.xsl")) .run(builder); } + if built_tools.contains("rustfmt") { + command(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rustfmt") + .args(heat_flags) + .arg("-cg") + .arg("RustFmtGroup") + .arg("-dr") + .arg("RustFmt") + .arg("-var") + .arg("var.RustFmtDir") + .arg("-out") + .arg(exe.join("RustFmtGroup.wxs")) + .arg("-t") + .arg(etc.join("msi/remove-duplicates.xsl")) + .run(builder); + } if built_tools.contains("miri") { command(&heat) .current_dir(&exe) @@ -1835,6 +1855,9 @@ impl Step for Extended { if built_tools.contains("clippy") { cmd.arg("-dClippyDir=clippy"); } + if built_tools.contains("rustfmt") { + cmd.arg("-dRustFmtDir=rustfmt"); + } if built_tools.contains("rust-docs") { cmd.arg("-dDocsDir=rust-docs"); } @@ -1861,6 +1884,9 @@ impl Step for Extended { if built_tools.contains("clippy") { candle("ClippyGroup.wxs".as_ref()); } + if built_tools.contains("rustfmt") { + candle("RustFmtGroup.wxs".as_ref()); + } if built_tools.contains("miri") { candle("MiriGroup.wxs".as_ref()); } @@ -1899,6 +1925,9 @@ impl Step for Extended { if built_tools.contains("clippy") { cmd.arg("ClippyGroup.wixobj"); } + if built_tools.contains("rustfmt") { + cmd.arg("RustFmtGroup.wixobj"); + } if built_tools.contains("miri") { cmd.arg("MiriGroup.wixobj"); } diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index f29e1e4d27a2..2d155bf0b101 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -172,6 +172,11 @@ + + + + + @@ -279,7 +284,41 @@ - + + + + + + + + + + + + + + + From a0abd613d031407c5d17bb1e7debebddf748d468 Mon Sep 17 00:00:00 2001 From: Giang Dao Date: Mon, 7 Oct 2024 19:10:18 +0800 Subject: [PATCH 090/546] fix missing rustfmt for apple darwin --- src/bootstrap/src/core/build_steps/dist.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 177696b922e0..b6c5a5add01c 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1585,9 +1585,15 @@ impl Step for Extended { prepare("cargo"); prepare("rust-std"); prepare("rust-analysis"); - prepare("clippy"); - prepare("rust-analyzer"); - for tool in &["rust-docs", "miri", "rustc-codegen-cranelift"] { + + for tool in &[ + "clippy", + "rustfmt", + "rust-analyzer", + "rust-docs", + "miri", + "rustc-codegen-cranelift", + ] { if built_tools.contains(tool) { prepare(tool); } From 43152ad47bb15e46c001820df854d4f65964e74a Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 16 Nov 2024 11:31:34 +0300 Subject: [PATCH 091/546] wix: allow to skip more components --- src/bootstrap/src/core/build_steps/dist.rs | 32 ++++++++- src/etc/installer/msi/rust.wxs | 80 +++++++++++++--------- 2 files changed, 78 insertions(+), 34 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index b6c5a5add01c..33155ab37959 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1856,7 +1856,7 @@ impl Step for Extended { .arg("-out") .arg(&output) .arg(input); - add_env(builder, &mut cmd, target); + add_env(builder, &mut cmd, target, &built_tools); if built_tools.contains("clippy") { cmd.arg("-dClippyDir=clippy"); @@ -1960,7 +1960,14 @@ impl Step for Extended { } } -fn add_env(builder: &Builder<'_>, cmd: &mut BootstrapCommand, target: TargetSelection) { +fn add_env( + builder: &Builder<'_>, + cmd: &mut BootstrapCommand, + target: TargetSelection, + built_tools: &HashSet<&'static str>, +) { + // envs for wix should be always defined, even if not used + // FIXME: is they affect ccache? let mut parts = builder.version.split('.'); cmd.env("CFG_RELEASE_INFO", builder.rust_version()) .env("CFG_RELEASE_NUM", &builder.version) @@ -1981,6 +1988,27 @@ fn add_env(builder: &Builder<'_>, cmd: &mut BootstrapCommand, target: TargetSele } else { cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC"); } + + if built_tools.contains("rustfmt") { + cmd.env("CFG_RUSTFMT", "1"); + } else { + cmd.env("CFG_RUSTFMT", "0"); + } + if built_tools.contains("clippy") { + cmd.env("CFG_CLIPPY", "1"); + } else { + cmd.env("CFG_CLIPPY", "0"); + } + if built_tools.contains("miri") { + cmd.env("CFG_MIRI", "1"); + } else { + cmd.env("CFG_MIRI", "0"); + } + if built_tools.contains("rust-analyzer") { + cmd.env("CFG_RA", "1"); + } else { + cmd.env("CFG_RA", "0"); + } } fn install_llvm_file( diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index 2d155bf0b101..64cceccc9758 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -172,11 +172,19 @@ - - - + + + + + + + + + - + + + @@ -284,34 +292,42 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + Date: Mon, 17 Mar 2025 18:34:28 +0800 Subject: [PATCH 092/546] adjust comment --- src/bootstrap/src/core/build_steps/dist.rs | 30 ++++++---------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 33155ab37959..a4a9cb7ef315 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1966,8 +1966,6 @@ fn add_env( target: TargetSelection, built_tools: &HashSet<&'static str>, ) { - // envs for wix should be always defined, even if not used - // FIXME: is they affect ccache? let mut parts = builder.version.split('.'); cmd.env("CFG_RELEASE_INFO", builder.rust_version()) .env("CFG_RELEASE_NUM", &builder.version) @@ -1989,26 +1987,14 @@ fn add_env( cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC"); } - if built_tools.contains("rustfmt") { - cmd.env("CFG_RUSTFMT", "1"); - } else { - cmd.env("CFG_RUSTFMT", "0"); - } - if built_tools.contains("clippy") { - cmd.env("CFG_CLIPPY", "1"); - } else { - cmd.env("CFG_CLIPPY", "0"); - } - if built_tools.contains("miri") { - cmd.env("CFG_MIRI", "1"); - } else { - cmd.env("CFG_MIRI", "0"); - } - if built_tools.contains("rust-analyzer") { - cmd.env("CFG_RA", "1"); - } else { - cmd.env("CFG_RA", "0"); - } + // ensure these variables are defined + let mut define_optional_tool = |tool_name: &str, env_name: &str| { + cmd.env(env_name, if built_tools.contains(tool_name) { "1" } else { "0" }); + }; + define_optional_tool("rustfmt", "CFG_RUSTFMT"); + define_optional_tool("clippy", "CFG_CLIPPY"); + define_optional_tool("miri", "CFG_MIRI"); + define_optional_tool("rust-analyzer", "CFG_RA"); } fn install_llvm_file( From 3270d71cec47bc8bf02352bafef8cc5edec3b7a2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 2 Dec 2023 14:17:33 +0000 Subject: [PATCH 093/546] Remove implicit #[no_mangle] for #[rustc_std_internal_symbol] --- src/allocator.rs | 30 +++++++++++++++++++++++------- src/lib.rs | 1 + 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 5e33b9d606fa..9cff8a84db3d 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -7,6 +7,7 @@ use rustc_ast::expand::allocator::{ }; use rustc_codegen_ssa::base::allocator_kind_for_codegen; use rustc_session::config::OomStrategy; +use rustc_symbol_mangling::mangle_internal_symbol; use crate::prelude::*; @@ -14,6 +15,7 @@ use crate::prelude::*; pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool { let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; codegen_inner( + tcx, module, kind, tcx.alloc_error_handler_kind(()).unwrap(), @@ -23,6 +25,7 @@ pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool { } fn codegen_inner( + tcx: TyCtxt<'_>, module: &mut dyn Module, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, @@ -62,8 +65,8 @@ fn codegen_inner( crate::common::create_wrapper_function( module, sig, - &global_fn_name(method.name), - &default_fn_name(method.name), + &mangle_internal_symbol(tcx, &global_fn_name(method.name)), + &mangle_internal_symbol(tcx, &default_fn_name(method.name)), ); } } @@ -76,19 +79,32 @@ fn codegen_inner( crate::common::create_wrapper_function( module, sig, - "__rust_alloc_error_handler", - &alloc_error_handler_name(alloc_error_handler_kind), + &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), + &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), ); - let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap(); + let data_id = module + .declare_data( + &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + Linkage::Export, + false, + false, + ) + .unwrap(); let mut data = DataDescription::new(); data.set_align(1); let val = oom_strategy.should_panic(); data.define(Box::new([val])); module.define_data(data_id, &data).unwrap(); - let data_id = - module.declare_data(NO_ALLOC_SHIM_IS_UNSTABLE, Linkage::Export, false, false).unwrap(); + let data_id = module + .declare_data( + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + Linkage::Export, + false, + false, + ) + .unwrap(); let mut data = DataDescription::new(); data.set_align(1); data.define(Box::new([0])); diff --git a/src/lib.rs b/src/lib.rs index 06939beb3742..ab3386a9b4cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ extern crate rustc_index; extern crate rustc_metadata; extern crate rustc_session; extern crate rustc_span; +extern crate rustc_symbol_mangling; extern crate rustc_target; #[macro_use] extern crate tracing; From 0ee94562c9e7e2e75a13f06d9820cd191e21a06a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Mar 2025 15:49:28 +0100 Subject: [PATCH 094/546] fix download-llvm logic for subtree sync branches --- src/build_helper/src/git.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 9f778a2fd774..3837a4e41ff1 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -140,6 +140,7 @@ pub fn get_closest_merge_commit( // cd \"/checkout\" && \"git\" \"merge-base\" \"origin/master\" \"HEAD\"\nexpected success, got: exit status: 1\n" // ``` // Investigate and resolve this issue instead of skipping it like this. + // NOTE (2025-03): this is probably caused by CI using a sparse checkout. (channel == "nightly" || !CiEnv::is_rust_lang_managed_ci_job()) { git_upstream_merge_base(config, git_dir).unwrap() @@ -150,11 +151,18 @@ pub fn get_closest_merge_commit( } }; + // Now that rust-lang/rust is the only repo using bors, we can search the entire + // history for a bors commit, not just "first parents". This is crucial to make + // this logic work when the user has currently checked out a subtree sync branch. + // At the same time, we use this logic in CI where only a tiny part of the history + // is even checked out, making this kind of history search very fragile. It turns + // out that by adding `--diff-merges=first-parent`, we get a usable reply + // even for sparse checkouts: it will just return the most recent bors commit. git.args([ "rev-list", &format!("--author={}", config.git_merge_commit_email), "-n1", - "--first-parent", + "--diff-merges=first-parent", &merge_base, ]); From 03ece26b79c8b04a916bcd6ee0ab26c8c20e7b66 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 17 Mar 2025 16:21:45 -0400 Subject: [PATCH 095/546] update tests --- tests/pretty/autodiff_forward.pp | 2 +- tests/pretty/autodiff_forward.rs | 2 +- tests/pretty/autodiff_reverse.pp | 2 +- tests/pretty/autodiff_reverse.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/pretty/autodiff_forward.pp b/tests/pretty/autodiff_forward.pp index 23c3b5b34a82..52d6eaff3c38 100644 --- a/tests/pretty/autodiff_forward.pp +++ b/tests/pretty/autodiff_forward.pp @@ -53,7 +53,7 @@ pub fn df2(x: &[f64], bx: &[f64], y: f64) -> f64 { pub fn f3(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } -#[rustc_autodiff(ForwardFirst, Dual, Const, Const,)] +#[rustc_autodiff(Forward, Dual, Const, Const,)] #[inline(never)] pub fn df3(x: &[f64], bx: &[f64], y: f64) -> f64 { unsafe { asm!("NOP", options(pure, nomem)); }; diff --git a/tests/pretty/autodiff_forward.rs b/tests/pretty/autodiff_forward.rs index 35108d0d6f11..bc5582116322 100644 --- a/tests/pretty/autodiff_forward.rs +++ b/tests/pretty/autodiff_forward.rs @@ -19,7 +19,7 @@ pub fn f2(x: &[f64], y: f64) -> f64 { unimplemented!() } -#[autodiff(df3, ForwardFirst, Dual, Const, Const)] +#[autodiff(df3, Forward, Dual, Const, Const)] pub fn f3(x: &[f64], y: f64) -> f64 { unimplemented!() } diff --git a/tests/pretty/autodiff_reverse.pp b/tests/pretty/autodiff_reverse.pp index a98d3782c703..b2cf0244af4c 100644 --- a/tests/pretty/autodiff_reverse.pp +++ b/tests/pretty/autodiff_reverse.pp @@ -51,7 +51,7 @@ pub fn df2() { pub fn f3(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } -#[rustc_autodiff(ReverseFirst, Duplicated, Const, Active,)] +#[rustc_autodiff(Reverse, Duplicated, Const, Active,)] #[inline(never)] pub fn df3(x: &[f64], dx: &mut [f64], y: f64, dret: f64) -> f64 { unsafe { asm!("NOP", options(pure, nomem)); }; diff --git a/tests/pretty/autodiff_reverse.rs b/tests/pretty/autodiff_reverse.rs index 657201caa940..3c024272f407 100644 --- a/tests/pretty/autodiff_reverse.rs +++ b/tests/pretty/autodiff_reverse.rs @@ -18,7 +18,7 @@ pub fn f1(x: &[f64], y: f64) -> f64 { #[autodiff(df2, Reverse)] pub fn f2() {} -#[autodiff(df3, ReverseFirst, Duplicated, Const, Active)] +#[autodiff(df3, Reverse, Duplicated, Const, Active)] pub fn f3(x: &[f64], y: f64) -> f64 { unimplemented!() } From b77590c1176839b127fe1f20b4557267d26d91a7 Mon Sep 17 00:00:00 2001 From: David Tenty Date: Mon, 17 Mar 2025 16:24:55 -0400 Subject: [PATCH 096/546] Use llvm_runtimes for compiler-rt --- src/bootstrap/src/core/build_steps/llvm.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 1e3148d631cb..0b1799198daf 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -479,7 +479,6 @@ impl Step for Llvm { if helpers::forcing_clang_based_tests() { enabled_llvm_projects.push("clang"); - enabled_llvm_projects.push("compiler-rt"); } if builder.config.llvm_polly { @@ -502,6 +501,10 @@ impl Step for Llvm { let mut enabled_llvm_runtimes = Vec::new(); + if helpers::forcing_clang_based_tests() { + enabled_llvm_runtimes.push("compiler-rt"); + } + if builder.config.llvm_offload { enabled_llvm_runtimes.push("offload"); //FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp. From f5c37c3732360b21dc6d049003838e99b5ec5263 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 17 Mar 2025 16:54:41 -0400 Subject: [PATCH 097/546] [NFC] split up gen_body_helper --- compiler/rustc_builtin_macros/src/autodiff.rs | 89 ++++++++++++++----- 1 file changed, 67 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 7b5c4a159b0c..06cc4d3d8ba4 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -359,30 +359,27 @@ mod llvm_enzyme { ty } - /// We only want this function to type-check, since we will replace the body - /// later on llvm level. Using `loop {}` does not cover all return types anymore, - /// so instead we build something that should pass. We also add a inline_asm - /// line, as one more barrier for rustc to prevent inlining of this function. - /// FIXME(ZuseZ4): We still have cases of incorrect inlining across modules, see - /// , so this isn't sufficient. - /// It also triggers an Enzyme crash if we due to a bug ever try to differentiate - /// this function (which should never happen, since it is only a placeholder). - /// Finally, we also add back_box usages of all input arguments, to prevent rustc - /// from optimizing any arguments away. - fn gen_enzyme_body( + // Will generate a body of the type: + // ``` + // { + // unsafe { + // asm!("NOP"); + // } + // ::core::hint::black_box(primal(args)); + // ::core::hint::black_box((args, ret)); + // + // } + // ``` + fn init_body_helper( ecx: &ExtCtxt<'_>, - x: &AutoDiffAttrs, - n_active: u32, - sig: &ast::FnSig, - d_sig: &ast::FnSig, + span: Span, primal: Ident, new_names: &[String], - span: Span, sig_span: Span, new_decl_span: Span, - idents: Vec, + idents: &[Ident], errored: bool, - ) -> P { + ) -> (P, P, P, P) { let blackbox_path = ecx.std_path(&[sym::hint, sym::black_box]); let noop = ast::InlineAsm { asm_macro: ast::AsmMacro::Asm, @@ -431,6 +428,54 @@ mod llvm_enzyme { } body.stmts.push(ecx.stmt_semi(black_box_remaining_args)); + (body, primal_call, black_box_primal_call, blackbox_call_expr) + } + + /// We only want this function to type-check, since we will replace the body + /// later on llvm level. Using `loop {}` does not cover all return types anymore, + /// so instead we build something that should pass. We also add a inline_asm + /// line, as one more barrier for rustc to prevent inlining of this function. + /// FIXME(ZuseZ4): We still have cases of incorrect inlining across modules, see + /// , so this isn't sufficient. + /// It also triggers an Enzyme crash if we due to a bug ever try to differentiate + /// this function (which should never happen, since it is only a placeholder). + /// Finally, we also add back_box usages of all input arguments, to prevent rustc + /// from optimizing any arguments away. + fn gen_enzyme_body( + ecx: &ExtCtxt<'_>, + x: &AutoDiffAttrs, + n_active: u32, + sig: &ast::FnSig, + d_sig: &ast::FnSig, + primal: Ident, + new_names: &[String], + span: Span, + sig_span: Span, + _new_decl_span: Span, + idents: Vec, + errored: bool, + ) -> P { + let new_decl_span = d_sig.span; + + // Just adding some default inline-asm and black_box usages to prevent early inlining + // and optimizations which alter the function signature. + // + // The bb_primal_call is the black_box call of the primal function. We keep it around, + // since it has the convenient property of returning the type of the primal function, + // Remember, we only care to match types here. + // No matter which return we pick, we always wrap it into a std::hint::black_box call, + // to prevent rustc from propagating it into the caller. + let (mut body, primal_call, bb_primal_call, bb_call_expr) = init_body_helper( + ecx, + span, + primal, + new_names, + sig_span, + new_decl_span, + &idents, + errored, + ); + if !has_ret(&d_sig.decl.output) { // there is no return type that we have to match, () works fine. return body; @@ -442,7 +487,7 @@ mod llvm_enzyme { if primal_ret && n_active == 0 && x.mode.is_rev() { // We only have the primal ret. - body.stmts.push(ecx.stmt_expr(black_box_primal_call)); + body.stmts.push(ecx.stmt_expr(bb_primal_call)); return body; } @@ -534,11 +579,11 @@ mod llvm_enzyme { return body; } [arg] => { - ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![arg.clone()]); + ret = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![arg.clone()]); } args => { let ret_tuple: P = ecx.expr_tuple(span, args.into()); - ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![ret_tuple]); + ret = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![ret_tuple]); } } assert!(has_ret(&d_sig.decl.output)); @@ -551,7 +596,7 @@ mod llvm_enzyme { ecx: &ExtCtxt<'_>, span: Span, primal: Ident, - idents: Vec, + idents: &[Ident], ) -> P { let has_self = idents.len() > 0 && idents[0].name == kw::SelfLower; if has_self { From f9d0a14639df0f92645ff58ed4958509473c03ad Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 17 Mar 2025 17:06:26 -0400 Subject: [PATCH 098/546] resolve repeated attribute fixme --- compiler/rustc_builtin_macros/src/autodiff.rs | 21 +++++++++++++++---- .../rustc_codegen_ssa/src/codegen_attrs.rs | 6 ------ tests/pretty/autodiff_forward.pp | 4 ---- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 06cc4d3d8ba4..d476a90fadf1 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -282,22 +282,35 @@ mod llvm_enzyme { span, }; + // We're avoid duplicating the attributes `#[rustc_autodiff]` and `#[inline(never)]`. + fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool { + match (attr, item) { + (ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => { + let a = &a.item.path; + let b = &b.item.path; + a.segments.len() == b.segments.len() + && a.segments.iter().zip(b.segments.iter()).all(|(a, b)| a.ident == b.ident) + } + _ => false, + } + } + // Don't add it multiple times: let orig_annotatable: Annotatable = match item { Annotatable::Item(ref mut iitem) => { - if !iitem.attrs.iter().any(|a| a.id == attr.id) { + if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { iitem.attrs.push(attr); } - if !iitem.attrs.iter().any(|a| a.id == inline_never.id) { + if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) { iitem.attrs.push(inline_never.clone()); } Annotatable::Item(iitem.clone()) } Annotatable::AssocItem(ref mut assoc_item, i @ Impl) => { - if !assoc_item.attrs.iter().any(|a| a.id == attr.id) { + if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { assoc_item.attrs.push(attr); } - if !assoc_item.attrs.iter().any(|a| a.id == inline_never.id) { + if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) { assoc_item.attrs.push(inline_never.clone()); } Annotatable::AssocItem(assoc_item.clone(), i) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 90c53c347689..5a3f0aa83105 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -798,16 +798,10 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { // check for exactly one autodiff attribute on placeholder functions. // There should only be one, since we generate a new placeholder per ad macro. - // FIXME(ZuseZ4): re-enable this check. Currently we add multiple, which doesn't cause harm but - // looks strange e.g. under cargo-expand. let attr = match &attrs[..] { [] => return None, [attr] => attr, - // These two attributes are the same and unfortunately duplicated due to a previous bug. - [attr, _attr2] => attr, _ => { - //FIXME(ZuseZ4): Once we fixed our parser, we should also prohibit the two-attribute - //branch above. span_bug!(attrs[1].span(), "cg_ssa: rustc_autodiff should only exist once per source"); } }; diff --git a/tests/pretty/autodiff_forward.pp b/tests/pretty/autodiff_forward.pp index 52d6eaff3c38..dc7a2712f423 100644 --- a/tests/pretty/autodiff_forward.pp +++ b/tests/pretty/autodiff_forward.pp @@ -73,10 +73,6 @@ pub fn df4() { } #[rustc_autodiff] #[inline(never)] -#[rustc_autodiff] -#[inline(never)] -#[rustc_autodiff] -#[inline(never)] pub fn f5(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } From 5f7ff8885346735289bb97d3676110a09844abab Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 17 Mar 2025 17:23:35 -0400 Subject: [PATCH 099/546] [NFC] use outer_normal_attr helper --- compiler/rustc_builtin_macros/src/autodiff.rs | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index d476a90fadf1..bfddb450cd76 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -25,6 +25,16 @@ mod llvm_enzyme { use crate::errors; + pub(crate) fn outer_normal_attr( + kind: &P, + id: rustc_ast::AttrId, + span: Span, + ) -> rustc_ast::Attribute { + let style = rustc_ast::AttrStyle::Outer; + let kind = rustc_ast::AttrKind::Normal(kind.clone()); + rustc_ast::Attribute { kind, id, style, span } + } + // If we have a default `()` return type or explicitley `()` return type, // then we often can skip doing some work. fn has_ret(ty: &FnRetTy) -> bool { @@ -268,19 +278,9 @@ mod llvm_enzyme { }; let inline_never_attr = P(ast::NormalAttr { item: inline_item, tokens: None }); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); - let attr: ast::Attribute = ast::Attribute { - kind: ast::AttrKind::Normal(rustc_ad_attr.clone()), - id: new_id, - style: ast::AttrStyle::Outer, - span, - }; + let attr = outer_normal_attr(&rustc_ad_attr, new_id, span); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); - let inline_never: ast::Attribute = ast::Attribute { - kind: ast::AttrKind::Normal(inline_never_attr), - id: new_id, - style: ast::AttrStyle::Outer, - span, - }; + let inline_never = outer_normal_attr(&inline_never_attr, new_id, span); // We're avoid duplicating the attributes `#[rustc_autodiff]` and `#[inline(never)]`. fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool { @@ -325,13 +325,7 @@ mod llvm_enzyme { delim: rustc_ast::token::Delimiter::Parenthesis, tokens: ts, }); - let d_attr: ast::Attribute = ast::Attribute { - kind: ast::AttrKind::Normal(rustc_ad_attr.clone()), - id: new_id, - style: ast::AttrStyle::Outer, - span, - }; - + let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span); let d_annotatable = if is_impl { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); let d_fn = P(ast::AssocItem { From f4c297802ff34cd6a36d077c1271041fc0501cb7 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 17 Mar 2025 18:58:51 -0400 Subject: [PATCH 100/546] [NFC] extract autodiff call lowering in cg_llvm into own function --- .../src/builder/autodiff.rs | 201 ++++++++++-------- 1 file changed, 108 insertions(+), 93 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 71705ecb4d0f..482af98aa1ab 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -28,6 +28,113 @@ fn get_params(fnc: &Value) -> Vec<&Value> { } } +fn match_args_from_caller_to_enzyme<'ll>( + cx: &SimpleCx<'ll>, + args: &mut Vec<&'ll llvm::Value>, + inputs: &[DiffActivity], + outer_args: &[&'ll llvm::Value], +) { + debug!("matching autodiff arguments"); + // We now handle the issue that Rust level arguments not always match the llvm-ir level + // arguments. A slice, `&[f32]`, for example, is represented as a pointer and a length on + // llvm-ir level. The number of activities matches the number of Rust level arguments, so we + // need to match those. + // FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it + // using iterators and peek()? + let mut outer_pos: usize = 0; + let mut activity_pos = 0; + + let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); + let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); + let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); + let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); + + while activity_pos < inputs.len() { + let diff_activity = inputs[activity_pos as usize]; + // Duplicated arguments received a shadow argument, into which enzyme will write the + // gradient. + let (activity, duplicated): (&Metadata, bool) = match diff_activity { + DiffActivity::None => panic!("not a valid input activity"), + DiffActivity::Const => (enzyme_const, false), + DiffActivity::Active => (enzyme_out, false), + DiffActivity::ActiveOnly => (enzyme_out, false), + DiffActivity::Dual => (enzyme_dup, true), + DiffActivity::DualOnly => (enzyme_dupnoneed, true), + DiffActivity::Duplicated => (enzyme_dup, true), + DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true), + DiffActivity::FakeActivitySize => (enzyme_const, false), + }; + let outer_arg = outer_args[outer_pos]; + args.push(cx.get_metadata_value(activity)); + args.push(outer_arg); + if duplicated { + // We know that duplicated args by construction have a following argument, + // so this can not be out of bounds. + let next_outer_arg = outer_args[outer_pos + 1]; + let next_outer_ty = cx.val_ty(next_outer_arg); + // FIXME(ZuseZ4): We should add support for Vec here too, but it's less urgent since + // vectors behind references (&Vec) are already supported. Users can not pass a + // Vec by value for reverse mode, so this would only help forward mode autodiff. + let slice = { + if activity_pos + 1 >= inputs.len() { + // If there is no arg following our ptr, it also can't be a slice, + // since that would lead to a ptr, int pair. + false + } else { + let next_activity = inputs[activity_pos + 1]; + // We analyze the MIR types and add this dummy activity if we visit a slice. + next_activity == DiffActivity::FakeActivitySize + } + }; + if slice { + // A duplicated slice will have the following two outer_fn arguments: + // (..., ptr1, int1, ptr2, int2, ...). We add the following llvm-ir to our __enzyme call: + // (..., metadata! enzyme_dup, ptr, ptr, int1, ...). + // FIXME(ZuseZ4): We will upstream a safety check later which asserts that + // int2 >= int1, which means the shadow vector is large enough to store the gradient. + assert!(unsafe { + llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Integer + }); + let next_outer_arg2 = outer_args[outer_pos + 2]; + let next_outer_ty2 = cx.val_ty(next_outer_arg2); + assert!(unsafe { + llvm::LLVMRustGetTypeKind(next_outer_ty2) == llvm::TypeKind::Pointer + }); + let next_outer_arg3 = outer_args[outer_pos + 3]; + let next_outer_ty3 = cx.val_ty(next_outer_arg3); + assert!(unsafe { + llvm::LLVMRustGetTypeKind(next_outer_ty3) == llvm::TypeKind::Integer + }); + args.push(next_outer_arg2); + args.push(cx.get_metadata_value(enzyme_const)); + args.push(next_outer_arg); + outer_pos += 4; + activity_pos += 2; + } else { + // A duplicated pointer will have the following two outer_fn arguments: + // (..., ptr, ptr, ...). We add the following llvm-ir to our __enzyme call: + // (..., metadata! enzyme_dup, ptr, ptr, ...). + if matches!(diff_activity, DiffActivity::Duplicated | DiffActivity::DuplicatedOnly) + { + assert!( + unsafe { llvm::LLVMRustGetTypeKind(next_outer_ty) } + == llvm::TypeKind::Pointer + ); + } + // In the case of Dual we don't have assumptions, e.g. f32 would be valid. + args.push(next_outer_arg); + outer_pos += 2; + activity_pos += 1; + } + } else { + // We do not differentiate with resprect to this argument. + // We already added the metadata and argument above, so just increase the counters. + outer_pos += 1; + activity_pos += 1; + } + } +} + /// When differentiating `fn_to_diff`, take a `outer_fn` and generate another /// function with expected naming and calling conventions[^1] which will be /// discovered by the enzyme LLVM pass and its body populated with the differentiated @@ -132,12 +239,7 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); - match output { DiffActivity::Dual => { args.push(cx.get_metadata_value(enzyme_primal_ret)); @@ -148,95 +250,8 @@ fn generate_enzyme_call<'ll>( _ => {} } - debug!("matching autodiff arguments"); - // We now handle the issue that Rust level arguments not always match the llvm-ir level - // arguments. A slice, `&[f32]`, for example, is represented as a pointer and a length on - // llvm-ir level. The number of activities matches the number of Rust level arguments, so we - // need to match those. - // FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it - // using iterators and peek()? - let mut outer_pos: usize = 0; - let mut activity_pos = 0; let outer_args: Vec<&llvm::Value> = get_params(outer_fn); - while activity_pos < inputs.len() { - let diff_activity = inputs[activity_pos as usize]; - // Duplicated arguments received a shadow argument, into which enzyme will write the - // gradient. - let (activity, duplicated): (&Metadata, bool) = match diff_activity { - DiffActivity::None => panic!("not a valid input activity"), - DiffActivity::Const => (enzyme_const, false), - DiffActivity::Active => (enzyme_out, false), - DiffActivity::ActiveOnly => (enzyme_out, false), - DiffActivity::Dual => (enzyme_dup, true), - DiffActivity::DualOnly => (enzyme_dupnoneed, true), - DiffActivity::Duplicated => (enzyme_dup, true), - DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true), - DiffActivity::FakeActivitySize => (enzyme_const, false), - }; - let outer_arg = outer_args[outer_pos]; - args.push(cx.get_metadata_value(activity)); - args.push(outer_arg); - if duplicated { - // We know that duplicated args by construction have a following argument, - // so this can not be out of bounds. - let next_outer_arg = outer_args[outer_pos + 1]; - let next_outer_ty = cx.val_ty(next_outer_arg); - // FIXME(ZuseZ4): We should add support for Vec here too, but it's less urgent since - // vectors behind references (&Vec) are already supported. Users can not pass a - // Vec by value for reverse mode, so this would only help forward mode autodiff. - let slice = { - if activity_pos + 1 >= inputs.len() { - // If there is no arg following our ptr, it also can't be a slice, - // since that would lead to a ptr, int pair. - false - } else { - let next_activity = inputs[activity_pos + 1]; - // We analyze the MIR types and add this dummy activity if we visit a slice. - next_activity == DiffActivity::FakeActivitySize - } - }; - if slice { - // A duplicated slice will have the following two outer_fn arguments: - // (..., ptr1, int1, ptr2, int2, ...). We add the following llvm-ir to our __enzyme call: - // (..., metadata! enzyme_dup, ptr, ptr, int1, ...). - // FIXME(ZuseZ4): We will upstream a safety check later which asserts that - // int2 >= int1, which means the shadow vector is large enough to store the gradient. - assert!(llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Integer); - let next_outer_arg2 = outer_args[outer_pos + 2]; - let next_outer_ty2 = cx.val_ty(next_outer_arg2); - assert!(llvm::LLVMRustGetTypeKind(next_outer_ty2) == llvm::TypeKind::Pointer); - let next_outer_arg3 = outer_args[outer_pos + 3]; - let next_outer_ty3 = cx.val_ty(next_outer_arg3); - assert!(llvm::LLVMRustGetTypeKind(next_outer_ty3) == llvm::TypeKind::Integer); - args.push(next_outer_arg2); - args.push(cx.get_metadata_value(enzyme_const)); - args.push(next_outer_arg); - outer_pos += 4; - activity_pos += 2; - } else { - // A duplicated pointer will have the following two outer_fn arguments: - // (..., ptr, ptr, ...). We add the following llvm-ir to our __enzyme call: - // (..., metadata! enzyme_dup, ptr, ptr, ...). - if matches!( - diff_activity, - DiffActivity::Duplicated | DiffActivity::DuplicatedOnly - ) { - assert!( - llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Pointer - ); - } - // In the case of Dual we don't have assumptions, e.g. f32 would be valid. - args.push(next_outer_arg); - outer_pos += 2; - activity_pos += 1; - } - } else { - // We do not differentiate with resprect to this argument. - // We already added the metadata and argument above, so just increase the counters. - outer_pos += 1; - activity_pos += 1; - } - } + match_args_from_caller_to_enzyme(&cx, &mut args, &inputs, &outer_args); let call = builder.call(enzyme_ty, ad_fn, &args, None); From 47c07ed9637bb59bb37d7b541ff3ed11d158a9ee Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 17 Mar 2025 19:13:09 -0400 Subject: [PATCH 101/546] [NFC] simplify matching --- .../rustc_codegen_llvm/src/builder/autodiff.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 482af98aa1ab..7cd4ee539d87 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -150,9 +150,6 @@ fn generate_enzyme_call<'ll>( outer_fn: &'ll Value, attrs: AutoDiffAttrs, ) { - let inputs = attrs.input_activity; - let output = attrs.ret_activity; - // We have to pick the name depending on whether we want forward or reverse mode autodiff. let mut ad_name: String = match attrs.mode { DiffMode::Forward => "__enzyme_fwddiff", @@ -240,18 +237,12 @@ fn generate_enzyme_call<'ll>( args.push(fn_to_diff); let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); - match output { - DiffActivity::Dual => { - args.push(cx.get_metadata_value(enzyme_primal_ret)); - } - DiffActivity::Active => { - args.push(cx.get_metadata_value(enzyme_primal_ret)); - } - _ => {} + if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { + args.push(cx.get_metadata_value(enzyme_primal_ret)); } let outer_args: Vec<&llvm::Value> = get_params(outer_fn); - match_args_from_caller_to_enzyme(&cx, &mut args, &inputs, &outer_args); + match_args_from_caller_to_enzyme(&cx, &mut args, &attrs.input_activity, &outer_args); let call = builder.call(enzyme_ty, ad_fn, &args, None); From 636285180daa00b62a604acee9c843128d70262f Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 1 May 2024 18:32:45 -0500 Subject: [PATCH 102/546] [bootstrap] Distribute split debuginfo if present If debuginfo has been requested in `config.toml`, it should be packaged alongside the appropriate binary when running `x.py dist`. Currently, this is only implemented for msvc environments where split debuginfo is (basically) the only option. I've tested that this correctly packages the `.pdb` for each binary in the various dist packages. --- src/bootstrap/src/core/build_steps/compile.rs | 56 ++++--- src/bootstrap/src/core/build_steps/dist.rs | 155 ++++++++++++------ src/bootstrap/src/core/build_steps/doc.rs | 3 +- src/bootstrap/src/core/build_steps/tool.rs | 32 ++-- src/bootstrap/src/lib.rs | 63 ++++++- src/bootstrap/src/utils/helpers.rs | 17 ++ src/bootstrap/src/utils/tarball.rs | 28 +++- 7 files changed, 255 insertions(+), 99 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 846b4de81426..18b5d4426b1e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -33,7 +33,7 @@ use crate::utils::exec::command; use crate::utils::helpers::{ exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; -use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode, debug, trace}; +use crate::{CLang, Compiler, DependencyType, FileType, GitRepo, LLVM_TOOLS, Mode, debug, trace}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Std { @@ -321,7 +321,7 @@ fn copy_and_stamp( dependency_type: DependencyType, ) { let target = libdir.join(name); - builder.copy_link(&sourcedir.join(name), &target); + builder.copy_link(&sourcedir.join(name), &target, FileType::Regular); target_deps.push((target, dependency_type)); } @@ -330,7 +330,7 @@ fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: & let libunwind_path = builder.ensure(llvm::Libunwind { target }); let libunwind_source = libunwind_path.join("libunwind.a"); let libunwind_target = libdir.join("libunwind.a"); - builder.copy_link(&libunwind_source, &libunwind_target); + builder.copy_link(&libunwind_source, &libunwind_target, FileType::NativeLibrary); libunwind_target } @@ -401,7 +401,7 @@ fn copy_self_contained_objects( for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] { let src = crt_path.join(obj); let target = libdir_self_contained.join(obj); - builder.copy_link(&src, &target); + builder.copy_link(&src, &target, FileType::NativeLibrary); target_deps.push((target, DependencyType::TargetSelfContained)); } } else { @@ -443,9 +443,9 @@ fn copy_self_contained_objects( } else if target.is_windows_gnu() { for obj in ["crt2.o", "dllcrt2.o"].iter() { let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj); - let target = libdir_self_contained.join(obj); - builder.copy_link(&src, &target); - target_deps.push((target, DependencyType::TargetSelfContained)); + let dst = libdir_self_contained.join(obj); + builder.copy_link(&src, &dst, FileType::NativeLibrary); + target_deps.push((dst, DependencyType::TargetSelfContained)); } } @@ -790,8 +790,11 @@ impl Step for StdLink { let file = t!(file); let path = file.path(); if path.is_file() { - builder - .copy_link(&path, &sysroot.join("lib").join(path.file_name().unwrap())); + builder.copy_link( + &path, + &sysroot.join("lib").join(path.file_name().unwrap()), + FileType::Regular, + ); } } } @@ -829,7 +832,7 @@ fn copy_sanitizers( for runtime in &runtimes { let dst = libdir.join(&runtime.name); - builder.copy_link(&runtime.path, &dst); + builder.copy_link(&runtime.path, &dst, FileType::NativeLibrary); // The `aarch64-apple-ios-macabi` and `x86_64-apple-ios-macabi` are also supported for // sanitizers, but they share a sanitizer runtime with `${arch}-apple-darwin`, so we do @@ -934,9 +937,9 @@ impl Step for StartupObjects { .run(builder); } - let target = sysroot_dir.join((*file).to_string() + ".o"); - builder.copy_link(dst_file, &target); - target_deps.push((target, DependencyType::Target)); + let obj = sysroot_dir.join((*file).to_string() + ".o"); + builder.copy_link(dst_file, &obj, FileType::NativeLibrary); + target_deps.push((obj, DependencyType::Target)); } target_deps @@ -952,7 +955,7 @@ fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, conte if src.is_dir() { t!(fs::create_dir_all(dst)); } else { - builder.copy_link(&src, &dst); + builder.copy_link(&src, &dst, FileType::Regular); } } } @@ -1707,7 +1710,7 @@ fn copy_codegen_backends_to_sysroot( let dot = filename.find('.').unwrap(); format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..]) }; - builder.copy_link(file, &dst.join(target_filename)); + builder.copy_link(file, &dst.join(target_filename), FileType::NativeLibrary); } } @@ -2011,7 +2014,11 @@ impl Step for Assemble { extra_features: vec![], }); let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); - builder.copy_link(&llvm_bitcode_linker.tool_path, &libdir_bin.join(tool_exe)); + builder.copy_link( + &llvm_bitcode_linker.tool_path, + &libdir_bin.join(tool_exe), + FileType::Executable, + ); } }; @@ -2072,8 +2079,8 @@ impl Step for Assemble { builder.sysroot_target_libdir(target_compiler, target_compiler.host); let dst_lib = libdir.join(&libenzyme).with_extension(lib_ext); let target_dst_lib = target_libdir.join(&libenzyme).with_extension(lib_ext); - builder.copy_link(&src_lib, &dst_lib); - builder.copy_link(&src_lib, &target_dst_lib); + builder.copy_link(&src_lib, &dst_lib, FileType::NativeLibrary); + builder.copy_link(&src_lib, &target_dst_lib, FileType::NativeLibrary); } // Build the libraries for this compiler to link to (i.e., the libraries @@ -2168,7 +2175,7 @@ impl Step for Assemble { }; if is_dylib_or_debug && can_be_rustc_dynamic_dep && !is_proc_macro { - builder.copy_link(&f.path(), &rustc_libdir.join(&filename)); + builder.copy_link(&f.path(), &rustc_libdir.join(&filename), FileType::Regular); } } @@ -2196,7 +2203,11 @@ impl Step for Assemble { // See . let src_exe = exe("llvm-objcopy", target_compiler.host); let dst_exe = exe("rust-objcopy", target_compiler.host); - builder.copy_link(&libdir_bin.join(src_exe), &libdir_bin.join(dst_exe)); + builder.copy_link( + &libdir_bin.join(src_exe), + &libdir_bin.join(dst_exe), + FileType::Executable, + ); } // In addition to `rust-lld` also install `wasm-component-ld` when @@ -2212,6 +2223,7 @@ impl Step for Assemble { builder.copy_link( &wasm_component.tool_path, &libdir_bin.join(wasm_component.tool_path.file_name().unwrap()), + FileType::Executable, ); } @@ -2234,7 +2246,7 @@ impl Step for Assemble { t!(fs::create_dir_all(bindir)); let compiler = builder.rustc(target_compiler); debug!(src = ?rustc, dst = ?compiler, "linking compiler binary itself"); - builder.copy_link(&rustc, &compiler); + builder.copy_link(&rustc, &compiler, FileType::Executable); target_compiler } @@ -2260,7 +2272,7 @@ pub fn add_to_sysroot( DependencyType::Target => sysroot_dst, DependencyType::TargetSelfContained => self_contained_dst, }; - builder.copy_link(&path, &dst.join(path.file_name().unwrap())); + builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::Regular); } } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 39f9680cb2f6..3305b7c2d362 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -32,7 +32,7 @@ use crate::utils::helpers::{ exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit, }; use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; -use crate::{Compiler, DependencyType, LLVM_TOOLS, Mode, trace}; +use crate::{Compiler, DependencyType, FileType, LLVM_TOOLS, Mode, trace}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { format!("{}-{}", component, builder.rust_package_vers()) @@ -81,7 +81,7 @@ impl Step for Docs { let mut tarball = Tarball::new(builder, "rust-docs", &host.triple); tarball.set_product_name("Rust Documentation"); tarball.add_bulk_dir(builder.doc_out(host), dest); - tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, 0o644); + tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, FileType::Regular); Some(tarball.generate()) } } @@ -418,7 +418,7 @@ impl Step for Rustc { .is_none_or(|tools| tools.iter().any(|tool| tool == "rustdoc")) { let rustdoc = builder.rustdoc(compiler); - builder.install(&rustdoc, &image.join("bin"), 0o755); + builder.install(&rustdoc, &image.join("bin"), FileType::Executable); } if let Some(ra_proc_macro_srv) = builder.ensure_if_default( @@ -432,7 +432,8 @@ impl Step for Rustc { }, builder.kind, ) { - builder.install(&ra_proc_macro_srv.tool_path, &image.join("libexec"), 0o755); + let dst = image.join("libexec"); + builder.install(&ra_proc_macro_srv.tool_path, &dst, FileType::Executable); } let libdir_relative = builder.libdir_relative(compiler); @@ -444,7 +445,7 @@ impl Step for Rustc { if is_dylib(&entry.path()) { // Don't use custom libdir here because ^lib/ will be resolved again // with installer - builder.install(&entry.path(), &image.join("lib"), 0o644); + builder.install(&entry.path(), &image.join("lib"), FileType::NativeLibrary); } } } @@ -463,7 +464,11 @@ impl Step for Rustc { if builder.config.lld_enabled { let src_dir = builder.sysroot_target_bindir(compiler, host); let rust_lld = exe("rust-lld", compiler.host); - builder.copy_link(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld)); + builder.copy_link( + &src_dir.join(&rust_lld), + &dst_dir.join(&rust_lld), + FileType::Executable, + ); let self_contained_lld_src_dir = src_dir.join("gcc-ld"); let self_contained_lld_dst_dir = dst_dir.join("gcc-ld"); t!(fs::create_dir(&self_contained_lld_dst_dir)); @@ -472,6 +477,7 @@ impl Step for Rustc { builder.copy_link( &self_contained_lld_src_dir.join(&exe_name), &self_contained_lld_dst_dir.join(&exe_name), + FileType::Executable, ); } } @@ -480,13 +486,17 @@ impl Step for Rustc { let src_dir = builder.sysroot_target_bindir(compiler, host); let llvm_objcopy = exe("llvm-objcopy", compiler.host); let rust_objcopy = exe("rust-objcopy", compiler.host); - builder.copy_link(&src_dir.join(&llvm_objcopy), &dst_dir.join(&rust_objcopy)); + builder.copy_link( + &src_dir.join(&llvm_objcopy), + &dst_dir.join(&rust_objcopy), + FileType::Executable, + ); } if builder.tool_enabled("wasm-component-ld") { let src_dir = builder.sysroot_target_bindir(compiler, host); let ld = exe("wasm-component-ld", compiler.host); - builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld)); + builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld), FileType::Executable); } // Man pages @@ -511,15 +521,19 @@ impl Step for Rustc { // HTML copyright files let file_list = builder.ensure(super::run::GenerateCopyright); for file in file_list { - builder.install(&file, &image.join("share/doc/rust"), 0o644); + builder.install(&file, &image.join("share/doc/rust"), FileType::Regular); } // README - builder.install(&builder.src.join("README.md"), &image.join("share/doc/rust"), 0o644); + builder.install( + &builder.src.join("README.md"), + &image.join("share/doc/rust"), + FileType::Regular, + ); // The REUSE-managed license files let license = |path: &Path| { - builder.install(path, &image.join("share/doc/rust/licenses"), 0o644); + builder.install(path, &image.join("share/doc/rust/licenses"), FileType::Regular); }; for entry in t!(std::fs::read_dir(builder.src.join("LICENSES"))).flatten() { license(&entry.path()); @@ -548,14 +562,14 @@ impl Step for DebuggerScripts { let dst = sysroot.join("lib/rustlib/etc"); t!(fs::create_dir_all(&dst)); let cp_debugger_script = |file: &str| { - builder.install(&builder.src.join("src/etc/").join(file), &dst, 0o644); + builder.install(&builder.src.join("src/etc/").join(file), &dst, FileType::Regular); }; if host.contains("windows-msvc") { // windbg debugger scripts builder.install( &builder.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"), - 0o755, + FileType::Script, ); cp_debugger_script("natvis/intrinsic.natvis"); @@ -567,15 +581,27 @@ impl Step for DebuggerScripts { cp_debugger_script("rust_types.py"); // gdb debugger scripts - builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"), 0o755); - builder.install(&builder.src.join("src/etc/rust-gdbgui"), &sysroot.join("bin"), 0o755); + builder.install( + &builder.src.join("src/etc/rust-gdb"), + &sysroot.join("bin"), + FileType::Script, + ); + builder.install( + &builder.src.join("src/etc/rust-gdbgui"), + &sysroot.join("bin"), + FileType::Script, + ); cp_debugger_script("gdb_load_rust_pretty_printers.py"); cp_debugger_script("gdb_lookup.py"); cp_debugger_script("gdb_providers.py"); // lldb debugger scripts - builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"), 0o755); + builder.install( + &builder.src.join("src/etc/rust-lldb"), + &sysroot.join("bin"), + FileType::Script, + ); cp_debugger_script("lldb_lookup.py"); cp_debugger_script("lldb_providers.py"); @@ -640,9 +666,13 @@ fn copy_target_libs( t!(fs::create_dir_all(&self_contained_dst)); for (path, dependency_type) in builder.read_stamp_file(stamp) { if dependency_type == DependencyType::TargetSelfContained { - builder.copy_link(&path, &self_contained_dst.join(path.file_name().unwrap())); + builder.copy_link( + &path, + &self_contained_dst.join(path.file_name().unwrap()), + FileType::NativeLibrary, + ); } else if dependency_type == DependencyType::Target || builder.is_builder_target(target) { - builder.copy_link(&path, &dst.join(path.file_name().unwrap())); + builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::NativeLibrary); } } } @@ -750,7 +780,11 @@ impl Step for RustcDev { &tarball.image_dir().join("lib/rustlib/rustc-src/rust"), ); for file in src_files { - tarball.add_file(builder.src.join(file), "lib/rustlib/rustc-src/rust", 0o644); + tarball.add_file( + builder.src.join(file), + "lib/rustlib/rustc-src/rust", + FileType::Regular, + ); } Some(tarball.generate()) @@ -1045,7 +1079,11 @@ impl Step for PlainSourceTarball { // Copy the files normally for item in &src_files { - builder.copy_link(&builder.src.join(item), &plain_dst_src.join(item)); + builder.copy_link( + &builder.src.join(item), + &plain_dst_src.join(item), + FileType::Regular, + ); } // Create the version file @@ -1147,9 +1185,14 @@ impl Step for Cargo { let mut tarball = Tarball::new(builder, "cargo", &target.triple); tarball.set_overlay(OverlayKind::Cargo); - tarball.add_file(cargo.tool_path, "bin", 0o755); - tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644); - tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo"); + tarball.add_file(&cargo.tool_path, "bin", FileType::Executable); + tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", FileType::Regular); + tarball.add_renamed_file( + etc.join("cargo.bashcomp.sh"), + "etc/bash_completion.d", + "cargo", + FileType::Regular, + ); tarball.add_dir(etc.join("man"), "share/man/man1"); tarball.add_legal_and_readme_to("share/doc/cargo"); @@ -1193,7 +1236,7 @@ impl Step for RustAnalyzer { let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); tarball.set_overlay(OverlayKind::RustAnalyzer); tarball.is_preview(true); - tarball.add_file(rust_analyzer.tool_path, "bin", 0o755); + tarball.add_file(&rust_analyzer.tool_path, "bin", FileType::Executable); tarball.add_legal_and_readme_to("share/doc/rust-analyzer"); Some(tarball.generate()) } @@ -1239,8 +1282,8 @@ impl Step for Clippy { let mut tarball = Tarball::new(builder, "clippy", &target.triple); tarball.set_overlay(OverlayKind::Clippy); tarball.is_preview(true); - tarball.add_file(clippy.tool_path, "bin", 0o755); - tarball.add_file(cargoclippy.tool_path, "bin", 0o755); + tarball.add_file(&clippy.tool_path, "bin", FileType::Executable); + tarball.add_file(&cargoclippy.tool_path, "bin", FileType::Executable); tarball.add_legal_and_readme_to("share/doc/clippy"); Some(tarball.generate()) } @@ -1289,8 +1332,8 @@ impl Step for Miri { let mut tarball = Tarball::new(builder, "miri", &target.triple); tarball.set_overlay(OverlayKind::Miri); tarball.is_preview(true); - tarball.add_file(miri.tool_path, "bin", 0o755); - tarball.add_file(cargomiri.tool_path, "bin", 0o755); + tarball.add_file(&miri.tool_path, "bin", FileType::Executable); + tarball.add_file(&cargomiri.tool_path, "bin", FileType::Executable); tarball.add_legal_and_readme_to("share/doc/miri"); Some(tarball.generate()) } @@ -1374,7 +1417,11 @@ impl Step for CodegenBackend { for backend in fs::read_dir(&backends_src).unwrap() { let file_name = backend.unwrap().file_name(); if file_name.to_str().unwrap().contains(&backend_name) { - tarball.add_file(backends_src.join(file_name), &backends_dst, 0o644); + tarball.add_file( + backends_src.join(file_name), + &backends_dst, + FileType::NativeLibrary, + ); found_backend = true; } } @@ -1420,8 +1467,8 @@ impl Step for Rustfmt { let mut tarball = Tarball::new(builder, "rustfmt", &target.triple); tarball.set_overlay(OverlayKind::Rustfmt); tarball.is_preview(true); - tarball.add_file(rustfmt.tool_path, "bin", 0o755); - tarball.add_file(cargofmt.tool_path, "bin", 0o755); + tarball.add_file(&rustfmt.tool_path, "bin", FileType::Executable); + tarball.add_file(&cargofmt.tool_path, "bin", FileType::Executable); tarball.add_legal_and_readme_to("share/doc/rustfmt"); Some(tarball.generate()) } @@ -1578,7 +1625,7 @@ impl Step for Extended { &work.join(format!("{}-{}", pkgname(builder, name), target.triple)), &pkg.join(name), ); - builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755); + builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), FileType::Script); pkgbuild(name); }; prepare("rustc"); @@ -1593,12 +1640,12 @@ impl Step for Extended { } } // create an 'uninstall' package - builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755); + builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), FileType::Script); pkgbuild("uninstall"); builder.create_dir(&pkg.join("res")); builder.create(&pkg.join("res/LICENSE.txt"), &license); - builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644); + builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), FileType::Regular); let mut cmd = command("productbuild"); cmd.arg("--distribution") .arg(xform(&etc.join("pkg/Distribution.xml"))) @@ -1655,7 +1702,7 @@ impl Step for Extended { prepare("rust-mingw"); } - builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644); + builder.install(&etc.join("gfx/rust-logo.ico"), &exe, FileType::Regular); // Generate msi installer let wix_path = env::var_os("WIX") @@ -1874,8 +1921,8 @@ impl Step for Extended { } builder.create(&exe.join("LICENSE.rtf"), &rtf); - builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644); - builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644); + builder.install(&etc.join("gfx/banner.bmp"), &exe, FileType::Regular); + builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, FileType::Regular); builder.info(&format!("building `msi` installer with {light:?}")); let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple); @@ -1961,13 +2008,13 @@ fn install_llvm_file( if source.is_symlink() { // If we have a symlink like libLLVM-18.so -> libLLVM.so.18.1, install the target of the // symlink, which is what will actually get loaded at runtime. - builder.install(&t!(fs::canonicalize(source)), destination, 0o644); + builder.install(&t!(fs::canonicalize(source)), destination, FileType::NativeLibrary); let full_dest = destination.join(source.file_name().unwrap()); if install_symlink { // For download-ci-llvm, also install the symlink, to match what LLVM does. Using a // symlink is fine here, as this is not a rustup component. - builder.copy_link(source, &full_dest); + builder.copy_link(source, &full_dest, FileType::NativeLibrary); } else { // Otherwise, replace the symlink with an equivalent linker script. This is used when // projects like miri link against librustc_driver.so. We don't use a symlink, as @@ -1984,7 +2031,7 @@ fn install_llvm_file( } } } else { - builder.install(source, destination, 0o644); + builder.install(source, destination, FileType::NativeLibrary); } } @@ -2036,7 +2083,7 @@ fn maybe_install_llvm( let src_libdir = builder.llvm_out(target).join("lib"); let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); if llvm_dylib_path.exists() { - builder.install(&llvm_dylib_path, dst_libdir, 0o644); + builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary); } !builder.config.dry_run() } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) = @@ -2186,7 +2233,7 @@ impl Step for LlvmTools { let dst_bindir = format!("lib/rustlib/{}/bin", target.triple); for tool in tools_to_install(&builder.paths) { let exe = src_bindir.join(exe(tool, target)); - tarball.add_file(&exe, &dst_bindir, 0o755); + tarball.add_file(&exe, &dst_bindir, FileType::Executable); } } @@ -2241,7 +2288,7 @@ impl Step for LlvmBitcodeLinker { tarball.set_overlay(OverlayKind::LlvmBitcodeLinker); tarball.is_preview(true); - tarball.add_file(llbc_linker.tool_path, self_contained_bin_dir, 0o755); + tarball.add_file(&llbc_linker.tool_path, self_contained_bin_dir, FileType::Executable); Some(tarball.generate()) } @@ -2302,7 +2349,7 @@ impl Step for RustDev { let entry = t!(entry); if entry.file_type().is_file() && !entry.path_is_symlink() { let name = entry.file_name().to_str().unwrap(); - tarball.add_file(src_bindir.join(name), "bin", 0o755); + tarball.add_file(src_bindir.join(name), "bin", FileType::Executable); } } } @@ -2314,11 +2361,11 @@ impl Step for RustDev { // We don't build LLD on some platforms, so only add it if it exists let lld_path = lld_out.join("bin").join(exe("lld", target)); if lld_path.exists() { - tarball.add_file(lld_path, "bin", 0o755); + tarball.add_file(&lld_path, "bin", FileType::Executable); } } - tarball.add_file(builder.llvm_filecheck(target), "bin", 0o755); + tarball.add_file(builder.llvm_filecheck(target), "bin", FileType::Executable); // Copy the include directory as well; needed mostly to build // librustc_llvm properly (e.g., llvm-config.h is in here). But also @@ -2379,7 +2426,11 @@ impl Step for Bootstrap { let bootstrap_outdir = &builder.bootstrap_out; for file in &["bootstrap", "rustc", "rustdoc"] { - tarball.add_file(bootstrap_outdir.join(exe(file, target)), "bootstrap/bin", 0o755); + tarball.add_file( + bootstrap_outdir.join(exe(file, target)), + "bootstrap/bin", + FileType::Executable, + ); } Some(tarball.generate()) @@ -2412,7 +2463,7 @@ impl Step for BuildManifest { let build_manifest = builder.tool_exe(Tool::BuildManifest); let tarball = Tarball::new(builder, "build-manifest", &self.target.triple); - tarball.add_file(build_manifest, "bin", 0o755); + tarball.add_file(&build_manifest, "bin", FileType::Executable); tarball.generate() } } @@ -2444,15 +2495,15 @@ impl Step for ReproducibleArtifacts { let mut added_anything = false; let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple); if let Some(path) = builder.config.rust_profile_use.as_ref() { - tarball.add_file(path, ".", 0o644); + tarball.add_file(path, ".", FileType::Regular); added_anything = true; } if let Some(path) = builder.config.llvm_profile_use.as_ref() { - tarball.add_file(path, ".", 0o644); + tarball.add_file(path, ".", FileType::Regular); added_anything = true; } for profile in &builder.config.reproducible_artifacts { - tarball.add_file(profile, ".", 0o644); + tarball.add_file(profile, ".", FileType::Regular); added_anything = true; } if added_anything { Some(tarball.generate()) } else { None } @@ -2481,7 +2532,7 @@ impl Step for Gcc { fn run(self, builder: &Builder<'_>) -> Self::Output { let tarball = Tarball::new(builder, "gcc", &self.target.triple); let output = builder.ensure(super::gcc::Gcc { target: self.target }); - tarball.add_file(output.libgccjit, "lib", 0o644); + tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary); tarball.generate() } } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index a8da41461006..7fccf85a0ea9 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -11,7 +11,6 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::{env, fs, mem}; -use crate::Mode; use crate::core::build_steps::compile; use crate::core::build_steps::tool::{self, SourceType, Tool, prepare_tool_cargo}; use crate::core::builder::{ @@ -19,6 +18,7 @@ use crate::core::builder::{ }; use crate::core::config::{Config, TargetSelection}; use crate::helpers::{submodule_path_of, symlink_dir, t, up_to_date}; +use crate::{FileType, Mode}; macro_rules! book { ($($name:ident, $path:expr, $book_name:expr, $lang:expr ;)+) => { @@ -546,6 +546,7 @@ impl Step for SharedAssets { builder.copy_link( &builder.src.join("src").join("doc").join("rust.css"), &out.join("rust.css"), + FileType::Regular, ); SharedAssetsPaths { version_info } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index aaf6712102cf..cd57e06ae04a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -26,7 +26,7 @@ use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection}; use crate::utils::channel::GitInfo; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{add_dylib_path, exe, t}; -use crate::{Compiler, Kind, Mode, gha}; +use crate::{Compiler, FileType, Kind, Mode, gha}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum SourceType { @@ -353,7 +353,7 @@ fn copy_link_tool_bin( ) -> PathBuf { let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target)); let bin = builder.tools_dir(compiler).join(exe(name, target)); - builder.copy_link(&cargo_out, &bin); + builder.copy_link(&cargo_out, &bin, FileType::Executable); bin } @@ -696,7 +696,7 @@ impl Step for Rustdoc { .join(exe("rustdoc", target_compiler.host)); let bin_rustdoc = bin_rustdoc(); - builder.copy_link(&precompiled_rustdoc, &bin_rustdoc); + builder.copy_link(&precompiled_rustdoc, &bin_rustdoc, FileType::Executable); return ToolBuildResult { tool_path: bin_rustdoc, @@ -743,7 +743,7 @@ impl Step for Rustdoc { compile::strip_debug(builder, target, &tool_path); } let bin_rustdoc = bin_rustdoc(); - builder.copy_link(&tool_path, &bin_rustdoc); + builder.copy_link(&tool_path, &bin_rustdoc, FileType::Executable); ToolBuildResult { tool_path: bin_rustdoc, build_compiler, target_compiler } } else { ToolBuildResult { tool_path, build_compiler, target_compiler } @@ -846,13 +846,20 @@ impl Step for LldWrapper { let src_exe = exe("lld", target); let dst_exe = exe("rust-lld", target); - builder.copy_link(&lld_install.join("bin").join(src_exe), &libdir_bin.join(dst_exe)); + builder.copy_link( + &lld_install.join("bin").join(src_exe), + &libdir_bin.join(dst_exe), + FileType::Executable, + ); let self_contained_lld_dir = libdir_bin.join("gcc-ld"); t!(fs::create_dir_all(&self_contained_lld_dir)); for name in crate::LLD_FILE_NAMES { - builder - .copy_link(&tool_result.tool_path, &self_contained_lld_dir.join(exe(name, target))); + builder.copy_link( + &tool_result.tool_path, + &self_contained_lld_dir.join(exe(name, target)), + FileType::Executable, + ); } tool_result @@ -949,8 +956,11 @@ impl Step for RustAnalyzerProcMacroSrv { // so that r-a can use it. let libexec_path = builder.sysroot(self.compiler).join("libexec"); t!(fs::create_dir_all(&libexec_path)); - builder - .copy_link(&tool_result.tool_path, &libexec_path.join("rust-analyzer-proc-macro-srv")); + builder.copy_link( + &tool_result.tool_path, + &libexec_path.join("rust-analyzer-proc-macro-srv"), + FileType::Executable, + ); Some(tool_result) } @@ -1007,7 +1017,7 @@ impl Step for LlvmBitcodeLinker { t!(fs::create_dir_all(&bindir_self_contained)); let bin_destination = bindir_self_contained .join(exe("llvm-bitcode-linker", tool_result.target_compiler.host)); - builder.copy_link(&tool_result.tool_path, &bin_destination); + builder.copy_link(&tool_result.tool_path, &bin_destination, FileType::Executable); ToolBuildResult { tool_path: bin_destination, build_compiler: tool_result.build_compiler, @@ -1189,7 +1199,7 @@ fn run_tool_build_step( for add_bin in add_bins_to_sysroot { let bin_destination = bindir.join(exe(add_bin, target_compiler.host)); - builder.copy_link(&tool_path, &bin_destination); + builder.copy_link(&tool_path, &bin_destination, FileType::Executable); } // Return a path into the bin dir. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 1943d0299b9e..a47b7a27790b 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -36,7 +36,9 @@ use crate::core::builder; use crate::core::builder::Kind; use crate::core::config::{DryRun, LldMode, LlvmLibunwind, Target, TargetSelection, flags}; use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command}; -use crate::utils::helpers::{self, dir_is_empty, exe, libdir, output, set_file_times, symlink_dir}; +use crate::utils::helpers::{ + self, dir_is_empty, exe, libdir, output, set_file_times, split_debuginfo, symlink_dir, +}; mod core; mod utils; @@ -274,6 +276,35 @@ pub enum CLang { Cxx, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FileType { + /// An executable binary file (like a `.exe`). + Executable, + /// A native, binary library file (like a `.so`, `.dll`, `.a`, `.lib` or `.o`). + NativeLibrary, + /// An executable (non-binary) script file (like a `.py` or `.sh`). + Script, + /// Any other regular file that is non-executable. + Regular, +} + +impl FileType { + /// Get Unix permissions appropriate for this file type. + pub fn perms(self) -> u32 { + match self { + FileType::Executable | FileType::Script => 0o755, + FileType::Regular | FileType::NativeLibrary => 0o644, + } + } + + pub fn could_have_split_debuginfo(self) -> bool { + match self { + FileType::Executable | FileType::NativeLibrary => true, + FileType::Script | FileType::Regular => false, + } + } +} + macro_rules! forward { ( $( $fn:ident( $($param:ident: $ty:ty),* ) $( -> $ret:ty)? ),+ $(,)? ) => { impl Build { @@ -1744,8 +1775,18 @@ Executed at: {executed_at}"#, /// Attempts to use hard links if possible, falling back to copying. /// You can neither rely on this being a copy nor it being a link, /// so do not write to dst. - pub fn copy_link(&self, src: &Path, dst: &Path) { + pub fn copy_link(&self, src: &Path, dst: &Path, file_type: FileType) { self.copy_link_internal(src, dst, false); + + if file_type.could_have_split_debuginfo() { + if let Some(dbg_file) = split_debuginfo(src) { + self.copy_link_internal( + &dbg_file, + &dst.with_extension(dbg_file.extension().unwrap()), + false, + ); + } + } } fn copy_link_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) { @@ -1808,7 +1849,7 @@ Executed at: {executed_at}"#, t!(fs::create_dir_all(&dst)); self.cp_link_r(&path, &dst); } else { - self.copy_link(&path, &dst); + self.copy_link(&path, &dst, FileType::Regular); } } } @@ -1844,7 +1885,7 @@ Executed at: {executed_at}"#, self.cp_link_filtered_recurse(&path, &dst, &relative, filter); } else { let _ = fs::remove_file(&dst); - self.copy_link(&path, &dst); + self.copy_link(&path, &dst, FileType::Regular); } } } @@ -1853,10 +1894,10 @@ Executed at: {executed_at}"#, fn copy_link_to_folder(&self, src: &Path, dest_folder: &Path) { let file_name = src.file_name().unwrap(); let dest = dest_folder.join(file_name); - self.copy_link(src, &dest); + self.copy_link(src, &dest, FileType::Regular); } - fn install(&self, src: &Path, dstdir: &Path, perms: u32) { + fn install(&self, src: &Path, dstdir: &Path, file_type: FileType) { if self.config.dry_run() { return; } @@ -1866,8 +1907,16 @@ Executed at: {executed_at}"#, if !src.exists() { panic!("ERROR: File \"{}\" not found!", src.display()); } + self.copy_link_internal(src, &dst, true); - chmod(&dst, perms); + chmod(&dst, file_type.perms()); + + // If this file can have debuginfo, look for split debuginfo and install it too. + if file_type.could_have_split_debuginfo() { + if let Some(dbg_file) = split_debuginfo(src) { + self.install(&dbg_file, dstdir, FileType::Regular); + } + } } fn read(&self, path: &Path) -> String { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 89d93a29acbc..f8e4d4e04717 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -52,6 +52,23 @@ pub fn exe(name: &str, target: TargetSelection) -> String { crate::utils::shared_helpers::exe(name, &target.triple) } +/// Returns the path to the split debug info for the specified file if it exists. +pub fn split_debuginfo(name: impl Into) -> Option { + // FIXME: only msvc is currently supported + + let path = name.into(); + let pdb = path.with_extension("pdb"); + if pdb.exists() { + return Some(pdb); + } + + // pdbs get named with '-' replaced by '_' + let file_name = pdb.file_name()?.to_str()?.replace("-", "_"); + + let pdb: PathBuf = [path.parent()?, Path::new(&file_name)].into_iter().collect(); + pdb.exists().then_some(pdb) +} + /// Returns `true` if the file name given looks like a dynamic library. pub fn is_dylib(path: &Path) -> bool { path.extension().and_then(|ext| ext.to_str()).is_some_and(|ext| { diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index f1678bacc976..7b77b2129341 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -7,6 +7,7 @@ use std::path::{Path, PathBuf}; +use crate::FileType; use crate::core::build_steps::dist::distdir; use crate::core::builder::{Builder, Kind}; use crate::core::config::BUILDER_CONFIG_FILENAME; @@ -182,7 +183,12 @@ impl<'a> Tarball<'a> { &self.image_dir } - pub(crate) fn add_file(&self, src: impl AsRef, destdir: impl AsRef, perms: u32) { + pub(crate) fn add_file( + &self, + src: impl AsRef, + destdir: impl AsRef, + file_type: FileType, + ) { // create_dir_all fails to create `foo/bar/.`, so when the destination is "." this simply // uses the base directory as the destination directory. let destdir = if destdir.as_ref() == Path::new(".") { @@ -192,7 +198,7 @@ impl<'a> Tarball<'a> { }; t!(std::fs::create_dir_all(&destdir)); - self.builder.install(src.as_ref(), &destdir, perms); + self.builder.install(src.as_ref(), &destdir, file_type); } pub(crate) fn add_renamed_file( @@ -200,15 +206,16 @@ impl<'a> Tarball<'a> { src: impl AsRef, destdir: impl AsRef, new_name: &str, + file_type: FileType, ) { let destdir = self.image_dir.join(destdir.as_ref()); t!(std::fs::create_dir_all(&destdir)); - self.builder.copy_link(src.as_ref(), &destdir.join(new_name)); + self.builder.copy_link(src.as_ref(), &destdir.join(new_name), file_type); } pub(crate) fn add_legal_and_readme_to(&self, destdir: impl AsRef) { for file in self.overlay.legal_and_readme() { - self.add_file(self.builder.src.join(file), destdir.as_ref(), 0o644); + self.add_file(self.builder.src.join(file), destdir.as_ref(), FileType::Regular); } } @@ -318,11 +325,20 @@ impl<'a> Tarball<'a> { // Add config file if present. if let Some(config) = &self.builder.config.config { - self.add_renamed_file(config, &self.overlay_dir, BUILDER_CONFIG_FILENAME); + self.add_renamed_file( + config, + &self.overlay_dir, + BUILDER_CONFIG_FILENAME, + FileType::Regular, + ); } for file in self.overlay.legal_and_readme() { - self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644); + self.builder.install( + &self.builder.src.join(file), + &self.overlay_dir, + FileType::Regular, + ); } let mut cmd = self.builder.tool_cmd(crate::core::build_steps::tool::Tool::RustInstaller); From bcac931956f7a5c271914f8e1973b8195eedb498 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Mon, 17 Mar 2025 17:18:05 -0700 Subject: [PATCH 103/546] Update test for SGX now implementing read_buf In #108326, `read_buf` was implemented for a variety of types, but SGX was saved for later. Update a test from then, now that #137355 implemented it for SGX types. --- library/std/src/net/tcp/tests.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index a7b5cdf4ec06..03003037b295 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -315,12 +315,8 @@ fn read_buf() { let mut buf = BorrowedBuf::from(buf.as_mut_slice()); t!(s.read_buf(buf.unfilled())); assert_eq!(buf.filled(), &[1, 2, 3, 4]); - - // FIXME: sgx uses default_read_buf that initializes the buffer. - if cfg!(not(target_env = "sgx")) { - // TcpStream::read_buf should omit buffer initialization. - assert_eq!(buf.init_len(), 4); - } + // TcpStream::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); t.join().ok().expect("thread panicked"); }) From 69a3ad0d0a1da2c1e723cbfe4056b629c10d32b1 Mon Sep 17 00:00:00 2001 From: makai410 Date: Tue, 18 Mar 2025 09:48:30 +0800 Subject: [PATCH 104/546] Add `MutMirVisitor` Implement `make_mir_visitor` macro to generate `MirVisitor` and `MutMirVisitor`. Add `ret_local_mut()`, `arg_locals_mut()` and `inner_locals_mut()` to `Body`, specifically for `MutMirVisitor`. --- compiler/stable_mir/src/mir.rs | 2 +- compiler/stable_mir/src/mir/body.rs | 16 + compiler/stable_mir/src/mir/visit.rs | 808 +++++++++++++++------------ 3 files changed, 461 insertions(+), 365 deletions(-) diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs index 82555461d644..413b5152bb3b 100644 --- a/compiler/stable_mir/src/mir.rs +++ b/compiler/stable_mir/src/mir.rs @@ -5,4 +5,4 @@ pub mod pretty; pub mod visit; pub use body::*; -pub use visit::MirVisitor; +pub use visit::{MirVisitor, MutMirVisitor}; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index f8b46f50a529..b1bf7bce828c 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -77,6 +77,22 @@ impl Body { &self.locals[self.arg_count + 1..] } + /// Returns a mutable reference to the local that holds this function's return value. + pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl { + &mut self.locals[RETURN_LOCAL] + } + + /// Returns a mutable slice of locals corresponding to this function's arguments. + pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] { + &mut self.locals[1..][..self.arg_count] + } + + /// Returns a mutable slice of inner locals for this function. + /// Inner locals are those that are neither the return local nor the argument locals. + pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] { + &mut self.locals[self.arg_count + 1..] + } + /// Convenience function to get all the locals in this function. /// /// Locals are typically accessed via the more specific methods `ret_local`, diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index d985a98fcbf0..09447e70dfb1 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -39,406 +39,486 @@ use crate::mir::*; use crate::ty::{GenericArgs, MirConst, Region, Ty, TyConst}; use crate::{Error, Opaque, Span}; -pub trait MirVisitor { - fn visit_body(&mut self, body: &Body) { - self.super_body(body) - } +macro_rules! make_mir_visitor { + ($visitor_trait_name:ident, $($mutability:ident)?) => { + pub trait $visitor_trait_name { + fn visit_body(&mut self, body: &$($mutability)? Body) { + self.super_body(body) + } - fn visit_basic_block(&mut self, bb: &BasicBlock) { - self.super_basic_block(bb) - } + fn visit_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { + self.super_basic_block(bb) + } - fn visit_ret_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_ret_decl(local, decl) - } + fn visit_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_ret_decl(local, decl) + } - fn visit_arg_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_arg_decl(local, decl) - } + fn visit_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_arg_decl(local, decl) + } - fn visit_local_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_local_decl(local, decl) - } + fn visit_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } - fn visit_statement(&mut self, stmt: &Statement, location: Location) { - self.super_statement(stmt, location) - } + fn visit_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { + self.super_statement(stmt, location) + } - fn visit_terminator(&mut self, term: &Terminator, location: Location) { - self.super_terminator(term, location) - } + fn visit_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { + self.super_terminator(term, location) + } - fn visit_span(&mut self, span: &Span) { - self.super_span(span) - } + fn visit_span(&mut self, span: &$($mutability)? Span) { + self.super_span(span) + } - fn visit_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { - self.super_place(place, ptx, location) - } + fn visit_place(&mut self, place: &$($mutability)? Place, ptx: PlaceContext, location: Location) { + self.super_place(place, ptx, location) + } - fn visit_projection_elem( - &mut self, - place_ref: PlaceRef<'_>, - elem: &ProjectionElem, - ptx: PlaceContext, - location: Location, - ) { - let _ = place_ref; - self.super_projection_elem(elem, ptx, location); - } + visit_place_fns!($($mutability)?); - fn visit_local(&mut self, local: &Local, ptx: PlaceContext, location: Location) { - let _ = (local, ptx, location); - } + fn visit_local(&mut self, local: &$($mutability)? Local, ptx: PlaceContext, location: Location) { + let _ = (local, ptx, location); + } - fn visit_rvalue(&mut self, rvalue: &Rvalue, location: Location) { - self.super_rvalue(rvalue, location) - } + fn visit_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) { + self.super_rvalue(rvalue, location) + } - fn visit_operand(&mut self, operand: &Operand, location: Location) { - self.super_operand(operand, location) - } + fn visit_operand(&mut self, operand: &$($mutability)? Operand, location: Location) { + self.super_operand(operand, location) + } - fn visit_user_type_projection(&mut self, projection: &UserTypeProjection) { - self.super_user_type_projection(projection) - } + fn visit_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) { + self.super_user_type_projection(projection) + } - fn visit_ty(&mut self, ty: &Ty, location: Location) { - let _ = location; - self.super_ty(ty) - } + fn visit_ty(&mut self, ty: &$($mutability)? Ty, location: Location) { + let _ = location; + self.super_ty(ty) + } - fn visit_const_operand(&mut self, constant: &ConstOperand, location: Location) { - self.super_const_operand(constant, location) - } + fn visit_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) { + self.super_const_operand(constant, location) + } - fn visit_mir_const(&mut self, constant: &MirConst, location: Location) { - self.super_mir_const(constant, location) - } + fn visit_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) { + self.super_mir_const(constant, location) + } - fn visit_ty_const(&mut self, constant: &TyConst, location: Location) { - let _ = location; - self.super_ty_const(constant) - } + fn visit_ty_const(&mut self, constant: &$($mutability)? TyConst, location: Location) { + let _ = location; + self.super_ty_const(constant) + } - fn visit_region(&mut self, region: &Region, location: Location) { - let _ = location; - self.super_region(region) - } + fn visit_region(&mut self, region: &$($mutability)? Region, location: Location) { + let _ = location; + self.super_region(region) + } - fn visit_args(&mut self, args: &GenericArgs, location: Location) { - let _ = location; - self.super_args(args) - } + fn visit_args(&mut self, args: &$($mutability)? GenericArgs, location: Location) { + let _ = location; + self.super_args(args) + } - fn visit_assert_msg(&mut self, msg: &AssertMessage, location: Location) { - self.super_assert_msg(msg, location) - } + fn visit_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) { + self.super_assert_msg(msg, location) + } - fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) { - self.super_var_debug_info(var_debug_info); - } + fn visit_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) { + self.super_var_debug_info(var_debug_info); + } - fn super_body(&mut self, body: &Body) { - let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = body; + fn super_body(&mut self, body: &$($mutability)? Body) { + super_body!(self, body, $($mutability)?); + } - for bb in blocks { - self.visit_basic_block(bb); + fn super_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { + let BasicBlock { statements, terminator } = bb; + for stmt in statements { + self.visit_statement(stmt, Location(stmt.span)); + } + self.visit_terminator(terminator, Location(terminator.span)); + } + + fn super_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + let _ = local; + let LocalDecl { ty, span, .. } = decl; + self.visit_ty(ty, Location(*span)); + } + + fn super_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } + + fn super_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } + + fn super_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { + let Statement { kind, span } = stmt; + self.visit_span(span); + match kind { + StatementKind::Assign(place, rvalue) => { + self.visit_place(place, PlaceContext::MUTATING, location); + self.visit_rvalue(rvalue, location); + } + StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location); + } + StatementKind::SetDiscriminant { place, .. } + | StatementKind::Deinit(place) + | StatementKind::Retag(_, place) => { + self.visit_place(place, PlaceContext::MUTATING, location); + } + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + self.visit_local(local, PlaceContext::NON_USE, location); + } + StatementKind::AscribeUserType { place, projections, variance: _ } => { + self.visit_place(place, PlaceContext::NON_USE, location); + self.visit_user_type_projection(projections); + } + StatementKind::Coverage(coverage) => visit_opaque(coverage), + StatementKind::Intrinsic(intrisic) => match intrisic { + NonDivergingIntrinsic::Assume(operand) => { + self.visit_operand(operand, location); + } + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src, + dst, + count, + }) => { + self.visit_operand(src, location); + self.visit_operand(dst, location); + self.visit_operand(count, location); + } + }, + StatementKind::ConstEvalCounter | StatementKind::Nop => {} + } + } + + fn super_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { + let Terminator { kind, span } = term; + self.visit_span(span); + match kind { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Unreachable => {} + TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { + self.visit_operand(cond, location); + self.visit_assert_msg(msg, location); + } + TerminatorKind::Drop { place, target: _, unwind: _ } => { + self.visit_place(place, PlaceContext::MUTATING, location); + } + TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => { + self.visit_operand(func, location); + for arg in args { + self.visit_operand(arg, location); + } + self.visit_place(destination, PlaceContext::MUTATING, location); + } + TerminatorKind::InlineAsm { operands, .. } => { + for op in operands { + let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op; + if let Some(input) = in_value { + self.visit_operand(input, location); + } + if let Some(output) = out_place { + self.visit_place(output, PlaceContext::MUTATING, location); + } + } + } + TerminatorKind::Return => { + let $($mutability)? local = RETURN_LOCAL; + self.visit_local(&$($mutability)? local, PlaceContext::NON_MUTATING, location); + } + TerminatorKind::SwitchInt { discr, targets: _ } => { + self.visit_operand(discr, location); + } + } + } + + fn super_span(&mut self, span: &$($mutability)? Span) { + let _ = span; + } + + fn super_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) { + match rvalue { + Rvalue::AddressOf(mutability, place) => { + let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut }; + self.visit_place(place, pcx, location); + } + Rvalue::Aggregate(_, operands) => { + for op in operands { + self.visit_operand(op, location); + } + } + Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { + self.visit_operand(lhs, location); + self.visit_operand(rhs, location); + } + Rvalue::Cast(_, op, ty) => { + self.visit_operand(op, location); + self.visit_ty(ty, location); + } + Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location); + } + Rvalue::Ref(region, kind, place) => { + self.visit_region(region, location); + let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) }; + self.visit_place(place, pcx, location); + } + Rvalue::Repeat(op, constant) => { + self.visit_operand(op, location); + self.visit_ty_const(constant, location); + } + Rvalue::ShallowInitBox(op, ty) => { + self.visit_ty(ty, location); + self.visit_operand(op, location) + } + Rvalue::ThreadLocalRef(_) => {} + Rvalue::NullaryOp(_, ty) => { + self.visit_ty(ty, location); + } + Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { + self.visit_operand(op, location); + } + } + } + + fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Location) { + match operand { + Operand::Copy(place) | Operand::Move(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location) + } + Operand::Constant(constant) => { + self.visit_const_operand(constant, location); + } + } + } + + fn super_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) { + // This is a no-op on mir::Visitor. + let _ = projection; + } + + fn super_ty(&mut self, ty: &$($mutability)? Ty) { + let _ = ty; + } + + fn super_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) { + let ConstOperand { span, user_ty: _, const_ } = constant; + self.visit_span(span); + self.visit_mir_const(const_, location); + } + + fn super_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) { + let MirConst { kind: _, ty, id: _ } = constant; + self.visit_ty(ty, location); + } + + fn super_ty_const(&mut self, constant: &$($mutability)? TyConst) { + let _ = constant; + } + + fn super_region(&mut self, region: &$($mutability)? Region) { + let _ = region; + } + + fn super_args(&mut self, args: &$($mutability)? GenericArgs) { + let _ = args; + } + + fn super_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) { + let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } = + var_debug_info; + self.visit_span(&$($mutability)? source_info.span); + let location = Location(source_info.span); + if let Some(composite) = composite { + self.visit_ty(&$($mutability)? composite.ty, location); + } + match value { + VarDebugInfoContents::Place(place) => { + self.visit_place(place, PlaceContext::NON_USE, location); + } + VarDebugInfoContents::Const(constant) => { + self.visit_mir_const(&$($mutability)? constant.const_, location); + } + } + } + + fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) { + match msg { + AssertMessage::BoundsCheck { len, index } => { + self.visit_operand(len, location); + self.visit_operand(index, location); + } + AssertMessage::Overflow(_, left, right) => { + self.visit_operand(left, location); + self.visit_operand(right, location); + } + AssertMessage::OverflowNeg(op) + | AssertMessage::DivisionByZero(op) + | AssertMessage::RemainderByZero(op) => { + self.visit_operand(op, location); + } + AssertMessage::ResumedAfterReturn(_) + | AssertMessage::ResumedAfterPanic(_) + | AssertMessage::NullPointerDereference => { + //nothing to visit + } + AssertMessage::MisalignedPointerDereference { required, found } => { + self.visit_operand(required, location); + self.visit_operand(found, location); + } + } + } + } + }; +} + +macro_rules! super_body { + ($self:ident, $body:ident, mut) => { + for bb in $body.blocks.iter_mut() { + $self.visit_basic_block(bb); } - self.visit_ret_decl(RETURN_LOCAL, body.ret_local()); + $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut()); - for (idx, arg) in body.arg_locals().iter().enumerate() { - self.visit_arg_decl(idx + 1, arg) + for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() { + $self.visit_arg_decl(idx + 1, arg) + } + + let local_start = $body.arg_count + 1; + for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() { + $self.visit_local_decl(idx + local_start, arg) + } + + for info in $body.var_debug_info.iter_mut() { + $self.visit_var_debug_info(info); + } + + $self.visit_span(&mut $body.span) + }; + + ($self:ident, $body:ident, ) => { + let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body; + + for bb in blocks { + $self.visit_basic_block(bb); + } + + $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local()); + + for (idx, arg) in $body.arg_locals().iter().enumerate() { + $self.visit_arg_decl(idx + 1, arg) } let local_start = arg_count + 1; - for (idx, arg) in body.inner_locals().iter().enumerate() { - self.visit_local_decl(idx + local_start, arg) + for (idx, arg) in $body.inner_locals().iter().enumerate() { + $self.visit_local_decl(idx + local_start, arg) } for info in var_debug_info.iter() { - self.visit_var_debug_info(info); + $self.visit_var_debug_info(info); } - self.visit_span(span) - } - - fn super_basic_block(&mut self, bb: &BasicBlock) { - let BasicBlock { statements, terminator } = bb; - for stmt in statements { - self.visit_statement(stmt, Location(stmt.span)); - } - self.visit_terminator(terminator, Location(terminator.span)); - } - - fn super_local_decl(&mut self, local: Local, decl: &LocalDecl) { - let _ = local; - let LocalDecl { ty, span, .. } = decl; - self.visit_ty(ty, Location(*span)); - } - - fn super_ret_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_local_decl(local, decl) - } - - fn super_arg_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_local_decl(local, decl) - } - - fn super_statement(&mut self, stmt: &Statement, location: Location) { - let Statement { kind, span } = stmt; - self.visit_span(span); - match kind { - StatementKind::Assign(place, rvalue) => { - self.visit_place(place, PlaceContext::MUTATING, location); - self.visit_rvalue(rvalue, location); - } - StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location); - } - StatementKind::SetDiscriminant { place, .. } - | StatementKind::Deinit(place) - | StatementKind::Retag(_, place) => { - self.visit_place(place, PlaceContext::MUTATING, location); - } - StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { - self.visit_local(local, PlaceContext::NON_USE, location); - } - StatementKind::AscribeUserType { place, projections, variance: _ } => { - self.visit_place(place, PlaceContext::NON_USE, location); - self.visit_user_type_projection(projections); - } - StatementKind::Coverage(coverage) => visit_opaque(coverage), - StatementKind::Intrinsic(intrisic) => match intrisic { - NonDivergingIntrinsic::Assume(operand) => { - self.visit_operand(operand, location); - } - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - src, - dst, - count, - }) => { - self.visit_operand(src, location); - self.visit_operand(dst, location); - self.visit_operand(count, location); - } - }, - StatementKind::ConstEvalCounter | StatementKind::Nop => {} - } - } - - fn super_terminator(&mut self, term: &Terminator, location: Location) { - let Terminator { kind, span } = term; - self.visit_span(span); - match kind { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Unreachable => {} - TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { - self.visit_operand(cond, location); - self.visit_assert_msg(msg, location); - } - TerminatorKind::Drop { place, target: _, unwind: _ } => { - self.visit_place(place, PlaceContext::MUTATING, location); - } - TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => { - self.visit_operand(func, location); - for arg in args { - self.visit_operand(arg, location); - } - self.visit_place(destination, PlaceContext::MUTATING, location); - } - TerminatorKind::InlineAsm { operands, .. } => { - for op in operands { - let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op; - if let Some(input) = in_value { - self.visit_operand(input, location); - } - if let Some(output) = out_place { - self.visit_place(output, PlaceContext::MUTATING, location); - } - } - } - TerminatorKind::Return => { - let local = RETURN_LOCAL; - self.visit_local(&local, PlaceContext::NON_MUTATING, location); - } - TerminatorKind::SwitchInt { discr, targets: _ } => { - self.visit_operand(discr, location); - } - } - } - - fn super_span(&mut self, span: &Span) { - let _ = span; - } - - fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { - let _ = location; - let _ = ptx; - self.visit_local(&place.local, ptx, location); - - for (idx, elem) in place.projection.iter().enumerate() { - let place_ref = PlaceRef { local: place.local, projection: &place.projection[..idx] }; - self.visit_projection_elem(place_ref, elem, ptx, location); - } - } - - fn super_projection_elem( - &mut self, - elem: &ProjectionElem, - ptx: PlaceContext, - location: Location, - ) { - match elem { - ProjectionElem::Downcast(_idx) => {} - ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } - | ProjectionElem::Deref - | ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} - ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), - ProjectionElem::Index(local) => self.visit_local(local, ptx, location), - ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => { - self.visit_ty(ty, location) - } - } - } - - fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) { - match rvalue { - Rvalue::AddressOf(mutability, place) => { - let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut }; - self.visit_place(place, pcx, location); - } - Rvalue::Aggregate(_, operands) => { - for op in operands { - self.visit_operand(op, location); - } - } - Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - self.visit_operand(lhs, location); - self.visit_operand(rhs, location); - } - Rvalue::Cast(_, op, ty) => { - self.visit_operand(op, location); - self.visit_ty(ty, location); - } - Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location); - } - Rvalue::Ref(region, kind, place) => { - self.visit_region(region, location); - let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) }; - self.visit_place(place, pcx, location); - } - Rvalue::Repeat(op, constant) => { - self.visit_operand(op, location); - self.visit_ty_const(constant, location); - } - Rvalue::ShallowInitBox(op, ty) => { - self.visit_ty(ty, location); - self.visit_operand(op, location) - } - Rvalue::ThreadLocalRef(_) => {} - Rvalue::NullaryOp(_, ty) => { - self.visit_ty(ty, location); - } - Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { - self.visit_operand(op, location); - } - } - } - - fn super_operand(&mut self, operand: &Operand, location: Location) { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location) - } - Operand::Constant(constant) => { - self.visit_const_operand(constant, location); - } - } - } - - fn super_user_type_projection(&mut self, projection: &UserTypeProjection) { - // This is a no-op on mir::Visitor. - let _ = projection; - } - - fn super_ty(&mut self, ty: &Ty) { - let _ = ty; - } - - fn super_const_operand(&mut self, constant: &ConstOperand, location: Location) { - let ConstOperand { span, user_ty: _, const_ } = constant; - self.visit_span(span); - self.visit_mir_const(const_, location); - } - - fn super_mir_const(&mut self, constant: &MirConst, location: Location) { - let MirConst { kind: _, ty, id: _ } = constant; - self.visit_ty(ty, location); - } - - fn super_ty_const(&mut self, constant: &TyConst) { - let _ = constant; - } - - fn super_region(&mut self, region: &Region) { - let _ = region; - } - - fn super_args(&mut self, args: &GenericArgs) { - let _ = args; - } - - fn super_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) { - let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } = - var_debug_info; - self.visit_span(&source_info.span); - let location = Location(source_info.span); - if let Some(composite) = composite { - self.visit_ty(&composite.ty, location); - } - match value { - VarDebugInfoContents::Place(place) => { - self.visit_place(place, PlaceContext::NON_USE, location); - } - VarDebugInfoContents::Const(constant) => { - self.visit_mir_const(&constant.const_, location); - } - } - } - - fn super_assert_msg(&mut self, msg: &AssertMessage, location: Location) { - match msg { - AssertMessage::BoundsCheck { len, index } => { - self.visit_operand(len, location); - self.visit_operand(index, location); - } - AssertMessage::Overflow(_, left, right) => { - self.visit_operand(left, location); - self.visit_operand(right, location); - } - AssertMessage::OverflowNeg(op) - | AssertMessage::DivisionByZero(op) - | AssertMessage::RemainderByZero(op) => { - self.visit_operand(op, location); - } - AssertMessage::ResumedAfterReturn(_) - | AssertMessage::ResumedAfterPanic(_) - | AssertMessage::NullPointerDereference => { - //nothing to visit - } - AssertMessage::MisalignedPointerDereference { required, found } => { - self.visit_operand(required, location); - self.visit_operand(found, location); - } - } - } + $self.visit_span(span) + }; } +macro_rules! visit_place_fns { + (mut) => { + fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) { + self.visit_local(&mut place.local, ptx, location); + + for elem in place.projection.iter_mut() { + self.visit_projection_elem(elem, ptx, location); + } + } + + // We don't have to replicate the `process_projection()` like we did in + // `rustc_middle::mir::visit.rs` here because the `projection` field in `Place` + // of Stable-MIR is not an immutable borrow, unlike in `Place` of MIR. + fn visit_projection_elem( + &mut self, + elem: &mut ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + self.super_projection_elem(elem, ptx, location) + } + + fn super_projection_elem( + &mut self, + elem: &mut ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Deref => {} + ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), + ProjectionElem::Index(local) => self.visit_local(local, ptx, location), + ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} + ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} + ProjectionElem::Downcast(_idx) => {} + ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), + ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), + } + } + }; + + () => { + fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { + self.visit_local(&place.local, ptx, location); + + for (idx, elem) in place.projection.iter().enumerate() { + let place_ref = + PlaceRef { local: place.local, projection: &place.projection[..idx] }; + self.visit_projection_elem(place_ref, elem, ptx, location); + } + } + + fn visit_projection_elem<'a>( + &mut self, + place_ref: PlaceRef<'a>, + elem: &ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + let _ = place_ref; + self.super_projection_elem(elem, ptx, location); + } + + fn super_projection_elem( + &mut self, + elem: &ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Deref => {} + ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), + ProjectionElem::Index(local) => self.visit_local(local, ptx, location), + ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} + ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} + ProjectionElem::Downcast(_idx) => {} + ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), + ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), + } + } + }; +} + +make_mir_visitor!(MirVisitor,); +make_mir_visitor!(MutMirVisitor, mut); + /// This function is a no-op that gets used to ensure this visitor is kept up-to-date. /// /// The idea is that whenever we replace an Opaque type by a real type, the compiler will fail From ad315f6074868024689aaa98021bffdd590e0841 Mon Sep 17 00:00:00 2001 From: makai410 Date: Tue, 18 Mar 2025 09:49:06 +0800 Subject: [PATCH 105/546] Add test for `MutMirVisitor` --- tests/ui-fulldeps/stable-mir/smir_visitor.rs | 81 +++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index cffb41742b4e..0a579a07cef1 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -18,6 +18,7 @@ extern crate stable_mir; use rustc_smir::rustc_internal; use stable_mir::mir::MirVisitor; +use stable_mir::mir::MutMirVisitor; use stable_mir::*; use std::collections::HashSet; use std::io::Write; @@ -99,6 +100,83 @@ impl<'a> mir::MirVisitor for TestVisitor<'a> { } } +fn test_mut_visitor() -> ControlFlow<()> { + let main_fn = stable_mir::entry_fn(); + let mut main_body = main_fn.unwrap().expect_body(); + let locals = main_body.locals().to_vec(); + let mut main_visitor = TestMutVisitor::collect(locals); + main_visitor.visit_body(&mut main_body); + assert!(main_visitor.ret_val.is_some()); + assert!(main_visitor.args.is_empty()); + assert!(main_visitor.tys.contains(&main_visitor.ret_val.unwrap().ty)); + assert!(!main_visitor.calls.is_empty()); + + let exit_fn = main_visitor.calls.last().unwrap(); + assert!(exit_fn.mangled_name().contains("exit_fn"), "Unexpected last function: {exit_fn:?}"); + + let mut exit_body = exit_fn.body().unwrap(); + let locals = exit_body.locals().to_vec(); + let mut exit_visitor = TestMutVisitor::collect(locals); + exit_visitor.visit_body(&mut exit_body); + assert!(exit_visitor.ret_val.is_some()); + assert_eq!(exit_visitor.args.len(), 1); + assert!(exit_visitor.tys.contains(&exit_visitor.ret_val.unwrap().ty)); + assert!(exit_visitor.tys.contains(&exit_visitor.args[0].ty)); + ControlFlow::Continue(()) +} + +struct TestMutVisitor { + locals: Vec, + pub tys: HashSet, + pub ret_val: Option, + pub args: Vec, + pub calls: Vec, +} + +impl TestMutVisitor { + fn collect(locals: Vec) -> TestMutVisitor { + let visitor = TestMutVisitor { + locals: locals, + tys: Default::default(), + ret_val: None, + args: vec![], + calls: vec![], + }; + visitor + } +} + +impl mir::MutMirVisitor for TestMutVisitor { + fn visit_ty(&mut self, ty: &mut ty::Ty, _location: mir::visit::Location) { + self.tys.insert(*ty); + self.super_ty(ty) + } + + fn visit_ret_decl(&mut self, local: mir::Local, decl: &mut mir::LocalDecl) { + assert!(local == mir::RETURN_LOCAL); + assert!(self.ret_val.is_none()); + self.ret_val = Some(decl.clone()); + self.super_ret_decl(local, decl); + } + + fn visit_arg_decl(&mut self, local: mir::Local, decl: &mut mir::LocalDecl) { + self.args.push(decl.clone()); + assert_eq!(local, self.args.len()); + self.super_arg_decl(local, decl); + } + + fn visit_terminator(&mut self, term: &mut mir::Terminator, location: mir::visit::Location) { + if let mir::TerminatorKind::Call { func, .. } = &mut term.kind { + let ty::TyKind::RigidTy(ty) = func.ty(&self.locals).unwrap().kind() else { + unreachable!() + }; + let ty::RigidTy::FnDef(def, args) = ty else { unreachable!() }; + self.calls.push(mir::mono::Instance::resolve(def, &args).unwrap()); + } + self.super_terminator(term, location); + } +} + /// This test will generate and analyze a dummy crate using the stable mir. /// For that, it will first write the dummy crate into a file. /// Then it will create a `StableMir` using custom arguments and then @@ -113,7 +191,8 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, test_visitor).unwrap(); + run!(args.clone(), test_visitor).unwrap(); + run!(args, test_mut_visitor).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { From 81b2d5508eb4e79af7ba4bd32486099eeaabc834 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 18 Mar 2025 02:47:37 -0400 Subject: [PATCH 106/546] addressing feedback, removing unused arg --- compiler/rustc_builtin_macros/src/autodiff.rs | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index bfddb450cd76..63f97f3ae29a 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -233,20 +233,8 @@ mod llvm_enzyme { .filter(|a| **a == DiffActivity::Active || **a == DiffActivity::ActiveOnly) .count() as u32; let (d_sig, new_args, idents, errored) = gen_enzyme_decl(ecx, &sig, &x, span); - let new_decl_span = d_sig.span; let d_body = gen_enzyme_body( - ecx, - &x, - n_active, - &sig, - &d_sig, - primal, - &new_args, - span, - sig_span, - new_decl_span, - idents, - errored, + ecx, &x, n_active, &sig, &d_sig, primal, &new_args, span, sig_span, idents, errored, ); let d_ident = first_ident(&meta_item_vec[0]); @@ -440,12 +428,10 @@ mod llvm_enzyme { /// We only want this function to type-check, since we will replace the body /// later on llvm level. Using `loop {}` does not cover all return types anymore, - /// so instead we build something that should pass. We also add a inline_asm - /// line, as one more barrier for rustc to prevent inlining of this function. - /// FIXME(ZuseZ4): We still have cases of incorrect inlining across modules, see - /// , so this isn't sufficient. - /// It also triggers an Enzyme crash if we due to a bug ever try to differentiate - /// this function (which should never happen, since it is only a placeholder). + /// so instead we manually build something that should pass the type checker. + /// We also add a inline_asm line, as one more barrier for rustc to prevent inlining + /// or const propagation. inline_asm will also triggers an Enzyme crash if due to another + /// bug would ever try to accidentially differentiate this placeholder function body. /// Finally, we also add back_box usages of all input arguments, to prevent rustc /// from optimizing any arguments away. fn gen_enzyme_body( @@ -458,7 +444,6 @@ mod llvm_enzyme { new_names: &[String], span: Span, sig_span: Span, - _new_decl_span: Span, idents: Vec, errored: bool, ) -> P { From 93a9102a06d4f1860f3881060e1f4f5c5a37dab6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 18 Mar 2025 09:01:19 +0000 Subject: [PATCH 107/546] Rustup to rustc 1.87.0-nightly (43a2e9d2c 2025-03-17) --- patches/coretests-lock.toml | 26 ++++++++++++++++++++++++++ rust-toolchain | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/patches/coretests-lock.toml b/patches/coretests-lock.toml index bb7f519f7a7c..d64892378229 100644 --- a/patches/coretests-lock.toml +++ b/patches/coretests-lock.toml @@ -8,6 +8,7 @@ version = "0.0.0" dependencies = [ "rand", "rand_xorshift", + "regex", ] [[package]] @@ -56,6 +57,31 @@ dependencies = [ "rand_core", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "syn" version = "2.0.98" diff --git a/rust-toolchain b/rust-toolchain index ec730a4402cf..1b2751c86e3c 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-12" +channel = "nightly-2025-03-18" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 5fe1e47f80de2c5edd63d575ad311ccbd55d8f46 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 18 Mar 2025 09:59:00 +0100 Subject: [PATCH 108/546] reintroduce remote-test support in run-make tests The old Makefile-based infrastructure included support for executing binaries with remote-test-client if configured, but that didn't get ported to run_make_support as part of the rmake migration. This PR re-introduces back that support, with the same implementation (and limitations) of the original Makefile-based support. --- src/tools/run-make-support/src/run.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 7812863ccc2c..60e711d34027 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -12,7 +12,20 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command { bin_path.push(cwd()); bin_path.push(name); let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); - let mut cmd = Command::new(bin_path); + + let mut cmd = if let Some(rtc) = env::var_os("REMOTE_TEST_CLIENT") { + let mut cmd = Command::new(rtc); + cmd.arg("run"); + // FIXME: the "0" indicates how many support files should be uploaded along with the binary + // to execute. If a test requires additional files to be pushed to the remote machine, this + // will have to be changed (and the support files will have to be uploaded). + cmd.arg("0"); + cmd.arg(bin_path); + cmd + } else { + Command::new(bin_path) + }; + if let Some(args) = args { for arg in args { cmd.arg(arg); From ebef14a7b6664c9f054f20f6803da17c31387ad5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 18 Mar 2025 09:40:43 +0000 Subject: [PATCH 109/546] Reuse the Cargo.lock of the library workspace for coretests --- build_system/tests.rs | 27 ++-- config.txt | 2 +- ...root_tests-128bit-atomic-operations.patch} | 12 +- ...ot_tests-Disable-long-running-tests.patch} | 8 +- patches/coretests-lock.toml | 120 ------------------ 5 files changed, 22 insertions(+), 147 deletions(-) rename patches/{0027-coretests-128bit-atomic-operations.patch => 0027-sysroot_tests-128bit-atomic-operations.patch} (84%) rename patches/{0028-coretests-Disable-long-running-tests.patch => 0028-sysroot_tests-Disable-long-running-tests.patch} (87%) delete mode 100644 patches/coretests-lock.toml diff --git a/build_system/tests.rs b/build_system/tests.rs index 9ec0d3850f11..9b4e2857519f 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -1,5 +1,4 @@ use std::ffi::OsStr; -use std::fs; use std::path::PathBuf; use std::process::Command; @@ -126,9 +125,9 @@ static PORTABLE_SIMD_SRC: RelPath = RelPath::build("portable-simd"); static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); -static LIBCORE_TESTS_SRC: RelPath = RelPath::build("coretests"); +static SYSROOT_TESTS_SRC: RelPath = RelPath::build("sysroot_tests"); -static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "coretests_target"); +static SYSROOT_TESTS: CargoProject = CargoProject::new(&SYSROOT_TESTS_SRC, "sysroot_tests_target"); const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ TestCase::custom("test.rust-random/rand", &|runner| { @@ -147,28 +146,24 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ spawn_and_wait(build_cmd); } }), - TestCase::custom("test.libcore", &|runner| { + TestCase::custom("test.sysroot", &|runner| { apply_patches( &runner.dirs, - "coretests", - &runner.stdlib_source.join("library/coretests"), - &LIBCORE_TESTS_SRC.to_path(&runner.dirs), + "sysroot_tests", + &runner.stdlib_source.join("library"), + &SYSROOT_TESTS_SRC.to_path(&runner.dirs), ); - let source_lockfile = runner.dirs.source_dir.join("patches/coretests-lock.toml"); - let target_lockfile = LIBCORE_TESTS_SRC.to_path(&runner.dirs).join("Cargo.lock"); - fs::copy(source_lockfile, target_lockfile).unwrap(); - - LIBCORE_TESTS.clean(&runner.dirs); + SYSROOT_TESTS.clean(&runner.dirs); if runner.is_native { - let mut test_cmd = LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs); - test_cmd.arg("--").arg("-q"); + let mut test_cmd = SYSROOT_TESTS.test(&runner.target_compiler, &runner.dirs); + test_cmd.args(["-p", "coretests", "--", "-q"]); spawn_and_wait(test_cmd); } else { eprintln!("Cross-Compiling: Not running tests"); - let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs); - build_cmd.arg("--tests"); + let mut build_cmd = SYSROOT_TESTS.build(&runner.target_compiler, &runner.dirs); + build_cmd.args(["-p", "coretests", "--tests"]); spawn_and_wait(build_cmd); } }), diff --git a/config.txt b/config.txt index f578cbef35e6..714414fe8d68 100644 --- a/config.txt +++ b/config.txt @@ -35,6 +35,6 @@ aot.raw-dylib testsuite.extended_sysroot test.rust-random/rand -test.libcore +test.sysroot test.regex test.portable-simd diff --git a/patches/0027-coretests-128bit-atomic-operations.patch b/patches/0027-sysroot_tests-128bit-atomic-operations.patch similarity index 84% rename from patches/0027-coretests-128bit-atomic-operations.patch rename to patches/0027-sysroot_tests-128bit-atomic-operations.patch index 4a06dc3f7ef8..16c8488acdb5 100644 --- a/patches/0027-coretests-128bit-atomic-operations.patch +++ b/patches/0027-sysroot_tests-128bit-atomic-operations.patch @@ -10,20 +10,20 @@ Cranelift doesn't support them yet library/core/tests/atomic.rs | 4 --- 4 files changed, 4 insertions(+), 50 deletions(-) -diff --git a/tests/lib.rs b/tests/lib.rs +diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs index 1e336bf..35e6f54 100644 ---- a/tests/lib.rs -+++ b/tests/lib.rs +--- a/coretests/tests/lib.rs ++++ b/coretests/tests/lib.rs @@ -2,5 +2,4 @@ // tidy-alphabetical-start -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(alloc_layout_extra)] #![feature(array_chunks)] -diff --git a/tests/atomic.rs b/tests/atomic.rs +diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs index b735957..ea728b6 100644 ---- a/tests/atomic.rs -+++ b/tests/atomic.rs +--- a/coretests/tests/atomic.rs ++++ b/coretests/tests/atomic.rs @@ -185,10 +185,6 @@ fn atomic_alignment() { assert_eq!(align_of::(), size_of::()); #[cfg(target_has_atomic = "64")] diff --git a/patches/0028-coretests-Disable-long-running-tests.patch b/patches/0028-sysroot_tests-Disable-long-running-tests.patch similarity index 87% rename from patches/0028-coretests-Disable-long-running-tests.patch rename to patches/0028-sysroot_tests-Disable-long-running-tests.patch index f5ae66c0eb13..50d93ec99dba 100644 --- a/patches/0028-coretests-Disable-long-running-tests.patch +++ b/patches/0028-sysroot_tests-Disable-long-running-tests.patch @@ -4,13 +4,13 @@ Date: Fri, 3 Dec 2021 12:16:30 +0100 Subject: [PATCH] Disable long running tests --- - library/core/tests/slice.rs | 2 ++ + library/coretests/tests/slice.rs | 2 ++ 1 file changed, 2 insertions(+) -diff --git a/tests/slice.rs b/tests/slice.rs +diff --git a/coretests/tests/slice.rs b/coretests/tests/slice.rs index 8402833..84592e0 100644 ---- a/tests/slice.rs -+++ b/tests/slice.rs +--- a/coretests/tests/slice.rs ++++ b/coretests/tests/slice.rs @@ -1809,6 +1809,7 @@ fn sort_unstable() { } } diff --git a/patches/coretests-lock.toml b/patches/coretests-lock.toml deleted file mode 100644 index d64892378229..000000000000 --- a/patches/coretests-lock.toml +++ /dev/null @@ -1,120 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "coretests" -version = "0.0.0" -dependencies = [ - "rand", - "rand_xorshift", - "regex", -] - -[[package]] -name = "proc-macro2" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" -dependencies = [ - "rand_core", - "zerocopy", -] - -[[package]] -name = "rand_core" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "rand_xorshift" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" -dependencies = [ - "rand_core", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "syn" -version = "2.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" - -[[package]] -name = "zerocopy" -version = "0.8.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] From 1adce908c60370fba57f342426ac151823860b02 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 18 Mar 2025 09:52:12 +0000 Subject: [PATCH 110/546] Run alloctests tests too --- build_system/tests.rs | 4 +- ...oot_tests-Disable-long-running-tests.patch | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/build_system/tests.rs b/build_system/tests.rs index 9b4e2857519f..36e108726121 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -158,12 +158,12 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ if runner.is_native { let mut test_cmd = SYSROOT_TESTS.test(&runner.target_compiler, &runner.dirs); - test_cmd.args(["-p", "coretests", "--", "-q"]); + test_cmd.args(["-p", "coretests", "-p", "alloctests", "--", "-q"]); spawn_and_wait(test_cmd); } else { eprintln!("Cross-Compiling: Not running tests"); let mut build_cmd = SYSROOT_TESTS.build(&runner.target_compiler, &runner.dirs); - build_cmd.args(["-p", "coretests", "--tests"]); + build_cmd.args(["-p", "coretests", "-p", "alloctests", "--tests"]); spawn_and_wait(build_cmd); } }), diff --git a/patches/0028-sysroot_tests-Disable-long-running-tests.patch b/patches/0028-sysroot_tests-Disable-long-running-tests.patch index 50d93ec99dba..357b8d306cf6 100644 --- a/patches/0028-sysroot_tests-Disable-long-running-tests.patch +++ b/patches/0028-sysroot_tests-Disable-long-running-tests.patch @@ -43,6 +43,63 @@ index 8402833..84592e0 100644 #[test] fn test_slice_from_ptr_range() { +diff --git a/alloctests/tests/sort/tests.rs b/alloctests/tests/sort/tests.rs +index d321f8d..8b2040a 100644 +--- a/alloctests/tests/sort/tests.rs ++++ b/alloctests/tests/sort/tests.rs +@@ -1,3 +1,5 @@ ++#![cfg(any())] ++ + use std::cell::Cell; + use std::cmp::Ordering; + use std::fmt::Debug; +diff --git a/alloctests/tests/str.rs b/alloctests/tests/str.rs +index 906fa2d..b82fa99 100644 +--- a/alloctests/tests/str.rs ++++ b/alloctests/tests/str.rs +@@ -2234,7 +2234,7 @@ fn const_str_ptr() { + const C: *const u8 = B as *const u8; + + // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) +- #[cfg(not(miri))] ++ #[cfg(any())] + { + let foo = &A as *const u8; + assert_eq!(foo, C); +diff --git a/alloctests/tests/task.rs b/alloctests/tests/task.rs +index 390dec1..87df6e6 100644 +--- a/alloctests/tests/task.rs ++++ b/alloctests/tests/task.rs +@@ -4,7 +4,7 @@ use alloc::task::{LocalWake, Wake}; + use core::task::{LocalWaker, Waker}; + + #[test] +-#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail ++#[ignore] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail + fn test_waker_will_wake_clone() { + struct NoopWaker; + +@@ -20,7 +20,7 @@ fn test_waker_will_wake_clone() { + } + + #[test] +-#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail ++#[ignore] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail + fn test_local_waker_will_wake_clone() { + struct NoopWaker; + +diff --git a/alloctests/tests/vec.rs b/alloctests/tests/vec.rs +index f430d97..cfbd3cb 100644 +--- a/alloctests/tests/vec.rs ++++ b/alloctests/tests/vec.rs +@@ -762,6 +762,7 @@ fn test_drain_inclusive_range() { + } + + #[test] ++#[ignore] + fn test_drain_max_vec_size() { + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { -- 2.26.2.7.g19db9cfb68 From 9fa158d70a75ce116e87b03d913104474af0e381 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 18 Mar 2025 19:27:53 +0530 Subject: [PATCH 111/546] std: uefi: fs: Implement mkdir - Since there is no direct mkdir in UEFI, first check if a file/dir with same path exists and then create the directory. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index defc1681d38a..54acd4c27b33 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -36,7 +36,7 @@ pub struct FilePermissions(bool); pub struct FileType(bool); #[derive(Debug)] -pub struct DirBuilder {} +pub struct DirBuilder; impl FileAttr { pub fn size(&self) -> u64 { @@ -248,11 +248,11 @@ impl File { impl DirBuilder { pub fn new() -> DirBuilder { - DirBuilder {} + DirBuilder } - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + uefi_fs::mkdir(p) } } @@ -452,4 +452,30 @@ mod uefi_fs { } } } + + /// An implementation of mkdir to allow creating new directory without having to open the + /// volume twice (once for checking and once for creating) + pub(crate) fn mkdir(path: &Path) -> io::Result<()> { + let absolute = crate::path::absolute(path)?; + + let p = helpers::OwnedDevicePath::from_text(absolute.as_os_str())?; + let (vol, mut path_remaining) = File::open_volume_from_device_path(p.borrow())?; + + // Check if file exists + match vol.open(&mut path_remaining, file::MODE_READ, 0) { + Ok(_) => { + return Err(io::Error::new(io::ErrorKind::AlreadyExists, "Path already exists")); + } + Err(e) if e.kind() == io::ErrorKind::NotFound => {} + Err(e) => return Err(e), + } + + let _ = vol.open( + &mut path_remaining, + file::MODE_READ | file::MODE_WRITE | file::MODE_CREATE, + file::DIRECTORY, + )?; + + Ok(()) + } } From cb4a25ca81e266703a8ffa4fe80a53e954bb992d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 18 Mar 2025 14:39:46 +0000 Subject: [PATCH 112/546] Remove liballoc compiler-builtins f16/f128 disable patch We already build with the compiler-builtins-no-f16-f128 feature enabled. --- ...le-f16-and-f128-in-compiler-builtins.patch | 26 ------------------- scripts/setup_rust_fork.sh | 1 + 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch deleted file mode 100644 index 754025ff49db..000000000000 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 175d52c5e1779764b66777db1e6f172c2dc365ff Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Fri, 9 Aug 2024 15:44:51 +0000 -Subject: [PATCH] Disable f16 and f128 in compiler-builtins - ---- - library/liballoc/Cargo.toml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/library/liballoc/Cargo.toml b/library/liballoc/Cargo.toml -index 7165c3e48af..968552ad435 100644 ---- a/library/alloc/Cargo.toml -+++ b/library/alloc/Cargo.toml -@@ -11,7 +11,7 @@ test = { path = "../test" } - bench = false - - [dependencies] - core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } - - [features] - compiler-builtins-mem = ['compiler_builtins/mem'] --- -2.34.1 - diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 54f6baff4fec..c2c8e625f60b 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -43,6 +43,7 @@ verbose-tests = false # disabled bootstrap will crash trying to copy llvm tools for the bootstrap # compiler. llvm-tools = false +std-features = ["panic-unwind", "compiler-builtins-no-f16-f128"] EOF popd From 2a0cd874a977bbe49077ca0e46805ed6201d7d30 Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Wed, 12 Mar 2025 17:50:02 +0800 Subject: [PATCH 113/546] Add stack overflow handler for cygwin --- .../std/src/sys/pal/unix/stack_overflow.rs | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 0ecccdc8812d..4bd0cedd44cc 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -585,6 +585,7 @@ mod imp { target_os = "openbsd", target_os = "solaris", target_os = "illumos", + target_os = "cygwin", )))] mod imp { pub unsafe fn init() {} @@ -597,3 +598,89 @@ mod imp { pub unsafe fn drop_handler(_data: *mut libc::c_void) {} } + +#[cfg(target_os = "cygwin")] +mod imp { + mod c { + pub type PVECTORED_EXCEPTION_HANDLER = + Option i32>; + pub type NTSTATUS = i32; + pub type BOOL = i32; + + unsafe extern "system" { + pub fn AddVectoredExceptionHandler( + first: u32, + handler: PVECTORED_EXCEPTION_HANDLER, + ) -> *mut core::ffi::c_void; + pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL; + } + + pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _; + pub const EXCEPTION_CONTINUE_SEARCH: i32 = 1i32; + + #[repr(C)] + #[derive(Clone, Copy)] + pub struct EXCEPTION_POINTERS { + pub ExceptionRecord: *mut EXCEPTION_RECORD, + // We don't need this field here + // pub Context: *mut CONTEXT, + } + #[repr(C)] + #[derive(Clone, Copy)] + pub struct EXCEPTION_RECORD { + pub ExceptionCode: NTSTATUS, + pub ExceptionFlags: u32, + pub ExceptionRecord: *mut EXCEPTION_RECORD, + pub ExceptionAddress: *mut core::ffi::c_void, + pub NumberParameters: u32, + pub ExceptionInformation: [usize; 15], + } + } + + /// Reserve stack space for use in stack overflow exceptions. + fn reserve_stack() { + let result = unsafe { c::SetThreadStackGuarantee(&mut 0x5000) }; + // Reserving stack space is not critical so we allow it to fail in the released build of libstd. + // We still use debug assert here so that CI will test that we haven't made a mistake calling the function. + debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling"); + } + + unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 { + // SAFETY: It's up to the caller (which in this case is the OS) to ensure that `ExceptionInfo` is valid. + unsafe { + let rec = &(*(*ExceptionInfo).ExceptionRecord); + let code = rec.ExceptionCode; + + if code == c::EXCEPTION_STACK_OVERFLOW { + crate::thread::with_current_name(|name| { + let name = name.unwrap_or(""); + rtprintpanic!("\nthread '{name}' has overflowed its stack\n"); + }); + } + c::EXCEPTION_CONTINUE_SEARCH + } + } + + pub unsafe fn init() { + // SAFETY: `vectored_handler` has the correct ABI and is safe to call during exception handling. + unsafe { + let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler)); + // Similar to the above, adding the stack overflow handler is allowed to fail + // but a debug assert is used so CI will still test that it normally works. + debug_assert!(!result.is_null(), "failed to install exception handler"); + } + // Set the thread stack guarantee for the main thread. + reserve_stack(); + } + + pub unsafe fn cleanup() {} + + pub unsafe fn make_handler(main_thread: bool) -> super::Handler { + if !main_thread { + reserve_stack(); + } + super::Handler::null() + } + + pub unsafe fn drop_handler(_data: *mut libc::c_void) {} +} From a3669b89825e6f1aabaa3e3993c1a9f9d7b70306 Mon Sep 17 00:00:00 2001 From: "aaishwarymishra@gmail.com" Date: Wed, 12 Mar 2025 16:54:14 +0530 Subject: [PATCH 114/546] updated compiler tests for rustc_intrinsic' Update compiler/rustc_error_codes/src/error_codes/E0622.md Co-authored-by: Ralf Jung reverted chages on E0622.md updated E0622.md --- compiler/rustc_error_codes/src/error_codes/E0092.md | 12 +++++------- compiler/rustc_error_codes/src/error_codes/E0093.md | 10 ++++------ compiler/rustc_error_codes/src/error_codes/E0211.md | 10 ++++------ compiler/rustc_error_codes/src/error_codes/E0511.md | 10 ++++------ 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md index 84ec0656d1ac..be459d040c28 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0092.md +++ b/compiler/rustc_error_codes/src/error_codes/E0092.md @@ -6,10 +6,9 @@ Erroneous code example: #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn atomic_foo(); // error: unrecognized atomic operation - // function -} +#[rustc_intrinsic] +unsafe fn atomic_foo(); // error: unrecognized atomic operation + // function ``` Please check you didn't make a mistake in the function's name. All intrinsic @@ -20,7 +19,6 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn atomic_fence_seqcst(); // ok! -} +#[rustc_intrinsic] +unsafe fn atomic_fence_seqcst(); // ok! ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md index 2bda4d74f726..9929a0699273 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0093.md +++ b/compiler/rustc_error_codes/src/error_codes/E0093.md @@ -6,9 +6,8 @@ Erroneous code example: #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn foo(); // error: unrecognized intrinsic function: `foo` -} +#[rustc_intrinsic] +unsafe fn foo(); // error: unrecognized intrinsic function: `foo` fn main() { unsafe { @@ -25,9 +24,8 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn atomic_fence_seqcst(); // ok! -} +#[rustc_intrinsic] +unsafe fn atomic_fence_seqcst(); // ok! fn main() { unsafe { diff --git a/compiler/rustc_error_codes/src/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md index 7aa42628549f..c702f14d4d6d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0211.md +++ b/compiler/rustc_error_codes/src/error_codes/E0211.md @@ -7,9 +7,8 @@ used. Erroneous code examples: #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn unreachable(); // error: intrinsic has wrong type -} +#[rustc_intrinsic] +unsafe fn unreachable(); // error: intrinsic has wrong type // or: @@ -43,9 +42,8 @@ For the first code example, please check the function definition. Example: #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn unreachable() -> !; // ok! -} +#[rustc_intrinsic] +unsafe fn unreachable() -> !; // ok! ``` The second case example is a bit particular: the main function must always diff --git a/compiler/rustc_error_codes/src/error_codes/E0511.md b/compiler/rustc_error_codes/src/error_codes/E0511.md index 45ff49bdebb2..0fb1cfda67dc 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0511.md +++ b/compiler/rustc_error_codes/src/error_codes/E0511.md @@ -5,9 +5,8 @@ Erroneous code example: ```compile_fail,E0511 #![feature(intrinsics)] -extern "rust-intrinsic" { - fn simd_add(a: T, b: T) -> T; -} +#[rustc_intrinsic] +unsafe fn simd_add(a: T, b: T) -> T; fn main() { unsafe { simd_add(0, 1); } @@ -25,9 +24,8 @@ The generic type has to be a SIMD type. Example: #[derive(Copy, Clone)] struct i32x2([i32; 2]); -extern "rust-intrinsic" { - fn simd_add(a: T, b: T) -> T; -} +#[rustc_intrinsic] +unsafe fn simd_add(a: T, b: T) -> T; unsafe { simd_add(i32x2([0, 0]), i32x2([1, 2])); } // ok! ``` From 3bfb6af978868f89785126e37e149136bf581655 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Mar 2025 16:43:39 +0000 Subject: [PATCH 115/546] Test windows file type equality --- library/std/src/fs/tests.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 6dd18e4f4c83..4712e58980cc 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1719,6 +1719,23 @@ fn test_eq_direntry_metadata() { } } +/// Test that windows file type equality is not affected by attributes unrelated +/// to the file type. +#[test] +#[cfg(target_os = "windows")] +fn test_eq_windows_file_type() { + let tmpdir = tmpdir(); + let file1 = File::create(tmpdir.join("file1")).unwrap(); + let file2 = File::create(tmpdir.join("file2")).unwrap(); + assert_eq!(file1.metadata().unwrap().file_type(), file2.metadata().unwrap().file_type()); + + // Change the readonly attribute of one file. + let mut perms = file1.metadata().unwrap().permissions(); + perms.set_readonly(true); + file1.set_permissions(perms).unwrap(); + assert_eq!(file1.metadata().unwrap().file_type(), file2.metadata().unwrap().file_type()); +} + /// Regression test for https://github.com/rust-lang/rust/issues/50619. #[test] #[cfg(target_os = "linux")] From 68267d0aedfda5db4dc9d233f02fd31d7c53d02f Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 19 Mar 2025 02:05:01 +0900 Subject: [PATCH 116/546] Fix build failure on Trusty --- library/std/src/sys/random/trusty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/random/trusty.rs b/library/std/src/sys/random/trusty.rs index da6ca3eea242..e4db24695f8b 100644 --- a/library/std/src/sys/random/trusty.rs +++ b/library/std/src/sys/random/trusty.rs @@ -1,4 +1,4 @@ -extern "C" { +unsafe extern "C" { fn trusty_rng_secure_rand(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t); } From 6b2fa32f142f341ba227b5ea784ea2a1a5e79fe8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Mar 2025 16:27:24 +0000 Subject: [PATCH 117/546] Windows: fix FileType PartialEq implementation --- library/std/src/sys/fs/windows.rs | 33 ++++++++++++++----------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 362e64abf1ac..06bba019393a 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -41,8 +41,8 @@ pub struct FileAttr { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct FileType { - attributes: u32, - reparse_tag: u32, + is_directory: bool, + is_symlink: bool, } pub struct ReadDir { @@ -1111,32 +1111,29 @@ impl FileTimes { } impl FileType { - fn new(attrs: u32, reparse_tag: u32) -> FileType { - FileType { attributes: attrs, reparse_tag } + fn new(attributes: u32, reparse_tag: u32) -> FileType { + let is_directory = attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0; + let is_symlink = { + let is_reparse_point = attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0; + let is_reparse_tag_name_surrogate = reparse_tag & 0x20000000 != 0; + is_reparse_point && is_reparse_tag_name_surrogate + }; + FileType { is_directory, is_symlink } } pub fn is_dir(&self) -> bool { - !self.is_symlink() && self.is_directory() + !self.is_symlink && self.is_directory } pub fn is_file(&self) -> bool { - !self.is_symlink() && !self.is_directory() + !self.is_symlink && !self.is_directory } pub fn is_symlink(&self) -> bool { - self.is_reparse_point() && self.is_reparse_tag_name_surrogate() + self.is_symlink } pub fn is_symlink_dir(&self) -> bool { - self.is_symlink() && self.is_directory() + self.is_symlink && self.is_directory } pub fn is_symlink_file(&self) -> bool { - self.is_symlink() && !self.is_directory() - } - fn is_directory(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 - } - fn is_reparse_point(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 - } - fn is_reparse_tag_name_surrogate(&self) -> bool { - self.reparse_tag & 0x20000000 != 0 + self.is_symlink && !self.is_directory } } From 1f64cb7e63943dd60df05f7ae06e0ae5a4724d43 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 18 Mar 2025 10:44:52 -0700 Subject: [PATCH 118/546] Add release notes for 1.85.1 --- RELEASES.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 381b9ebc952e..58df0b00d50a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,14 @@ +Version 1.85.1 (2025-03-18) +========================== + + + +- [Fix the doctest-merging feature of the 2024 Edition.](https://github.com/rust-lang/rust/pull/137899/) +- [Relax some `target_feature` checks when generating docs.](https://github.com/rust-lang/rust/pull/137632/) +- [Fix errors in `std::fs::rename` on Windows 1607.](https://github.com/rust-lang/rust/pull/137528/) +- [Downgrade bootstrap `cc` to fix custom targets.](https://github.com/rust-lang/rust/pull/137460/) +- [Skip submodule updates when building Rust from a source tarball.](https://github.com/rust-lang/rust/pull/137338/) + Version 1.85.0 (2025-02-20) ========================== From 795a6669f83274ce3ada1046e6c9284b8e900a98 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Tue, 18 Mar 2025 16:32:09 -0400 Subject: [PATCH 119/546] rustc_resolve: fix instability in lib.rmeta contents rust-lang/rust@23032f31c91f2 accidentally introduced some nondeterminism in the ordering of lib.rmeta files, which we caught in our bazel-based builds only recently due to being further behind than normal. In my testing, this fixes the issue. --- Cargo.lock | 1 + compiler/rustc_resolve/Cargo.toml | 1 + compiler/rustc_resolve/src/rustdoc.rs | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 63a3f5dd0377..67ddac6032b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4316,6 +4316,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "bitflags", + "itertools", "pulldown-cmark 0.11.3", "rustc_arena", "rustc_ast", diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index f4771f1af2cf..9ea9c58cfd17 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" +itertools = "0.12" pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 52aaab77ebed..9fda1eb4dc45 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -1,6 +1,7 @@ use std::mem; use std::ops::Range; +use itertools::Itertools; use pulldown_cmark::{ BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, Options, Parser, Tag, }; @@ -454,7 +455,7 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { } } - for (label, refdef) in event_iter.reference_definitions().iter() { + for (label, refdef) in event_iter.reference_definitions().iter().sorted_by_key(|x| x.0) { if !refids.contains(label) { links.push(preprocess_link(&refdef.dest)); } From bf374475c87f23690a0228ec945b48908786ff38 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 19 Mar 2025 14:43:51 +0800 Subject: [PATCH 120/546] Reject `{true,false}` as revision names Because they would imply `--cfg={true,false}` otherwise, and the test writer has to use `cfg(r#true)` and `cfg(r#false)` in the test. --- src/tools/compiletest/src/header.rs | 38 +++++++++++++++++------ src/tools/compiletest/src/header/tests.rs | 7 +++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 7675e13990d6..fb2b90d74bda 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -924,7 +924,14 @@ fn iter_header( impl Config { fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec) { - const FORBIDDEN_REVISION_NAMES: [&str; 9] = + const FORBIDDEN_REVISION_NAMES: [&str; 2] = [ + // `//@ revisions: true false` Implying `--cfg=true` and `--cfg=false` makes it very + // weird for the test, since if the test writer wants a cfg of the same revision name + // they'd have to use `cfg(r#true)` and `cfg(r#false)`. + "true", "false", + ]; + + const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] = ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"]; if let Some(raw) = self.parse_name_value_directive(line, "revisions") { @@ -933,25 +940,38 @@ impl Config { } let mut duplicates: HashSet<_> = existing.iter().cloned().collect(); - for revision in raw.split_whitespace().map(|r| r.to_string()) { - if !duplicates.insert(revision.clone()) { + for revision in raw.split_whitespace() { + if !duplicates.insert(revision.to_string()) { panic!( "duplicate revision: `{}` in line `{}`: {}", revision, raw, testfile.display() ); - } else if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt) - && FORBIDDEN_REVISION_NAMES.contains(&revision.as_str()) - { + } + + if FORBIDDEN_REVISION_NAMES.contains(&revision) { panic!( - "revision name `{revision}` is not permitted in a test suite that uses `FileCheck` annotations\n\ - as it is confusing when used as custom `FileCheck` prefix: `{revision}` in line `{}`: {}", + "revision name `{revision}` is not permitted: `{}` in line `{}`: {}", + revision, raw, testfile.display() ); } - existing.push(revision); + + if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt) + && FILECHECK_FORBIDDEN_REVISION_NAMES.contains(&revision) + { + panic!( + "revision name `{revision}` is not permitted in a test suite that uses \ + `FileCheck` annotations as it is confusing when used as custom `FileCheck` \ + prefix: `{revision}` in line `{}`: {}", + raw, + testfile.display() + ); + } + + existing.push(revision.to_string()); } } } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 007318be7cc3..4d90f152ee20 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -567,6 +567,13 @@ fn test_assembly_mode_forbidden_revisions() { parse_rs(&config, "//@ revisions: CHECK"); } +#[test] +#[should_panic(expected = "revision name `true` is not permitted")] +fn test_forbidden_revisions() { + let config = cfg().mode("ui").build(); + parse_rs(&config, "//@ revisions: true"); +} + #[test] #[should_panic( expected = "revision name `CHECK` is not permitted in a test suite that uses `FileCheck` annotations" From 39efa7c590a9e0d761550005d161a9356a54339a Mon Sep 17 00:00:00 2001 From: Vladyslav Tsilytskyi Date: Mon, 17 Mar 2025 14:19:55 +0100 Subject: [PATCH 121/546] Make default_codegen_backend serializable --- compiler/rustc_target/src/spec/json.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 134405f3630e..4b6de5e18f50 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -103,6 +103,12 @@ impl Target { base.$key_name = Some(s); } } ); + ($key_name:ident, Option>) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(s) = obj.remove(&name).and_then(|b| Some(b.as_str()?.to_string())) { + base.$key_name = Some(s.into()); + } + } ); ($key_name:ident, BinaryFormat) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|f| f.as_str().and_then(|s| { @@ -623,6 +629,7 @@ impl Target { key!(stack_probes, StackProbeType)?; key!(min_global_align, Option); key!(default_codegen_units, Option); + key!(default_codegen_backend, Option>); key!(trap_unreachable, bool); key!(requires_lto, bool); key!(singlethread, bool); @@ -801,6 +808,7 @@ impl ToJson for Target { target_option_val!(stack_probes); target_option_val!(min_global_align); target_option_val!(default_codegen_units); + target_option_val!(default_codegen_backend); target_option_val!(trap_unreachable); target_option_val!(requires_lto); target_option_val!(singlethread); From f23e76e0d273b2c7612421b2d8505f84c9ea480f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Mar 2025 12:49:18 +0100 Subject: [PATCH 122/546] Allow spawning threads after TLS destruction. --- library/std/src/thread/spawnhook.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index 99b5ad9cb9fe..98f471ad54b2 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -113,18 +113,23 @@ where pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks { // Get a snapshot of the spawn hooks. // (Increments the refcount to the first node.) - let hooks = SPAWN_HOOKS.with(|hooks| { + if let Ok(hooks) = SPAWN_HOOKS.try_with(|hooks| { let snapshot = hooks.take(); hooks.set(snapshot.clone()); snapshot - }); - // Iterate over the hooks, run them, and collect the results in a vector. - let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref()) - .map(|hook| (hook.hook)(thread)) - .collect(); - // Pass on the snapshot of the hooks and the results to the new thread, - // which will then run SpawnHookResults::run(). - ChildSpawnHooks { hooks, to_run } + }) { + // Iterate over the hooks, run them, and collect the results in a vector. + let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref()) + .map(|hook| (hook.hook)(thread)) + .collect(); + // Pass on the snapshot of the hooks and the results to the new thread, + // which will then run SpawnHookResults::run(). + ChildSpawnHooks { hooks, to_run } + } else { + // TLS has been destroyed. Skip running the hooks. + // See https://github.com/rust-lang/rust/issues/138696 + ChildSpawnHooks::default() + } } /// The results of running the spawn hooks. From 5912dadf08fa2b29f723ec2c2b2315399a75c06e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Mar 2025 12:49:41 +0100 Subject: [PATCH 123/546] Add test. --- tests/ui/thread-local/spawn-hook-atexit.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/ui/thread-local/spawn-hook-atexit.rs diff --git a/tests/ui/thread-local/spawn-hook-atexit.rs b/tests/ui/thread-local/spawn-hook-atexit.rs new file mode 100644 index 000000000000..cc517e8fa4c6 --- /dev/null +++ b/tests/ui/thread-local/spawn-hook-atexit.rs @@ -0,0 +1,22 @@ +// Regression test for https://github.com/rust-lang/rust/issues/138696 +//@ run-pass + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + std::thread::spawn(|| { + unsafe { libc::atexit(spawn_in_atexit) }; + }) + .join() + .unwrap(); +} + +extern "C" fn spawn_in_atexit() { + std::thread::spawn(|| { + println!("Thread spawned in atexit"); + }) + .join() + .unwrap(); +} From 599dc823c9d7049e8ee9eb80203a24cac41cb124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 16 Mar 2025 13:23:41 +0100 Subject: [PATCH 124/546] Simplify `get_git_modified_files` It only ever returned `Some`, so `Option` was useless in its return type. --- src/bootstrap/src/core/build_steps/format.rs | 2 +- src/build_helper/src/git.rs | 4 ++-- src/tools/compiletest/src/lib.rs | 3 +-- src/tools/suggest-tests/src/main.rs | 6 +----- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 9817e47baa10..3435c1773c27 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -94,7 +94,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result>, Str return Ok(None); } - get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]) + get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]).map(Some) } #[derive(serde_derive::Deserialize)] diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 9f778a2fd774..ea473c8c3976 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -173,7 +173,7 @@ pub fn get_git_modified_files( config: &GitConfig<'_>, git_dir: Option<&Path>, extensions: &[&str], -) -> Result>, String> { +) -> Result, String> { let merge_base = get_closest_merge_commit(git_dir, config, &[])?; let mut git = Command::new("git"); @@ -195,7 +195,7 @@ pub fn get_git_modified_files( } }) .collect(); - Ok(Some(files)) + Ok(files) } /// Returns the files that haven't been added to git yet. diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index dd611b19a8d0..3ec984edacbe 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -747,8 +747,7 @@ fn modified_tests(config: &Config, dir: &Path) -> Result, String> { } let files = - get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])? - .unwrap_or(vec![]); + get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?; // Add new test cases to the list, it will be convenient in daily development. let untracked_files = get_git_untracked_files(&config.git_config(), None)?.unwrap_or(vec![]); diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs index ee8cc40404d4..ee212af36260 100644 --- a/src/tools/suggest-tests/src/main.rs +++ b/src/tools/suggest-tests/src/main.rs @@ -14,11 +14,7 @@ fn main() -> ExitCode { &Vec::new(), ); let modified_files = match modified_files { - Ok(Some(files)) => files, - Ok(None) => { - eprintln!("git error"); - return ExitCode::FAILURE; - } + Ok(files) => files, Err(err) => { eprintln!("Could not get modified files from git: \"{err}\""); return ExitCode::FAILURE; From 2139a783b0c08f6d2718d88112bc50988006daab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 16 Mar 2025 13:26:30 +0100 Subject: [PATCH 125/546] Fix bug in `get_git_modified_files` It was ignoring files without extension. --- src/build_helper/src/git.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index ea473c8c3976..8d737450444a 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -186,7 +186,10 @@ pub fn get_git_modified_files( let (status, name) = f.trim().split_once(char::is_whitespace).unwrap(); if status == "D" { None - } else if Path::new(name).extension().map_or(false, |ext| { + } else if Path::new(name).extension().map_or(extensions.is_empty(), |ext| { + // If there is no extension, we allow the path if `extensions` is empty + // If there is an extension, we allow it if `extension` is empty or it contains the + // extension. extensions.is_empty() || extensions.contains(&ext.to_str().unwrap()) }) { Some(name.to_owned()) From b24dc75ee46c702404d6137e402f967876b0b68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 19 Mar 2025 10:31:12 +0100 Subject: [PATCH 126/546] Respect `--src` bootstrap flag Previously it was simply ignored. --- src/bootstrap/src/core/config/config.rs | 94 +++++++++++++------------ 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f8ed8072c3df..88ed786582ee 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1425,52 +1425,56 @@ impl Config { // Infer the rest of the configuration. - // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary, - // running on a completely different machine from where it was compiled. - let mut cmd = helpers::git(None); - // NOTE: we cannot support running from outside the repository because the only other path we have available - // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally. - // We still support running outside the repository if we find we aren't in a git directory. - - // NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path, - // and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap - // has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path. - cmd.arg("rev-parse").arg("--show-cdup"); - // Discard stderr because we expect this to fail when building from a tarball. - let output = cmd - .as_command_mut() - .stderr(std::process::Stdio::null()) - .output() - .ok() - .and_then(|output| if output.status.success() { Some(output) } else { None }); - if let Some(output) = output { - let git_root_relative = String::from_utf8(output.stdout).unwrap(); - // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes, - // and to resolve any relative components. - let git_root = env::current_dir() - .unwrap() - .join(PathBuf::from(git_root_relative.trim())) - .canonicalize() - .unwrap(); - let s = git_root.to_str().unwrap(); - - // Bootstrap is quite bad at handling /? in front of paths - let git_root = match s.strip_prefix("\\\\?\\") { - Some(p) => PathBuf::from(p), - None => git_root, - }; - // If this doesn't have at least `stage0`, we guessed wrong. This can happen when, - // for example, the build directory is inside of another unrelated git directory. - // In that case keep the original `CARGO_MANIFEST_DIR` handling. - // - // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside - // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1. - if git_root.join("src").join("stage0").exists() { - config.src = git_root; - } + if let Some(src) = flags.src { + config.src = src } else { - // We're building from a tarball, not git sources. - // We don't support pre-downloaded bootstrap in this case. + // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary, + // running on a completely different machine from where it was compiled. + let mut cmd = helpers::git(None); + // NOTE: we cannot support running from outside the repository because the only other path we have available + // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally. + // We still support running outside the repository if we find we aren't in a git directory. + + // NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path, + // and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap + // has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path. + cmd.arg("rev-parse").arg("--show-cdup"); + // Discard stderr because we expect this to fail when building from a tarball. + let output = cmd + .as_command_mut() + .stderr(std::process::Stdio::null()) + .output() + .ok() + .and_then(|output| if output.status.success() { Some(output) } else { None }); + if let Some(output) = output { + let git_root_relative = String::from_utf8(output.stdout).unwrap(); + // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes, + // and to resolve any relative components. + let git_root = env::current_dir() + .unwrap() + .join(PathBuf::from(git_root_relative.trim())) + .canonicalize() + .unwrap(); + let s = git_root.to_str().unwrap(); + + // Bootstrap is quite bad at handling /? in front of paths + let git_root = match s.strip_prefix("\\\\?\\") { + Some(p) => PathBuf::from(p), + None => git_root, + }; + // If this doesn't have at least `stage0`, we guessed wrong. This can happen when, + // for example, the build directory is inside of another unrelated git directory. + // In that case keep the original `CARGO_MANIFEST_DIR` handling. + // + // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside + // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1. + if git_root.join("src").join("stage0").exists() { + config.src = git_root; + } + } else { + // We're building from a tarball, not git sources. + // We don't support pre-downloaded bootstrap in this case. + } } if cfg!(test) { From 9b88fd09d73b3808d8ff5a8cf3d68a0ca5ac1ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 19 Mar 2025 15:35:47 +0100 Subject: [PATCH 127/546] Update GCC submodule --- src/gcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gcc b/src/gcc index 48664a6cab29..13cc8243226a 160000 --- a/src/gcc +++ b/src/gcc @@ -1 +1 @@ -Subproject commit 48664a6cab29d48138ffa004b7978d52ef73e3ac +Subproject commit 13cc8243226a9028bb08ab6c5e1c5fe6d533bcdf From b54ca0e433e9cf5ef139aeebb36133be8ddee111 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 6 Mar 2025 15:09:14 -0800 Subject: [PATCH 128/546] Add a MIR pre-codegen test for tuple comparisons We have codegen ones, but it looks like we could make those less flakey by just doing something better in the first place... --- ...e_ord.demo_ge_partial.PreCodegen.after.mir | 237 ++++++++++++++++++ ...ple_ord.demo_le_total.PreCodegen.after.mir | 145 +++++++++++ tests/mir-opt/pre-codegen/tuple_ord.rs | 16 ++ 3 files changed, 398 insertions(+) create mode 100644 tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir create mode 100644 tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir create mode 100644 tests/mir-opt/pre-codegen/tuple_ord.rs diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir new file mode 100644 index 000000000000..696a45117779 --- /dev/null +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir @@ -0,0 +1,237 @@ +// MIR for `demo_ge_partial` after PreCodegen + +fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool { + debug a => _1; + debug b => _2; + let mut _0: bool; + scope 1 (inlined std::cmp::impls::::le) { + scope 2 (inlined core::tuple::::le) { + let mut _12: bool; + let _15: std::option::Option; + let _19: &f32; + let _20: &f32; + scope 3 { + let mut _9: &std::option::Option; + let mut _13: &std::option::Option; + scope 4 (inlined as PartialEq>::ne) { + let mut _11: bool; + scope 5 (inlined as PartialEq>::eq) { + let mut _10: isize; + let mut _16: isize; + scope 6 { + scope 7 (inlined ::eq) { + let _17: i8; + scope 8 { + let _18: i8; + scope 9 { + } + } + } + } + } + } + scope 10 (inlined as PartialEq>::eq) { + let mut _14: isize; + let mut _21: isize; + scope 11 { + scope 12 (inlined ::eq) { + let _22: i8; + scope 13 { + let _23: i8; + scope 14 { + } + } + } + } + } + } + scope 15 (inlined std::cmp::impls::::partial_cmp) { + let mut _3: f32; + let mut _4: f32; + let mut _5: bool; + let mut _6: f32; + let mut _7: f32; + let mut _8: bool; + } + } + } + + bb0: { + StorageLive(_19); + StorageLive(_20); + StorageLive(_13); + StorageLive(_9); + StorageLive(_15); + StorageLive(_5); + StorageLive(_8); + StorageLive(_3); + _3 = copy ((*_1).0: f32); + StorageLive(_4); + _4 = copy ((*_2).0: f32); + _5 = Le(move _3, move _4); + StorageDead(_4); + StorageDead(_3); + StorageLive(_6); + _6 = copy ((*_1).0: f32); + StorageLive(_7); + _7 = copy ((*_2).0: f32); + _8 = Ge(move _6, move _7); + StorageDead(_7); + StorageDead(_6); + switchInt(copy _5) -> [0: bb1, otherwise: bb5]; + } + + bb1: { + switchInt(copy _8) -> [0: bb2, otherwise: bb4]; + } + + bb2: { + StorageDead(_8); + StorageDead(_5); + StorageLive(_12); + _9 = const core::tuple::::le::promoted[1]; + StorageLive(_11); + StorageLive(_16); + StorageLive(_10); + _10 = discriminant((*_9)); + _11 = Eq(copy _10, const 0_isize); + StorageDead(_10); + StorageDead(_16); + _12 = Not(move _11); + StorageDead(_11); + switchInt(move _12) -> [0: bb11, otherwise: bb3]; + } + + bb3: { + _13 = const core::tuple::::le::promoted[0]; + StorageLive(_21); + StorageLive(_14); + _14 = discriminant((*_13)); + _0 = Eq(copy _14, const 0_isize); + goto -> bb16; + } + + bb4: { + _15 = const Option::::Some(Greater); + StorageDead(_8); + StorageDead(_5); + StorageLive(_12); + _9 = const core::tuple::::le::promoted[1]; + StorageLive(_11); + StorageLive(_16); + StorageLive(_10); + goto -> bb8; + } + + bb5: { + switchInt(copy _8) -> [0: bb6, otherwise: bb7]; + } + + bb6: { + _15 = const Option::::Some(Less); + StorageDead(_8); + StorageDead(_5); + StorageLive(_12); + _9 = const core::tuple::::le::promoted[1]; + StorageLive(_11); + StorageLive(_16); + StorageLive(_10); + goto -> bb8; + } + + bb7: { + _15 = const Option::::Some(Equal); + StorageDead(_8); + StorageDead(_5); + StorageLive(_12); + _9 = const core::tuple::::le::promoted[1]; + StorageLive(_11); + StorageLive(_16); + StorageLive(_10); + goto -> bb8; + } + + bb8: { + _16 = discriminant((*_9)); + switchInt(move _16) -> [0: bb9, 1: bb10, otherwise: bb18]; + } + + bb9: { + StorageDead(_10); + StorageDead(_16); + StorageDead(_11); + _13 = const core::tuple::::le::promoted[0]; + StorageLive(_21); + StorageLive(_14); + goto -> bb13; + } + + bb10: { + StorageLive(_17); + StorageLive(_18); + _17 = discriminant(((_15 as Some).0: std::cmp::Ordering)); + _18 = discriminant((((*_9) as Some).0: std::cmp::Ordering)); + _11 = Eq(copy _17, copy _18); + StorageDead(_18); + StorageDead(_17); + StorageDead(_10); + StorageDead(_16); + _12 = Not(move _11); + StorageDead(_11); + switchInt(move _12) -> [0: bb11, otherwise: bb12]; + } + + bb11: { + _19 = &((*_1).1: f32); + _20 = &((*_2).1: f32); + _0 = ::le(move _19, move _20) -> [return: bb17, unwind continue]; + } + + bb12: { + _13 = const core::tuple::::le::promoted[0]; + StorageLive(_21); + StorageLive(_14); + goto -> bb13; + } + + bb13: { + _21 = discriminant((*_13)); + switchInt(move _21) -> [0: bb14, 1: bb15, otherwise: bb18]; + } + + bb14: { + _0 = const false; + goto -> bb16; + } + + bb15: { + StorageLive(_22); + StorageLive(_23); + _22 = discriminant(((_15 as Some).0: std::cmp::Ordering)); + _23 = discriminant((((*_13) as Some).0: std::cmp::Ordering)); + _0 = Eq(copy _22, copy _23); + StorageDead(_23); + StorageDead(_22); + goto -> bb16; + } + + bb16: { + StorageDead(_14); + StorageDead(_21); + goto -> bb17; + } + + bb17: { + StorageDead(_12); + StorageDead(_15); + StorageDead(_9); + StorageDead(_13); + StorageDead(_20); + StorageDead(_19); + return; + } + + bb18: { + unreachable; + } +} diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir new file mode 100644 index 000000000000..15c3ae76ae93 --- /dev/null +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir @@ -0,0 +1,145 @@ +// MIR for `demo_le_total` after PreCodegen + +fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool { + debug a => _1; + debug b => _2; + let mut _0: bool; + scope 1 (inlined std::cmp::impls::::le) { + scope 2 (inlined core::tuple::::le) { + let mut _12: bool; + let _13: &i16; + let _14: &i16; + scope 3 { + let mut _6: &std::option::Option; + let mut _8: &std::option::Option; + scope 4 (inlined as PartialEq>::ne) { + let mut _11: bool; + scope 5 (inlined as PartialEq>::eq) { + let mut _7: isize; + scope 6 { + scope 7 (inlined ::eq) { + let _9: i8; + scope 8 { + let _10: i8; + scope 9 { + } + } + } + } + } + } + scope 10 (inlined as PartialEq>::eq) { + let mut _15: isize; + scope 11 { + scope 12 (inlined ::eq) { + let _16: i8; + scope 13 { + let _17: i8; + scope 14 { + } + } + } + } + } + } + scope 15 (inlined std::cmp::impls::::partial_cmp) { + let mut _3: u16; + let mut _4: u16; + let mut _5: std::cmp::Ordering; + } + } + } + + bb0: { + StorageLive(_13); + StorageLive(_14); + StorageLive(_8); + StorageLive(_6); + StorageLive(_3); + _3 = copy ((*_1).0: u16); + StorageLive(_4); + _4 = copy ((*_2).0: u16); + _5 = Cmp(move _3, move _4); + StorageDead(_4); + StorageDead(_3); + StorageLive(_12); + _6 = const core::tuple::::le::promoted[1]; + StorageLive(_11); + StorageLive(_7); + _7 = discriminant((*_6)); + switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb10]; + } + + bb1: { + StorageDead(_7); + StorageDead(_11); + _8 = const core::tuple::::le::promoted[0]; + StorageLive(_15); + goto -> bb5; + } + + bb2: { + StorageLive(_9); + StorageLive(_10); + _9 = discriminant(_5); + _10 = discriminant((((*_6) as Some).0: std::cmp::Ordering)); + _11 = Eq(copy _9, copy _10); + StorageDead(_10); + StorageDead(_9); + StorageDead(_7); + _12 = Not(move _11); + StorageDead(_11); + switchInt(move _12) -> [0: bb3, otherwise: bb4]; + } + + bb3: { + _13 = &((*_1).1: i16); + _14 = &((*_2).1: i16); + _0 = ::le(move _13, move _14) -> [return: bb9, unwind continue]; + } + + bb4: { + _8 = const core::tuple::::le::promoted[0]; + StorageLive(_15); + goto -> bb5; + } + + bb5: { + _15 = discriminant((*_8)); + switchInt(move _15) -> [0: bb6, 1: bb7, otherwise: bb10]; + } + + bb6: { + _0 = const false; + goto -> bb8; + } + + bb7: { + StorageLive(_16); + StorageLive(_17); + _16 = discriminant(_5); + _17 = discriminant((((*_8) as Some).0: std::cmp::Ordering)); + _0 = Eq(copy _16, copy _17); + StorageDead(_17); + StorageDead(_16); + goto -> bb8; + } + + bb8: { + StorageDead(_15); + goto -> bb9; + } + + bb9: { + StorageDead(_12); + StorageDead(_6); + StorageDead(_8); + StorageDead(_14); + StorageDead(_13); + return; + } + + bb10: { + unreachable; + } +} diff --git a/tests/mir-opt/pre-codegen/tuple_ord.rs b/tests/mir-opt/pre-codegen/tuple_ord.rs new file mode 100644 index 000000000000..435ac7a5be93 --- /dev/null +++ b/tests/mir-opt/pre-codegen/tuple_ord.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0 -Z inline-mir-hint-threshold=9999 +//@ needs-unwind + +#![crate_type = "lib"] + +// EMIT_MIR tuple_ord.demo_le_total.PreCodegen.after.mir +pub fn demo_le_total(a: &(u16, i16), b: &(u16, i16)) -> bool { + // CHECK-LABEL: demo_le_total + a <= b +} + +// EMIT_MIR tuple_ord.demo_ge_partial.PreCodegen.after.mir +pub fn demo_ge_partial(a: &(f32, f32), b: &(f32, f32)) -> bool { + // CHECK-LABEL: demo_ge_partial + a <= b +} From 35248c6830383e67b8e2890ddd5ee48d44ad6b87 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 6 Mar 2025 15:55:40 -0800 Subject: [PATCH 129/546] Add chaining versions of lt/le/gt/ge and use them in tuple PartialOrd --- library/core/src/cmp.rs | 84 ++++++ library/core/src/tuple.rs | 25 +- ...e_ord.demo_ge_partial.PreCodegen.after.mir | 243 +++--------------- ...ple_ord.demo_le_total.PreCodegen.after.mir | 147 +++-------- tests/mir-opt/pre-codegen/tuple_ord.rs | 4 +- 5 files changed, 174 insertions(+), 329 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 25bd17d5802f..af14c4b50725 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -29,6 +29,7 @@ mod bytewise; pub(crate) use bytewise::BytewiseEq; use self::Ordering::*; +use crate::ops::ControlFlow::{self, Break, Continue}; /// Trait for comparisons using the equality operator. /// @@ -1446,6 +1447,54 @@ pub macro PartialOrd($item:item) { /* compiler built-in */ } +/// Helpers for chaining together field PartialOrds into the full type's ordering. +/// +/// If the two values are equal, returns `ControlFlow::Continue`. +/// If the two values are not equal, returns `ControlFlow::Break(self OP other)`. +/// +/// This allows simple types like `i32` and `f64` to just emit two comparisons +/// directly, instead of needing to optimize the 3-way comparison. +/// +/// Currently this is done using specialization, but it doesn't need that: +/// it could be provided methods on `PartialOrd` instead and work fine. +pub(crate) trait SpecChainingPartialOrd: PartialOrd { + fn spec_chain_lt(&self, other: &Rhs) -> ControlFlow; + fn spec_chain_le(&self, other: &Rhs) -> ControlFlow; + fn spec_chain_gt(&self, other: &Rhs) -> ControlFlow; + fn spec_chain_ge(&self, other: &Rhs) -> ControlFlow; +} + +impl, U> SpecChainingPartialOrd for T { + #[inline] + default fn spec_chain_lt(&self, other: &U) -> ControlFlow { + match PartialOrd::partial_cmp(self, other) { + Some(Equal) => Continue(()), + c => Break(c.is_some_and(Ordering::is_lt)), + } + } + #[inline] + default fn spec_chain_le(&self, other: &U) -> ControlFlow { + match PartialOrd::partial_cmp(self, other) { + Some(Equal) => Continue(()), + c => Break(c.is_some_and(Ordering::is_le)), + } + } + #[inline] + default fn spec_chain_gt(&self, other: &U) -> ControlFlow { + match PartialOrd::partial_cmp(self, other) { + Some(Equal) => Continue(()), + c => Break(c.is_some_and(Ordering::is_gt)), + } + } + #[inline] + default fn spec_chain_ge(&self, other: &U) -> ControlFlow { + match PartialOrd::partial_cmp(self, other) { + Some(Equal) => Continue(()), + c => Break(c.is_some_and(Ordering::is_ge)), + } + } +} + /// Compares and returns the minimum of two values. /// /// Returns the first argument if the comparison determines them to be equal. @@ -1741,6 +1790,7 @@ where mod impls { use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::hint::unreachable_unchecked; + use crate::ops::ControlFlow::{self, Break, Continue}; macro_rules! partial_eq_impl { ($($t:ty)*) => ($( @@ -1779,6 +1829,36 @@ mod impls { eq_impl! { () bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + macro_rules! chaining_impl { + ($t:ty) => { + // These implementations are the same for `Ord` or `PartialOrd` types + // because if either is NAN the `==` test will fail so we end up in + // the `Break` case and the comparison will correctly return `false`. + impl super::SpecChainingPartialOrd<$t> for $t { + #[inline] + fn spec_chain_lt(&self, other: &Self) -> ControlFlow { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs < rhs) } + } + #[inline] + fn spec_chain_le(&self, other: &Self) -> ControlFlow { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs <= rhs) } + } + #[inline] + fn spec_chain_gt(&self, other: &Self) -> ControlFlow { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs > rhs) } + } + #[inline] + fn spec_chain_ge(&self, other: &Self) -> ControlFlow { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs >= rhs) } + } + } + }; + } + macro_rules! partial_ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] @@ -1801,6 +1881,8 @@ mod impls { #[inline(always)] fn gt(&self, other: &$t) -> bool { (*self) > (*other) } } + + chaining_impl!($t); )*) } @@ -1840,6 +1922,8 @@ mod impls { fn gt(&self, other: &$t) -> bool { (*self) > (*other) } } + chaining_impl!($t); + #[stable(feature = "rust1", since = "1.0.0")] impl Ord for $t { #[inline] diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 206b5b9e2c24..75faaa06ee7f 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,7 +1,9 @@ // See core/src/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; +use crate::cmp::SpecChainingPartialOrd; use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; +use crate::ops::ControlFlow::{Break, Continue}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -80,19 +82,19 @@ macro_rules! tuple_impls { } #[inline] fn lt(&self, other: &($($T,)+)) -> bool { - lexical_ord!(lt, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(lt, spec_chain_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn le(&self, other: &($($T,)+)) -> bool { - lexical_ord!(le, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(le, spec_chain_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn ge(&self, other: &($($T,)+)) -> bool { - lexical_ord!(ge, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(ge, spec_chain_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn gt(&self, other: &($($T,)+)) -> bool { - lexical_ord!(gt, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(gt, spec_chain_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } } } @@ -171,15 +173,16 @@ macro_rules! maybe_tuple_doc { // `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1, // a2, b2, a3, b3)` (and similarly for `lexical_cmp`) // -// `$ne_rel` is only used to determine the result after checking that they're -// not equal, so `lt` and `le` can both just use `Less`. +// `$chain_rel` is the method from `SpecChainingPartialOrd` to use for all but the +// final value, to produce better results for simple primitives. 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 c != Some(Equal) { c == Some($ne_rel) } - else { lexical_ord!($rel, $ne_rel, $($rest_a, $rest_b),+) } + ($rel: ident, $chain_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{ + match SpecChainingPartialOrd::$chain_rel(&$a, &$b) { + Break(val) => val, + Continue(()) => lexical_ord!($rel, $chain_rel, $($rest_a, $rest_b),+), + } }}; - ($rel: ident, $ne_rel: ident, $a:expr, $b:expr) => { + ($rel: ident, $chain_rel: ident, $a:expr, $b:expr) => { // Use the specific method for the last element PartialOrd::$rel(&$a, &$b) }; diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir index 696a45117779..6531683b6445 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir @@ -4,234 +4,67 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool { debug a => _1; debug b => _2; let mut _0: bool; - scope 1 (inlined std::cmp::impls::::le) { - scope 2 (inlined core::tuple::::le) { - let mut _12: bool; - let _15: std::option::Option; - let _19: &f32; - let _20: &f32; + scope 1 (inlined std::cmp::impls::::ge) { + scope 2 (inlined core::tuple::::ge) { + let mut _7: std::ops::ControlFlow; + let _8: bool; scope 3 { - let mut _9: &std::option::Option; - let mut _13: &std::option::Option; - scope 4 (inlined as PartialEq>::ne) { - let mut _11: bool; - scope 5 (inlined as PartialEq>::eq) { - let mut _10: isize; - let mut _16: isize; - scope 6 { - scope 7 (inlined ::eq) { - let _17: i8; - scope 8 { - let _18: i8; - scope 9 { - } - } - } - } - } - } - scope 10 (inlined as PartialEq>::eq) { - let mut _14: isize; - let mut _21: isize; - scope 11 { - scope 12 (inlined ::eq) { - let _22: i8; - scope 13 { - let _23: i8; - scope 14 { - } - } - } - } - } } - scope 15 (inlined std::cmp::impls::::partial_cmp) { + scope 4 (inlined std::cmp::impls:: for f32>::spec_chain_ge) { let mut _3: f32; let mut _4: f32; let mut _5: bool; - let mut _6: f32; - let mut _7: f32; - let mut _8: bool; + let mut _6: bool; + scope 5 { + } + } + scope 6 (inlined std::cmp::impls::::ge) { + let mut _9: f32; + let mut _10: f32; } } } bb0: { - StorageLive(_19); - StorageLive(_20); - StorageLive(_13); - StorageLive(_9); - StorageLive(_15); - StorageLive(_5); - StorageLive(_8); - StorageLive(_3); - _3 = copy ((*_1).0: f32); - StorageLive(_4); - _4 = copy ((*_2).0: f32); - _5 = Le(move _3, move _4); - StorageDead(_4); - StorageDead(_3); - StorageLive(_6); - _6 = copy ((*_1).0: f32); StorageLive(_7); - _7 = copy ((*_2).0: f32); - _8 = Ge(move _6, move _7); - StorageDead(_7); - StorageDead(_6); - switchInt(copy _5) -> [0: bb1, otherwise: bb5]; + StorageLive(_3); + StorageLive(_4); + _3 = copy ((*_1).0: f32); + _4 = copy ((*_2).0: f32); + StorageLive(_5); + _5 = Eq(copy _3, copy _4); + switchInt(move _5) -> [0: bb1, otherwise: bb2]; } bb1: { - switchInt(copy _8) -> [0: bb2, otherwise: bb4]; + StorageLive(_6); + _6 = Ge(copy _3, copy _4); + _7 = ControlFlow::::Break(move _6); + StorageDead(_6); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + _8 = copy ((_7 as Break).0: bool); + _0 = copy _8; + goto -> bb3; } bb2: { - StorageDead(_8); StorageDead(_5); - StorageLive(_12); - _9 = const core::tuple::::le::promoted[1]; - StorageLive(_11); - StorageLive(_16); + StorageDead(_4); + StorageDead(_3); + StorageLive(_9); + _9 = copy ((*_1).1: f32); StorageLive(_10); - _10 = discriminant((*_9)); - _11 = Eq(copy _10, const 0_isize); + _10 = copy ((*_2).1: f32); + _0 = Ge(move _9, move _10); StorageDead(_10); - StorageDead(_16); - _12 = Not(move _11); - StorageDead(_11); - switchInt(move _12) -> [0: bb11, otherwise: bb3]; + StorageDead(_9); + goto -> bb3; } bb3: { - _13 = const core::tuple::::le::promoted[0]; - StorageLive(_21); - StorageLive(_14); - _14 = discriminant((*_13)); - _0 = Eq(copy _14, const 0_isize); - goto -> bb16; - } - - bb4: { - _15 = const Option::::Some(Greater); - StorageDead(_8); - StorageDead(_5); - StorageLive(_12); - _9 = const core::tuple::::le::promoted[1]; - StorageLive(_11); - StorageLive(_16); - StorageLive(_10); - goto -> bb8; - } - - bb5: { - switchInt(copy _8) -> [0: bb6, otherwise: bb7]; - } - - bb6: { - _15 = const Option::::Some(Less); - StorageDead(_8); - StorageDead(_5); - StorageLive(_12); - _9 = const core::tuple::::le::promoted[1]; - StorageLive(_11); - StorageLive(_16); - StorageLive(_10); - goto -> bb8; - } - - bb7: { - _15 = const Option::::Some(Equal); - StorageDead(_8); - StorageDead(_5); - StorageLive(_12); - _9 = const core::tuple::::le::promoted[1]; - StorageLive(_11); - StorageLive(_16); - StorageLive(_10); - goto -> bb8; - } - - bb8: { - _16 = discriminant((*_9)); - switchInt(move _16) -> [0: bb9, 1: bb10, otherwise: bb18]; - } - - bb9: { - StorageDead(_10); - StorageDead(_16); - StorageDead(_11); - _13 = const core::tuple::::le::promoted[0]; - StorageLive(_21); - StorageLive(_14); - goto -> bb13; - } - - bb10: { - StorageLive(_17); - StorageLive(_18); - _17 = discriminant(((_15 as Some).0: std::cmp::Ordering)); - _18 = discriminant((((*_9) as Some).0: std::cmp::Ordering)); - _11 = Eq(copy _17, copy _18); - StorageDead(_18); - StorageDead(_17); - StorageDead(_10); - StorageDead(_16); - _12 = Not(move _11); - StorageDead(_11); - switchInt(move _12) -> [0: bb11, otherwise: bb12]; - } - - bb11: { - _19 = &((*_1).1: f32); - _20 = &((*_2).1: f32); - _0 = ::le(move _19, move _20) -> [return: bb17, unwind continue]; - } - - bb12: { - _13 = const core::tuple::::le::promoted[0]; - StorageLive(_21); - StorageLive(_14); - goto -> bb13; - } - - bb13: { - _21 = discriminant((*_13)); - switchInt(move _21) -> [0: bb14, 1: bb15, otherwise: bb18]; - } - - bb14: { - _0 = const false; - goto -> bb16; - } - - bb15: { - StorageLive(_22); - StorageLive(_23); - _22 = discriminant(((_15 as Some).0: std::cmp::Ordering)); - _23 = discriminant((((*_13) as Some).0: std::cmp::Ordering)); - _0 = Eq(copy _22, copy _23); - StorageDead(_23); - StorageDead(_22); - goto -> bb16; - } - - bb16: { - StorageDead(_14); - StorageDead(_21); - goto -> bb17; - } - - bb17: { - StorageDead(_12); - StorageDead(_15); - StorageDead(_9); - StorageDead(_13); - StorageDead(_20); - StorageDead(_19); + StorageDead(_7); return; } - - bb18: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir index 15c3ae76ae93..d252052f0aef 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir @@ -6,140 +6,65 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool { let mut _0: bool; scope 1 (inlined std::cmp::impls::::le) { scope 2 (inlined core::tuple::::le) { - let mut _12: bool; - let _13: &i16; - let _14: &i16; + let mut _7: std::ops::ControlFlow; + let _8: bool; scope 3 { - let mut _6: &std::option::Option; - let mut _8: &std::option::Option; - scope 4 (inlined as PartialEq>::ne) { - let mut _11: bool; - scope 5 (inlined as PartialEq>::eq) { - let mut _7: isize; - scope 6 { - scope 7 (inlined ::eq) { - let _9: i8; - scope 8 { - let _10: i8; - scope 9 { - } - } - } - } - } - } - scope 10 (inlined as PartialEq>::eq) { - let mut _15: isize; - scope 11 { - scope 12 (inlined ::eq) { - let _16: i8; - scope 13 { - let _17: i8; - scope 14 { - } - } - } - } - } } - scope 15 (inlined std::cmp::impls::::partial_cmp) { + scope 4 (inlined std::cmp::impls:: for u16>::spec_chain_le) { let mut _3: u16; let mut _4: u16; - let mut _5: std::cmp::Ordering; + let mut _5: bool; + let mut _6: bool; + scope 5 { + } + } + scope 6 (inlined std::cmp::impls::::le) { + let mut _9: i16; + let mut _10: i16; } } } bb0: { - StorageLive(_13); - StorageLive(_14); - StorageLive(_8); - StorageLive(_6); - StorageLive(_3); - _3 = copy ((*_1).0: u16); - StorageLive(_4); - _4 = copy ((*_2).0: u16); - _5 = Cmp(move _3, move _4); - StorageDead(_4); - StorageDead(_3); - StorageLive(_12); - _6 = const core::tuple::::le::promoted[1]; - StorageLive(_11); StorageLive(_7); - _7 = discriminant((*_6)); - switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb10]; + StorageLive(_3); + StorageLive(_4); + _3 = copy ((*_1).0: u16); + _4 = copy ((*_2).0: u16); + StorageLive(_5); + _5 = Eq(copy _3, copy _4); + switchInt(move _5) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageDead(_7); - StorageDead(_11); - _8 = const core::tuple::::le::promoted[0]; - StorageLive(_15); - goto -> bb5; + StorageLive(_6); + _6 = Le(copy _3, copy _4); + _7 = ControlFlow::::Break(move _6); + StorageDead(_6); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + _8 = copy ((_7 as Break).0: bool); + _0 = copy _8; + goto -> bb3; } bb2: { + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); StorageLive(_9); + _9 = copy ((*_1).1: i16); StorageLive(_10); - _9 = discriminant(_5); - _10 = discriminant((((*_6) as Some).0: std::cmp::Ordering)); - _11 = Eq(copy _9, copy _10); + _10 = copy ((*_2).1: i16); + _0 = Le(move _9, move _10); StorageDead(_10); StorageDead(_9); - StorageDead(_7); - _12 = Not(move _11); - StorageDead(_11); - switchInt(move _12) -> [0: bb3, otherwise: bb4]; + goto -> bb3; } bb3: { - _13 = &((*_1).1: i16); - _14 = &((*_2).1: i16); - _0 = ::le(move _13, move _14) -> [return: bb9, unwind continue]; - } - - bb4: { - _8 = const core::tuple::::le::promoted[0]; - StorageLive(_15); - goto -> bb5; - } - - bb5: { - _15 = discriminant((*_8)); - switchInt(move _15) -> [0: bb6, 1: bb7, otherwise: bb10]; - } - - bb6: { - _0 = const false; - goto -> bb8; - } - - bb7: { - StorageLive(_16); - StorageLive(_17); - _16 = discriminant(_5); - _17 = discriminant((((*_8) as Some).0: std::cmp::Ordering)); - _0 = Eq(copy _16, copy _17); - StorageDead(_17); - StorageDead(_16); - goto -> bb8; - } - - bb8: { - StorageDead(_15); - goto -> bb9; - } - - bb9: { - StorageDead(_12); - StorageDead(_6); - StorageDead(_8); - StorageDead(_14); - StorageDead(_13); + StorageDead(_7); return; } - - bb10: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/tuple_ord.rs b/tests/mir-opt/pre-codegen/tuple_ord.rs index 435ac7a5be93..74a919e54246 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.rs +++ b/tests/mir-opt/pre-codegen/tuple_ord.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0 -Z inline-mir-hint-threshold=9999 +//@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0 //@ needs-unwind #![crate_type = "lib"] @@ -12,5 +12,5 @@ pub fn demo_le_total(a: &(u16, i16), b: &(u16, i16)) -> bool { // EMIT_MIR tuple_ord.demo_ge_partial.PreCodegen.after.mir pub fn demo_ge_partial(a: &(f32, f32), b: &(f32, f32)) -> bool { // CHECK-LABEL: demo_ge_partial - a <= b + a >= b } From f8fe978fab83d6cdb7ccd148a7e2bd5c9caae156 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 19 Mar 2025 17:32:21 +0100 Subject: [PATCH 130/546] remove unnecessary loop --- compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 142078900f0e..075dc590b997 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -371,14 +371,8 @@ impl RpitConstraintChecker<'_> { // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; debug!(?concrete_opaque_types); - for (&def_id, &concrete_type) in concrete_opaque_types { - if def_id != self.def_id { - // Ignore constraints for other opaque types. - continue; - } - + if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) { debug!(?concrete_type, "found constraint"); - if concrete_type.ty != self.found.ty { if let Ok(d) = self.found.build_mismatch_error(&concrete_type, self.tcx) { d.emit(); From 7c085f7ffdf731175430b908bc11bd97282cff9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 19 Mar 2025 17:29:31 +0100 Subject: [PATCH 131/546] add rustc_macro_edition_2021 --- .../src/attributes.rs | 1 + .../rustc_attr_data_structures/src/lib.rs | 11 ++++------- .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/rustc.rs | 19 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 ++ compiler/rustc_feature/src/builtin_attrs.rs | 8 ++++++++ compiler/rustc_resolve/src/macros.rs | 6 +++++- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/pin.rs | 1 + library/coretests/tests/pin.rs | 13 +++++++++++++ 10 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/rustc.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d2d1285b0756..969bce7ae20a 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -191,6 +191,7 @@ pub enum AttributeKind { }, MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), + RustcMacroEdition2021, Stability { stability: Stability, /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index bbd3308809c3..c61b44b273de 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -182,21 +182,18 @@ macro_rules! find_attr { }}; ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ - fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator) {} - check_attribute_iterator(&$attributes_list); - - let find_attribute = |iter| { + 'done: { for i in $attributes_list { + let i: &rustc_hir::Attribute = i; match i { rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { - return Some($e); + break 'done Some($e); } _ => {} } } None - }; - find_attribute($attributes_list) + } }}; } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 6ecd6b4d7dbb..bac111159db5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -28,6 +28,7 @@ pub(crate) mod cfg; pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod repr; +pub(crate) mod rustc; pub(crate) mod stability; pub(crate) mod transparency; pub(crate) mod util; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc.rs b/compiler/rustc_attr_parsing/src/attributes/rustc.rs new file mode 100644 index 000000000000..bdd3bef2834b --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/rustc.rs @@ -0,0 +1,19 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_span::sym; + +use super::{AcceptContext, SingleAttributeParser}; +use crate::parser::ArgParser; + +pub(crate) struct RustcMacroEdition2021Parser; + +// FIXME(jdonszelmann): make these proper diagnostics +impl SingleAttributeParser for RustcMacroEdition2021Parser { + const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_edition_2021]; + + fn on_duplicate(_cx: &crate::context::AcceptContext<'_>, _first_span: rustc_span::Span) {} + + fn convert(_cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { + assert!(args.no_args()); + Some(AttributeKind::RustcMacroEdition2021) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 35541bb04bd7..a68d4578b40f 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,6 +15,7 @@ use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInterna use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::repr::ReprParser; +use crate::attributes::rustc::RustcMacroEdition2021Parser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; @@ -76,6 +77,7 @@ attribute_groups!( // tidy-alphabetical-start Single, Single, + Single, Single, // tidy-alphabetical-end ]; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 40857e0066ee..2511ae610f8d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -661,6 +661,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "`rustc_never_type_options` is used to experiment with never type fallback and work on \ never type stabilization, and will never be stable" ), + rustc_attr!( + rustc_macro_edition_2021, + Normal, + template!(Word), + ErrorFollowing, + EncodeCrossCrate::No, + "makes spans in this macro edition 2021" + ), // ========================================================================== // Internal attributes: Runtime related: diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 7100d89ad61a..5bb6ec3e7ced 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::StabilityLevel; +use rustc_attr_parsing::{AttributeKind, StabilityLevel, find_attr}; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, StashKey}; use rustc_expand::base::{ @@ -1125,6 +1125,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { edition, ); + if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021 {}) { + ext.edition = Edition::Edition2021; + } + if let Some(builtin_name) = ext.builtin_name { // The macro was marked with `#[rustc_builtin_macro]`. if let Some(builtin_macro) = self.builtin_macros.get_mut(&builtin_name) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a8bec35d819..31d9ad104386 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1793,6 +1793,7 @@ symbols! { rustc_lint_opt_ty, rustc_lint_query_instability, rustc_lint_untracked_query_information, + rustc_macro_edition_2021, rustc_macro_transparency, rustc_main, rustc_mir, diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 7fcd19f67ee2..bc097bf198d0 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1943,6 +1943,7 @@ unsafe impl PinCoerceUnsized for *mut T {} #[stable(feature = "pin_macro", since = "1.68.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(unsafe_pin_internals)] +#[cfg_attr(not(bootstrap), rustc_macro_edition_2021)] pub macro pin($value:expr $(,)?) { // This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's // review such a hypothetical macro (that any user-code could define): diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs index b3fb06e710d4..d31b24144e2a 100644 --- a/library/coretests/tests/pin.rs +++ b/library/coretests/tests/pin.rs @@ -81,3 +81,16 @@ mod pin_coerce_unsized { arg } } + +#[test] +fn spans_2021() { + // Check that we accept a Rust 2024 $expr. + std::pin::pin!(const { 1 }); + + // Check that temporary lifetimes work as in Rust 2021. + match std::pin::pin!(foo(&mut 0)) { + _f => {} + } +} + +async fn foo(_: &mut usize) {} From 93d5ca82b0b1e9cb3aff5939b2a10731caea32f1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Mar 2025 17:42:43 +0100 Subject: [PATCH 132/546] Pin tests. --- library/coretests/tests/pin.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs index d31b24144e2a..43f0448f0064 100644 --- a/library/coretests/tests/pin.rs +++ b/library/coretests/tests/pin.rs @@ -34,6 +34,9 @@ fn pin_const() { } pin_mut_const(); + + // Check that we accept a Rust 2024 $expr. + std::pin::pin!(const { 1 }); } #[allow(unused)] @@ -83,14 +86,11 @@ mod pin_coerce_unsized { } #[test] -fn spans_2021() { - // Check that we accept a Rust 2024 $expr. - std::pin::pin!(const { 1 }); - +fn temp_lifetime() { // Check that temporary lifetimes work as in Rust 2021. + // Regression test for https://github.com/rust-lang/rust/issues/138596 match std::pin::pin!(foo(&mut 0)) { - _f => {} + _ => {} } + async fn foo(_: &mut usize) {} } - -async fn foo(_: &mut usize) {} From cfc78cec79653e0c68e894b28295765a4208639e Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 19 Mar 2025 17:52:53 +0100 Subject: [PATCH 133/546] merge opaque types of nested bodies --- compiler/rustc_borrowck/src/lib.rs | 7 ++- compiler/rustc_borrowck/src/nll.rs | 20 ++++--- compiler/rustc_borrowck/src/opaque_types.rs | 55 +++++++++++++++++++ .../src/region_infer/opaque_types.rs | 37 +++---------- compiler/rustc_borrowck/src/type_check/mod.rs | 10 +++- .../src/collect/type_of/opaque.rs | 6 -- tests/crashes/122904.rs | 12 ---- .../impl-fn-predefined-lifetimes.rs | 3 +- .../impl-fn-predefined-lifetimes.stderr | 18 ++---- tests/ui/impl-trait/issues/issue-86800.rs | 1 - tests/ui/impl-trait/issues/issue-86800.stderr | 23 +------- .../const_generic_type.no_infer.stderr | 19 +------ .../const_generic_type.rs | 1 - .../error-tainting-issue-122904.rs | 18 ++++++ .../error-tainting-issue-122904.stderr | 30 ++++++++++ .../type-alias-impl-trait/hkl_forbidden4.rs | 1 - .../hkl_forbidden4.stderr | 19 +------ .../in-assoc-ty-early-bound2.rs | 2 +- .../in-assoc-ty-early-bound2.stderr | 10 +--- 19 files changed, 146 insertions(+), 146 deletions(-) create mode 100644 compiler/rustc_borrowck/src/opaque_types.rs delete mode 100644 tests/crashes/122904.rs create mode 100644 tests/ui/type-alias-impl-trait/error-tainting-issue-122904.rs create mode 100644 tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index ed95545dea42..84b7b8c6a2de 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -73,6 +73,7 @@ mod def_use; mod diagnostics; mod member_constraints; mod nll; +mod opaque_types; mod path_utils; mod place_ext; mod places_conflict; @@ -192,7 +193,7 @@ fn do_mir_borrowck<'tcx>( // Compute non-lexical lifetimes. let nll::NllOutput { regioncx, - opaque_type_values, + concrete_opaque_types, polonius_input, polonius_output, opt_closure_req, @@ -222,7 +223,7 @@ fn do_mir_borrowck<'tcx>( body, ®ioncx, &opt_closure_req, - &opaque_type_values, + &concrete_opaque_types, diags_buffer, ); @@ -357,7 +358,7 @@ fn do_mir_borrowck<'tcx>( let tainted_by_errors = mbcx.emit_errors(); let result = BorrowCheckResult { - concrete_opaque_types: opaque_type_values, + concrete_opaque_types: concrete_opaque_types.into_inner(), closure_requirements: opt_closure_req, used_mut_upvars: mbcx.used_mut_upvars, tainted_by_errors, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 2031579dfd50..d0bd364425a5 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -6,8 +6,6 @@ use std::str::FromStr; use std::{env, io}; use polonius_engine::{Algorithm, Output}; -use rustc_data_structures::fx::FxIndexMap; -use rustc_hir::def_id::LocalDefId; use rustc_index::IndexSlice; use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; use rustc_middle::mir::{ @@ -15,7 +13,7 @@ use rustc_middle::mir::{ dump_enabled, dump_mir, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; @@ -27,6 +25,7 @@ use tracing::{debug, instrument}; use crate::borrow_set::BorrowSet; use crate::consumers::ConsumerOptions; use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors}; +use crate::opaque_types::ConcreteOpaqueTypes; use crate::polonius::PoloniusDiagnosticsContext; use crate::polonius::legacy::{ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, @@ -40,7 +39,7 @@ use crate::{BorrowckInferCtxt, polonius, renumber}; /// closure requirements to propagate, and any generated errors. pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: FxIndexMap>, + pub concrete_opaque_types: ConcreteOpaqueTypes<'tcx>, pub polonius_input: Option>, pub polonius_output: Option>, pub opt_closure_req: Option>, @@ -99,6 +98,8 @@ pub(crate) fn compute_regions<'a, 'tcx>( let location_map = Rc::new(DenseLocationMap::new(body)); + let mut concrete_opaque_types = ConcreteOpaqueTypes::default(); + // Run the MIR type-checker. let MirTypeckResults { constraints, @@ -116,6 +117,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( flow_inits, move_data, Rc::clone(&location_map), + &mut concrete_opaque_types, ); // Create the region inference context, taking ownership of the @@ -180,11 +182,11 @@ pub(crate) fn compute_regions<'a, 'tcx>( infcx.set_tainted_by_errors(guar); } - let remapped_opaque_tys = regioncx.infer_opaque_types(infcx, opaque_type_values); + regioncx.infer_opaque_types(infcx, opaque_type_values, &mut concrete_opaque_types); NllOutput { regioncx, - opaque_type_values: remapped_opaque_tys, + concrete_opaque_types, polonius_input: polonius_facts.map(Box::new), polonius_output, opt_closure_req: closure_region_requirements, @@ -300,7 +302,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, - opaque_type_values: &FxIndexMap>, + concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>, diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>, ) { let tcx = infcx.tcx; @@ -343,8 +345,8 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( err }; - if !opaque_type_values.is_empty() { - err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}")); + if !concrete_opaque_types.is_empty() { + err.note(format!("Inferred opaque type values:\n{concrete_opaque_types:#?}")); } diagnostics_buffer.buffer_non_error(err); diff --git a/compiler/rustc_borrowck/src/opaque_types.rs b/compiler/rustc_borrowck/src/opaque_types.rs new file mode 100644 index 000000000000..5c78814abdd2 --- /dev/null +++ b/compiler/rustc_borrowck/src/opaque_types.rs @@ -0,0 +1,55 @@ +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt}; + +#[derive(Debug, Default)] +pub(super) struct ConcreteOpaqueTypes<'tcx> { + concrete_opaque_types: FxIndexMap>, +} + +impl<'tcx> ConcreteOpaqueTypes<'tcx> { + pub(super) fn is_empty(&self) -> bool { + self.concrete_opaque_types.is_empty() + } + + pub(super) fn into_inner(self) -> FxIndexMap> { + self.concrete_opaque_types + } + + /// Insert an opaque type into the list of opaque types defined by this function + /// after mapping the hidden type to the generic parameters of the opaque type + /// definition. + pub(super) fn insert( + &mut self, + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + hidden_ty: OpaqueHiddenType<'tcx>, + ) { + // Sometimes two opaque types are the same only after we remap the generic parameters + // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to + // `(X, Y)` and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we + // only know that once we convert the generic parameters to those of the opaque type. + if let Some(prev) = self.concrete_opaque_types.get_mut(&def_id) { + if prev.ty != hidden_ty.ty { + let (Ok(guar) | Err(guar)) = + prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit()); + prev.ty = Ty::new_error(tcx, guar); + } + // Pick a better span if there is one. + // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. + prev.span = prev.span.substitute_dummy(hidden_ty.span); + } else { + self.concrete_opaque_types.insert(def_id, hidden_ty); + } + } + + pub(super) fn extend_from_nested_body( + &mut self, + tcx: TyCtxt<'tcx>, + nested_body: &FxIndexMap>, + ) { + for (&def_id, &hidden_ty) in nested_body { + self.insert(tcx, def_id, hidden_ty); + } + } +} diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 048394485962..ca8b9fb4e9d8 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -15,6 +15,7 @@ use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument}; use super::RegionInferenceContext; +use crate::opaque_types::ConcreteOpaqueTypes; use crate::session_diagnostics::{LifetimeMismatchOpaqueParam, NonGenericOpaqueTypeParam}; use crate::universal_regions::RegionClassification; @@ -67,8 +68,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'tcx>, opaque_ty_decls: FxIndexMap, OpaqueHiddenType<'tcx>>, - ) -> FxIndexMap> { - let mut result: FxIndexMap> = FxIndexMap::default(); + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + ) { let mut decls_modulo_regions: FxIndexMap, (OpaqueTypeKey<'tcx>, Span)> = FxIndexMap::default(); @@ -143,33 +144,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { continue; } } - // Sometimes two opaque types are the same only after we remap the generic parameters - // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to - // `(X, Y)` and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we - // only know that once we convert the generic parameters to those of the opaque type. - if let Some(prev) = result.get_mut(&opaque_type_key.def_id) { - if prev.ty != ty { - let guar = ty.error_reported().err().unwrap_or_else(|| { - let (Ok(e) | Err(e)) = prev - .build_mismatch_error( - &OpaqueHiddenType { ty, span: concrete_type.span }, - infcx.tcx, - ) - .map(|d| d.emit()); - e - }); - prev.ty = Ty::new_error(infcx.tcx, guar); - } - // Pick a better span if there is one. - // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. - prev.span = prev.span.substitute_dummy(concrete_type.span); - } else { - result.insert( - opaque_type_key.def_id, - OpaqueHiddenType { ty, span: concrete_type.span }, - ); - } + concrete_opaque_types.insert( + infcx.tcx, + opaque_type_key.def_id, + OpaqueHiddenType { ty, span: concrete_type.span }, + ); // Check that all opaque types have the same region parameters if they have the same // non-region parameters. This is necessary because within the new solver we perform // various query operations modulo regions, and thus could unsoundly select some impls @@ -193,7 +173,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); } } - result } /// Map the regions in the type to named regions. This is similar to what diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0fda3e31690d..f6144a25938c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -45,6 +45,7 @@ use crate::borrow_set::BorrowSet; use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet}; use crate::diagnostics::UniverseInfo; use crate::member_constraints::MemberConstraintSet; +use crate::opaque_types::ConcreteOpaqueTypes; use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable}; use crate::polonius::{PoloniusContext, PoloniusLivenessContext}; use crate::region_infer::TypeTest; @@ -111,6 +112,7 @@ pub(crate) fn type_check<'a, 'tcx>( flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, location_map: Rc, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, ) -> MirTypeckResults<'tcx> { let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { @@ -165,6 +167,7 @@ pub(crate) fn type_check<'a, 'tcx>( polonius_facts, borrow_set, constraints: &mut constraints, + concrete_opaque_types, polonius_liveness, }; @@ -230,6 +233,7 @@ struct TypeChecker<'a, 'tcx> { polonius_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + concrete_opaque_types: &'a mut ConcreteOpaqueTypes<'tcx>, /// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints. polonius_liveness: Option, } @@ -2499,7 +2503,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { args: GenericArgsRef<'tcx>, locations: Locations, ) -> ty::InstantiatedPredicates<'tcx> { - if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements { + let closure_borrowck_results = tcx.mir_borrowck(def_id); + self.concrete_opaque_types + .extend_from_nested_body(tcx, &closure_borrowck_results.concrete_opaque_types); + + if let Some(closure_requirements) = &closure_borrowck_results.closure_requirements { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 075dc590b997..3dec1e286b4e 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -258,9 +258,6 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { self.tcx } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if let hir::ExprKind::Closure(closure) = ex.kind { - self.check(closure.def_id); - } intravisit::walk_expr(self, ex); } fn visit_item(&mut self, it: &'tcx Item<'tcx>) { @@ -389,9 +386,6 @@ impl<'tcx> intravisit::Visitor<'tcx> for RpitConstraintChecker<'tcx> { self.tcx } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if let hir::ExprKind::Closure(closure) = ex.kind { - self.check(closure.def_id); - } intravisit::walk_expr(self, ex); } fn visit_item(&mut self, it: &'tcx Item<'tcx>) { diff --git a/tests/crashes/122904.rs b/tests/crashes/122904.rs deleted file mode 100644 index 2068cd9d239d..000000000000 --- a/tests/crashes/122904.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #122904 -trait T {} - -type Alias<'a> = impl T; - -struct S; -impl<'a> T for &'a S {} - -#[define_opaque(Alias)] -fn with_positive(fun: impl Fn(Alias<'_>)) { - with_positive(|&n| ()); -} diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs index 2f17c0ff5086..776bb7278ce1 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs @@ -2,8 +2,7 @@ use std::fmt::Debug; fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - //~^ ERROR cannot resolve opaque type - //~| WARNING elided lifetime has a name + //~^ WARNING elided lifetime has a name |x| x //~^ ERROR expected generic lifetime parameter, found `'_` } diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr index 91550f0e284c..209186db4cc1 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -7,24 +7,14 @@ LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { = note: `#[warn(elided_named_lifetimes)]` on by default error[E0792]: expected generic lifetime parameter, found `'_` - --> $DIR/impl-fn-predefined-lifetimes.rs:7:9 + --> $DIR/impl-fn-predefined-lifetimes.rs:6:9 | LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { | -- this generic parameter must be used with a generic lifetime parameter -... +LL | LL | |x| x | ^ -error[E0720]: cannot resolve opaque type - --> $DIR/impl-fn-predefined-lifetimes.rs:4:35 - | -LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - | ^^^^^^^^^^^^^^^ recursive opaque type -... -LL | |x| x - | ----- returning here with type `{closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8}` +error: aborting due to 1 previous error; 1 warning emitted -error: aborting due to 2 previous errors; 1 warning emitted - -Some errors have detailed explanations: E0720, E0792. -For more information about an error, try `rustc --explain E0720`. +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/issues/issue-86800.rs b/tests/ui/impl-trait/issues/issue-86800.rs index c1176255f244..9e8ea439dde9 100644 --- a/tests/ui/impl-trait/issues/issue-86800.rs +++ b/tests/ui/impl-trait/issues/issue-86800.rs @@ -40,7 +40,6 @@ impl Context { f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>, ) -> TransactionResult { //~^ ERROR expected generic lifetime parameter, found `'_` - //~| ERROR: item does not constrain let mut conn = Connection {}; let mut transaction = TestTransaction { conn: &mut conn }; f(&mut transaction).await diff --git a/tests/ui/impl-trait/issues/issue-86800.stderr b/tests/ui/impl-trait/issues/issue-86800.stderr index 11e23d97d72d..80aa5d75c3c6 100644 --- a/tests/ui/impl-trait/issues/issue-86800.stderr +++ b/tests/ui/impl-trait/issues/issue-86800.stderr @@ -24,26 +24,6 @@ note: this opaque type is supposed to be constrained LL | type TransactionFuture<'__, O> = impl '__ + Future>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: item does not constrain `TransactionFuture::{opaque#0}` - --> $DIR/issue-86800.rs:41:31 - | -LL | ) -> TransactionResult { - | _______________________________^ -LL | | -LL | | -LL | | let mut conn = Connection {}; -LL | | let mut transaction = TestTransaction { conn: &mut conn }; -LL | | f(&mut transaction).await -LL | | } - | |_____^ - | - = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` -note: this opaque type is supposed to be constrained - --> $DIR/issue-86800.rs:21:34 - | -LL | type TransactionFuture<'__, O> = impl '__ + Future>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0792]: expected generic lifetime parameter, found `'_` --> $DIR/issue-86800.rs:31:5 | @@ -62,13 +42,12 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future TransactionResult { | _______________________________^ LL | | -LL | | LL | | let mut conn = Connection {}; LL | | let mut transaction = TestTransaction { conn: &mut conn }; LL | | f(&mut transaction).await LL | | } | |_____^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr index ba97bbf89f8b..241eccc5f2b0 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr +++ b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr @@ -19,22 +19,5 @@ note: this opaque type is supposed to be constrained LL | type Bar = impl std::fmt::Display; | ^^^^^^^^^^^^^^^^^^^^^^ -error: item does not constrain `Bar::{opaque#0}` - --> $DIR/const_generic_type.rs:8:31 - | -LL | async fn test() { - | _______________________________^ -... | -LL | | let x: u32 = N; -LL | | } - | |_^ - | - = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` -note: this opaque type is supposed to be constrained - --> $DIR/const_generic_type.rs:5:12 - | -LL | type Bar = impl std::fmt::Display; - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.rs b/tests/ui/type-alias-impl-trait/const_generic_type.rs index 5b093be92312..9b38f1449f89 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.rs +++ b/tests/ui/type-alias-impl-trait/const_generic_type.rs @@ -8,7 +8,6 @@ type Bar = impl std::fmt::Display; async fn test() { //~^ ERROR: `Bar` is forbidden as the type of a const generic parameter //[no_infer]~^^ ERROR item does not constrain - //[no_infer]~| ERROR item does not constrain #[cfg(infer)] let x: u32 = N; } diff --git a/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.rs b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.rs new file mode 100644 index 000000000000..a2de3957c0bd --- /dev/null +++ b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.rs @@ -0,0 +1,18 @@ +// We previously didn't taint the borrowck result in this test, +// causing an ICE later on. +#![feature(type_alias_impl_trait)] +trait T {} + +type Alias<'a> = impl T; + +struct S; +impl<'a> T for &'a S {} + +#[define_opaque(Alias)] +fn with_positive(fun: impl Fn(Alias<'_>)) { + //~^ WARN function cannot return without recursing + with_positive(|&n| ()); + //~^ ERROR cannot move out of a shared reference +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr new file mode 100644 index 000000000000..956ce3e5936b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr @@ -0,0 +1,30 @@ +warning: function cannot return without recursing + --> $DIR/error-tainting-issue-122904.rs:12:1 + | +LL | fn with_positive(fun: impl Fn(Alias<'_>)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | +LL | with_positive(|&n| ()); + | ---------------------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error[E0507]: cannot move out of a shared reference + --> $DIR/error-tainting-issue-122904.rs:14:20 + | +LL | with_positive(|&n| ()); + | ^- + | | + | data moved here + | move occurs because `n` has type `S`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - with_positive(|&n| ()); +LL + with_positive(|n| ()); + | + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs index 7e010918b294..cbd8150d1177 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs @@ -22,7 +22,6 @@ where for<'any> F: FnMut(&'any mut ()) -> FutNothing<'any>, { //~^ ERROR: expected generic lifetime parameter, found `'any` - //~| ERROR item does not constrain } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr index 2ca6a1994485..2c0be0cbcdca 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr @@ -11,21 +11,6 @@ note: this opaque type is supposed to be constrained LL | type FutNothing<'a> = impl 'a + Future; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: item does not constrain `FutNothing::{opaque#0}` - --> $DIR/hkl_forbidden4.rs:23:1 - | -LL | / { -... | -LL | | } - | |_^ - | - = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` -note: this opaque type is supposed to be constrained - --> $DIR/hkl_forbidden4.rs:10:23 - | -LL | type FutNothing<'a> = impl 'a + Future; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: concrete type differs from previous defining opaque type use --> $DIR/hkl_forbidden4.rs:12:1 | @@ -54,10 +39,10 @@ LL | type FutNothing<'a> = impl 'a + Future; | -- this generic parameter must be used with a generic lifetime parameter ... LL | / { -... | +LL | | LL | | } | |_^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs index 7452000b65dc..92c8a8f32162 100644 --- a/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs +++ b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs @@ -6,7 +6,7 @@ trait Foo { } impl Foo for () { - type Assoc<'a> = impl Sized; //~ ERROR unconstrained opaque type + type Assoc<'a> = impl Sized; fn bar<'a: 'a>() where Self::Assoc<'a>:, diff --git a/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.stderr b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.stderr index 1274a8b60dea..7ce4517fb1e9 100644 --- a/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.stderr +++ b/tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.stderr @@ -9,14 +9,6 @@ LL | fn bar<'a: 'a>() LL | let _: Self::Assoc<'a> = x; | ^^^^^^^^^^^^^^^ -error: unconstrained opaque type - --> $DIR/in-assoc-ty-early-bound2.rs:9:22 - | -LL | type Assoc<'a> = impl Sized; - | ^^^^^^^^^^ - | - = note: `Assoc` must be used in combination with a concrete type within the same impl - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0700`. From ef815f3205eedec26c715463f51a6793e2fa651f Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Wed, 19 Mar 2025 12:55:02 -0400 Subject: [PATCH 134/546] Specify a concrete stack size in channel tests The channel-stack-overflow-issue-102246 regression test fails on platforms with a small default stack size (e.g. Fuchsia, with a default of 256KiB). Update the test to specify an exact stack size for both the sender and receiver operations, to ensure it is platform agnostic. Set the stack size to less than the total allocation size of the mpsc channel, to continue to prove that the allocation is on the heap. --- .../channel-stack-overflow-issue-102246.rs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/ui/std/channel-stack-overflow-issue-102246.rs b/tests/ui/std/channel-stack-overflow-issue-102246.rs index 984ebdd553fa..7bf6647bdc5f 100644 --- a/tests/ui/std/channel-stack-overflow-issue-102246.rs +++ b/tests/ui/std/channel-stack-overflow-issue-102246.rs @@ -10,9 +10,16 @@ // Ref: https://github.com/rust-lang/rust/issues/102246 use std::sync::mpsc::channel; -use std::thread; +use std::thread::Builder; const N: usize = 32_768; +const SLOTS: usize = 32; +// Use a stack size that's smaller than N * SLOTS, proving the allocation is on the heap. +// +// The test explicitly specifies the stack size, because not all platforms have the same default +// size. +const STACK_SIZE: usize = (N*SLOTS) - 1; + struct BigStruct { _data: [u8; N], } @@ -20,10 +27,13 @@ struct BigStruct { fn main() { let (sender, receiver) = channel::(); - let thread1 = thread::spawn(move || { + let thread1 = Builder::new().stack_size(STACK_SIZE).spawn(move || { sender.send(BigStruct { _data: [0u8; N] }).unwrap(); - }); - + }).expect("thread1 should spawn successfully"); thread1.join().unwrap(); - for _data in receiver.try_iter() {} + + let thread2 = Builder::new().stack_size(STACK_SIZE).spawn(move || { + for _data in receiver.try_iter() {} + }).expect("thread2 should spawn successfully"); + thread2.join().unwrap(); } From 25896cc668ebb652d38e0a1d69a0f983e0b3408e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Mar 2025 18:08:23 +0100 Subject: [PATCH 135/546] Add cfg(not(bootstrap)) for new test. --- library/coretests/tests/pin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs index 43f0448f0064..a866cf12a3bb 100644 --- a/library/coretests/tests/pin.rs +++ b/library/coretests/tests/pin.rs @@ -86,6 +86,7 @@ mod pin_coerce_unsized { } #[test] +#[cfg(not(bootstrap))] fn temp_lifetime() { // Check that temporary lifetimes work as in Rust 2021. // Regression test for https://github.com/rust-lang/rust/issues/138596 From 20432c9eee4d22047994f1e334a639c891535aa9 Mon Sep 17 00:00:00 2001 From: Jesus Checa Hidalgo Date: Wed, 19 Mar 2025 19:29:08 +0100 Subject: [PATCH 136/546] Use explicit cpu in some asm and codegen tests. Some tests expect to be compiled for a specific CPU or require certain target features to be present (or absent). These tests work fine with default CPUs but fail in downstream builds for RHEL and Fedora, where we use non-default CPUs such as z13 on s390x, pwr9 on ppc64le, or x86-64-v2/x86-64-v3 on x86_64. --- tests/assembly/powerpc64-struct-abi.rs | 2 +- tests/assembly/s390x-vector-abi.rs | 4 +-- tests/codegen/asm/s390x-clobbers.rs | 2 +- tests/codegen/slice-is-ascii.rs | 2 +- tests/ui/abi/simd-abi-checks-avx.rs | 1 + tests/ui/abi/simd-abi-checks-avx.stderr | 44 ++++++++++++------------- tests/ui/abi/simd-abi-checks-s390x.rs | 2 +- 7 files changed, 29 insertions(+), 28 deletions(-) diff --git a/tests/assembly/powerpc64-struct-abi.rs b/tests/assembly/powerpc64-struct-abi.rs index eb27afc4f23c..ee4965deb4fd 100644 --- a/tests/assembly/powerpc64-struct-abi.rs +++ b/tests/assembly/powerpc64-struct-abi.rs @@ -6,7 +6,7 @@ //@[elfv1-be] needs-llvm-components: powerpc //@[elfv2-be] compile-flags: --target powerpc64-unknown-linux-musl //@[elfv2-be] needs-llvm-components: powerpc -//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu +//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu -C target-cpu=pwr8 //@[elfv2-le] needs-llvm-components: powerpc //@[aix] compile-flags: --target powerpc64-ibm-aix //@[aix] needs-llvm-components: powerpc diff --git a/tests/assembly/s390x-vector-abi.rs b/tests/assembly/s390x-vector-abi.rs index 7d86559c0026..e159a3576850 100644 --- a/tests/assembly/s390x-vector-abi.rs +++ b/tests/assembly/s390x-vector-abi.rs @@ -2,9 +2,9 @@ // ignore-tidy-linelength //@ assembly-output: emit-asm //@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -//@[z10] compile-flags: --target s390x-unknown-linux-gnu --cfg no_vector +//@[z10] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 --cfg no_vector //@[z10] needs-llvm-components: systemz -//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector +//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 -C target-feature=+vector //@[z10_vector] needs-llvm-components: systemz //@[z13] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 //@[z13] needs-llvm-components: systemz diff --git a/tests/codegen/asm/s390x-clobbers.rs b/tests/codegen/asm/s390x-clobbers.rs index cbb6630553cf..0ba22a32abf3 100644 --- a/tests/codegen/asm/s390x-clobbers.rs +++ b/tests/codegen/asm/s390x-clobbers.rs @@ -1,6 +1,6 @@ //@ add-core-stubs //@ revisions: s390x -//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 //@[s390x] needs-llvm-components: systemz #![crate_type = "rlib"] diff --git a/tests/codegen/slice-is-ascii.rs b/tests/codegen/slice-is-ascii.rs index b1e97154609b..67537c871a0a 100644 --- a/tests/codegen/slice-is-ascii.rs +++ b/tests/codegen/slice-is-ascii.rs @@ -1,5 +1,5 @@ //@ only-x86_64 -//@ compile-flags: -C opt-level=3 +//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64 #![crate_type = "lib"] /// Check that the fast-path of `is_ascii` uses a `pmovmskb` instruction. diff --git a/tests/ui/abi/simd-abi-checks-avx.rs b/tests/ui/abi/simd-abi-checks-avx.rs index acab74300b8f..fa4b3ba3054f 100644 --- a/tests/ui/abi/simd-abi-checks-avx.rs +++ b/tests/ui/abi/simd-abi-checks-avx.rs @@ -1,6 +1,7 @@ //@ only-x86_64 //@ build-pass //@ ignore-pass (test emits codegen-time warnings) +//@ compile-flags: -C target-feature=-avx #![feature(avx512_target_feature)] #![feature(portable_simd)] diff --git a/tests/ui/abi/simd-abi-checks-avx.stderr b/tests/ui/abi/simd-abi-checks-avx.stderr index 0dddc7dfa1c1..5419970f8093 100644 --- a/tests/ui/abi/simd-abi-checks-avx.stderr +++ b/tests/ui/abi/simd-abi-checks-avx.stderr @@ -1,5 +1,5 @@ warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:64:11 + --> $DIR/simd-abi-checks-avx.rs:65:11 | LL | f(g()); | ^^^ function called here @@ -10,7 +10,7 @@ LL | f(g()); = note: `#[warn(abi_unsupported_vector_types)]` on by default warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:64:9 + --> $DIR/simd-abi-checks-avx.rs:65:9 | LL | f(g()); | ^^^^^^ function called here @@ -20,7 +20,7 @@ LL | f(g()); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:72:14 + --> $DIR/simd-abi-checks-avx.rs:73:14 | LL | gavx(favx()); | ^^^^^^ function called here @@ -30,7 +30,7 @@ LL | gavx(favx()); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:72:9 + --> $DIR/simd-abi-checks-avx.rs:73:9 | LL | gavx(favx()); | ^^^^^^^^^^^^ function called here @@ -40,7 +40,7 @@ LL | gavx(favx()); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:84:19 + --> $DIR/simd-abi-checks-avx.rs:85:19 | LL | w(Wrapper(g())); | ^^^ function called here @@ -50,7 +50,7 @@ LL | w(Wrapper(g())); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function call uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:84:9 + --> $DIR/simd-abi-checks-avx.rs:85:9 | LL | w(Wrapper(g())); | ^^^^^^^^^^^^^^^ function called here @@ -60,7 +60,7 @@ LL | w(Wrapper(g())); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:100:9 + --> $DIR/simd-abi-checks-avx.rs:101:9 | LL | some_extern(); | ^^^^^^^^^^^^^ function called here @@ -70,7 +70,7 @@ LL | some_extern(); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:27:1 + --> $DIR/simd-abi-checks-avx.rs:28:1 | LL | unsafe extern "C" fn g() -> __m256 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -80,7 +80,7 @@ LL | unsafe extern "C" fn g() -> __m256 { = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:21:1 + --> $DIR/simd-abi-checks-avx.rs:22:1 | LL | unsafe extern "C" fn f(_: __m256) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -90,7 +90,7 @@ LL | unsafe extern "C" fn f(_: __m256) { = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function definition uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:15:1 + --> $DIR/simd-abi-checks-avx.rs:16:1 | LL | unsafe extern "C" fn w(_: Wrapper) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -100,7 +100,7 @@ LL | unsafe extern "C" fn w(_: Wrapper) { = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:57:8 + --> $DIR/simd-abi-checks-avx.rs:58:8 | LL | || g() | ^^^ function called here @@ -113,7 +113,7 @@ warning: 11 warnings emitted Future incompatibility report: Future breakage diagnostic: warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:64:11 + --> $DIR/simd-abi-checks-avx.rs:65:11 | LL | f(g()); | ^^^ function called here @@ -125,7 +125,7 @@ LL | f(g()); Future breakage diagnostic: warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:64:9 + --> $DIR/simd-abi-checks-avx.rs:65:9 | LL | f(g()); | ^^^^^^ function called here @@ -137,7 +137,7 @@ LL | f(g()); Future breakage diagnostic: warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:72:14 + --> $DIR/simd-abi-checks-avx.rs:73:14 | LL | gavx(favx()); | ^^^^^^ function called here @@ -149,7 +149,7 @@ LL | gavx(favx()); Future breakage diagnostic: warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:72:9 + --> $DIR/simd-abi-checks-avx.rs:73:9 | LL | gavx(favx()); | ^^^^^^^^^^^^ function called here @@ -161,7 +161,7 @@ LL | gavx(favx()); Future breakage diagnostic: warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:84:19 + --> $DIR/simd-abi-checks-avx.rs:85:19 | LL | w(Wrapper(g())); | ^^^ function called here @@ -173,7 +173,7 @@ LL | w(Wrapper(g())); Future breakage diagnostic: warning: this function call uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:84:9 + --> $DIR/simd-abi-checks-avx.rs:85:9 | LL | w(Wrapper(g())); | ^^^^^^^^^^^^^^^ function called here @@ -185,7 +185,7 @@ LL | w(Wrapper(g())); Future breakage diagnostic: warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:100:9 + --> $DIR/simd-abi-checks-avx.rs:101:9 | LL | some_extern(); | ^^^^^^^^^^^^^ function called here @@ -197,7 +197,7 @@ LL | some_extern(); Future breakage diagnostic: warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:27:1 + --> $DIR/simd-abi-checks-avx.rs:28:1 | LL | unsafe extern "C" fn g() -> __m256 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -209,7 +209,7 @@ LL | unsafe extern "C" fn g() -> __m256 { Future breakage diagnostic: warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:21:1 + --> $DIR/simd-abi-checks-avx.rs:22:1 | LL | unsafe extern "C" fn f(_: __m256) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -221,7 +221,7 @@ LL | unsafe extern "C" fn f(_: __m256) { Future breakage diagnostic: warning: this function definition uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:15:1 + --> $DIR/simd-abi-checks-avx.rs:16:1 | LL | unsafe extern "C" fn w(_: Wrapper) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -233,7 +233,7 @@ LL | unsafe extern "C" fn w(_: Wrapper) { Future breakage diagnostic: warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:57:8 + --> $DIR/simd-abi-checks-avx.rs:58:8 | LL | || g() | ^^^ function called here diff --git a/tests/ui/abi/simd-abi-checks-s390x.rs b/tests/ui/abi/simd-abi-checks-s390x.rs index 424ac00edcfc..3743c75bf1ed 100644 --- a/tests/ui/abi/simd-abi-checks-s390x.rs +++ b/tests/ui/abi/simd-abi-checks-s390x.rs @@ -1,7 +1,7 @@ //@ add-core-stubs //@ revisions: z10 z13_no_vector z13_soft_float //@ build-fail -//@[z10] compile-flags: --target s390x-unknown-linux-gnu +//@[z10] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 //@[z10] needs-llvm-components: systemz //@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector //@[z13_no_vector] needs-llvm-components: systemz From 5a21f890e9b6aad452638a45e0ebce025da7334f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 12 Mar 2023 11:56:20 +0100 Subject: [PATCH 137/546] Only use the new node hashmap for anonymous nodes. --- compiler/rustc_codegen_ssa/src/base.rs | 11 +- .../rustc_incremental/src/persist/save.rs | 2 +- .../rustc_query_system/src/dep_graph/graph.rs | 149 ++++++++++++------ compiler/rustc_session/src/options.rs | 3 +- 4 files changed, 110 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 396febcc6370..6d047f82566f 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1104,11 +1104,12 @@ pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> // know that later). If we are not doing LTO, there is only one optimized // version of each module, so we re-use that. let dep_node = cgu.codegen_dep_node(tcx); - assert!( - !tcx.dep_graph.dep_node_exists(&dep_node), - "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.", - cgu.name() - ); + tcx.dep_graph.assert_dep_node_not_yet_allocated_in_current_session(&dep_node, || { + format!( + "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.", + cgu.name() + ) + }); if tcx.try_mark_green(&dep_node) { // We can re-use either the pre- or the post-thinlto state. If no LTO is diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 8fc50ca1b435..94ce6d9fa81f 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -173,7 +173,7 @@ pub(crate) fn build_dep_graph( sess.opts.dep_tracking_hash(false).encode(&mut encoder); Some(DepGraph::new( - &sess.prof, + sess, prev_graph, prev_work_products, encoder, diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index bfd8b3207152..22926c0d1465 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,4 +1,5 @@ use std::assert_matches::assert_matches; +use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; @@ -7,8 +8,8 @@ use std::sync::atomic::{AtomicU32, Ordering}; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::profiling::{QueryInvocationId, SelfProfilerRef}; -use rustc_data_structures::sharded::{self, ShardedHashMap}; +use rustc_data_structures::profiling::QueryInvocationId; +use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_data_structures::unord::UnordMap; @@ -16,6 +17,7 @@ use rustc_errors::DiagInner; use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; +use rustc_session::Session; use tracing::{debug, instrument}; #[cfg(debug_assertions)] use {super::debug::EdgeFilter, std::env}; @@ -117,7 +119,7 @@ where impl DepGraph { pub fn new( - profiler: &SelfProfilerRef, + session: &Session, prev_graph: Arc, prev_work_products: WorkProductMap, encoder: FileEncoder, @@ -127,7 +129,7 @@ impl DepGraph { let prev_graph_node_count = prev_graph.node_count(); let current = CurrentDepGraph::new( - profiler, + session, prev_graph_node_count, encoder, record_graph, @@ -351,12 +353,13 @@ impl DepGraphData { // in `DepGraph::try_mark_green()`. // 2. Two distinct query keys get mapped to the same `DepNode` // (see for example #48923). - assert!( - !self.dep_node_exists(&key), - "forcing query with already existing `DepNode`\n\ + self.assert_dep_node_not_yet_allocated_in_current_session(&key, || { + format!( + "forcing query with already existing `DepNode`\n\ - query-key: {arg:?}\n\ - dep-node: {key:?}" - ); + ) + }); let with_deps = |task_deps| D::with_deps(task_deps, || task(cx, arg)); let (result, edges) = if cx.dep_context().is_eval_always(key.kind) { @@ -436,7 +439,31 @@ impl DepGraphData { hash: self.current.anon_id_seed.combine(hasher.finish()).into(), }; - self.current.intern_new_node(target_dep_node, task_deps, Fingerprint::ZERO) + // The DepNodes generated by the process above are not unique. 2 queries could + // have exactly the same dependencies. However, deserialization does not handle + // duplicated nodes, so we do the deduplication here directly. + // + // As anonymous nodes are a small quantity compared to the full dep-graph, the + // memory impact of this `anon_node_to_index` map remains tolerable, and helps + // us avoid useless growth of the graph with almost-equivalent nodes. + match self + .current + .anon_node_to_index + .get_shard_by_value(&target_dep_node) + .lock() + .entry(target_dep_node) + { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let dep_node_index = self.current.intern_new_node( + target_dep_node, + task_deps, + Fingerprint::ZERO, + ); + entry.insert(dep_node_index); + dep_node_index + } + } } }; @@ -637,20 +664,22 @@ impl DepGraph { } impl DepGraphData { - #[inline] - fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option { + fn assert_dep_node_not_yet_allocated_in_current_session( + &self, + dep_node: &DepNode, + msg: impl FnOnce() -> S, + ) { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { - self.current.prev_index_to_index.lock()[prev_index] - } else { - self.current.new_node_to_index.get(dep_node) + let current = self.current.prev_index_to_index.lock()[prev_index]; + assert!(current.is_none(), "{}", msg()) + } else if let Some(nodes_newly_allocated_in_current_session) = + &self.current.nodes_newly_allocated_in_current_session + { + let seen = nodes_newly_allocated_in_current_session.lock().contains(dep_node); + assert!(!seen, "{}", msg()); } } - #[inline] - fn dep_node_exists(&self, dep_node: &DepNode) -> bool { - self.dep_node_index_of_opt(dep_node).is_some() - } - fn node_color(&self, dep_node: &DepNode) -> Option { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { self.colors.get(prev_index) @@ -734,11 +763,6 @@ impl DepGraphData { } impl DepGraph { - #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { - self.data.as_ref().is_some_and(|data| data.dep_node_exists(dep_node)) - } - /// Checks whether a previous work product exists for `v` and, if /// so, return the path that leads to it. Used to skip doing work. pub fn previous_work_product(&self, v: &WorkProductId) -> Option { @@ -964,6 +988,16 @@ impl DepGraph { self.node_color(dep_node).is_some_and(|c| c.is_green()) } + pub fn assert_dep_node_not_yet_allocated_in_current_session( + &self, + dep_node: &DepNode, + msg: impl FnOnce() -> S, + ) { + if let Some(data) = &self.data { + data.assert_dep_node_not_yet_allocated_in_current_session(dep_node, msg) + } + } + /// This method loads all on-disk cacheable query results into memory, so /// they can be written out to the new cache file again. Most query results /// will already be in memory but in the case where we marked something as @@ -1069,24 +1103,24 @@ rustc_index::newtype_index! { /// largest in the compiler. /// /// For this reason, we avoid storing `DepNode`s more than once as map -/// keys. The `new_node_to_index` map only contains nodes not in the previous +/// keys. The `anon_node_to_index` map only contains nodes of anonymous queries not in the previous /// graph, and we map nodes in the previous graph to indices via a two-step /// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`, /// and the `prev_index_to_index` vector (which is more compact and faster than /// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`. /// -/// This struct uses three locks internally. The `data`, `new_node_to_index`, +/// This struct uses three locks internally. The `data`, `anon_node_to_index`, /// and `prev_index_to_index` fields are locked separately. Operations that take /// a `DepNodeIndex` typically just access the `data` field. /// /// We only need to manipulate at most two locks simultaneously: -/// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When -/// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index` +/// `anon_node_to_index` and `data`, or `prev_index_to_index` and `data`. When +/// manipulating both, we acquire `anon_node_to_index` or `prev_index_to_index` /// first, and `data` second. pub(super) struct CurrentDepGraph { encoder: GraphEncoder, - new_node_to_index: ShardedHashMap, prev_index_to_index: Lock>>, + anon_node_to_index: Sharded>, /// This is used to verify that fingerprints do not change between the creation of a node /// and its recomputation. @@ -1098,6 +1132,13 @@ pub(super) struct CurrentDepGraph { #[cfg(debug_assertions)] forbidden_edge: Option, + /// Used to verify the absence of hash collisions among DepNodes. + /// This field is only `Some` if the `-Z incremental_verify_ich` option is present. + /// + /// The map contains all DepNodes that have been allocated in the current session so far and + /// for which there is no equivalent in the previous session. + nodes_newly_allocated_in_current_session: Option>>, + /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of /// their edges. This has the beneficial side-effect that multiple anonymous /// nodes can be coalesced into one without changing the semantics of the @@ -1119,7 +1160,7 @@ pub(super) struct CurrentDepGraph { impl CurrentDepGraph { fn new( - profiler: &SelfProfilerRef, + session: &Session, prev_graph_node_count: usize, encoder: FileEncoder, record_graph: bool, @@ -1151,18 +1192,31 @@ impl CurrentDepGraph { prev_graph_node_count, record_graph, record_stats, - profiler, + &session.prof, previous, ), - new_node_to_index: ShardedHashMap::with_capacity( - new_node_count_estimate / sharded::shards(), - ), + anon_node_to_index: Sharded::new(|| { + FxHashMap::with_capacity_and_hasher( + new_node_count_estimate / sharded::shards(), + Default::default(), + ) + }), prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)), anon_id_seed, #[cfg(debug_assertions)] forbidden_edge, #[cfg(debug_assertions)] fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)), + nodes_newly_allocated_in_current_session: session + .opts + .unstable_opts + .incremental_verify_ich + .then(|| { + Lock::new(FxHashSet::with_capacity_and_hasher( + new_node_count_estimate, + Default::default(), + )) + }), total_read_count: AtomicU64::new(0), total_duplicate_read_count: AtomicU64::new(0), } @@ -1186,13 +1240,19 @@ impl CurrentDepGraph { edges: EdgesVec, current_fingerprint: Fingerprint, ) -> DepNodeIndex { - let dep_node_index = self - .new_node_to_index - .get_or_insert_with(key, || self.encoder.send(key, current_fingerprint, edges)); + let dep_node_index = self.encoder.send(key, current_fingerprint, edges); #[cfg(debug_assertions)] self.record_edge(dep_node_index, key, current_fingerprint); + if let Some(ref nodes_newly_allocated_in_current_session) = + self.nodes_newly_allocated_in_current_session + { + if !nodes_newly_allocated_in_current_session.lock().insert(key) { + panic!("Found duplicate dep-node {key:?}"); + } + } + dep_node_index } @@ -1286,7 +1346,10 @@ impl CurrentDepGraph { ) { let node = &prev_graph.index_to_node(prev_index); debug_assert!( - !self.new_node_to_index.get(node).is_some(), + !self + .nodes_newly_allocated_in_current_session + .as_ref() + .map_or(false, |set| set.lock().contains(node)), "node from previous graph present in new node collection" ); } @@ -1408,16 +1471,6 @@ fn panic_on_forbidden_read(data: &DepGraphData, dep_node_index: DepN } } - if dep_node.is_none() { - // Try to find it among the new nodes - for shard in data.current.new_node_to_index.lock_shards() { - if let Some((node, _)) = shard.iter().find(|(_, index)| *index == dep_node_index) { - dep_node = Some(*node); - break; - } - } - } - let dep_node = dep_node.map_or_else( || format!("with index {:?}", dep_node_index), |dep_node| format!("`{:?}`", dep_node), diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b3be4b611f03..d2f202eb24e3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2227,7 +2227,8 @@ options! { incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], "verify extended properties for incr. comp. (default: no): - hashes of green query instances - - hash collisions of query keys"), + - hash collisions of query keys + - hash collisions when creating dep-nodes"), inline_llvm: bool = (true, parse_bool, [TRACKED], "enable LLVM inlining (default: yes)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], From e70cafec4e632aa0b14c5e81d1d64c5d944021cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 00:05:45 +0100 Subject: [PATCH 138/546] Outline some cold code and turn on hash collision detection with debug_assertions --- .../rustc_query_system/src/dep_graph/graph.rs | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 22926c0d1465..89372bd24d22 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -8,6 +8,7 @@ use std::sync::atomic::{AtomicU32, Ordering}; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::outline; use rustc_data_structures::profiling::QueryInvocationId; use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -675,8 +676,10 @@ impl DepGraphData { } else if let Some(nodes_newly_allocated_in_current_session) = &self.current.nodes_newly_allocated_in_current_session { - let seen = nodes_newly_allocated_in_current_session.lock().contains(dep_node); - assert!(!seen, "{}", msg()); + outline(|| { + let seen = nodes_newly_allocated_in_current_session.lock().contains(dep_node); + assert!(!seen, "{}", msg()); + }); } } @@ -1133,7 +1136,8 @@ pub(super) struct CurrentDepGraph { forbidden_edge: Option, /// Used to verify the absence of hash collisions among DepNodes. - /// This field is only `Some` if the `-Z incremental_verify_ich` option is present. + /// This field is only `Some` if the `-Z incremental_verify_ich` option is present + /// or if `debug_assertions` are enabled. /// /// The map contains all DepNodes that have been allocated in the current session so far and /// for which there is no equivalent in the previous session. @@ -1186,6 +1190,9 @@ impl CurrentDepGraph { let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200; + let new_node_dbg = + session.opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions); + CurrentDepGraph { encoder: GraphEncoder::new( encoder, @@ -1207,16 +1214,12 @@ impl CurrentDepGraph { forbidden_edge, #[cfg(debug_assertions)] fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)), - nodes_newly_allocated_in_current_session: session - .opts - .unstable_opts - .incremental_verify_ich - .then(|| { - Lock::new(FxHashSet::with_capacity_and_hasher( - new_node_count_estimate, - Default::default(), - )) - }), + nodes_newly_allocated_in_current_session: new_node_dbg.then(|| { + Lock::new(FxHashSet::with_capacity_and_hasher( + new_node_count_estimate, + Default::default(), + )) + }), total_read_count: AtomicU64::new(0), total_duplicate_read_count: AtomicU64::new(0), } @@ -1248,9 +1251,11 @@ impl CurrentDepGraph { if let Some(ref nodes_newly_allocated_in_current_session) = self.nodes_newly_allocated_in_current_session { - if !nodes_newly_allocated_in_current_session.lock().insert(key) { - panic!("Found duplicate dep-node {key:?}"); - } + outline(|| { + if !nodes_newly_allocated_in_current_session.lock().insert(key) { + panic!("Found duplicate dep-node {key:?}"); + } + }); } dep_node_index From cdbf19a6fbb4446fe4dea62187a0924318c7c2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 00:07:19 +0100 Subject: [PATCH 139/546] Add fixme --- compiler/rustc_query_system/src/dep_graph/graph.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 89372bd24d22..c7749adb114d 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1204,6 +1204,7 @@ impl CurrentDepGraph { ), anon_node_to_index: Sharded::new(|| { FxHashMap::with_capacity_and_hasher( + // FIXME: The count estimate is off as anon nodes are only a portion of the nodes. new_node_count_estimate / sharded::shards(), Default::default(), ) From bd8b62826267e9c2ce0669383ed0875b2a85cb9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 00:26:32 +0100 Subject: [PATCH 140/546] Check for duplicate dep nodes when creating the index --- compiler/rustc_query_system/src/dep_graph/serialized.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 2c6fd7d494f0..8bd147c98fe0 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -252,7 +252,14 @@ impl SerializedDepGraph { .collect(); for (idx, node) in nodes.iter_enumerated() { - index[node.kind.as_usize()].insert(node.hash, idx); + if index[node.kind.as_usize()].insert(node.hash, idx).is_some() { + panic!( + "Error: A dep graph node does not have an unique index. \ + Running a clean build on a nightly compiler with `-Z incremental-verify-ich` \ + can help narrow down the issue for reporting. A clean build may also work around the issue.\n + DepNode: {node:?}" + ) + } } Arc::new(SerializedDepGraph { From 129f39cb89c02d4199fd641036f21ff7d1707238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 13:02:01 +0100 Subject: [PATCH 141/546] Use `nodes_newly_allocated_in_current_session` to lookup forbidden reads --- .../rustc_query_system/src/dep_graph/graph.rs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index c7749adb114d..11c06455141f 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -677,7 +677,7 @@ impl DepGraphData { &self.current.nodes_newly_allocated_in_current_session { outline(|| { - let seen = nodes_newly_allocated_in_current_session.lock().contains(dep_node); + let seen = nodes_newly_allocated_in_current_session.lock().contains_key(dep_node); assert!(!seen, "{}", msg()); }); } @@ -1141,7 +1141,7 @@ pub(super) struct CurrentDepGraph { /// /// The map contains all DepNodes that have been allocated in the current session so far and /// for which there is no equivalent in the previous session. - nodes_newly_allocated_in_current_session: Option>>, + nodes_newly_allocated_in_current_session: Option>>, /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of /// their edges. This has the beneficial side-effect that multiple anonymous @@ -1216,7 +1216,7 @@ impl CurrentDepGraph { #[cfg(debug_assertions)] fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)), nodes_newly_allocated_in_current_session: new_node_dbg.then(|| { - Lock::new(FxHashSet::with_capacity_and_hasher( + Lock::new(FxHashMap::with_capacity_and_hasher( new_node_count_estimate, Default::default(), )) @@ -1253,7 +1253,11 @@ impl CurrentDepGraph { self.nodes_newly_allocated_in_current_session { outline(|| { - if !nodes_newly_allocated_in_current_session.lock().insert(key) { + if nodes_newly_allocated_in_current_session + .lock() + .insert(key, dep_node_index) + .is_some() + { panic!("Found duplicate dep-node {key:?}"); } }); @@ -1355,7 +1359,7 @@ impl CurrentDepGraph { !self .nodes_newly_allocated_in_current_session .as_ref() - .map_or(false, |set| set.lock().contains(node)), + .map_or(false, |set| set.lock().contains_key(node)), "node from previous graph present in new node collection" ); } @@ -1477,6 +1481,15 @@ fn panic_on_forbidden_read(data: &DepGraphData, dep_node_index: DepN } } + if dep_node.is_none() + && let Some(nodes) = &data.current.nodes_newly_allocated_in_current_session + { + // Try to find it among the nodes allocated so far in this session + if let Some((node, _)) = nodes.lock().iter().find(|&(_, index)| *index == dep_node_index) { + dep_node = Some(*node); + } + } + let dep_node = dep_node.map_or_else( || format!("with index {:?}", dep_node_index), |dep_node| format!("`{:?}`", dep_node), From 58c148a3d82a644f92562fbbf4096b71d1f0a6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 13:08:33 +0100 Subject: [PATCH 142/546] Use `ShardedHashMap` for `anon_node_to_index` --- .../rustc_query_system/src/dep_graph/graph.rs | 37 +++++-------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 11c06455141f..7de222198559 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,5 +1,4 @@ use std::assert_matches::assert_matches; -use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; @@ -10,7 +9,7 @@ use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::outline; use rustc_data_structures::profiling::QueryInvocationId; -use rustc_data_structures::sharded::{self, Sharded}; +use rustc_data_structures::sharded::{self, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_data_structures::unord::UnordMap; @@ -447,24 +446,9 @@ impl DepGraphData { // As anonymous nodes are a small quantity compared to the full dep-graph, the // memory impact of this `anon_node_to_index` map remains tolerable, and helps // us avoid useless growth of the graph with almost-equivalent nodes. - match self - .current - .anon_node_to_index - .get_shard_by_value(&target_dep_node) - .lock() - .entry(target_dep_node) - { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let dep_node_index = self.current.intern_new_node( - target_dep_node, - task_deps, - Fingerprint::ZERO, - ); - entry.insert(dep_node_index); - dep_node_index - } - } + self.current.anon_node_to_index.get_or_insert_with(target_dep_node, || { + self.current.intern_new_node(target_dep_node, task_deps, Fingerprint::ZERO) + }) } }; @@ -1123,7 +1107,7 @@ rustc_index::newtype_index! { pub(super) struct CurrentDepGraph { encoder: GraphEncoder, prev_index_to_index: Lock>>, - anon_node_to_index: Sharded>, + anon_node_to_index: ShardedHashMap, /// This is used to verify that fingerprints do not change between the creation of a node /// and its recomputation. @@ -1202,13 +1186,10 @@ impl CurrentDepGraph { &session.prof, previous, ), - anon_node_to_index: Sharded::new(|| { - FxHashMap::with_capacity_and_hasher( - // FIXME: The count estimate is off as anon nodes are only a portion of the nodes. - new_node_count_estimate / sharded::shards(), - Default::default(), - ) - }), + anon_node_to_index: ShardedHashMap::with_capacity( + // FIXME: The count estimate is off as anon nodes are only a portion of the nodes. + new_node_count_estimate / sharded::shards(), + ), prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)), anon_id_seed, #[cfg(debug_assertions)] From f5dc674bf898cbd1ee8e206a55450b0b2132c0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 13:12:21 +0100 Subject: [PATCH 143/546] Rename `intern_new_node` to `alloc_new_node` --- compiler/rustc_query_system/src/dep_graph/graph.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 7de222198559..de5bbacf2740 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -140,7 +140,7 @@ impl DepGraph { let colors = DepNodeColorMap::new(prev_graph_node_count); // Instantiate a dependy-less node only once for anonymous queries. - let _green_node_index = current.intern_new_node( + let _green_node_index = current.alloc_new_node( DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() }, EdgesVec::new(), Fingerprint::ZERO, @@ -447,7 +447,7 @@ impl DepGraphData { // memory impact of this `anon_node_to_index` map remains tolerable, and helps // us avoid useless growth of the graph with almost-equivalent nodes. self.current.anon_node_to_index.get_or_insert_with(target_dep_node, || { - self.current.intern_new_node(target_dep_node, task_deps, Fingerprint::ZERO) + self.current.alloc_new_node(target_dep_node, task_deps, Fingerprint::ZERO) }) } }; @@ -1219,7 +1219,7 @@ impl CurrentDepGraph { /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it. /// Assumes that this is a node that has no equivalent in the previous dep-graph. #[inline(always)] - fn intern_new_node( + fn alloc_new_node( &self, key: DepNode, edges: EdgesVec, @@ -1298,7 +1298,7 @@ impl CurrentDepGraph { let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO); // This is a new node: it didn't exist in the previous compilation session. - let dep_node_index = self.intern_new_node(key, edges, fingerprint); + let dep_node_index = self.alloc_new_node(key, edges, fingerprint); (dep_node_index, None) } From 68fd771bc1f186bfa7e825d8a87ac8f06a6efced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 22:26:44 +0100 Subject: [PATCH 144/546] Pass in dep kind names to the duplicate dep node check --- compiler/rustc_incremental/src/persist/load.rs | 11 +++++++---- compiler/rustc_interface/src/passes.rs | 5 ++++- compiler/rustc_middle/src/dep_graph/dep_node.rs | 9 +++++++++ compiler/rustc_middle/src/dep_graph/mod.rs | 8 +++++++- compiler/rustc_query_impl/src/plumbing.rs | 4 ++++ compiler/rustc_query_system/src/dep_graph/mod.rs | 4 +++- .../rustc_query_system/src/dep_graph/serialized.rs | 7 ++++--- 7 files changed, 38 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 50e47533ab6c..0e646b136c45 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -91,7 +91,10 @@ fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) { work_product::delete_workproduct_files(sess, &swp.work_product); } -fn load_dep_graph(sess: &Session) -> LoadResult<(Arc, WorkProductMap)> { +fn load_dep_graph( + sess: &Session, + deps: &DepsType, +) -> LoadResult<(Arc, WorkProductMap)> { let prof = sess.prof.clone(); if sess.opts.incremental.is_none() { @@ -171,7 +174,7 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc, WorkPr return LoadResult::DataOutOfDate; } - let dep_graph = SerializedDepGraph::decode::(&mut decoder); + let dep_graph = SerializedDepGraph::decode::(&mut decoder, deps); LoadResult::Ok { data: (dep_graph, prev_work_products) } } @@ -205,11 +208,11 @@ pub fn load_query_result_cache(sess: &Session) -> Option { /// Setups the dependency graph by loading an existing graph from disk and set up streaming of a /// new graph to an incremental session directory. -pub fn setup_dep_graph(sess: &Session, crate_name: Symbol) -> DepGraph { +pub fn setup_dep_graph(sess: &Session, crate_name: Symbol, deps: &DepsType) -> DepGraph { // `load_dep_graph` can only be called after `prepare_session_directory`. prepare_session_directory(sess, crate_name); - let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess)); + let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess, deps)); if sess.opts.incremental.is_some() { sess.time("incr_comp_garbage_collect_session_directories", || { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e47385d08994..0c74eb7dba31 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -19,6 +19,7 @@ use rustc_incremental::setup_dep_graph; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store}; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; +use rustc_middle::dep_graph::DepsType; use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; use rustc_parse::{ @@ -774,7 +775,9 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( sess.cfg_version, ); let outputs = util::build_output_filenames(&pre_configured_attrs, sess); - let dep_graph = setup_dep_graph(sess, crate_name); + + let dep_type = DepsType { dep_names: rustc_query_impl::dep_kind_names() }; + let dep_graph = setup_dep_graph(sess, crate_name, &dep_type); let cstore = FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _); diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index f967d8b92c71..be34c7ef4bd5 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -21,6 +21,15 @@ macro_rules! define_dep_nodes { ($mod:ident) => {[ $($mod::$variant()),* ]}; } + #[macro_export] + macro_rules! make_dep_kind_name_array { + ($mod:ident) => { + vec! { + $(*$mod::$variant().name),* + } + }; + } + /// This enum serves as an index into arrays built by `make_dep_kind_array`. // This enum has more than u8::MAX variants so we need some kind of multi-byte // encoding. The derived Encodable/Decodable uses leb128 encoding which is diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index c927538b4cf3..739c0be1a91d 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -20,7 +20,9 @@ pub type DepGraph = rustc_query_system::dep_graph::DepGraph; pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct>; #[derive(Clone)] -pub struct DepsType; +pub struct DepsType { + pub dep_names: Vec<&'static str>, +} impl Deps for DepsType { fn with_deps(task_deps: TaskDepsRef<'_>, op: OP) -> R @@ -44,6 +46,10 @@ impl Deps for DepsType { }) } + fn name(&self, dep_kind: DepKind) -> &'static str { + self.dep_names[dep_kind.as_usize()] + } + const DEP_KIND_NULL: DepKind = dep_kinds::Null; const DEP_KIND_RED: DepKind = dep_kinds::Red; const DEP_KIND_SIDE_EFFECT: DepKind = dep_kinds::SideEffect; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 2b8457ace8ee..6fc7f023cf0b 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -863,5 +863,9 @@ macro_rules! define_queries { pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] { arena.alloc_from_iter(rustc_middle::make_dep_kind_array!(query_callbacks)) } + + pub fn dep_kind_names() -> Vec<&'static str> { + rustc_middle::make_dep_kind_name_array!(query_callbacks) + } } } diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index e3d64d1c0f80..4eeb6078d149 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -100,6 +100,8 @@ pub trait Deps { where OP: for<'a> FnOnce(TaskDepsRef<'a>); + fn name(&self, dep_kind: DepKind) -> &'static str; + /// We use this for most things when incr. comp. is turned off. const DEP_KIND_NULL: DepKind; @@ -154,7 +156,7 @@ pub enum FingerprintStyle { impl FingerprintStyle { #[inline] - pub fn reconstructible(self) -> bool { + pub const fn reconstructible(self) -> bool { match self { FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => { true diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 8bd147c98fe0..c96a58047723 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -179,8 +179,8 @@ fn mask(bits: usize) -> usize { } impl SerializedDepGraph { - #[instrument(level = "debug", skip(d))] - pub fn decode(d: &mut MemDecoder<'_>) -> Arc { + #[instrument(level = "debug", skip(d, deps))] + pub fn decode(d: &mut MemDecoder<'_>, deps: &D) -> Arc { // The last 16 bytes are the node count and edge count. debug!("position: {:?}", d.position()); let (node_count, edge_count) = @@ -253,8 +253,9 @@ impl SerializedDepGraph { for (idx, node) in nodes.iter_enumerated() { if index[node.kind.as_usize()].insert(node.hash, idx).is_some() { + let name = deps.name(node.kind); panic!( - "Error: A dep graph node does not have an unique index. \ + "Error: A dep graph node ({name}) does not have an unique index. \ Running a clean build on a nightly compiler with `-Z incremental-verify-ich` \ can help narrow down the issue for reporting. A clean build may also work around the issue.\n DepNode: {node:?}" From 2736a2a84f972baabe4012f890aaae14489af8d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 22:30:43 +0100 Subject: [PATCH 145/546] Allow duplicates for side effect nodes --- compiler/rustc_query_system/src/dep_graph/serialized.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index c96a58047723..f4b2cf631ed7 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -253,13 +253,16 @@ impl SerializedDepGraph { for (idx, node) in nodes.iter_enumerated() { if index[node.kind.as_usize()].insert(node.hash, idx).is_some() { - let name = deps.name(node.kind); - panic!( + // Side effect nodes can have duplicates + if node.kind != D::DEP_KIND_SIDE_EFFECT { + let name = deps.name(node.kind); + panic!( "Error: A dep graph node ({name}) does not have an unique index. \ Running a clean build on a nightly compiler with `-Z incremental-verify-ich` \ can help narrow down the issue for reporting. A clean build may also work around the issue.\n DepNode: {node:?}" ) + } } } From f8791b2f4237db261f2d1f58d91ebf9a2ece2e26 Mon Sep 17 00:00:00 2001 From: Lukas Woodtli Date: Mon, 17 Mar 2025 21:34:48 +0100 Subject: [PATCH 146/546] Add mipsel maintainer --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 +- .../mipsel-unknown-linux-gnu.md | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 542ee9fffce3..2e7228e82981 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -65,6 +65,7 @@ - [m68k-unknown-none-elf](platform-support/m68k-unknown-none-elf.md) - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md) - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md) + - [mipsel-unknown-linux-gnu](platform-support/mipsel-unknown-linux-gnu.md) - [mips\*-mti-none-elf](platform-support/mips-mti-none-elf.md) - [mipsisa\*r6\*-unknown-linux-gnu\*](platform-support/mips-release-6.md) - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d9587297e790..3df2167325cf 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -334,7 +334,7 @@ target | std | host | notes `mips64el-unknown-linux-muslabi64` | ✓ | | MIPS64 (little endian) Linux, N64 ABI, musl 1.2.3 `mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP) [`mipsel-sony-psx`](platform-support/mipsel-sony-psx.md) | * | | MIPS (LE) Sony PlayStation 1 (PSX) -`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (little endian) Linux (kernel 4.4, glibc 2.23) +[`mipsel-unknown-linux-gnu`](platform-support/mipsel-unknown-linux-gnu.md) | ✓ | ✓ | MIPS (little endian) Linux (kernel 4.4, glibc 2.23) `mipsel-unknown-linux-musl` | ✓ | | MIPS (little endian) Linux with musl 1.2.3 `mipsel-unknown-linux-uclibc` | ✓ | | MIPS (LE) Linux with uClibc [`mipsel-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | 32-bit MIPS (LE), requires mips32 cpu support diff --git a/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md new file mode 100644 index 000000000000..b1ee8728c020 --- /dev/null +++ b/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md @@ -0,0 +1,28 @@ +# `mipsel-unknown-linux-gnu` + +**Tier: 3** + +Little-endian 32 bit MIPS for Linux with `glibc. + +## Target maintainers + +- [@LukasWoodtli](https://github.com/LukasWoodtli) + +## Requirements + +The target supports std on Linux. Host tools are supported but not tested. + + +## Building the target + +For cross compilation the GNU C compiler for the mipsel architecture needs to +be installed. On Ubuntu install the packets: `gcc-mipsel-linux-gnu` and +`g++-mipsel-linux-gnu`. + +Add `mipsel-unknown-linux-gnu` as `target` list in `config.toml`. + +## Building Rust programs + +Rust does not ship pre-compiled artifacts for this target. To compile for +this target, you will need to build Rust with the target enabled (see +"Building the target" above). From 0577300b414f43f2384fd4f29cd1f3ed0d406169 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Mar 2025 21:51:03 +0100 Subject: [PATCH 147/546] Address review comments. --- compiler/rustc_resolve/src/macros.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5bb6ec3e7ced..a7cbc816b836 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1125,7 +1125,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { edition, ); - if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021 {}) { + // The #[rustc_macro_edition_2021] attribute is used by the pin!() macro + // as a temporary workaround for a regression in expressiveness in Rust 2024. + // See https://github.com/rust-lang/rust/issues/138718. + if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021) { ext.edition = Edition::Edition2021; } From 8e7d8ddffe802180b504e0ecaaa40b10b28b291e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 17 Mar 2025 21:29:07 -0400 Subject: [PATCH 148/546] Lower to a memset(undef) when Rvalue::Repeat repeats uninit --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 21 +++++++++++++-- compiler/rustc_middle/src/mir/consts.rs | 28 ++++++++++++++++++-- tests/codegen/uninit-repeat-in-aggregate.rs | 21 +++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 tests/codegen/uninit-repeat-in-aggregate.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 72cfd2bffb5d..1df00465f74d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -86,13 +86,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Rvalue::Repeat(ref elem, count) => { - let cg_elem = self.codegen_operand(bx, elem); - // Do not generate the loop for zero-sized elements or empty arrays. if dest.layout.is_zst() { return; } + // When the element is a const with all bytes uninit, emit a single memset that + // writes undef to the entire destination. + if let mir::Operand::Constant(const_op) = elem { + let val = self.eval_mir_constant(const_op); + if val.all_bytes_uninit(self.cx.tcx()) { + let size = bx.const_usize(dest.layout.size.bytes()); + bx.memset( + dest.val.llval, + bx.const_undef(bx.type_i8()), + size, + dest.val.align, + MemFlags::empty(), + ); + return; + } + } + + let cg_elem = self.codegen_operand(bx, elem); + let try_init_all_same = |bx: &mut Bx, v| { let start = dest.val.llval; let size = bx.const_usize(dest.layout.size.bytes()); diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 34b27c2e1cce..2b2ffa716288 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -9,7 +9,9 @@ use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_type_ir::TypeVisitableExt; use super::interpret::ReportedErrorInfo; -use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range}; +use crate::mir::interpret::{ + AllocId, AllocRange, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar, alloc_range, +}; use crate::mir::{Promoted, pretty_print_const_value}; use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt}; @@ -192,9 +194,31 @@ impl<'tcx> ConstValue<'tcx> { .unwrap_memory() .inner() .provenance() - .range_empty(super::AllocRange::from(offset..offset + size), &tcx), + .range_empty(AllocRange::from(offset..offset + size), &tcx), } } + + /// Check if a constant only contains uninitialized bytes. + pub fn all_bytes_uninit(&self, tcx: TyCtxt<'tcx>) -> bool { + let ConstValue::Indirect { alloc_id, .. } = self else { + return false; + }; + let alloc = tcx.global_alloc(*alloc_id); + let GlobalAlloc::Memory(alloc) = alloc else { + return false; + }; + let init_mask = alloc.0.init_mask(); + let init_range = init_mask.is_range_initialized(AllocRange { + start: Size::ZERO, + size: Size::from_bytes(alloc.0.len()), + }); + if let Err(range) = init_range { + if range.size == alloc.0.size() { + return true; + } + } + false + } } /////////////////////////////////////////////////////////////////////////// diff --git a/tests/codegen/uninit-repeat-in-aggregate.rs b/tests/codegen/uninit-repeat-in-aggregate.rs new file mode 100644 index 000000000000..0fa2eb7d56cd --- /dev/null +++ b/tests/codegen/uninit-repeat-in-aggregate.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +use std::mem::MaybeUninit; + +// We need to make sure len is at offset 0, otherwise codegen needs an extra instruction +#[repr(C)] +pub struct SmallVec { + pub len: u64, + pub arr: [MaybeUninit; 24], +} + +// CHECK-LABEL: @uninit_arr_via_const +#[no_mangle] +pub fn uninit_arr_via_const() -> SmallVec { + // CHECK-NEXT: start: + // CHECK-NEXT: store i64 0, + // CHECK-NEXT: ret + SmallVec { len: 0, arr: [const { MaybeUninit::uninit() }; 24] } +} From 55add8fce38ab100e161d2530a134f645ba78802 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 20 Mar 2025 19:47:57 +0900 Subject: [PATCH 149/546] rustc_target: Add more RISC-V vector-related features --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 4 ++- compiler/rustc_target/src/target_features.rs | 38 +++++++++++++++++++- tests/ui/check-cfg/target_feature.stderr | 38 +++++++++++++++++++- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 4a166b0872df..5bf931965c70 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -274,7 +274,9 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("fullfp16")), // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single // feature called `fast-unaligned-access`. In LLVM 19, it was split back out. - ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => { + ("riscv32" | "riscv64", "unaligned-scalar-mem" | "unaligned-vector-mem") + if get_version().0 == 18 => + { Some(LLVMFeature::new("fast-unaligned-access")) } // Filter out features that are not supported by the current LLVM version diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index a96caf227f74..e1865c624c4d 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -497,7 +497,8 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("m", Stable, &[]), ("relax", Unstable(sym::riscv_target_feature), &[]), ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), - ("v", Unstable(sym::riscv_target_feature), &[]), + ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), + ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), ("za128rs", Unstable(sym::riscv_target_feature), &[]), ("za64rs", Unstable(sym::riscv_target_feature), &[]), ("zaamo", Unstable(sym::riscv_target_feature), &[]), @@ -529,6 +530,41 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zksed", Stable, &[]), ("zksh", Stable, &[]), ("zkt", Stable, &[]), + ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), + ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]), + ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]), + ("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b"]), + ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]), + ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]), + ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]), + ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zfhmin"]), + ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]), + ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvkn", Unstable(sym::riscv_target_feature), &["zvkned", "zvknhb", "zvkb", "zvkt"]), + ("zvknc", Unstable(sym::riscv_target_feature), &["zvkn", "zvbc"]), + ("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]), + ("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvknhb", Unstable(sym::riscv_target_feature), &["zve64x"]), + ("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]), + ("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]), + ("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvksg", Unstable(sym::riscv_target_feature), &["zvks", "zvkg"]), + ("zvksh", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvkt", Unstable(sym::riscv_target_feature), &[]), + ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]), + ("zvl128b", Unstable(sym::riscv_target_feature), &["zvl64b"]), + ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]), + ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]), + ("zvl256b", Unstable(sym::riscv_target_feature), &["zvl128b"]), + ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]), + ("zvl32b", Unstable(sym::riscv_target_feature), &[]), + ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]), + ("zvl512b", Unstable(sym::riscv_target_feature), &["zvl256b"]), + ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]), + ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]), + ("zvl8192b", Unstable(sym::riscv_target_feature), &["zvl4096b"]), // tidy-alphabetical-end ]; diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index a9d67481ba15..e23984dc5958 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -245,6 +245,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `trustzone` `ual` `unaligned-scalar-mem` +`unaligned-vector-mem` `v` `v5te` `v6` @@ -325,7 +326,42 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zkr` `zks` `zksed` -`zksh`, and `zkt` +`zksh` +`zkt` +`zvbb` +`zvbc` +`zve32f` +`zve32x` +`zve64d` +`zve64f` +`zve64x` +`zvfh` +`zvfhmin` +`zvkb` +`zvkg` +`zvkn` +`zvknc` +`zvkned` +`zvkng` +`zvknha` +`zvknhb` +`zvks` +`zvksc` +`zvksed` +`zvksg` +`zvksh` +`zvkt` +`zvl1024b` +`zvl128b` +`zvl16384b` +`zvl2048b` +`zvl256b` +`zvl32768b` +`zvl32b` +`zvl4096b` +`zvl512b` +`zvl64b` +`zvl65536b`, and `zvl8192b` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default From 8a6f96a4a08df2bbb73ffbb7afb9b94f137bd24b Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 20 Mar 2025 19:48:02 +0900 Subject: [PATCH 150/546] rustc_target: Use zvl*b target features in vector ABI check --- compiler/rustc_target/src/target_features.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index e1865c624c4d..0e6523f0880e 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -740,8 +740,20 @@ const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(1 const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")]; const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")]; const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")]; -const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = - &[/*(64, "zvl64b"), */ (128, "v")]; +const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[ + (32, "zvl32b"), + (64, "zvl64b"), + (128, "zvl128b"), + (256, "zvl256b"), + (512, "zvl512b"), + (1024, "zvl1024b"), + (2048, "zvl2048b"), + (4096, "zvl4096b"), + (8192, "zvl8192b"), + (16384, "zvl16384b"), + (32768, "zvl32768b"), + (65536, "zvl65536b"), +]; // Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment. const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/]; From b9e67a2e286e17d3dd5d88ff9dadb98641a6b21b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 20 Mar 2025 13:50:13 +0000 Subject: [PATCH 151/546] Enable target features in inline asm on arm64 --- src/inline_asm.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 59d109341311..fbc33a642853 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -612,6 +612,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(".att_syntax\n"); } + if self.arch == InlineAsmArch::AArch64 { + for feature in &self.tcx.codegen_fn_attrs(self.enclosing_def_id).target_features { + if feature.name == sym::neon { + continue; + } + writeln!(generated_asm, ".arch_extension {}", feature.name).unwrap(); + } + } + // The actual inline asm for piece in self.template { match piece { @@ -679,6 +688,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } generated_asm.push('\n'); + if self.arch == InlineAsmArch::AArch64 { + for feature in &self.tcx.codegen_fn_attrs(self.enclosing_def_id).target_features { + if feature.name == sym::neon { + continue; + } + writeln!(generated_asm, ".arch_extension no{}", feature.name).unwrap(); + } + } + if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push_str(".intel_syntax noprefix\n"); } From 8fb99bcb1011a76d07ad124692c6e007034fc855 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 20 Mar 2025 13:54:08 +0000 Subject: [PATCH 152/546] Fix implementation of vaddlvq_u8 --- src/intrinsics/llvm_aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index b77c99fa2896..aa5d268e251c 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -253,7 +253,7 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( } let res = CValue::by_val( fx.bcx.ins().uextend(types::I32, res_val), - fx.layout_of(fx.tcx.types.u32), + fx.layout_of(fx.tcx.types.i32), ); ret.write_cvalue(fx, res); } From ce57133ad170cb069a06f2595d84d3be2e478a86 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 20 Mar 2025 13:59:01 +0000 Subject: [PATCH 153/546] Update LLVM intrinsic name This got updated in rust-lang/stdarch@13219b5 --- src/intrinsics/llvm_aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index aa5d268e251c..387c87d123a3 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -21,7 +21,7 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( fx.bcx.ins().fence(); } - "llvm.aarch64.neon.ld1x4.v16i8.p0i8" => { + "llvm.aarch64.neon.ld1x4.v16i8.p0" => { intrinsic_args!(fx, args => (ptr); intrinsic); let ptr = ptr.load_scalar(fx); From a8311b4a46f6dcb08a7802397acac548a8ada0ed Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 20 Mar 2025 14:08:02 +0000 Subject: [PATCH 154/546] Temporarily disable FreeBSD testing --- .cirrus.yml | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 1ec99eb3d17a..ee5de8b42f46 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,20 +1,21 @@ -task: - name: freebsd - freebsd_instance: - image: freebsd-13-2-release-amd64 - setup_rust_script: - - pkg install -y git-tiny binutils - - curl https://sh.rustup.rs -sSf --output rustup.sh - - sh rustup.sh --default-toolchain none -y --profile=minimal - target_cache: - folder: build/cg_clif - prepare_script: - - . $HOME/.cargo/env - - ./y.sh prepare - test_script: - - . $HOME/.cargo/env - # Disabling incr comp reduces cache size and incr comp doesn't save as much - # on CI anyway. - - export CARGO_BUILD_INCREMENTAL=false - # Skip rand as it fails on FreeBSD due to rust-random/rand#1355 - - ./y.sh test --skip-test test.rust-random/rand +# FIXME re-enable once https://github.com/rust-lang/rust/issues/134863 is fixed. +# task: +# name: freebsd +# freebsd_instance: +# image: freebsd-13-2-release-amd64 +# setup_rust_script: +# - pkg install -y git-tiny binutils +# - curl https://sh.rustup.rs -sSf --output rustup.sh +# - sh rustup.sh --default-toolchain none -y --profile=minimal +# target_cache: +# folder: build/cg_clif +# prepare_script: +# - . $HOME/.cargo/env +# - ./y.sh prepare +# test_script: +# - . $HOME/.cargo/env +# # Disabling incr comp reduces cache size and incr comp doesn't save as much +# # on CI anyway. +# - export CARGO_BUILD_INCREMENTAL=false +# # Skip rand as it fails on FreeBSD due to rust-random/rand#1355 +# - ./y.sh test --skip-test test.rust-random/rand From cafd23896db923e5fc83a81bb0226307940e4dde Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Tue, 18 Mar 2025 11:11:51 -0400 Subject: [PATCH 155/546] tests: accept some noise from LLVM 21 in symbols-all-mangled I'm not entirely sure this is correct, but it doesn't feel obviously-wrong so I figured I'd just start by sending a PR rather than filing a bug and letting it linger. @rustbot label llvm-main --- tests/run-make/symbols-all-mangled/rmake.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/run-make/symbols-all-mangled/rmake.rs b/tests/run-make/symbols-all-mangled/rmake.rs index 81f2678e55cd..1fb03c62399a 100644 --- a/tests/run-make/symbols-all-mangled/rmake.rs +++ b/tests/run-make/symbols-all-mangled/rmake.rs @@ -41,7 +41,13 @@ fn symbols_check_archive(path: &str) { continue; // Unfortunately LLVM doesn't allow us to mangle this symbol } - panic!("Unmangled symbol found: {name}"); + if name.contains(".llvm.") { + // Starting in LLVM 21 we get various implementation-detail functions which + // contain .llvm. that are not a problem. + continue; + } + + panic!("Unmangled symbol found in {path}: {name}"); } } @@ -75,7 +81,13 @@ fn symbols_check(path: &str) { continue; // Unfortunately LLVM doesn't allow us to mangle this symbol } - panic!("Unmangled symbol found: {name}"); + if name.contains(".llvm.") { + // Starting in LLVM 21 we get various implementation-detail functions which + // contain .llvm. that are not a problem. + continue; + } + + panic!("Unmangled symbol found in {path}: {name}"); } } From 15fff5d2d28c78f6590582f857deaf72e21c1142 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 5 Mar 2025 09:54:13 +0000 Subject: [PATCH 156/546] Update to Cranelift 0.118 --- Cargo.lock | 64 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 24 ++++++++++---------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 011e291cd203..e5f1896b9230 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,39 +43,39 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-assembler-x64" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b83fcf2fc1c8954561490d02079b496fd0c757da88129981e15bfe3a548229" +checksum = "3e4b56ebe316895d3fa37775d0a87b0c889cc933f5c8b253dbcc7c7bcb7fe7e4" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7496a6e92b5cee48c5d772b0443df58816dee30fed6ba19b2a28e78037ecedf" +checksum = "95cabbc01dfbd7dcd6c329ca44f0212910309c221797ac736a67a5bc8857fe1b" [[package]] name = "cranelift-bforest" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73a9dc0a8d3d49ee772101924968830f1c1937d650c571d3c2dd69dc36a68f41" +checksum = "76ffe46df300a45f1dc6f609dc808ce963f0e3a2e971682c479a2d13e3b9b8ef" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573c641174c40ef31021ae4a5a3ad78974e280633502d0dfc6e362385e0c100f" +checksum = "b265bed7c51e1921fdae6419791d31af77d33662ee56d7b0fa0704dc8d231cab" [[package]] name = "cranelift-codegen" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d7c94d572615156f2db682181cadbd96342892c31e08cc26a757344319a9220" +checksum = "e606230a7e3a6897d603761baee0d19f88d077f17b996bb5089488a29ae96e41" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -98,9 +98,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beecd9fcf2c3e06da436d565de61a42676097ea6eb6b4499346ac6264b6bb9ce" +checksum = "8a63bffafc23bc60969ad528e138788495999d935f0adcfd6543cb151ca8637d" dependencies = [ "cranelift-assembler-x64", "cranelift-codegen-shared", @@ -108,33 +108,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4ff8d2e1235f2d6e7fc3c6738be6954ba972cd295f09079ebffeca2f864e22" +checksum = "af50281b67324b58e843170a6a5943cf6d387c06f7eeacc9f5696e4ab7ae7d7e" [[package]] name = "cranelift-control" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001312e9fbc7d9ca9517474d6fe71e29d07e52997fd7efe18f19e8836446ceb2" +checksum = "8c20c1b38d1abfbcebb0032e497e71156c0e3b8dcb3f0a92b9863b7bcaec290c" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb0fd6d4aae680275fcbceb08683416b744e65c8b607352043d3f0951d72b3b2" +checksum = "0c2c67d95507c51b4a1ff3f3555fe4bfec36b9e13c1b684ccc602736f5d5f4a2" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd44e7e5dcea20ca104d45894748205c51365ce4cdb18f4418e3ba955971d1b" +checksum = "4e002691cc69c38b54fc7ec93e5be5b744f627d027031d991cc845d1d512d0ce" dependencies = [ "cranelift-codegen", "log", @@ -144,15 +144,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f900e0a3847d51eed0321f0777947fb852ccfce0da7fb070100357f69a2f37fc" +checksum = "e93588ed1796cbcb0e2ad160403509e2c5d330d80dd6e0014ac6774c7ebac496" [[package]] name = "cranelift-jit" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e37088dec72b7819f980558faaba9215d248fec4a2c3b89357b474f9e46f21" +checksum = "17f6682f0b193d6b7873cc8e7ed67e8776a8a26f50eeabf88534e9be618b9a03" dependencies = [ "anyhow", "cranelift-codegen", @@ -170,9 +170,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c3d728819ff644e8613d808378cbfed54fef464790f32e62079e638639eeff" +checksum = "ff19784c6de05116e63e6a34791012bd927b2a4eac56233039c46f1b6a4edac8" dependencies = [ "anyhow", "cranelift-codegen", @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7617f13f392ebb63c5126258aca8b8eca739636ca7e4eeee301d3eff68489a6a" +checksum = "e5b09bdd6407bf5d89661b80cf926ce731c9e8cc184bf49102267a2369a8358e" dependencies = [ "cranelift-codegen", "libc", @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60fc9092f7d9bba17c96ce51de5d91461f7905f3e1c43d1ba965df4b884d16ce" +checksum = "685e8661a30d1cb69509f589ac643adeee79c5f63c0da316431b9fad29e6d3b4" dependencies = [ "anyhow", "cranelift-codegen", @@ -436,9 +436,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" -version = "30.0.2" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f180cc0d2745e3a5df5d02231cd3046f49c75512eaa987b8202363b112e125d" +checksum = "a54f6c6c7e9d7eeee32dfcc10db7f29d505ee7dd28d00593ea241d5f70698e64" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index fa3037e77a0c..08b60de14c1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.117.2", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.117.2" } -cranelift-module = { version = "0.117.2" } -cranelift-native = { version = "0.117.2" } -cranelift-jit = { version = "0.117.2", optional = true } -cranelift-object = { version = "0.117.2" } +cranelift-codegen = { version = "0.118.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.118.0" } +cranelift-module = { version = "0.118.0" } +cranelift-native = { version = "0.118.0" } +cranelift-jit = { version = "0.118.0", optional = true } +cranelift-object = { version = "0.118.0" } target-lexicon = "0.13" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-30.0.0", version = "0.117.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } From 2133fb94b76bdf5b095e8b011a2df4e787afbbcd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:02:29 +0000 Subject: [PATCH 157/546] Disable PIC when jitting This fixes jitting on non-x86_64 targets. --- build_system/tests.rs | 6 ++---- src/driver/aot.rs | 2 +- src/driver/jit.rs | 2 +- src/lib.rs | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/build_system/tests.rs b/build_system/tests.rs index 36e108726121..122b541fa35f 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -325,10 +325,8 @@ impl<'a> TestRunner<'a> { target_compiler.rustflags.extend(rustflags_from_env("RUSTFLAGS")); target_compiler.rustdocflags.extend(rustflags_from_env("RUSTDOCFLAGS")); - let jit_supported = use_unstable_features - && is_native - && target_compiler.triple.contains("x86_64") - && !target_compiler.triple.contains("windows"); + let jit_supported = + use_unstable_features && is_native && !target_compiler.triple.contains("windows"); Self { is_native, jit_supported, skip_tests, dirs, target_compiler, stdlib_source } } diff --git a/src/driver/aot.rs b/src/driver/aot.rs index a52b18573b15..57c01f87b86c 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -329,7 +329,7 @@ fn produce_final_output_artifacts( } fn make_module(sess: &Session, name: String) -> UnwindModule { - let isa = crate::build_isa(sess); + let isa = crate::build_isa(sess, false); let mut builder = ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 4a08937f4aa9..41f8bb9161ca 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -18,7 +18,7 @@ use crate::unwind_module::UnwindModule; fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule, CodegenCx) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); - let isa = crate::build_isa(tcx.sess); + let isa = crate::build_isa(tcx.sess, true); let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info)); diff --git a/src/lib.rs b/src/lib.rs index caaa06967ed8..1e18c53b99c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,13 +250,13 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple { } } -fn build_isa(sess: &Session) -> Arc { +fn build_isa(sess: &Session, jit: bool) -> Arc { use target_lexicon::BinaryFormat; let target_triple = crate::target_triple(sess); let mut flags_builder = settings::builder(); - flags_builder.enable("is_pic").unwrap(); + flags_builder.set("is_pic", if jit { "false" } else { "true" }).unwrap(); let enable_verifier = if enable_verifier(sess) { "true" } else { "false" }; flags_builder.set("enable_verifier", enable_verifier).unwrap(); flags_builder.set("regalloc_checker", enable_verifier).unwrap(); From f90f43d62b1ce6d4c3dc49b450a7e30b9172ef42 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Mar 2025 15:46:19 +0000 Subject: [PATCH 158/546] Fix diagnostic struct typo, make sure is_array_like_block checks that it's a block --- compiler/rustc_parse/src/errors.rs | 6 ++--- compiler/rustc_parse/src/parser/expr.rs | 8 ++++--- tests/ui/parser/closure-return-syntax.rs | 16 ++++++++++++- tests/ui/parser/closure-return-syntax.stderr | 24 +++++++++++++++++++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e090d9cf7600..eb3bbef350a2 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -810,16 +810,16 @@ pub(crate) enum WrapInParentheses { #[derive(Diagnostic)] #[diag(parse_array_brackets_instead_of_braces)] -pub(crate) struct ArrayBracketsInsteadOfSpaces { +pub(crate) struct ArrayBracketsInsteadOfBraces { #[primary_span] pub span: Span, #[subdiagnostic] - pub sub: ArrayBracketsInsteadOfSpacesSugg, + pub sub: ArrayBracketsInsteadOfBracesSugg, } #[derive(Subdiagnostic)] #[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")] -pub(crate) struct ArrayBracketsInsteadOfSpacesSugg { +pub(crate) struct ArrayBracketsInsteadOfBracesSugg { #[suggestion_part(code = "[")] pub left: Span, #[suggestion_part(code = "]")] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index cd931888fbaa..1e14446efb51 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2190,7 +2190,9 @@ impl<'a> Parser<'a> { } fn is_array_like_block(&mut self) -> bool { - self.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_))) + matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace)) + && self + .look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_))) && self.look_ahead(2, |t| t == &token::Comma) && self.look_ahead(3, |t| t.can_begin_expr()) } @@ -2202,9 +2204,9 @@ impl<'a> Parser<'a> { let mut snapshot = self.create_snapshot_for_diagnostic(); match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) { Ok(arr) => { - let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces { + let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfBraces { span: arr.span, - sub: errors::ArrayBracketsInsteadOfSpacesSugg { + sub: errors::ArrayBracketsInsteadOfBracesSugg { left: lo, right: snapshot.prev_token.span, }, diff --git a/tests/ui/parser/closure-return-syntax.rs b/tests/ui/parser/closure-return-syntax.rs index c6a08abeff4b..6865d8c5393d 100644 --- a/tests/ui/parser/closure-return-syntax.rs +++ b/tests/ui/parser/closure-return-syntax.rs @@ -1,7 +1,21 @@ // Test that we cannot parse a closure with an explicit return type // unless it uses braces. -fn main() { +fn needs_braces_1() { let x = || -> i32 22; //~^ ERROR expected `{`, found `22` } + +// Check other delimiters too. + +fn needs_braces_2() { + let x = || -> (i32, i32) (1, 2); + //~^ ERROR expected `{`, found `(` +} + +fn needs_braces_3() { + let c = || -> [i32; 2] [1, 2]; + //~^ ERROR expected `{`, found `[` +} + +fn main() {} diff --git a/tests/ui/parser/closure-return-syntax.stderr b/tests/ui/parser/closure-return-syntax.stderr index aacc31ed871d..6f2106b77adb 100644 --- a/tests/ui/parser/closure-return-syntax.stderr +++ b/tests/ui/parser/closure-return-syntax.stderr @@ -9,5 +9,27 @@ help: you might have meant to write this as part of a block LL | let x = || -> i32 { 22 }; | + + -error: aborting due to 1 previous error +error: expected `{`, found `(` + --> $DIR/closure-return-syntax.rs:12:34 + | +LL | let x = || -> (i32, i32) (1, 2); + | ^ expected `{` + | +help: you might have meant to write this as part of a block + | +LL | let x = || -> (i32, i32) { (1, 2) }; + | + + + +error: expected `{`, found `[` + --> $DIR/closure-return-syntax.rs:17:32 + | +LL | let c = || -> [i32; 2] [1, 2]; + | ^ expected `{` + | +help: you might have meant to write this as part of a block + | +LL | let c = || -> [i32; 2] { [1, 2] }; + | + + + +error: aborting due to 3 previous errors From dbda7d44b8c6fcb737f790986a4884f4bbd6b126 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Mar 2025 15:44:44 +0000 Subject: [PATCH 159/546] Make dedicated recovery for missing braces on closure with return --- compiler/rustc_parse/src/parser/expr.rs | 53 +++++++++++++++++--- tests/ui/parser/closure-return-syntax.stderr | 18 ++++--- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1e14446efb51..1efde7fc54b7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2329,7 +2329,8 @@ impl<'a> Parser<'a> { let capture_clause = self.parse_capture_clause()?; let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; - let mut body = match fn_decl.output { + let mut body = match &fn_decl.output { + // No return type. FnRetTy::Default(_) => { let restrictions = self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; @@ -2341,11 +2342,8 @@ impl<'a> Parser<'a> { Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?, } } - _ => { - // If an explicit return type is given, require a block to appear (RFC 968). - let body_lo = self.token.span; - self.parse_expr_block(None, body_lo, BlockCheckMode::Default)? - } + // Explicit return type (`->`) needs block `-> T { }`. + FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?, }; match coroutine_kind { @@ -2397,6 +2395,49 @@ impl<'a> Parser<'a> { Ok(closure) } + /// If an explicit return type is given, require a block to appear (RFC 968). + fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P> { + if self.may_recover() + && self.token.can_begin_expr() + && !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace)) + && !self.token.is_whole_block() + { + let snapshot = self.create_snapshot_for_diagnostic(); + let restrictions = + self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; + let tok = self.token.clone(); + match self.parse_expr_res(restrictions, AttrWrapper::empty()) { + Ok((expr, _)) => { + let descr = super::token_descr(&tok); + let mut diag = self + .dcx() + .struct_span_err(tok.span, format!("expected `{{`, found {descr}")); + diag.span_label( + ret_span, + "explicit return type requires closure body to be enclosed in braces", + ); + diag.multipart_suggestion_verbose( + "wrap the expression in curly braces", + vec![ + (expr.span.shrink_to_lo(), "{ ".to_string()), + (expr.span.shrink_to_hi(), " }".to_string()), + ], + Applicability::MachineApplicable, + ); + diag.emit(); + return Ok(expr); + } + Err(diag) => { + diag.cancel(); + self.restore_snapshot(snapshot); + } + } + } + + let body_lo = self.token.span; + self.parse_expr_block(None, body_lo, BlockCheckMode::Default) + } + /// Parses an optional `move` or `use` prefix to a closure-like construct. fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { if self.eat_keyword(exp!(Move)) { diff --git a/tests/ui/parser/closure-return-syntax.stderr b/tests/ui/parser/closure-return-syntax.stderr index 6f2106b77adb..763f19ccc645 100644 --- a/tests/ui/parser/closure-return-syntax.stderr +++ b/tests/ui/parser/closure-return-syntax.stderr @@ -2,9 +2,11 @@ error: expected `{`, found `22` --> $DIR/closure-return-syntax.rs:5:23 | LL | let x = || -> i32 22; - | ^^ expected `{` + | --- ^^ + | | + | explicit return type requires closure body to be enclosed in braces | -help: you might have meant to write this as part of a block +help: wrap the expression in curly braces | LL | let x = || -> i32 { 22 }; | + + @@ -13,9 +15,11 @@ error: expected `{`, found `(` --> $DIR/closure-return-syntax.rs:12:34 | LL | let x = || -> (i32, i32) (1, 2); - | ^ expected `{` + | ---------- ^ + | | + | explicit return type requires closure body to be enclosed in braces | -help: you might have meant to write this as part of a block +help: wrap the expression in curly braces | LL | let x = || -> (i32, i32) { (1, 2) }; | + + @@ -24,9 +28,11 @@ error: expected `{`, found `[` --> $DIR/closure-return-syntax.rs:17:32 | LL | let c = || -> [i32; 2] [1, 2]; - | ^ expected `{` + | -------- ^ + | | + | explicit return type requires closure body to be enclosed in braces | -help: you might have meant to write this as part of a block +help: wrap the expression in curly braces | LL | let c = || -> [i32; 2] { [1, 2] }; | + + From 485c14f373c4bd2365283375ceba5fa105451dbe Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 19 Mar 2025 14:18:15 +0000 Subject: [PATCH 160/546] Make `crate_hash` not iterate over `hir_crate` owners anymore --- compiler/rustc_middle/src/hir/map.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 2e589150d3ee..236183d6b2f7 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1176,15 +1176,14 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher); if tcx.sess.opts.incremental.is_some() { let definitions = tcx.untracked().definitions.freeze(); - let mut owner_spans: Vec<_> = krate - .owners - .iter_enumerated() - .filter_map(|(def_id, info)| { - let _ = info.as_owner()?; + let mut owner_spans: Vec<_> = tcx + .hir_crate_items(()) + .definitions() + .map(|def_id| { let def_path_hash = definitions.def_path_hash(def_id); let span = tcx.source_span(def_id); debug_assert_eq!(span.parent(), None); - Some((def_path_hash, span)) + (def_path_hash, span) }) .collect(); owner_spans.sort_unstable_by_key(|bn| bn.0); From 38cf49dde8a5b0b284bb6dffd423d223c9f8f7a3 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Thu, 20 Mar 2025 19:08:16 +0100 Subject: [PATCH 161/546] wasm: increase default thread stack size to 1 MB The default stack size for the main thread is 1 MB as specified by linker options. However, the default stack size for threads was only 64 kB. This is surprisingly small and thus we increase it to 1 MB to match the main thread. --- library/std/src/sys/pal/wasi/thread.rs | 2 +- library/std/src/sys/pal/wasm/atomics/thread.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index c85b03d4a891..cc569bb3daf6 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -67,7 +67,7 @@ cfg_if::cfg_if! { } } -pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs index afdb159fe6f8..dd5aff391fd8 100644 --- a/library/std/src/sys/pal/wasm/atomics/thread.rs +++ b/library/std/src/sys/pal/wasm/atomics/thread.rs @@ -6,7 +6,7 @@ use crate::time::Duration; pub struct Thread(!); -pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements From a0918b7f5fc92988e54a4fe391a5ca5a51758b36 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Thu, 20 Mar 2025 22:38:46 +0000 Subject: [PATCH 162/546] jsondocck: Replace `jsonpath_lib` with `jsonpath-rust` --- Cargo.lock | 68 +++++++++++++++++++--- src/bootstrap/src/utils/proc_macro_deps.rs | 15 +++++ src/tools/jsondocck/Cargo.toml | 2 +- src/tools/jsondocck/src/cache.rs | 2 +- 4 files changed, 77 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a8dea0b1051..6f1db253d260 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1925,7 +1925,7 @@ version = "0.1.0" dependencies = [ "fs-err", "getopts", - "jsonpath_lib", + "jsonpath-rust", "regex", "serde_json", "shlex", @@ -1945,14 +1945,16 @@ dependencies = [ ] [[package]] -name = "jsonpath_lib" -version = "0.3.0" +name = "jsonpath-rust" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" +checksum = "9b0231bb404a6cd6c8f0ab41b907049063a089fc02aa7636cc5cd9a4d87364c9" dependencies = [ - "log", - "serde", + "pest", + "pest_derive", + "regex", "serde_json", + "thiserror 2.0.11", ] [[package]] @@ -2021,7 +2023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -2645,6 +2647,51 @@ dependencies = [ "libc", ] +[[package]] +name = "pest" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +dependencies = [ + "memchr", + "thiserror 2.0.11", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "pest_meta" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "phf" version = "0.11.3" @@ -4780,7 +4827,6 @@ version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ - "indexmap", "itoa", "memchr", "ryu", @@ -5486,6 +5532,12 @@ dependencies = [ "regex-lite", ] +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "ui_test" version = "0.26.5" diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs index 34bf6bb7013f..dbfd6f47dc67 100644 --- a/src/bootstrap/src/utils/proc_macro_deps.rs +++ b/src/bootstrap/src/utils/proc_macro_deps.rs @@ -6,18 +6,25 @@ pub static CRATES: &[&str] = &[ "annotate-snippets", "anstyle", "basic-toml", + "block-buffer", "bumpalo", + "cfg-if", + "cpufeatures", + "crypto-common", "darling", "darling_core", "derive_builder_core", + "digest", "fluent-bundle", "fluent-langneg", "fluent-syntax", "fnv", + "generic-array", "heck", "ident_case", "intl-memoizer", "intl_pluralrules", + "libc", "log", "memchr", "mime", @@ -25,12 +32,17 @@ pub static CRATES: &[&str] = &[ "minimal-lexical", "nom", "num-conv", + "once_cell", + "pest", + "pest_generator", + "pest_meta", "proc-macro2", "quote", "rinja_parser", "rustc-hash", "self_cell", "serde", + "sha2", "smallvec", "stable_deref_trait", "strsim", @@ -40,12 +52,15 @@ pub static CRATES: &[&str] = &[ "time-core", "tinystr", "type-map", + "typenum", + "ucd-trie", "unic-langid", "unic-langid-impl", "unic-langid-macros", "unicase", "unicode-ident", "unicode-width", + "version_check", "wasm-bindgen-backend", "wasm-bindgen-macro-support", "wasm-bindgen-shared", diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index e1eb6d056651..80fc26cbe668 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -jsonpath_lib = "0.3" +jsonpath-rust = "1.0.0" getopts = "0.2" regex = "1.4" shlex = "1.0" diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs index 47512039740b..1369c8ded007 100644 --- a/src/tools/jsondocck/src/cache.rs +++ b/src/tools/jsondocck/src/cache.rs @@ -30,6 +30,6 @@ impl Cache { // FIXME: Make this failible, so jsonpath syntax error has line number. pub fn select(&self, path: &str) -> Vec<&Value> { - jsonpath_lib::select(&self.value, path).unwrap() + jsonpath_rust::query::js_path_vals(path, &self.value).unwrap() } } From 7ab71c417b90695ea5186003745699e05164e746 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Thu, 20 Mar 2025 23:01:32 +0000 Subject: [PATCH 163/546] tests/rustdoc-json: replace `$.index[*][?` with `$.index[?` Done automatically with VSCode. --- tests/rustdoc-json/assoc_items.rs | 24 ++-- tests/rustdoc-json/assoc_type.rs | 8 +- tests/rustdoc-json/attrs/deprecated.rs | 32 ++--- tests/rustdoc-json/attrs/export_name_2021.rs | 2 +- tests/rustdoc-json/attrs/export_name_2024.rs | 2 +- tests/rustdoc-json/attrs/must_use.rs | 4 +- tests/rustdoc-json/attrs/no_mangle_2021.rs | 2 +- tests/rustdoc-json/attrs/no_mangle_2024.rs | 2 +- tests/rustdoc-json/attrs/non_exhaustive.rs | 6 +- tests/rustdoc-json/attrs/repr_align.rs | 2 +- tests/rustdoc-json/attrs/repr_c.rs | 6 +- tests/rustdoc-json/attrs/repr_combination.rs | 22 ++-- tests/rustdoc-json/attrs/repr_int_enum.rs | 6 +- tests/rustdoc-json/attrs/repr_packed.rs | 4 +- tests/rustdoc-json/attrs/repr_transparent.rs | 8 +- tests/rustdoc-json/blanket_impls.rs | 6 +- tests/rustdoc-json/doc_hidden_failure.rs | 4 +- .../rustdoc-json/enums/discriminant/basic.rs | 12 +- tests/rustdoc-json/enums/discriminant/expr.rs | 36 ++--- .../rustdoc-json/enums/discriminant/limits.rs | 32 ++--- .../discriminant/num_underscore_and_suffix.rs | 16 +-- .../only_some_have_discriminant.rs | 8 +- .../rustdoc-json/enums/discriminant/struct.rs | 14 +- .../rustdoc-json/enums/discriminant/tuple.rs | 14 +- .../enums/doc_link_to_foreign_variant.rs | 6 +- tests/rustdoc-json/enums/field_hidden.rs | 8 +- tests/rustdoc-json/enums/field_order.rs | 40 +++--- tests/rustdoc-json/enums/kind.rs | 38 +++--- .../rustdoc-json/enums/struct_field_hidden.rs | 12 +- .../rustdoc-json/enums/tuple_fields_hidden.rs | 124 +++++++++--------- tests/rustdoc-json/enums/use_glob.rs | 10 +- tests/rustdoc-json/enums/use_variant.rs | 12 +- .../rustdoc-json/enums/use_variant_foreign.rs | 4 +- tests/rustdoc-json/enums/variant_order.rs | 40 +++--- tests/rustdoc-json/enums/variant_struct.rs | 14 +- .../enums/variant_tuple_struct.rs | 14 +- tests/rustdoc-json/fn_pointer/abi.rs | 14 +- tests/rustdoc-json/fn_pointer/generics.rs | 14 +- tests/rustdoc-json/fn_pointer/qualifiers.rs | 12 +- tests/rustdoc-json/fns/abi.rs | 14 +- tests/rustdoc-json/fns/async_return.rs | 24 ++-- tests/rustdoc-json/fns/extern_c_variadic.rs | 4 +- tests/rustdoc-json/fns/extern_safe.rs | 8 +- tests/rustdoc-json/fns/generic_args.rs | 88 ++++++------- tests/rustdoc-json/fns/generic_returns.rs | 10 +- tests/rustdoc-json/fns/generics.rs | 30 ++--- tests/rustdoc-json/fns/pattern_arg.rs | 4 +- tests/rustdoc-json/fns/qualifiers.rs | 36 ++--- tests/rustdoc-json/fns/return_type_alias.rs | 4 +- .../generic-associated-types/gats.rs | 34 ++--- tests/rustdoc-json/generic_impl.rs | 6 +- tests/rustdoc-json/glob_import.rs | 4 +- .../rustdoc-json/impl-trait-in-assoc-type.rs | 18 +-- .../impl-trait-precise-capturing.rs | 6 +- tests/rustdoc-json/impls/auto.rs | 6 +- .../rustdoc-json/impls/blanket_with_local.rs | 8 +- tests/rustdoc-json/impls/foreign_for_local.rs | 12 +- .../impls/impl_item_visibility.rs | 6 +- .../impls/impl_item_visibility_show_hidden.rs | 6 +- .../impl_item_visibility_show_private.rs | 6 +- .../rustdoc-json/impls/import_from_private.rs | 12 +- .../issue-112852-dangling-trait-impl-id-2.rs | 10 +- .../issue-112852-dangling-trait-impl-id-3.rs | 6 +- .../issue-112852-dangling-trait-impl-id.rs | 10 +- tests/rustdoc-json/impls/local_for_foreign.rs | 12 +- tests/rustdoc-json/impls/local_for_local.rs | 14 +- .../impls/local_for_local_primitive.rs | 12 +- .../rustdoc-json/impls/local_for_primitive.rs | 6 +- .../impls/pub_for_hidden_private.rs | 2 +- .../rustdoc-json/impls/trait-for-dyn-trait.rs | 14 +- .../intra-doc-links/foreign_variant.rs | 6 +- .../rustdoc-json/intra-doc-links/non_page.rs | 20 +-- .../intra-doc-links/user_written.rs | 4 +- tests/rustdoc-json/keyword.rs | 8 +- tests/rustdoc-json/keyword_private.rs | 16 +-- tests/rustdoc-json/lifetime/longest.rs | 34 ++--- tests/rustdoc-json/lifetime/outlives.rs | 30 ++--- .../lifetime/outlives_in_param.rs | 10 +- .../lifetime/outlives_in_where.rs | 22 ++-- tests/rustdoc-json/methods/abi.rs | 30 ++--- tests/rustdoc-json/methods/qualifiers.rs | 36 ++--- tests/rustdoc-json/nested.rs | 38 +++--- tests/rustdoc-json/non_lifetime_binders.rs | 10 +- tests/rustdoc-json/output_generics.rs | 10 +- tests/rustdoc-json/path_name.rs | 40 +++--- .../primitives/local_primitive.rs | 10 +- .../primitives/primitive_impls.rs | 18 +-- .../primitives/primitive_overloading.rs | 4 +- .../rustdoc-json/primitives/primitive_type.rs | 12 +- .../rustdoc-json/primitives/use_primitive.rs | 12 +- tests/rustdoc-json/pub_mod_in_private_mod.rs | 2 +- .../reexport/doc_inline_external_crate.rs | 8 +- .../reexport/export_extern_crate_as_self.rs | 2 +- .../reexport/extern_crate_glob.rs | 8 +- tests/rustdoc-json/reexport/glob_collision.rs | 16 +-- tests/rustdoc-json/reexport/glob_empty_mod.rs | 6 +- tests/rustdoc-json/reexport/glob_extern.rs | 18 +-- tests/rustdoc-json/reexport/glob_private.rs | 26 ++-- .../rustdoc-json/reexport/in_root_and_mod.rs | 4 +- .../reexport/in_root_and_mod_pub.rs | 12 +- tests/rustdoc-json/reexport/macro.rs | 6 +- .../rustdoc-json/reexport/mod_not_included.rs | 4 +- .../reexport/private_twice_one_inline.rs | 16 +-- .../reexport/private_two_names.rs | 18 +-- .../reexport/pub_use_doc_hidden.rs | 4 +- .../reexport_method_from_private_module.rs | 12 +- .../reexport/reexport_of_hidden.rs | 2 +- tests/rustdoc-json/reexport/rename_private.rs | 6 +- tests/rustdoc-json/reexport/rename_public.rs | 10 +- .../reexport/same_name_different_types.rs | 4 +- .../same_type_reexported_more_than_once.rs | 8 +- tests/rustdoc-json/reexport/simple_private.rs | 12 +- tests/rustdoc-json/reexport/simple_public.rs | 12 +- .../reexport/synthesize_trait_with_docs.rs | 2 +- tests/rustdoc-json/return-type-notation.rs | 4 +- tests/rustdoc-json/return_private.rs | 8 +- tests/rustdoc-json/statics/extern.rs | 36 ++--- tests/rustdoc-json/statics/statics.rs | 16 +-- tests/rustdoc-json/stripped_modules.rs | 10 +- tests/rustdoc-json/structs/field_order.rs | 40 +++--- tests/rustdoc-json/structs/plain_all_pub.rs | 12 +- .../rustdoc-json/structs/plain_doc_hidden.rs | 10 +- tests/rustdoc-json/structs/plain_empty.rs | 8 +- tests/rustdoc-json/structs/plain_pub_priv.rs | 8 +- tests/rustdoc-json/structs/tuple.rs | 6 +- tests/rustdoc-json/structs/tuple_empty.rs | 2 +- tests/rustdoc-json/structs/tuple_pub_priv.rs | 10 +- tests/rustdoc-json/structs/unit.rs | 6 +- tests/rustdoc-json/structs/with_generics.rs | 16 +-- tests/rustdoc-json/structs/with_primitives.rs | 12 +- tests/rustdoc-json/trait_alias.rs | 12 +- tests/rustdoc-json/traits/has_body.rs | 16 +-- tests/rustdoc-json/traits/implementors.rs | 14 +- .../rustdoc-json/traits/is_dyn_compatible.rs | 12 +- .../rustdoc-json/traits/private_supertrait.rs | 8 +- tests/rustdoc-json/traits/self.rs | 30 ++--- tests/rustdoc-json/traits/supertrait.rs | 22 ++-- tests/rustdoc-json/traits/trait_alias.rs | 22 ++-- .../rustdoc-json/traits/uses_extern_trait.rs | 4 +- tests/rustdoc-json/type/dyn.rs | 74 +++++------ tests/rustdoc-json/type/extern.rs | 4 +- tests/rustdoc-json/type/fn_lifetime.rs | 38 +++--- tests/rustdoc-json/type/generic_default.rs | 46 +++---- tests/rustdoc-json/type/hrtb.rs | 16 +-- .../type/inherent_associated_type.rs | 16 +-- .../type/inherent_associated_type_bound.rs | 18 +-- .../inherent_associated_type_projections.rs | 26 ++-- tests/rustdoc-json/type_alias.rs | 12 +- tests/rustdoc-json/unions/field_order.rs | 40 +++--- tests/rustdoc-json/unions/impl.rs | 10 +- tests/rustdoc-json/unions/union.rs | 12 +- 151 files changed, 1155 insertions(+), 1155 deletions(-) diff --git a/tests/rustdoc-json/assoc_items.rs b/tests/rustdoc-json/assoc_items.rs index f315f37966d0..f47a522e81a4 100644 --- a/tests/rustdoc-json/assoc_items.rs +++ b/tests/rustdoc-json/assoc_items.rs @@ -3,32 +3,32 @@ pub struct Simple; impl Simple { - //@ has "$.index[*][?(@.name=='CONSTANT')].inner.assoc_const" + //@ has "$.index[?(@.name=='CONSTANT')].inner.assoc_const" pub const CONSTANT: usize = 0; } pub trait EasyToImpl { - //@ has "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type" - //@ is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.type" null - //@ is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.bounds" [] + //@ has "$.index[?(@.docs=='ToDeclare trait')].inner.assoc_type" + //@ is "$.index[?(@.docs=='ToDeclare trait')].inner.assoc_type.type" null + //@ is "$.index[?(@.docs=='ToDeclare trait')].inner.assoc_type.bounds" [] /// ToDeclare trait type ToDeclare; - //@ has "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const" - //@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.value" null - //@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.type.primitive" '"usize"' + //@ has "$.index[?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const" + //@ is "$.index[?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.value" null + //@ is "$.index[?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.type.primitive" '"usize"' /// AN_ATTRIBUTE trait const AN_ATTRIBUTE: usize; } impl EasyToImpl for Simple { - //@ has "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type" - //@ is "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type.type.primitive" \"usize\" + //@ has "$.index[?(@.docs=='ToDeclare impl')].inner.assoc_type" + //@ is "$.index[?(@.docs=='ToDeclare impl')].inner.assoc_type.type.primitive" \"usize\" /// ToDeclare impl type ToDeclare = usize; - //@ has "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const" - //@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.type.primitive" \"usize\" - //@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.value" \"12\" + //@ has "$.index[?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const" + //@ is "$.index[?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.type.primitive" \"usize\" + //@ is "$.index[?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.value" \"12\" /// AN_ATTRIBUTE impl const AN_ATTRIBUTE: usize = 12; } diff --git a/tests/rustdoc-json/assoc_type.rs b/tests/rustdoc-json/assoc_type.rs index 43b4d387d924..816075ca17ae 100644 --- a/tests/rustdoc-json/assoc_type.rs +++ b/tests/rustdoc-json/assoc_type.rs @@ -1,9 +1,9 @@ // Regression test for . -//@ has "$.index[*][?(@.name=='Trait')]" -//@ has "$.index[*][?(@.name=='AssocType')]" -//@ has "$.index[*][?(@.name=='S')]" -//@ has "$.index[*][?(@.name=='S2')]" +//@ has "$.index[?(@.name=='Trait')]" +//@ has "$.index[?(@.name=='AssocType')]" +//@ has "$.index[?(@.name=='S')]" +//@ has "$.index[?(@.name=='S2')]" pub trait Trait { type AssocType; diff --git a/tests/rustdoc-json/attrs/deprecated.rs b/tests/rustdoc-json/attrs/deprecated.rs index 5cde7af841f7..0799471fc888 100644 --- a/tests/rustdoc-json/attrs/deprecated.rs +++ b/tests/rustdoc-json/attrs/deprecated.rs @@ -1,38 +1,38 @@ -//@ is "$.index[*][?(@.name=='not')].attrs" [] -//@ is "$.index[*][?(@.name=='not')].deprecation" null +//@ is "$.index[?(@.name=='not')].attrs" [] +//@ is "$.index[?(@.name=='not')].deprecation" null pub fn not() {} -//@ is "$.index[*][?(@.name=='raw')].attrs" [] -//@ is "$.index[*][?(@.name=='raw')].deprecation" '{"since": null, "note": null}' +//@ is "$.index[?(@.name=='raw')].attrs" [] +//@ is "$.index[?(@.name=='raw')].deprecation" '{"since": null, "note": null}' #[deprecated] pub fn raw() {} -//@ is "$.index[*][?(@.name=='equals_string')].attrs" [] -//@ is "$.index[*][?(@.name=='equals_string')].deprecation" '{"since": null, "note": "here is a reason"}' +//@ is "$.index[?(@.name=='equals_string')].attrs" [] +//@ is "$.index[?(@.name=='equals_string')].deprecation" '{"since": null, "note": "here is a reason"}' #[deprecated = "here is a reason"] pub fn equals_string() {} -//@ is "$.index[*][?(@.name=='since')].attrs" [] -//@ is "$.index[*][?(@.name=='since')].deprecation" '{"since": "yoinks ago", "note": null}' +//@ is "$.index[?(@.name=='since')].attrs" [] +//@ is "$.index[?(@.name=='since')].deprecation" '{"since": "yoinks ago", "note": null}' #[deprecated(since = "yoinks ago")] pub fn since() {} -//@ is "$.index[*][?(@.name=='note')].attrs" [] -//@ is "$.index[*][?(@.name=='note')].deprecation" '{"since": null, "note": "7"}' +//@ is "$.index[?(@.name=='note')].attrs" [] +//@ is "$.index[?(@.name=='note')].deprecation" '{"since": null, "note": "7"}' #[deprecated(note = "7")] pub fn note() {} -//@ is "$.index[*][?(@.name=='since_and_note')].attrs" [] -//@ is "$.index[*][?(@.name=='since_and_note')].deprecation" '{"since": "tomorrow", "note": "sorry"}' +//@ is "$.index[?(@.name=='since_and_note')].attrs" [] +//@ is "$.index[?(@.name=='since_and_note')].deprecation" '{"since": "tomorrow", "note": "sorry"}' #[deprecated(since = "tomorrow", note = "sorry")] pub fn since_and_note() {} -//@ is "$.index[*][?(@.name=='note_and_since')].attrs" [] -//@ is "$.index[*][?(@.name=='note_and_since')].deprecation" '{"since": "a year from tomorrow", "note": "your welcome"}' +//@ is "$.index[?(@.name=='note_and_since')].attrs" [] +//@ is "$.index[?(@.name=='note_and_since')].deprecation" '{"since": "a year from tomorrow", "note": "your welcome"}' #[deprecated(note = "your welcome", since = "a year from tomorrow")] pub fn note_and_since() {} -//@ is "$.index[*][?(@.name=='neither_but_parens')].attrs" [] -//@ is "$.index[*][?(@.name=='neither_but_parens')].deprecation" '{"since": null, "note": null}' +//@ is "$.index[?(@.name=='neither_but_parens')].attrs" [] +//@ is "$.index[?(@.name=='neither_but_parens')].deprecation" '{"since": null, "note": null}' #[deprecated()] pub fn neither_but_parens() {} diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs index badf124bdde3..254e9f6ef5bf 100644 --- a/tests/rustdoc-json/attrs/export_name_2021.rs +++ b/tests/rustdoc-json/attrs/export_name_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[*][?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' #[export_name = "altered"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs index c5bb9dcc8f68..8129c109306c 100644 --- a/tests/rustdoc-json/attrs/export_name_2024.rs +++ b/tests/rustdoc-json/attrs/export_name_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024 // is still `#[export_name = ..]` without the `unsafe` attribute wrapper. -//@ is "$.index[*][?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' #[unsafe(export_name = "altered")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs index dca73abc76a1..64df8e5f509f 100644 --- a/tests/rustdoc-json/attrs/must_use.rs +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -1,9 +1,9 @@ #![no_std] -//@ is "$.index[*][?(@.name=='example')].attrs" '["#[must_use]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[must_use]"]' #[must_use] pub fn example() -> impl Iterator {} -//@ is "$.index[*][?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]' +//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]' #[must_use = "does nothing if you do not use it"] pub fn explicit_message() -> impl Iterator {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs index 258542086ec3..588be7256db5 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2021.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[*][?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' #[no_mangle] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs index 4c01082d045e..0d500e20e6c5 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2024.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024 // is still `#[no_mangle]` without the `unsafe` attribute wrapper. -//@ is "$.index[*][?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' #[unsafe(no_mangle)] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs index 5d738fc0560d..b95f1a8171fd 100644 --- a/tests/rustdoc-json/attrs/non_exhaustive.rs +++ b/tests/rustdoc-json/attrs/non_exhaustive.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[*][?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' #[non_exhaustive] pub enum MyEnum { First, } pub enum NonExhaustiveVariant { - //@ is "$.index[*][?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' + //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' #[non_exhaustive] Variant(i64), } -//@ is "$.index[*][?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' #[non_exhaustive] pub struct MyStruct { pub x: i64, diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs index bebbe1fea349..83506737b211 100644 --- a/tests/rustdoc-json/attrs/repr_align.rs +++ b/tests/rustdoc-json/attrs/repr_align.rs @@ -1,6 +1,6 @@ #![no_std] -//@ is "$.index[*][?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]' +//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]' #[repr(align(4))] pub struct Aligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs index 609d33d94de7..018086b3c1ff 100644 --- a/tests/rustdoc-json/attrs/repr_c.rs +++ b/tests/rustdoc-json/attrs/repr_c.rs @@ -1,16 +1,16 @@ #![no_std] -//@ is "$.index[*][?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]' #[repr(C)] pub struct ReprCStruct(pub i64); -//@ is "$.index[*][?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]' #[repr(C)] pub enum ReprCEnum { First, } -//@ is "$.index[*][?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]' #[repr(C)] pub union ReprCUnion { pub left: i64, diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs index 662bfef67cb8..c3ef8becb779 100644 --- a/tests/rustdoc-json/attrs/repr_combination.rs +++ b/tests/rustdoc-json/attrs/repr_combination.rs @@ -2,33 +2,33 @@ // Combinations of `#[repr(..)]` attributes. -//@ is "$.index[*][?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]' +//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]' #[repr(C, i8)] pub enum ReprCI8 { First, } -//@ is "$.index[*][?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]' #[repr(C)] #[repr(i16)] pub enum SeparateReprCI16 { First, } -//@ is "$.index[*][?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]' #[repr(usize, C)] pub enum ReversedReprCUsize { First, } -//@ is "$.index[*][?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]' #[repr(C, packed)] pub struct ReprCPacked { a: i8, b: i64, } -//@ is "$.index[*][?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]' #[repr(C)] #[repr(packed(2))] pub struct SeparateReprCPacked { @@ -36,21 +36,21 @@ pub struct SeparateReprCPacked { b: i64, } -//@ is "$.index[*][?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]' #[repr(packed(2), C)] pub struct ReversedReprCPacked { a: i8, b: i64, } -//@ is "$.index[*][?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]' #[repr(C, align(16))] pub struct ReprCAlign { a: i8, b: i64, } -//@ is "$.index[*][?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]' #[repr(C)] #[repr(align(2))] pub struct SeparateReprCAlign { @@ -58,20 +58,20 @@ pub struct SeparateReprCAlign { b: i64, } -//@ is "$.index[*][?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]' #[repr(align(2), C)] pub struct ReversedReprCAlign { a: i8, b: i64, } -//@ is "$.index[*][?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]' +//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]' #[repr(C, align(16), isize)] pub enum AlignedExplicitRepr { First, } -//@ is "$.index[*][?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]' #[repr(isize, C, align(16))] pub enum ReorderedAlignedExplicitRepr { First, diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs index 2ad57de27988..206cb7835f52 100644 --- a/tests/rustdoc-json/attrs/repr_int_enum.rs +++ b/tests/rustdoc-json/attrs/repr_int_enum.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[*][?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]' +//@ is "$.index[?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]' #[repr(i8)] pub enum I8 { First, } -//@ is "$.index[*][?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' +//@ is "$.index[?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' #[repr(i32)] pub enum I32 { First, } -//@ is "$.index[*][?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]' +//@ is "$.index[?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]' #[repr(usize)] pub enum Usize { First, diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs index 33acc23b7c89..d4c400f72f81 100644 --- a/tests/rustdoc-json/attrs/repr_packed.rs +++ b/tests/rustdoc-json/attrs/repr_packed.rs @@ -3,14 +3,14 @@ // Note the normalization: // `#[repr(packed)]` in has the implict "1" in rustdoc JSON. -//@ is "$.index[*][?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]' +//@ is "$.index[?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]' #[repr(packed)] pub struct Packed { a: i8, b: i64, } -//@ is "$.index[*][?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]' +//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]' #[repr(packed(4))] pub struct PackedAligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_transparent.rs b/tests/rustdoc-json/attrs/repr_transparent.rs index ef6e69f8703b..3f57b21dcc52 100644 --- a/tests/rustdoc-json/attrs/repr_transparent.rs +++ b/tests/rustdoc-json/attrs/repr_transparent.rs @@ -5,18 +5,18 @@ // // https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent -//@ is "$.index[*][?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' #[repr(transparent)] pub struct Transparent(pub i64); -//@ is "$.index[*][?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' #[repr(transparent)] pub struct TransparentNonPub(i64); -//@ is "$.index[*][?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' #[repr(transparent)] pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ()); -//@ is "$.index[*][?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' #[repr(transparent)] pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ()); diff --git a/tests/rustdoc-json/blanket_impls.rs b/tests/rustdoc-json/blanket_impls.rs index bf0983e66a17..d500bf5af6bd 100644 --- a/tests/rustdoc-json/blanket_impls.rs +++ b/tests/rustdoc-json/blanket_impls.rs @@ -2,7 +2,7 @@ #![no_std] -//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type" -//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path" -//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path.path" \"Infallible\" +//@ has "$.index[?(@.name=='Error')].inner.assoc_type" +//@ has "$.index[?(@.name=='Error')].inner.assoc_type.type.resolved_path" +//@ has "$.index[?(@.name=='Error')].inner.assoc_type.type.resolved_path.path" \"Infallible\" pub struct ForBlanketTryFromImpl; diff --git a/tests/rustdoc-json/doc_hidden_failure.rs b/tests/rustdoc-json/doc_hidden_failure.rs index 249e35b72436..e68df7e9c61d 100644 --- a/tests/rustdoc-json/doc_hidden_failure.rs +++ b/tests/rustdoc-json/doc_hidden_failure.rs @@ -11,8 +11,8 @@ mod auto { } } -//@ count "$.index[*][?(@.name=='builders')]" 1 -//@ has "$.index[*][?(@.name == 'ActionRowBuilder')"] +//@ count "$.index[?(@.name=='builders')]" 1 +//@ has "$.index[?(@.name == 'ActionRowBuilder')"] pub use auto::*; pub mod builders { diff --git a/tests/rustdoc-json/enums/discriminant/basic.rs b/tests/rustdoc-json/enums/discriminant/basic.rs index 06a240404fb7..c7f164f34081 100644 --- a/tests/rustdoc-json/enums/discriminant/basic.rs +++ b/tests/rustdoc-json/enums/discriminant/basic.rs @@ -1,12 +1,12 @@ #[repr(i8)] pub enum Ordering { - //@ is "$.index[*][?(@.name=='Less')].inner.variant.discriminant.expr" '"-1"' - //@ is "$.index[*][?(@.name=='Less')].inner.variant.discriminant.value" '"-1"' + //@ is "$.index[?(@.name=='Less')].inner.variant.discriminant.expr" '"-1"' + //@ is "$.index[?(@.name=='Less')].inner.variant.discriminant.value" '"-1"' Less = -1, - //@ is "$.index[*][?(@.name=='Equal')].inner.variant.discriminant.expr" '"0"' - //@ is "$.index[*][?(@.name=='Equal')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[?(@.name=='Equal')].inner.variant.discriminant.expr" '"0"' + //@ is "$.index[?(@.name=='Equal')].inner.variant.discriminant.value" '"0"' Equal = 0, - //@ is "$.index[*][?(@.name=='Greater')].inner.variant.discriminant.expr" '"1"' - //@ is "$.index[*][?(@.name=='Greater')].inner.variant.discriminant.value" '"1"' + //@ is "$.index[?(@.name=='Greater')].inner.variant.discriminant.expr" '"1"' + //@ is "$.index[?(@.name=='Greater')].inner.variant.discriminant.value" '"1"' Greater = 1, } diff --git a/tests/rustdoc-json/enums/discriminant/expr.rs b/tests/rustdoc-json/enums/discriminant/expr.rs index bf2bce851080..3743b13fec80 100644 --- a/tests/rustdoc-json/enums/discriminant/expr.rs +++ b/tests/rustdoc-json/enums/discriminant/expr.rs @@ -1,30 +1,30 @@ pub enum Foo { - //@ is "$.index[*][?(@.name=='Addition')].inner.variant.discriminant.value" '"0"' - //@ is "$.index[*][?(@.name=='Addition')].inner.variant.discriminant.expr" '"{ _ }"' + //@ is "$.index[?(@.name=='Addition')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[?(@.name=='Addition')].inner.variant.discriminant.expr" '"{ _ }"' Addition = 0 + 0, - //@ is "$.index[*][?(@.name=='Bin')].inner.variant.discriminant.value" '"1"' - //@ is "$.index[*][?(@.name=='Bin')].inner.variant.discriminant.expr" '"0b1"' + //@ is "$.index[?(@.name=='Bin')].inner.variant.discriminant.value" '"1"' + //@ is "$.index[?(@.name=='Bin')].inner.variant.discriminant.expr" '"0b1"' Bin = 0b1, - //@ is "$.index[*][?(@.name=='Oct')].inner.variant.discriminant.value" '"2"' - //@ is "$.index[*][?(@.name=='Oct')].inner.variant.discriminant.expr" '"0o2"' + //@ is "$.index[?(@.name=='Oct')].inner.variant.discriminant.value" '"2"' + //@ is "$.index[?(@.name=='Oct')].inner.variant.discriminant.expr" '"0o2"' Oct = 0o2, - //@ is "$.index[*][?(@.name=='PubConst')].inner.variant.discriminant.value" '"3"' - //@ is "$.index[*][?(@.name=='PubConst')].inner.variant.discriminant.expr" '"THREE"' + //@ is "$.index[?(@.name=='PubConst')].inner.variant.discriminant.value" '"3"' + //@ is "$.index[?(@.name=='PubConst')].inner.variant.discriminant.expr" '"THREE"' PubConst = THREE, - //@ is "$.index[*][?(@.name=='Hex')].inner.variant.discriminant.value" '"4"' - //@ is "$.index[*][?(@.name=='Hex')].inner.variant.discriminant.expr" '"0x4"' + //@ is "$.index[?(@.name=='Hex')].inner.variant.discriminant.value" '"4"' + //@ is "$.index[?(@.name=='Hex')].inner.variant.discriminant.expr" '"0x4"' Hex = 0x4, - //@ is "$.index[*][?(@.name=='Cast')].inner.variant.discriminant.value" '"5"' - //@ is "$.index[*][?(@.name=='Cast')].inner.variant.discriminant.expr" '"{ _ }"' + //@ is "$.index[?(@.name=='Cast')].inner.variant.discriminant.value" '"5"' + //@ is "$.index[?(@.name=='Cast')].inner.variant.discriminant.expr" '"{ _ }"' Cast = 5 as isize, - //@ is "$.index[*][?(@.name=='PubCall')].inner.variant.discriminant.value" '"6"' - //@ is "$.index[*][?(@.name=='PubCall')].inner.variant.discriminant.expr" '"{ _ }"' + //@ is "$.index[?(@.name=='PubCall')].inner.variant.discriminant.value" '"6"' + //@ is "$.index[?(@.name=='PubCall')].inner.variant.discriminant.expr" '"{ _ }"' PubCall = six(), - //@ is "$.index[*][?(@.name=='PrivCall')].inner.variant.discriminant.value" '"7"' - //@ is "$.index[*][?(@.name=='PrivCall')].inner.variant.discriminant.expr" '"{ _ }"' + //@ is "$.index[?(@.name=='PrivCall')].inner.variant.discriminant.value" '"7"' + //@ is "$.index[?(@.name=='PrivCall')].inner.variant.discriminant.expr" '"{ _ }"' PrivCall = seven(), - //@ is "$.index[*][?(@.name=='PrivConst')].inner.variant.discriminant.value" '"8"' - //@ is "$.index[*][?(@.name=='PrivConst')].inner.variant.discriminant.expr" '"EIGHT"' + //@ is "$.index[?(@.name=='PrivConst')].inner.variant.discriminant.value" '"8"' + //@ is "$.index[?(@.name=='PrivConst')].inner.variant.discriminant.expr" '"EIGHT"' PrivConst = EIGHT, } diff --git a/tests/rustdoc-json/enums/discriminant/limits.rs b/tests/rustdoc-json/enums/discriminant/limits.rs index 7508490d6661..c84181334e35 100644 --- a/tests/rustdoc-json/enums/discriminant/limits.rs +++ b/tests/rustdoc-json/enums/discriminant/limits.rs @@ -3,40 +3,40 @@ #[repr(u64)] pub enum U64 { - //@ is "$.index[*][?(@.name=='U64Min')].inner.variant.discriminant.value" '"0"' - //@ is "$.index[*][?(@.name=='U64Min')].inner.variant.discriminant.expr" '"u64::MIN"' + //@ is "$.index[?(@.name=='U64Min')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[?(@.name=='U64Min')].inner.variant.discriminant.expr" '"u64::MIN"' U64Min = u64::MIN, - //@ is "$.index[*][?(@.name=='U64Max')].inner.variant.discriminant.value" '"18446744073709551615"' - //@ is "$.index[*][?(@.name=='U64Max')].inner.variant.discriminant.expr" '"u64::MAX"' + //@ is "$.index[?(@.name=='U64Max')].inner.variant.discriminant.value" '"18446744073709551615"' + //@ is "$.index[?(@.name=='U64Max')].inner.variant.discriminant.expr" '"u64::MAX"' U64Max = u64::MAX, } #[repr(i64)] pub enum I64 { - //@ is "$.index[*][?(@.name=='I64Min')].inner.variant.discriminant.value" '"-9223372036854775808"' - //@ is "$.index[*][?(@.name=='I64Min')].inner.variant.discriminant.expr" '"i64::MIN"' + //@ is "$.index[?(@.name=='I64Min')].inner.variant.discriminant.value" '"-9223372036854775808"' + //@ is "$.index[?(@.name=='I64Min')].inner.variant.discriminant.expr" '"i64::MIN"' I64Min = i64::MIN, - //@ is "$.index[*][?(@.name=='I64Max')].inner.variant.discriminant.value" '"9223372036854775807"' - //@ is "$.index[*][?(@.name=='I64Max')].inner.variant.discriminant.expr" '"i64::MAX"' + //@ is "$.index[?(@.name=='I64Max')].inner.variant.discriminant.value" '"9223372036854775807"' + //@ is "$.index[?(@.name=='I64Max')].inner.variant.discriminant.expr" '"i64::MAX"' I64Max = i64::MAX, } #[repr(u128)] pub enum U128 { - //@ is "$.index[*][?(@.name=='U128Min')].inner.variant.discriminant.value" '"0"' - //@ is "$.index[*][?(@.name=='U128Min')].inner.variant.discriminant.expr" '"u128::MIN"' + //@ is "$.index[?(@.name=='U128Min')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[?(@.name=='U128Min')].inner.variant.discriminant.expr" '"u128::MIN"' U128Min = u128::MIN, - //@ is "$.index[*][?(@.name=='U128Max')].inner.variant.discriminant.value" '"340282366920938463463374607431768211455"' - //@ is "$.index[*][?(@.name=='U128Max')].inner.variant.discriminant.expr" '"u128::MAX"' + //@ is "$.index[?(@.name=='U128Max')].inner.variant.discriminant.value" '"340282366920938463463374607431768211455"' + //@ is "$.index[?(@.name=='U128Max')].inner.variant.discriminant.expr" '"u128::MAX"' U128Max = u128::MAX, } #[repr(i128)] pub enum I128 { - //@ is "$.index[*][?(@.name=='I128Min')].inner.variant.discriminant.value" '"-170141183460469231731687303715884105728"' - //@ is "$.index[*][?(@.name=='I128Min')].inner.variant.discriminant.expr" '"i128::MIN"' + //@ is "$.index[?(@.name=='I128Min')].inner.variant.discriminant.value" '"-170141183460469231731687303715884105728"' + //@ is "$.index[?(@.name=='I128Min')].inner.variant.discriminant.expr" '"i128::MIN"' I128Min = i128::MIN, - //@ is "$.index[*][?(@.name=='I128Max')].inner.variant.discriminant.value" '"170141183460469231731687303715884105727"' - //@ is "$.index[*][?(@.name=='I128Max')].inner.variant.discriminant.expr" '"i128::MAX"' + //@ is "$.index[?(@.name=='I128Max')].inner.variant.discriminant.value" '"170141183460469231731687303715884105727"' + //@ is "$.index[?(@.name=='I128Max')].inner.variant.discriminant.expr" '"i128::MAX"' I128Max = i128::MAX, } diff --git a/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs b/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs index 6f66495bed25..acf58048d3a6 100644 --- a/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs +++ b/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs @@ -1,15 +1,15 @@ #[repr(u32)] pub enum Foo { - //@ is "$.index[*][?(@.name=='Basic')].inner.variant.discriminant.value" '"0"' - //@ is "$.index[*][?(@.name=='Basic')].inner.variant.discriminant.expr" '"0"' + //@ is "$.index[?(@.name=='Basic')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[?(@.name=='Basic')].inner.variant.discriminant.expr" '"0"' Basic = 0, - //@ is "$.index[*][?(@.name=='Suffix')].inner.variant.discriminant.value" '"10"' - //@ is "$.index[*][?(@.name=='Suffix')].inner.variant.discriminant.expr" '"10u32"' + //@ is "$.index[?(@.name=='Suffix')].inner.variant.discriminant.value" '"10"' + //@ is "$.index[?(@.name=='Suffix')].inner.variant.discriminant.expr" '"10u32"' Suffix = 10u32, - //@ is "$.index[*][?(@.name=='Underscore')].inner.variant.discriminant.value" '"100"' - //@ is "$.index[*][?(@.name=='Underscore')].inner.variant.discriminant.expr" '"1_0_0"' + //@ is "$.index[?(@.name=='Underscore')].inner.variant.discriminant.value" '"100"' + //@ is "$.index[?(@.name=='Underscore')].inner.variant.discriminant.expr" '"1_0_0"' Underscore = 1_0_0, - //@ is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant.discriminant.value" '"1000"' - //@ is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant.discriminant.expr" '"1_0_0_0u32"' + //@ is "$.index[?(@.name=='SuffixUnderscore')].inner.variant.discriminant.value" '"1000"' + //@ is "$.index[?(@.name=='SuffixUnderscore')].inner.variant.discriminant.expr" '"1_0_0_0u32"' SuffixUnderscore = 1_0_0_0u32, } diff --git a/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs b/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs index 8e7985f07f41..d8b92cfabb3e 100644 --- a/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs +++ b/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs @@ -1,10 +1,10 @@ pub enum Foo { - //@ is "$.index[*][?(@.name=='Has')].inner.variant.discriminant" '{"expr":"0", "value":"0"}' + //@ is "$.index[?(@.name=='Has')].inner.variant.discriminant" '{"expr":"0", "value":"0"}' Has = 0, - //@ is "$.index[*][?(@.name=='Doesnt')].inner.variant.discriminant" null + //@ is "$.index[?(@.name=='Doesnt')].inner.variant.discriminant" null Doesnt, - //@ is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant.discriminant" null + //@ is "$.index[?(@.name=='AlsoDoesnt')].inner.variant.discriminant" null AlsoDoesnt, - //@ is "$.index[*][?(@.name=='AlsoHas')].inner.variant.discriminant" '{"expr":"44", "value":"44"}' + //@ is "$.index[?(@.name=='AlsoHas')].inner.variant.discriminant" '{"expr":"44", "value":"44"}' AlsoHas = 44, } diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index f2bed77902b0..08fb80540fa9 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,13 +1,13 @@ #[repr(i32)] -//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' +//@ is "$.index[?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' pub enum Foo { - //@ is "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null - //@ count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 + //@ is "$.index[?(@.name=='Struct')].inner.variant.discriminant" null + //@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 Struct {}, - //@ is "$.index[*][?(@.name=='StructWithDiscr')].inner.variant.discriminant" '{"expr": "42", "value": "42"}' - //@ count "$.index[*][?(@.name=='StructWithDiscr')].inner.variant.kind.struct.fields[*]" 1 + //@ is "$.index[?(@.name=='StructWithDiscr')].inner.variant.discriminant" '{"expr": "42", "value": "42"}' + //@ count "$.index[?(@.name=='StructWithDiscr')].inner.variant.kind.struct.fields[*]" 1 StructWithDiscr { x: i32 } = 42, - //@ is "$.index[*][?(@.name=='StructWithHexDiscr')].inner.variant.discriminant" '{"expr": "0x42", "value": "66"}' - //@ count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.variant.kind.struct.fields[*]" 2 + //@ is "$.index[?(@.name=='StructWithHexDiscr')].inner.variant.discriminant" '{"expr": "0x42", "value": "66"}' + //@ count "$.index[?(@.name=='StructWithHexDiscr')].inner.variant.kind.struct.fields[*]" 2 StructWithHexDiscr { x: i32, y: bool } = 0x42, } diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index 201c1cdc88e7..c74e9a2c58dd 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,13 +1,13 @@ #[repr(u32)] -//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(U32))])]\n"]' +//@ is "$.index[?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(U32))])]\n"]' pub enum Foo { - //@ is "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null - //@ count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 + //@ is "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null + //@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 Tuple(), - //@ is "$.index[*][?(@.name=='TupleWithDiscr')].inner.variant.discriminant" '{"expr": "1", "value": "1"}' - //@ count "$.index[*][?(@.name=='TupleWithDiscr')].inner.variant.kind.tuple[*]" 1 + //@ is "$.index[?(@.name=='TupleWithDiscr')].inner.variant.discriminant" '{"expr": "1", "value": "1"}' + //@ count "$.index[?(@.name=='TupleWithDiscr')].inner.variant.kind.tuple[*]" 1 TupleWithDiscr(i32) = 1, - //@ is "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.variant.discriminant" '{"expr": "0b10", "value": "2"}' - //@ count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[?(@.name=='TupleWithBinDiscr')].inner.variant.discriminant" '{"expr": "0b10", "value": "2"}' + //@ count "$.index[?(@.name=='TupleWithBinDiscr')].inner.variant.kind.tuple[*]" 2 TupleWithBinDiscr(i32, i32) = 0b10, } diff --git a/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs b/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs index 6aec6960b5f6..6ecd98fadf5b 100644 --- a/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs +++ b/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs @@ -5,7 +5,7 @@ extern crate color; use color::Color::Red; -//@ set red = "$.index[*][?(@.inner.module.is_crate)].links.Red" +//@ set red = "$.index[?(@.inner.module.is_crate)].links.Red" -//@ !has "$.index[*][?(@.name == 'Red')]" -//@ !has "$.index[*][?(@.name == 'Color')]" +//@ !has "$.index[?(@.name == 'Red')]" +//@ !has "$.index[?(@.name == 'Color')]" diff --git a/tests/rustdoc-json/enums/field_hidden.rs b/tests/rustdoc-json/enums/field_hidden.rs index b353678ac923..07ee0e62ea91 100644 --- a/tests/rustdoc-json/enums/field_hidden.rs +++ b/tests/rustdoc-json/enums/field_hidden.rs @@ -1,9 +1,9 @@ // Regression test for . -//@ has "$.index[*][?(@.name=='ParseError')]" -//@ has "$.index[*][?(@.name=='UnexpectedEndTag')]" -//@ is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant.kind.tuple" [null] -//@ is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant.discriminant" null +//@ has "$.index[?(@.name=='ParseError')]" +//@ has "$.index[?(@.name=='UnexpectedEndTag')]" +//@ is "$.index[?(@.name=='UnexpectedEndTag')].inner.variant.kind.tuple" [null] +//@ is "$.index[?(@.name=='UnexpectedEndTag')].inner.variant.discriminant" null pub enum ParseError { UnexpectedEndTag(#[doc(hidden)] u32), diff --git a/tests/rustdoc-json/enums/field_order.rs b/tests/rustdoc-json/enums/field_order.rs index a78be200b418..e85606879540 100644 --- a/tests/rustdoc-json/enums/field_order.rs +++ b/tests/rustdoc-json/enums/field_order.rs @@ -17,24 +17,24 @@ pub enum Whatever { }, } -//@ set 0 = '$.index[*][?(@.name == "ews_0")].id' -//@ set 1 = '$.index[*][?(@.name == "dik_1")].id' -//@ set 2 = '$.index[*][?(@.name == "hsk_2")].id' -//@ set 3 = '$.index[*][?(@.name == "djt_3")].id' -//@ set 4 = '$.index[*][?(@.name == "jnr_4")].id' -//@ set 5 = '$.index[*][?(@.name == "dfs_5")].id' -//@ set 6 = '$.index[*][?(@.name == "bja_6")].id' -//@ set 7 = '$.index[*][?(@.name == "lyc_7")].id' -//@ set 8 = '$.index[*][?(@.name == "yqd_8")].id' -//@ set 9 = '$.index[*][?(@.name == "vll_9")].id' +//@ set 0 = '$.index[?(@.name == "ews_0")].id' +//@ set 1 = '$.index[?(@.name == "dik_1")].id' +//@ set 2 = '$.index[?(@.name == "hsk_2")].id' +//@ set 3 = '$.index[?(@.name == "djt_3")].id' +//@ set 4 = '$.index[?(@.name == "jnr_4")].id' +//@ set 5 = '$.index[?(@.name == "dfs_5")].id' +//@ set 6 = '$.index[?(@.name == "bja_6")].id' +//@ set 7 = '$.index[?(@.name == "lyc_7")].id' +//@ set 8 = '$.index[?(@.name == "yqd_8")].id' +//@ set 9 = '$.index[?(@.name == "vll_9")].id' -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[0]' $0 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[1]' $1 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[2]' $2 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[3]' $3 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[4]' $4 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[5]' $5 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[6]' $6 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[7]' $7 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[8]' $8 -//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[9]' $9 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[0]' $0 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[1]' $1 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[2]' $2 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[3]' $3 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[4]' $4 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[5]' $5 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[6]' $6 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[7]' $7 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[8]' $8 +//@ is '$.index[?(@.name == "Foo")].inner.variant.kind.struct.fields[9]' $9 diff --git a/tests/rustdoc-json/enums/kind.rs b/tests/rustdoc-json/enums/kind.rs index 517a53828b78..3c011858630e 100644 --- a/tests/rustdoc-json/enums/kind.rs +++ b/tests/rustdoc-json/enums/kind.rs @@ -1,27 +1,27 @@ pub enum Foo { - //@ set Unit = "$.index[*][?(@.name=='Unit')].id" - //@ is "$.index[*][?(@.name=='Unit')].inner.variant.kind" '"plain"' + //@ set Unit = "$.index[?(@.name=='Unit')].id" + //@ is "$.index[?(@.name=='Unit')].inner.variant.kind" '"plain"' Unit, - //@ set Named = "$.index[*][?(@.name=='Named')].id" - //@ is "$.index[*][?(@.name=='Named')].inner.variant.kind.struct" '{"fields": [], "has_stripped_fields": false}' + //@ set Named = "$.index[?(@.name=='Named')].id" + //@ is "$.index[?(@.name=='Named')].inner.variant.kind.struct" '{"fields": [], "has_stripped_fields": false}' Named {}, - //@ set Tuple = "$.index[*][?(@.name=='Tuple')].id" - //@ is "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple" [] + //@ set Tuple = "$.index[?(@.name=='Tuple')].id" + //@ is "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple" [] Tuple(), - //@ set NamedField = "$.index[*][?(@.name=='NamedField')].id" - //@ set x = "$.index[*][?(@.name=='x' && @.inner.struct_field)].id" - //@ is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields[*]" $x - //@ is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.has_stripped_fields" false + //@ set NamedField = "$.index[?(@.name=='NamedField')].id" + //@ set x = "$.index[?(@.name=='x' && @.inner.struct_field)].id" + //@ is "$.index[?(@.name=='NamedField')].inner.variant.kind.struct.fields[*]" $x + //@ is "$.index[?(@.name=='NamedField')].inner.variant.kind.struct.has_stripped_fields" false NamedField { x: i32 }, - //@ set TupleField = "$.index[*][?(@.name=='TupleField')].id" - //@ set tup_field = "$.index[*][?(@.name=='0' && @.inner.struct_field)].id" - //@ is "$.index[*][?(@.name=='TupleField')].inner.variant.kind.tuple[*]" $tup_field + //@ set TupleField = "$.index[?(@.name=='TupleField')].id" + //@ set tup_field = "$.index[?(@.name=='0' && @.inner.struct_field)].id" + //@ is "$.index[?(@.name=='TupleField')].inner.variant.kind.tuple[*]" $tup_field TupleField(i32), } -//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[0]" $Unit -//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[1]" $Named -//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[2]" $Tuple -//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[3]" $NamedField -//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[4]" $TupleField -//@ count "$.index[*][?(@.name=='Foo')].inner.enum.variants[*]" 5 +//@ is "$.index[?(@.name=='Foo')].inner.enum.variants[0]" $Unit +//@ is "$.index[?(@.name=='Foo')].inner.enum.variants[1]" $Named +//@ is "$.index[?(@.name=='Foo')].inner.enum.variants[2]" $Tuple +//@ is "$.index[?(@.name=='Foo')].inner.enum.variants[3]" $NamedField +//@ is "$.index[?(@.name=='Foo')].inner.enum.variants[4]" $TupleField +//@ count "$.index[?(@.name=='Foo')].inner.enum.variants[*]" 5 diff --git a/tests/rustdoc-json/enums/struct_field_hidden.rs b/tests/rustdoc-json/enums/struct_field_hidden.rs index 2184f58b1da8..cd9d2ce0b8a4 100644 --- a/tests/rustdoc-json/enums/struct_field_hidden.rs +++ b/tests/rustdoc-json/enums/struct_field_hidden.rs @@ -2,15 +2,15 @@ pub enum Foo { Variant { #[doc(hidden)] a: i32, - //@ set b = "$.index[*][?(@.name=='b')].id" + //@ set b = "$.index[?(@.name=='b')].id" b: i32, #[doc(hidden)] x: i32, - //@ set y = "$.index[*][?(@.name=='y')].id" + //@ set y = "$.index[?(@.name=='y')].id" y: i32, }, - //@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.has_stripped_fields" true - //@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[0]" $b - //@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[1]" $y - //@ count "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[*]" 2 + //@ is "$.index[?(@.name=='Variant')].inner.variant.kind.struct.has_stripped_fields" true + //@ is "$.index[?(@.name=='Variant')].inner.variant.kind.struct.fields[0]" $b + //@ is "$.index[?(@.name=='Variant')].inner.variant.kind.struct.fields[1]" $y + //@ count "$.index[?(@.name=='Variant')].inner.variant.kind.struct.fields[*]" 2 } diff --git a/tests/rustdoc-json/enums/tuple_fields_hidden.rs b/tests/rustdoc-json/enums/tuple_fields_hidden.rs index 3ac7a3ce0fc1..aa25625b94cf 100644 --- a/tests/rustdoc-json/enums/tuple_fields_hidden.rs +++ b/tests/rustdoc-json/enums/tuple_fields_hidden.rs @@ -1,80 +1,80 @@ -//@ set 1.1.0 = "$.index[*][?(@.docs=='1.1.0')].id" -//@ set 2.1.0 = "$.index[*][?(@.docs=='2.1.0')].id" -//@ set 2.1.1 = "$.index[*][?(@.docs=='2.1.1')].id" -//@ set 2.2.1 = "$.index[*][?(@.docs=='2.2.1')].id" -//@ set 2.3.0 = "$.index[*][?(@.docs=='2.3.0')].id" -//@ set 3.1.1 = "$.index[*][?(@.docs=='3.1.1')].id" -//@ set 3.1.2 = "$.index[*][?(@.docs=='3.1.2')].id" -//@ set 3.2.0 = "$.index[*][?(@.docs=='3.2.0')].id" -//@ set 3.2.2 = "$.index[*][?(@.docs=='3.2.2')].id" -//@ set 3.3.0 = "$.index[*][?(@.docs=='3.3.0')].id" -//@ set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id" +//@ set 1.1.0 = "$.index[?(@.docs=='1.1.0')].id" +//@ set 2.1.0 = "$.index[?(@.docs=='2.1.0')].id" +//@ set 2.1.1 = "$.index[?(@.docs=='2.1.1')].id" +//@ set 2.2.1 = "$.index[?(@.docs=='2.2.1')].id" +//@ set 2.3.0 = "$.index[?(@.docs=='2.3.0')].id" +//@ set 3.1.1 = "$.index[?(@.docs=='3.1.1')].id" +//@ set 3.1.2 = "$.index[?(@.docs=='3.1.2')].id" +//@ set 3.2.0 = "$.index[?(@.docs=='3.2.0')].id" +//@ set 3.2.2 = "$.index[?(@.docs=='3.2.2')].id" +//@ set 3.3.0 = "$.index[?(@.docs=='3.3.0')].id" +//@ set 3.3.1 = "$.index[?(@.docs=='3.3.1')].id" pub enum EnumWithStrippedTupleVariants { - //@ count "$.index[*][?(@.name=='None')].inner.variant.kind.tuple[*]" 0 + //@ count "$.index[?(@.name=='None')].inner.variant.kind.tuple[*]" 0 None(), - //@ count "$.index[*][?(@.name=='One')].inner.variant.kind.tuple[*]" 1 - //@ is "$.index[*][?(@.name=='One')].inner.variant.kind.tuple[0]" $1.1.0 + //@ count "$.index[?(@.name=='One')].inner.variant.kind.tuple[*]" 1 + //@ is "$.index[?(@.name=='One')].inner.variant.kind.tuple[0]" $1.1.0 One(/** 1.1.0*/ bool), - //@ count "$.index[*][?(@.name=='OneHidden')].inner.variant.kind.tuple[*]" 1 - //@ is "$.index[*][?(@.name=='OneHidden')].inner.variant.kind.tuple[0]" null + //@ count "$.index[?(@.name=='OneHidden')].inner.variant.kind.tuple[*]" 1 + //@ is "$.index[?(@.name=='OneHidden')].inner.variant.kind.tuple[0]" null OneHidden(#[doc(hidden)] bool), - //@ count "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[*]" 2 - //@ is "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[0]" $2.1.0 - //@ is "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[1]" $2.1.1 + //@ count "$.index[?(@.name=='Two')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[?(@.name=='Two')].inner.variant.kind.tuple[0]" $2.1.0 + //@ is "$.index[?(@.name=='Two')].inner.variant.kind.tuple[1]" $2.1.1 Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool), - //@ count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[*]" 2 - //@ is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[0]" null - //@ is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[1]" $2.2.1 + //@ count "$.index[?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[0]" null + //@ is "$.index[?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[1]" $2.2.1 TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool), - //@ count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[*]" 2 - //@ is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[0]" $2.3.0 - //@ is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[1]" null + //@ count "$.index[?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[0]" $2.3.0 + //@ is "$.index[?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[1]" null TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool), - //@ count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[*]" 2 - //@ is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[0]" null - //@ is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[1]" null + //@ count "$.index[?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[0]" null + //@ is "$.index[?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[1]" null TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool), - //@ count "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[*]" 3 - //@ is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[0]" null - //@ is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[1]" $3.1.1 - //@ is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[2]" $3.1.2 + //@ count "$.index[?(@.name=='Three1')].inner.variant.kind.tuple[*]" 3 + //@ is "$.index[?(@.name=='Three1')].inner.variant.kind.tuple[0]" null + //@ is "$.index[?(@.name=='Three1')].inner.variant.kind.tuple[1]" $3.1.1 + //@ is "$.index[?(@.name=='Three1')].inner.variant.kind.tuple[2]" $3.1.2 Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool), - //@ count "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[*]" 3 - //@ is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[0]" $3.2.0 - //@ is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[1]" null - //@ is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[2]" $3.2.2 + //@ count "$.index[?(@.name=='Three2')].inner.variant.kind.tuple[*]" 3 + //@ is "$.index[?(@.name=='Three2')].inner.variant.kind.tuple[0]" $3.2.0 + //@ is "$.index[?(@.name=='Three2')].inner.variant.kind.tuple[1]" null + //@ is "$.index[?(@.name=='Three2')].inner.variant.kind.tuple[2]" $3.2.2 Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool), - //@ count "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[*]" 3 - //@ is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[0]" $3.3.0 - //@ is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[1]" $3.3.1 - //@ is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[2]" null + //@ count "$.index[?(@.name=='Three3')].inner.variant.kind.tuple[*]" 3 + //@ is "$.index[?(@.name=='Three3')].inner.variant.kind.tuple[0]" $3.3.0 + //@ is "$.index[?(@.name=='Three3')].inner.variant.kind.tuple[1]" $3.3.1 + //@ is "$.index[?(@.name=='Three3')].inner.variant.kind.tuple[2]" null Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool), } -//@ is "$.index[*][?(@.docs=='1.1.0')].name" '"0"' -//@ is "$.index[*][?(@.docs=='2.1.0')].name" '"0"' -//@ is "$.index[*][?(@.docs=='2.1.1')].name" '"1"' -//@ is "$.index[*][?(@.docs=='2.2.1')].name" '"1"' -//@ is "$.index[*][?(@.docs=='2.3.0')].name" '"0"' -//@ is "$.index[*][?(@.docs=='3.1.1')].name" '"1"' -//@ is "$.index[*][?(@.docs=='3.1.2')].name" '"2"' -//@ is "$.index[*][?(@.docs=='3.2.0')].name" '"0"' -//@ is "$.index[*][?(@.docs=='3.2.2')].name" '"2"' -//@ is "$.index[*][?(@.docs=='3.3.0')].name" '"0"' -//@ is "$.index[*][?(@.docs=='3.3.1')].name" '"1"' +//@ is "$.index[?(@.docs=='1.1.0')].name" '"0"' +//@ is "$.index[?(@.docs=='2.1.0')].name" '"0"' +//@ is "$.index[?(@.docs=='2.1.1')].name" '"1"' +//@ is "$.index[?(@.docs=='2.2.1')].name" '"1"' +//@ is "$.index[?(@.docs=='2.3.0')].name" '"0"' +//@ is "$.index[?(@.docs=='3.1.1')].name" '"1"' +//@ is "$.index[?(@.docs=='3.1.2')].name" '"2"' +//@ is "$.index[?(@.docs=='3.2.0')].name" '"0"' +//@ is "$.index[?(@.docs=='3.2.2')].name" '"2"' +//@ is "$.index[?(@.docs=='3.3.0')].name" '"0"' +//@ is "$.index[?(@.docs=='3.3.1')].name" '"1"' -//@ is "$.index[*][?(@.docs=='1.1.0')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='2.1.0')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='2.1.1')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='2.2.1')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='2.3.0')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='3.1.1')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='3.1.2')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='3.2.0')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='3.2.2')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='3.3.0')].inner.struct_field" '{"primitive": "bool"}' -//@ is "$.index[*][?(@.docs=='3.3.1')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='1.1.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='2.1.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='2.1.1')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='2.2.1')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='2.3.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='3.1.1')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='3.1.2')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='3.2.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='3.2.2')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='3.3.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[?(@.docs=='3.3.1')].inner.struct_field" '{"primitive": "bool"}' diff --git a/tests/rustdoc-json/enums/use_glob.rs b/tests/rustdoc-json/enums/use_glob.rs index 2631b43da8e0..18f21ff09033 100644 --- a/tests/rustdoc-json/enums/use_glob.rs +++ b/tests/rustdoc-json/enums/use_glob.rs @@ -1,15 +1,15 @@ // Regression test for -//@ set Color = "$.index[*][?(@.name == 'Color')].id" +//@ set Color = "$.index[?(@.name == 'Color')].id" pub enum Color { Red, Green, Blue, } -//@ set use_Color = "$.index[*][?(@.inner.use)].id" -//@ is "$.index[*][?(@.inner.use)].inner.use.id" $Color -//@ is "$.index[*][?(@.inner.use)].inner.use.is_glob" true +//@ set use_Color = "$.index[?(@.inner.use)].id" +//@ is "$.index[?(@.inner.use)].inner.use.id" $Color +//@ is "$.index[?(@.inner.use)].inner.use.is_glob" true pub use Color::*; -//@ ismany "$.index[*][?(@.name == 'use_glob')].inner.module.items[*]" $Color $use_Color +//@ ismany "$.index[?(@.name == 'use_glob')].inner.module.items[*]" $Color $use_Color diff --git a/tests/rustdoc-json/enums/use_variant.rs b/tests/rustdoc-json/enums/use_variant.rs index 6d3322e0ba9a..26cca0743d92 100644 --- a/tests/rustdoc-json/enums/use_variant.rs +++ b/tests/rustdoc-json/enums/use_variant.rs @@ -1,12 +1,12 @@ -//@ set AlwaysNone = "$.index[*][?(@.name == 'AlwaysNone')].id" +//@ set AlwaysNone = "$.index[?(@.name == 'AlwaysNone')].id" pub enum AlwaysNone { - //@ set None = "$.index[*][?(@.name == 'None')].id" + //@ set None = "$.index[?(@.name == 'None')].id" None, } -//@ is "$.index[*][?(@.name == 'AlwaysNone')].inner.enum.variants[*]" $None +//@ is "$.index[?(@.name == 'AlwaysNone')].inner.enum.variants[*]" $None -//@ set use_None = "$.index[*][?(@.inner.use)].id" -//@ is "$.index[*][?(@.inner.use)].inner.use.id" $None +//@ set use_None = "$.index[?(@.inner.use)].id" +//@ is "$.index[?(@.inner.use)].inner.use.id" $None pub use AlwaysNone::None; -//@ ismany "$.index[*][?(@.name == 'use_variant')].inner.module.items[*]" $AlwaysNone $use_None +//@ ismany "$.index[?(@.name == 'use_variant')].inner.module.items[*]" $AlwaysNone $use_None diff --git a/tests/rustdoc-json/enums/use_variant_foreign.rs b/tests/rustdoc-json/enums/use_variant_foreign.rs index a9ad61b9fe35..844dd758680c 100644 --- a/tests/rustdoc-json/enums/use_variant_foreign.rs +++ b/tests/rustdoc-json/enums/use_variant_foreign.rs @@ -5,5 +5,5 @@ extern crate color; //@ has "$.index[*].inner.use[?(@.name == 'Red')]" pub use color::Color::Red; -//@ !has "$.index[*][?(@.name == 'Red')]" -//@ !has "$.index[*][?(@.name == 'Color')]" +//@ !has "$.index[?(@.name == 'Red')]" +//@ !has "$.index[?(@.name == 'Color')]" diff --git a/tests/rustdoc-json/enums/variant_order.rs b/tests/rustdoc-json/enums/variant_order.rs index 6ebe28c94ca1..dd11c0963eed 100644 --- a/tests/rustdoc-json/enums/variant_order.rs +++ b/tests/rustdoc-json/enums/variant_order.rs @@ -15,24 +15,24 @@ pub enum Foo { Vll9, } -//@ set 0 = '$.index[*][?(@.name == "Ews0")].id' -//@ set 1 = '$.index[*][?(@.name == "Dik1")].id' -//@ set 2 = '$.index[*][?(@.name == "Hsk2")].id' -//@ set 3 = '$.index[*][?(@.name == "Djt3")].id' -//@ set 4 = '$.index[*][?(@.name == "Jnr4")].id' -//@ set 5 = '$.index[*][?(@.name == "Dfs5")].id' -//@ set 6 = '$.index[*][?(@.name == "Bja6")].id' -//@ set 7 = '$.index[*][?(@.name == "Lyc7")].id' -//@ set 8 = '$.index[*][?(@.name == "Yqd8")].id' -//@ set 9 = '$.index[*][?(@.name == "Vll9")].id' +//@ set 0 = '$.index[?(@.name == "Ews0")].id' +//@ set 1 = '$.index[?(@.name == "Dik1")].id' +//@ set 2 = '$.index[?(@.name == "Hsk2")].id' +//@ set 3 = '$.index[?(@.name == "Djt3")].id' +//@ set 4 = '$.index[?(@.name == "Jnr4")].id' +//@ set 5 = '$.index[?(@.name == "Dfs5")].id' +//@ set 6 = '$.index[?(@.name == "Bja6")].id' +//@ set 7 = '$.index[?(@.name == "Lyc7")].id' +//@ set 8 = '$.index[?(@.name == "Yqd8")].id' +//@ set 9 = '$.index[?(@.name == "Vll9")].id' -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[0]' $0 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[1]' $1 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[2]' $2 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[3]' $3 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[4]' $4 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[5]' $5 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[6]' $6 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[7]' $7 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[8]' $8 -//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[9]' $9 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[0]' $0 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[1]' $1 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[2]' $2 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[3]' $3 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[4]' $4 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[5]' $5 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[6]' $6 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[7]' $7 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[8]' $8 +//@ is '$.index[?(@.name == "Foo")].inner.enum.variants[9]' $9 diff --git a/tests/rustdoc-json/enums/variant_struct.rs b/tests/rustdoc-json/enums/variant_struct.rs index 44a0c946711f..730689c8afa0 100644 --- a/tests/rustdoc-json/enums/variant_struct.rs +++ b/tests/rustdoc-json/enums/variant_struct.rs @@ -1,10 +1,10 @@ -//@ is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='EnumStruct')].inner.enum" +//@ is "$.index[?(@.name=='EnumStruct')].visibility" \"public\" +//@ has "$.index[?(@.name=='EnumStruct')].inner.enum" pub enum EnumStruct { - //@ has "$.index[*][?(@.name=='x')].inner.struct_field" - //@ set x = "$.index[*][?(@.name=='x')].id" - //@ has "$.index[*][?(@.name=='y')].inner.struct_field" - //@ set y = "$.index[*][?(@.name=='y')].id" - //@ ismany "$.index[*][?(@.name=='VariantS')].inner.variant.kind.struct.fields[*]" $x $y + //@ has "$.index[?(@.name=='x')].inner.struct_field" + //@ set x = "$.index[?(@.name=='x')].id" + //@ has "$.index[?(@.name=='y')].inner.struct_field" + //@ set y = "$.index[?(@.name=='y')].id" + //@ ismany "$.index[?(@.name=='VariantS')].inner.variant.kind.struct.fields[*]" $x $y VariantS { x: u32, y: String }, } diff --git a/tests/rustdoc-json/enums/variant_tuple_struct.rs b/tests/rustdoc-json/enums/variant_tuple_struct.rs index 04f0cbb40c4a..0fc06920e4b2 100644 --- a/tests/rustdoc-json/enums/variant_tuple_struct.rs +++ b/tests/rustdoc-json/enums/variant_tuple_struct.rs @@ -1,10 +1,10 @@ -//@ is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='EnumTupleStruct')].inner.enum" +//@ is "$.index[?(@.name=='EnumTupleStruct')].visibility" \"public\" +//@ has "$.index[?(@.name=='EnumTupleStruct')].inner.enum" pub enum EnumTupleStruct { - //@ has "$.index[*][?(@.name=='0')].inner.struct_field" - //@ set f0 = "$.index[*][?(@.name=='0')].id" - //@ has "$.index[*][?(@.name=='1')].inner.struct_field" - //@ set f1 = "$.index[*][?(@.name=='1')].id" - //@ ismany "$.index[*][?(@.name=='VariantA')].inner.variant.kind.tuple[*]" $f0 $f1 + //@ has "$.index[?(@.name=='0')].inner.struct_field" + //@ set f0 = "$.index[?(@.name=='0')].id" + //@ has "$.index[?(@.name=='1')].inner.struct_field" + //@ set f1 = "$.index[?(@.name=='1')].id" + //@ ismany "$.index[?(@.name=='VariantA')].inner.variant.kind.tuple[*]" $f0 $f1 VariantA(u32, String), } diff --git a/tests/rustdoc-json/fn_pointer/abi.rs b/tests/rustdoc-json/fn_pointer/abi.rs index 13a967bd35e2..34150c0fe89e 100644 --- a/tests/rustdoc-json/fn_pointer/abi.rs +++ b/tests/rustdoc-json/fn_pointer/abi.rs @@ -1,22 +1,22 @@ #![feature(abi_vectorcall)] -//@ is "$.index[*][?(@.name=='AbiRust')].inner.type_alias.type.function_pointer.header.abi" \"Rust\" +//@ is "$.index[?(@.name=='AbiRust')].inner.type_alias.type.function_pointer.header.abi" \"Rust\" pub type AbiRust = fn(); -//@ is "$.index[*][?(@.name=='AbiC')].inner.type_alias.type.function_pointer.header.abi" '{"C": {"unwind": false}}' +//@ is "$.index[?(@.name=='AbiC')].inner.type_alias.type.function_pointer.header.abi" '{"C": {"unwind": false}}' pub type AbiC = extern "C" fn(); -//@ is "$.index[*][?(@.name=='AbiSystem')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": false}}' +//@ is "$.index[?(@.name=='AbiSystem')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": false}}' pub type AbiSystem = extern "system" fn(); -//@ is "$.index[*][?(@.name=='AbiCUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"C": {"unwind": true}}' +//@ is "$.index[?(@.name=='AbiCUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"C": {"unwind": true}}' pub type AbiCUnwind = extern "C-unwind" fn(); -//@ is "$.index[*][?(@.name=='AbiSystemUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": true}}' +//@ is "$.index[?(@.name=='AbiSystemUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": true}}' pub type AbiSystemUnwind = extern "system-unwind" fn(); -//@ is "$.index[*][?(@.name=='AbiVecorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""' +//@ is "$.index[?(@.name=='AbiVecorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""' pub type AbiVecorcall = extern "vectorcall" fn(); -//@ is "$.index[*][?(@.name=='AbiVecorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' +//@ is "$.index[?(@.name=='AbiVecorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn(); diff --git a/tests/rustdoc-json/fn_pointer/generics.rs b/tests/rustdoc-json/fn_pointer/generics.rs index c974b472297c..960b91e7d8ea 100644 --- a/tests/rustdoc-json/fn_pointer/generics.rs +++ b/tests/rustdoc-json/fn_pointer/generics.rs @@ -1,8 +1,8 @@ -//@ count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[*]" 1 -//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[0][0]" '"val"' -//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[0][1].borrowed_ref.lifetime" \"\'c\" -//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.output.primitive" \"i32\" -//@ count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[*]" 1 -//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].name" \"\'c\" -//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +//@ count "$.index[?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[*]" 1 +//@ is "$.index[?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[0][0]" '"val"' +//@ is "$.index[?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[0][1].borrowed_ref.lifetime" \"\'c\" +//@ is "$.index[?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.output.primitive" \"i32\" +//@ count "$.index[?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[*]" 1 +//@ is "$.index[?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].name" \"\'c\" +//@ is "$.index[?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' pub type WithHigherRankTraitBounds = for<'c> fn(val: &'c i32) -> i32; diff --git a/tests/rustdoc-json/fn_pointer/qualifiers.rs b/tests/rustdoc-json/fn_pointer/qualifiers.rs index 398e31f72db0..769749d0dd4c 100644 --- a/tests/rustdoc-json/fn_pointer/qualifiers.rs +++ b/tests/rustdoc-json/fn_pointer/qualifiers.rs @@ -1,9 +1,9 @@ -//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_unsafe" false -//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_const" false -//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_async" false +//@ is "$.index[?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_unsafe" false +//@ is "$.index[?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_const" false +//@ is "$.index[?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_async" false pub type FnPointer = fn(); -//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_unsafe" true -//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_const" false -//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_async" false +//@ is "$.index[?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_unsafe" true +//@ is "$.index[?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_const" false +//@ is "$.index[?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_async" false pub type UnsafePointer = unsafe fn(); diff --git a/tests/rustdoc-json/fns/abi.rs b/tests/rustdoc-json/fns/abi.rs index 68957f799521..7277bb1f59a4 100644 --- a/tests/rustdoc-json/fns/abi.rs +++ b/tests/rustdoc-json/fns/abi.rs @@ -1,22 +1,22 @@ #![feature(abi_vectorcall)] -//@ is "$.index[*][?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" +//@ is "$.index[?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" pub fn abi_rust() {} -//@ is "$.index[*][?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' +//@ is "$.index[?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' pub extern "C" fn abi_c() {} -//@ is "$.index[*][?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' +//@ is "$.index[?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' pub extern "system" fn abi_system() {} -//@ is "$.index[*][?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' +//@ is "$.index[?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' pub extern "C-unwind" fn abi_c_unwind() {} -//@ is "$.index[*][?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' +//@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} -//@ is "$.index[*][?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' +//@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' pub extern "vectorcall" fn abi_vectorcall() {} -//@ is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' +//@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} diff --git a/tests/rustdoc-json/fns/async_return.rs b/tests/rustdoc-json/fns/async_return.rs index ddfd4ccf90d0..e7c6a2981ace 100644 --- a/tests/rustdoc-json/fns/async_return.rs +++ b/tests/rustdoc-json/fns/async_return.rs @@ -4,30 +4,30 @@ use std::future::Future; -//@ is "$.index[*][?(@.name=='get_int')].inner.function.sig.output.primitive" \"i32\" -//@ is "$.index[*][?(@.name=='get_int')].inner.function.header.is_async" false +//@ is "$.index[?(@.name=='get_int')].inner.function.sig.output.primitive" \"i32\" +//@ is "$.index[?(@.name=='get_int')].inner.function.header.is_async" false pub fn get_int() -> i32 { 42 } -//@ is "$.index[*][?(@.name=='get_int_async')].inner.function.sig.output.primitive" \"i32\" -//@ is "$.index[*][?(@.name=='get_int_async')].inner.function.header.is_async" true +//@ is "$.index[?(@.name=='get_int_async')].inner.function.sig.output.primitive" \"i32\" +//@ is "$.index[?(@.name=='get_int_async')].inner.function.header.is_async" true pub async fn get_int_async() -> i32 { 42 } -//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.path" '"Future"' -//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"' -//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\" -//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.header.is_async" false +//@ is "$.index[?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.path" '"Future"' +//@ is "$.index[?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"' +//@ is "$.index[?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\" +//@ is "$.index[?(@.name=='get_int_future')].inner.function.header.is_async" false pub fn get_int_future() -> impl Future { async { 42 } } -//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.path" '"Future"' -//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"' -//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\" -//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.header.is_async" true +//@ is "$.index[?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.path" '"Future"' +//@ is "$.index[?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"' +//@ is "$.index[?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\" +//@ is "$.index[?(@.name=='get_int_future_async')].inner.function.header.is_async" true pub async fn get_int_future_async() -> impl Future { async { 42 } } diff --git a/tests/rustdoc-json/fns/extern_c_variadic.rs b/tests/rustdoc-json/fns/extern_c_variadic.rs index 8e9085640e04..d90bb83d98ff 100644 --- a/tests/rustdoc-json/fns/extern_c_variadic.rs +++ b/tests/rustdoc-json/fns/extern_c_variadic.rs @@ -1,6 +1,6 @@ extern "C" { - //@ is "$.index[*][?(@.name == 'not_variadic')].inner.function.sig.is_c_variadic" false + //@ is "$.index[?(@.name == 'not_variadic')].inner.function.sig.is_c_variadic" false pub fn not_variadic(_: i32); - //@ is "$.index[*][?(@.name == 'variadic')].inner.function.sig.is_c_variadic" true + //@ is "$.index[?(@.name == 'variadic')].inner.function.sig.is_c_variadic" true pub fn variadic(_: i32, ...); } diff --git a/tests/rustdoc-json/fns/extern_safe.rs b/tests/rustdoc-json/fns/extern_safe.rs index b00f9f50bd2b..bc217ae914c4 100644 --- a/tests/rustdoc-json/fns/extern_safe.rs +++ b/tests/rustdoc-json/fns/extern_safe.rs @@ -1,17 +1,17 @@ extern "C" { - //@ is "$.index[*][?(@.name=='f1')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='f1')].inner.function.header.is_unsafe" true pub fn f1(); // items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers } unsafe extern "C" { - //@ is "$.index[*][?(@.name=='f4')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='f4')].inner.function.header.is_unsafe" true pub fn f4(); - //@ is "$.index[*][?(@.name=='f5')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='f5')].inner.function.header.is_unsafe" true pub unsafe fn f5(); - //@ is "$.index[*][?(@.name=='f6')].inner.function.header.is_unsafe" false + //@ is "$.index[?(@.name=='f6')].inner.function.header.is_unsafe" false pub safe fn f6(); } diff --git a/tests/rustdoc-json/fns/generic_args.rs b/tests/rustdoc-json/fns/generic_args.rs index 6a7124976f8b..2ea68173d68d 100644 --- a/tests/rustdoc-json/fns/generic_args.rs +++ b/tests/rustdoc-json/fns/generic_args.rs @@ -1,58 +1,58 @@ -//@ set foo = "$.index[*][?(@.name=='Foo')].id" +//@ set foo = "$.index[?(@.name=='Foo')].id" pub trait Foo {} -//@ set generic_foo = "$.index[*][?(@.name=='GenericFoo')].id" +//@ set generic_foo = "$.index[?(@.name=='GenericFoo')].id" pub trait GenericFoo<'a> {} -//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.where_predicates" "[]" -//@ count "$.index[*][?(@.name=='generics')].inner.function.generics.params[*]" 1 -//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].name" '"F"' -//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.default" 'null' -//@ count "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[*]" 1 -//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" '$foo' -//@ count "$.index[*][?(@.name=='generics')].inner.function.sig.inputs[*]" 1 -//@ is "$.index[*][?(@.name=='generics')].inner.function.sig.inputs[0][0]" '"f"' -//@ is "$.index[*][?(@.name=='generics')].inner.function.sig.inputs[0][1].generic" '"F"' +//@ is "$.index[?(@.name=='generics')].inner.function.generics.where_predicates" "[]" +//@ count "$.index[?(@.name=='generics')].inner.function.generics.params[*]" 1 +//@ is "$.index[?(@.name=='generics')].inner.function.generics.params[0].name" '"F"' +//@ is "$.index[?(@.name=='generics')].inner.function.generics.params[0].kind.type.default" 'null' +//@ count "$.index[?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[*]" 1 +//@ is "$.index[?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" '$foo' +//@ count "$.index[?(@.name=='generics')].inner.function.sig.inputs[*]" 1 +//@ is "$.index[?(@.name=='generics')].inner.function.sig.inputs[0][0]" '"f"' +//@ is "$.index[?(@.name=='generics')].inner.function.sig.inputs[0][1].generic" '"F"' pub fn generics(f: F) {} -//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.where_predicates" "[]" -//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[*]" 1 -//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].name" '"impl Foo"' -//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $foo -//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.sig.inputs[*]" 1 -//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.sig.inputs[0][0]" '"f"' -//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.sig.inputs[0][1].impl_trait[*]" 1 -//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.id" $foo +//@ is "$.index[?(@.name=='impl_trait')].inner.function.generics.where_predicates" "[]" +//@ count "$.index[?(@.name=='impl_trait')].inner.function.generics.params[*]" 1 +//@ is "$.index[?(@.name=='impl_trait')].inner.function.generics.params[0].name" '"impl Foo"' +//@ is "$.index[?(@.name=='impl_trait')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $foo +//@ count "$.index[?(@.name=='impl_trait')].inner.function.sig.inputs[*]" 1 +//@ is "$.index[?(@.name=='impl_trait')].inner.function.sig.inputs[0][0]" '"f"' +//@ count "$.index[?(@.name=='impl_trait')].inner.function.sig.inputs[0][1].impl_trait[*]" 1 +//@ is "$.index[?(@.name=='impl_trait')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.id" $foo pub fn impl_trait(f: impl Foo) {} -//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[*]" 3 -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].name" '"F"' -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "is_synthetic": false}}' -//@ count "$.index[*][?(@.name=='where_clase')].inner.function.sig.inputs[*]" 3 -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.sig.inputs[0][0]" '"f"' -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.sig.inputs[0][1].generic" '"F"' -//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[*]" 3 +//@ count "$.index[?(@.name=='where_clase')].inner.function.generics.params[*]" 3 +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.params[0].name" '"F"' +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "is_synthetic": false}}' +//@ count "$.index[?(@.name=='where_clase')].inner.function.sig.inputs[*]" 3 +//@ is "$.index[?(@.name=='where_clase')].inner.function.sig.inputs[0][0]" '"f"' +//@ is "$.index[?(@.name=='where_clase')].inner.function.sig.inputs[0][1].generic" '"F"' +//@ count "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[*]" 3 -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.type.generic" \"F\" -//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]" 1 -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.id" $foo +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.type.generic" \"F\" +//@ count "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]" 1 +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.id" $foo -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.type.generic" \"G\" -//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[*]" 1 -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.id" $generic_foo -//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1 -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\" -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind.lifetime.outlives" "[]" -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.generic_params" "[]" +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.type.generic" \"G\" +//@ count "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[*]" 1 +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.id" $generic_foo +//@ count "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1 +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\" +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind.lifetime.outlives" "[]" +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.generic_params" "[]" -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.lifetime" \"\'b\" -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.type.generic" \"H\" -//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[*]" 1 -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.id" $foo -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]" -//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[*]" 1 -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\" -//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].kind.lifetime.outlives" "[]" +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.lifetime" \"\'b\" +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.type.generic" \"H\" +//@ count "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[*]" 1 +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.id" $foo +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]" +//@ count "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[*]" 1 +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\" +//@ is "$.index[?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].kind.lifetime.outlives" "[]" pub fn where_clase(f: F, g: G, h: H) where F: Foo, diff --git a/tests/rustdoc-json/fns/generic_returns.rs b/tests/rustdoc-json/fns/generic_returns.rs index 90e17525c446..a0d4c745599c 100644 --- a/tests/rustdoc-json/fns/generic_returns.rs +++ b/tests/rustdoc-json/fns/generic_returns.rs @@ -1,11 +1,11 @@ -//@ count "$.index[*][?(@.name=='generic_returns')].inner.module.items[*]" 2 +//@ count "$.index[?(@.name=='generic_returns')].inner.module.items[*]" 2 -//@ set foo = "$.index[*][?(@.name=='Foo')].id" +//@ set foo = "$.index[?(@.name=='Foo')].id" pub trait Foo {} -//@ is "$.index[*][?(@.name=='get_foo')].inner.function.sig.inputs" [] -//@ count "$.index[*][?(@.name=='get_foo')].inner.function.sig.output.impl_trait[*]" 1 -//@ is "$.index[*][?(@.name=='get_foo')].inner.function.sig.output.impl_trait[0].trait_bound.trait.id" $foo +//@ is "$.index[?(@.name=='get_foo')].inner.function.sig.inputs" [] +//@ count "$.index[?(@.name=='get_foo')].inner.function.sig.output.impl_trait[*]" 1 +//@ is "$.index[?(@.name=='get_foo')].inner.function.sig.output.impl_trait[0].trait_bound.trait.id" $foo pub fn get_foo() -> impl Foo { Fooer {} } diff --git a/tests/rustdoc-json/fns/generics.rs b/tests/rustdoc-json/fns/generics.rs index b953094b5de6..3efd917309a0 100644 --- a/tests/rustdoc-json/fns/generics.rs +++ b/tests/rustdoc-json/fns/generics.rs @@ -1,20 +1,20 @@ -//@ set wham_id = "$.index[*][?(@.name=='Wham')].id" +//@ set wham_id = "$.index[?(@.name=='Wham')].id" pub trait Wham {} -//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.where_predicates" [] -//@ count "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[*]" 1 -//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].name" '"T"' -//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.is_synthetic" false -//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id -//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.sig.inputs" '[["w", {"generic": "T"}]]' +//@ is "$.index[?(@.name=='one_generic_param_fn')].inner.function.generics.where_predicates" [] +//@ count "$.index[?(@.name=='one_generic_param_fn')].inner.function.generics.params[*]" 1 +//@ is "$.index[?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].name" '"T"' +//@ is "$.index[?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.is_synthetic" false +//@ is "$.index[?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id +//@ is "$.index[?(@.name=='one_generic_param_fn')].inner.function.sig.inputs" '[["w", {"generic": "T"}]]' pub fn one_generic_param_fn(w: T) {} -//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.where_predicates" [] -//@ count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[*]" 1 -//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].name" '"impl Wham"' -//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.is_synthetic" true -//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id -//@ count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[*]" 1 -//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[0][0]" '"w"' -//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.id" $wham_id +//@ is "$.index[?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.where_predicates" [] +//@ count "$.index[?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[*]" 1 +//@ is "$.index[?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].name" '"impl Wham"' +//@ is "$.index[?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.is_synthetic" true +//@ is "$.index[?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id +//@ count "$.index[?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[*]" 1 +//@ is "$.index[?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[0][0]" '"w"' +//@ is "$.index[?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.id" $wham_id pub fn one_synthetic_generic_param_fn(w: impl Wham) {} diff --git a/tests/rustdoc-json/fns/pattern_arg.rs b/tests/rustdoc-json/fns/pattern_arg.rs index d2a00f47438e..059318a42958 100644 --- a/tests/rustdoc-json/fns/pattern_arg.rs +++ b/tests/rustdoc-json/fns/pattern_arg.rs @@ -1,7 +1,7 @@ -//@ is "$.index[*][?(@.name=='fst')].inner.function.sig.inputs[0][0]" '"(x, _)"' +//@ is "$.index[?(@.name=='fst')].inner.function.sig.inputs[0][0]" '"(x, _)"' pub fn fst((x, _): (X, Y)) -> X { x } -//@ is "$.index[*][?(@.name=='drop_int')].inner.function.sig.inputs[0][0]" '"_"' +//@ is "$.index[?(@.name=='drop_int')].inner.function.sig.inputs[0][0]" '"_"' pub fn drop_int(_: i32) {} diff --git a/tests/rustdoc-json/fns/qualifiers.rs b/tests/rustdoc-json/fns/qualifiers.rs index 67e49f0780ae..7d93a3bf2437 100644 --- a/tests/rustdoc-json/fns/qualifiers.rs +++ b/tests/rustdoc-json/fns/qualifiers.rs @@ -1,33 +1,33 @@ //@ edition:2018 -//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.is_async" false -//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.is_const" false -//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.is_unsafe" false +//@ is "$.index[?(@.name=='nothing_fn')].inner.function.header.is_async" false +//@ is "$.index[?(@.name=='nothing_fn')].inner.function.header.is_const" false +//@ is "$.index[?(@.name=='nothing_fn')].inner.function.header.is_unsafe" false pub fn nothing_fn() {} -//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.is_async" false -//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.is_const" false -//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.is_unsafe" true +//@ is "$.index[?(@.name=='unsafe_fn')].inner.function.header.is_async" false +//@ is "$.index[?(@.name=='unsafe_fn')].inner.function.header.is_const" false +//@ is "$.index[?(@.name=='unsafe_fn')].inner.function.header.is_unsafe" true pub unsafe fn unsafe_fn() {} -//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.is_async" false -//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.is_const" true -//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.is_unsafe" false +//@ is "$.index[?(@.name=='const_fn')].inner.function.header.is_async" false +//@ is "$.index[?(@.name=='const_fn')].inner.function.header.is_const" true +//@ is "$.index[?(@.name=='const_fn')].inner.function.header.is_unsafe" false pub const fn const_fn() {} -//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.is_async" true -//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.is_const" false -//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.is_unsafe" false +//@ is "$.index[?(@.name=='async_fn')].inner.function.header.is_async" true +//@ is "$.index[?(@.name=='async_fn')].inner.function.header.is_const" false +//@ is "$.index[?(@.name=='async_fn')].inner.function.header.is_unsafe" false pub async fn async_fn() {} -//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.is_async" true -//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.is_const" false -//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.is_unsafe" true +//@ is "$.index[?(@.name=='async_unsafe_fn')].inner.function.header.is_async" true +//@ is "$.index[?(@.name=='async_unsafe_fn')].inner.function.header.is_const" false +//@ is "$.index[?(@.name=='async_unsafe_fn')].inner.function.header.is_unsafe" true pub async unsafe fn async_unsafe_fn() {} -//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.is_async" false -//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.is_const" true -//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.is_unsafe" true +//@ is "$.index[?(@.name=='const_unsafe_fn')].inner.function.header.is_async" false +//@ is "$.index[?(@.name=='const_unsafe_fn')].inner.function.header.is_const" true +//@ is "$.index[?(@.name=='const_unsafe_fn')].inner.function.header.is_unsafe" true pub const unsafe fn const_unsafe_fn() {} // It's impossible for a function to be both const and async, so no test for that diff --git a/tests/rustdoc-json/fns/return_type_alias.rs b/tests/rustdoc-json/fns/return_type_alias.rs index d60c4b682589..0aa1db47b7f9 100644 --- a/tests/rustdoc-json/fns/return_type_alias.rs +++ b/tests/rustdoc-json/fns/return_type_alias.rs @@ -1,9 +1,9 @@ // Regression test for -///@ set foo = "$.index[*][?(@.name=='Foo')].id" +///@ set foo = "$.index[?(@.name=='Foo')].id" pub type Foo = i32; -//@ is "$.index[*][?(@.name=='demo')].inner.function.sig.output.resolved_path.id" $foo +//@ is "$.index[?(@.name=='demo')].inner.function.sig.output.resolved_path.id" $foo pub fn demo() -> Foo { 42 } diff --git a/tests/rustdoc-json/generic-associated-types/gats.rs b/tests/rustdoc-json/generic-associated-types/gats.rs index d1172b35fda4..5218cc886e35 100644 --- a/tests/rustdoc-json/generic-associated-types/gats.rs +++ b/tests/rustdoc-json/generic-associated-types/gats.rs @@ -1,32 +1,32 @@ pub trait Display {} pub trait LendingIterator { - //@ count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.params[*]" 1 - //@ is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.params[*].name" \"\'a\" - //@ count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*]" 1 - //@ is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.type.generic" \"Self\" - //@ is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\" - //@ count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.bounds[*]" 1 + //@ count "$.index[?(@.name=='LendingItem')].inner.assoc_type.generics.params[*]" 1 + //@ is "$.index[?(@.name=='LendingItem')].inner.assoc_type.generics.params[*].name" \"\'a\" + //@ count "$.index[?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*]" 1 + //@ is "$.index[?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.type.generic" \"Self\" + //@ is "$.index[?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\" + //@ count "$.index[?(@.name=='LendingItem')].inner.assoc_type.bounds[*]" 1 type LendingItem<'a>: Display where Self: 'a; - //@ count "$.index[*][?(@.name=='lending_next')].inner.function.sig.output.qualified_path.args.angle_bracketed.args[*]" 1 - //@ count "$.index[*][?(@.name=='lending_next')].inner.function.sig.output.qualified_path.args.angle_bracketed.bindings[*]" 0 - //@ is "$.index[*][?(@.name=='lending_next')].inner.function.sig.output.qualified_path.self_type.generic" \"Self\" - //@ is "$.index[*][?(@.name=='lending_next')].inner.function.sig.output.qualified_path.name" \"LendingItem\" + //@ count "$.index[?(@.name=='lending_next')].inner.function.sig.output.qualified_path.args.angle_bracketed.args[*]" 1 + //@ count "$.index[?(@.name=='lending_next')].inner.function.sig.output.qualified_path.args.angle_bracketed.bindings[*]" 0 + //@ is "$.index[?(@.name=='lending_next')].inner.function.sig.output.qualified_path.self_type.generic" \"Self\" + //@ is "$.index[?(@.name=='lending_next')].inner.function.sig.output.qualified_path.name" \"LendingItem\" fn lending_next<'a>(&'a self) -> Self::LendingItem<'a>; } pub trait Iterator { - //@ count "$.index[*][?(@.name=='Item')].inner.assoc_type.generics.params[*]" 0 - //@ count "$.index[*][?(@.name=='Item')].inner.assoc_type.generics.where_predicates[*]" 0 - //@ count "$.index[*][?(@.name=='Item')].inner.assoc_type.bounds[*]" 1 + //@ count "$.index[?(@.name=='Item')].inner.assoc_type.generics.params[*]" 0 + //@ count "$.index[?(@.name=='Item')].inner.assoc_type.generics.where_predicates[*]" 0 + //@ count "$.index[?(@.name=='Item')].inner.assoc_type.bounds[*]" 1 type Item: Display; - //@ count "$.index[*][?(@.name=='next')].inner.function.sig.output.qualified_path.args.angle_bracketed.args[*]" 0 - //@ count "$.index[*][?(@.name=='next')].inner.function.sig.output.qualified_path.args.angle_bracketed.bindings[*]" 0 - //@ is "$.index[*][?(@.name=='next')].inner.function.sig.output.qualified_path.self_type.generic" \"Self\" - //@ is "$.index[*][?(@.name=='next')].inner.function.sig.output.qualified_path.name" \"Item\" + //@ count "$.index[?(@.name=='next')].inner.function.sig.output.qualified_path.args.angle_bracketed.args[*]" 0 + //@ count "$.index[?(@.name=='next')].inner.function.sig.output.qualified_path.args.angle_bracketed.bindings[*]" 0 + //@ is "$.index[?(@.name=='next')].inner.function.sig.output.qualified_path.self_type.generic" \"Self\" + //@ is "$.index[?(@.name=='next')].inner.function.sig.output.qualified_path.name" \"Item\" fn next<'a>(&'a self) -> Self::Item; } diff --git a/tests/rustdoc-json/generic_impl.rs b/tests/rustdoc-json/generic_impl.rs index e7a5d2a78c15..90bda1644ff8 100644 --- a/tests/rustdoc-json/generic_impl.rs +++ b/tests/rustdoc-json/generic_impl.rs @@ -1,8 +1,8 @@ // Regression test for . -//@ has "$.index[*][?(@.name=='f')]" -//@ has "$.index[*][?(@.name=='AssocTy')]" -//@ has "$.index[*][?(@.name=='AssocConst')]" +//@ has "$.index[?(@.name=='f')]" +//@ has "$.index[?(@.name=='AssocTy')]" +//@ has "$.index[?(@.name=='AssocConst')]" pub mod m { pub struct S; diff --git a/tests/rustdoc-json/glob_import.rs b/tests/rustdoc-json/glob_import.rs index b63e5dadd9e7..6887f9ff63d1 100644 --- a/tests/rustdoc-json/glob_import.rs +++ b/tests/rustdoc-json/glob_import.rs @@ -2,8 +2,8 @@ #![no_std] -//@ has "$.index[*][?(@.name=='glob')]" -//@ has "$.index[*][?(@.inner.use)].inner.use.name" \"*\" +//@ has "$.index[?(@.name=='glob')]" +//@ has "$.index[?(@.inner.use)].inner.use.name" \"*\" mod m1 { pub fn f() {} diff --git a/tests/rustdoc-json/impl-trait-in-assoc-type.rs b/tests/rustdoc-json/impl-trait-in-assoc-type.rs index fc12fc87e8da..742a46e89674 100644 --- a/tests/rustdoc-json/impl-trait-in-assoc-type.rs +++ b/tests/rustdoc-json/impl-trait-in-assoc-type.rs @@ -4,25 +4,25 @@ pub struct AlwaysTrue; /// impl IntoIterator impl IntoIterator for AlwaysTrue { - //@ set Item = '$.index[*][?(@.docs=="type Item")].id' + //@ set Item = '$.index[?(@.docs=="type Item")].id' /// type Item type Item = bool; - //@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[*]' 1 - //@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.path' '"Iterator"' - //@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[*]' 1 - //@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name' '"Item"' - //@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive' '"bool"' + //@ count '$.index[?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[*]' 1 + //@ is '$.index[?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.path' '"Iterator"' + //@ count '$.index[?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[*]' 1 + //@ is '$.index[?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name' '"Item"' + //@ is '$.index[?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive' '"bool"' - //@ set IntoIter = '$.index[*][?(@.docs=="type IntoIter")].id' + //@ set IntoIter = '$.index[?(@.docs=="type IntoIter")].id' /// type IntoIter type IntoIter = impl Iterator; - //@ set into_iter = '$.index[*][?(@.docs=="fn into_iter")].id' + //@ set into_iter = '$.index[?(@.docs=="fn into_iter")].id' /// fn into_iter fn into_iter(self) -> Self::IntoIter { std::iter::repeat(true) } } -//@ ismany '$.index[*][?(@.docs=="impl IntoIterator")].inner.impl.items[*]' $Item $IntoIter $into_iter +//@ ismany '$.index[?(@.docs=="impl IntoIterator")].inner.impl.items[*]' $Item $IntoIter $into_iter diff --git a/tests/rustdoc-json/impl-trait-precise-capturing.rs b/tests/rustdoc-json/impl-trait-precise-capturing.rs index 06be95099b4d..37adb514f55f 100644 --- a/tests/rustdoc-json/impl-trait-precise-capturing.rs +++ b/tests/rustdoc-json/impl-trait-precise-capturing.rs @@ -1,4 +1,4 @@ -//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[0].lifetime" \"\'a\" -//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[1].param" \"T\" -//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[2].param" \"N\" +//@ is "$.index[?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[0].lifetime" \"\'a\" +//@ is "$.index[?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[1].param" \"T\" +//@ is "$.index[?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[2].param" \"N\" pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs index f37dae4c1ed4..f94f7338480b 100644 --- a/tests/rustdoc-json/impls/auto.rs +++ b/tests/rustdoc-json/impls/auto.rs @@ -15,8 +15,8 @@ impl Foo { } // Testing spans, so all tests below code -//@ is "$.index[*][?(@.docs=='has span')].span.begin" "[13, 0]" -//@ is "$.index[*][?(@.docs=='has span')].span.end" "[15, 1]" +//@ is "$.index[?(@.docs=='has span')].span.begin" "[13, 0]" +//@ is "$.index[?(@.docs=='has span')].span.end" "[15, 1]" // FIXME: this doesn't work due to https://github.com/freestrings/jsonpath/issues/91 -// is "$.index[*][?(@.inner.impl.is_synthetic==true)].span" null +// is "$.index[?(@.inner.impl.is_synthetic==true)].span" null pub struct Foo; diff --git a/tests/rustdoc-json/impls/blanket_with_local.rs b/tests/rustdoc-json/impls/blanket_with_local.rs index de92dafae0b4..24ee6cf66700 100644 --- a/tests/rustdoc-json/impls/blanket_with_local.rs +++ b/tests/rustdoc-json/impls/blanket_with_local.rs @@ -1,11 +1,11 @@ // Test for the ICE in rust/83718 // A blanket impl plus a local type together shouldn't result in mismatched ID issues -//@ has "$.index[*][?(@.name=='Load')]" +//@ has "$.index[?(@.name=='Load')]" pub trait Load { - //@ has "$.index[*][?(@.name=='load')]" + //@ has "$.index[?(@.name=='load')]" fn load() {} - //@ has "$.index[*][?(@.name=='write')]" + //@ has "$.index[?(@.name=='write')]" fn write(self) {} } @@ -14,5 +14,5 @@ impl

Load for P { fn write(self) {} } -//@ has "$.index[*][?(@.name=='Wrapper')]" +//@ has "$.index[?(@.name=='Wrapper')]" pub struct Wrapper {} diff --git a/tests/rustdoc-json/impls/foreign_for_local.rs b/tests/rustdoc-json/impls/foreign_for_local.rs index 1347f954cade..e46b158d8020 100644 --- a/tests/rustdoc-json/impls/foreign_for_local.rs +++ b/tests/rustdoc-json/impls/foreign_for_local.rs @@ -3,16 +3,16 @@ extern crate foreign_trait; /// ForeignTrait id hack pub use foreign_trait::ForeignTrait as _; -//@ set ForeignTrait = "$.index[*][?(@.docs=='ForeignTrait id hack')].inner.use.id" +//@ set ForeignTrait = "$.index[?(@.docs=='ForeignTrait id hack')].inner.use.id" pub struct LocalStruct; -//@ set LocalStruct = "$.index[*][?(@.name=='LocalStruct')].id" +//@ set LocalStruct = "$.index[?(@.name=='LocalStruct')].id" /// foreign for local impl foreign_trait::ForeignTrait for LocalStruct {} -//@ set impl = "$.index[*][?(@.docs=='foreign for local')].id" -//@ is "$.index[*][?(@.docs=='foreign for local')].inner.impl.for.resolved_path.id" $LocalStruct -//@ is "$.index[*][?(@.docs=='foreign for local')].inner.impl.trait.id" $ForeignTrait +//@ set impl = "$.index[?(@.docs=='foreign for local')].id" +//@ is "$.index[?(@.docs=='foreign for local')].inner.impl.for.resolved_path.id" $LocalStruct +//@ is "$.index[?(@.docs=='foreign for local')].inner.impl.trait.id" $ForeignTrait -//@ has "$.index[*][?(@.name=='LocalStruct')].inner.struct.impls[*]" $impl +//@ has "$.index[?(@.name=='LocalStruct')].inner.struct.impls[*]" $impl diff --git a/tests/rustdoc-json/impls/impl_item_visibility.rs b/tests/rustdoc-json/impls/impl_item_visibility.rs index 293dd965804a..680ea175d0bb 100644 --- a/tests/rustdoc-json/impls/impl_item_visibility.rs +++ b/tests/rustdoc-json/impls/impl_item_visibility.rs @@ -4,13 +4,13 @@ pub struct Foo; impl Foo { fn baz() {} } -//@ !has '$.index[*][?(@.docs=="impl Foo priv")]' +//@ !has '$.index[?(@.docs=="impl Foo priv")]' /// impl Foo pub impl Foo { pub fn qux() {} } -//@ is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' +//@ is '$.index[?(@.docs=="impl Foo pub")].visibility' '"default"' /// impl Foo hidden impl Foo { @@ -18,4 +18,4 @@ impl Foo { pub fn __quazl() {} } // FIXME(#111564): Is this the right behaviour? -//@ is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' +//@ is '$.index[?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs b/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs index 77ee717b03a2..82d59b97b013 100644 --- a/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs +++ b/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs @@ -7,13 +7,13 @@ impl Foo { fn baz() {} } // FIXME(#111564): Is this the right behaviour? -//@ is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' +//@ is '$.index[?(@.docs=="impl Foo priv")].visibility' '"default"' /// impl Foo pub impl Foo { pub fn qux() {} } -//@ is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' +//@ is '$.index[?(@.docs=="impl Foo pub")].visibility' '"default"' /// impl Foo hidden impl Foo { @@ -21,4 +21,4 @@ impl Foo { pub fn __quazl() {} } // FIXME(#111564): Is this the right behaviour? -//@ is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' +//@ is '$.index[?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs b/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs index 80c47eee6cb7..a3b145adb869 100644 --- a/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs +++ b/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs @@ -6,13 +6,13 @@ pub struct Foo; impl Foo { fn baz() {} } -//@ is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' +//@ is '$.index[?(@.docs=="impl Foo priv")].visibility' '"default"' /// impl Foo pub impl Foo { pub fn qux() {} } -//@ is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' +//@ is '$.index[?(@.docs=="impl Foo pub")].visibility' '"default"' /// impl Foo hidden impl Foo { @@ -20,4 +20,4 @@ impl Foo { pub fn __quazl() {} } // FIXME(#111564): Is this the right behaviour? -//@ is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' +//@ is '$.index[?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/import_from_private.rs b/tests/rustdoc-json/impls/import_from_private.rs index 32b9abb0717c..02262d9b65fa 100644 --- a/tests/rustdoc-json/impls/import_from_private.rs +++ b/tests/rustdoc-json/impls/import_from_private.rs @@ -1,20 +1,20 @@ // https://github.com/rust-lang/rust/issues/100252 mod bar { - //@ set baz = "$.index[*][?(@.name == 'Baz')].id" + //@ set baz = "$.index[?(@.name == 'Baz')].id" pub struct Baz; - //@ set impl = "$.index[*][?(@.docs == 'impl')].id" + //@ set impl = "$.index[?(@.docs == 'impl')].id" /// impl impl Baz { - //@ set doit = "$.index[*][?(@.name == 'doit')].id" + //@ set doit = "$.index[?(@.name == 'doit')].id" pub fn doit() {} } } -//@ set import = "$.index[*][?(@.inner.use)].id" +//@ set import = "$.index[?(@.inner.use)].id" pub use bar::Baz; //@ is "$.index[*].inner.module.items[*]" $import //@ is "$.index[*].inner.use.id" $baz -//@ has "$.index[*][?(@.name == 'Baz')].inner.struct.impls[*]" $impl -//@ is "$.index[*][?(@.docs=='impl')].inner.impl.items[*]" $doit +//@ has "$.index[?(@.name == 'Baz')].inner.struct.impls[*]" $impl +//@ is "$.index[?(@.docs=='impl')].inner.impl.items[*]" $doit diff --git a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-2.rs b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-2.rs index 4a313044920a..54ec08135be7 100644 --- a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-2.rs +++ b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-2.rs @@ -1,8 +1,8 @@ -//@ has "$.index[*][?(@.docs=='Here')]" -//@ !has "$.index[*][?(@.docs=='Not Here')]" -//@ !has "$.index[*][?(@.name == 'HiddenPubStruct')]" -//@ has "$.index[*][?(@.name == 'NotHiddenPubStruct')]" -//@ has "$.index[*][?(@.name=='PubTrait')]" +//@ has "$.index[?(@.docs=='Here')]" +//@ !has "$.index[?(@.docs=='Not Here')]" +//@ !has "$.index[?(@.name == 'HiddenPubStruct')]" +//@ has "$.index[?(@.name == 'NotHiddenPubStruct')]" +//@ has "$.index[?(@.name=='PubTrait')]" pub trait PubTrait {} #[doc(hidden)] diff --git a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-3.rs b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-3.rs index d3f2180f22cf..afb29fd63166 100644 --- a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-3.rs +++ b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-3.rs @@ -1,8 +1,8 @@ //@ compile-flags: --document-hidden-items -//@ has "$.index[*][?(@.name == 'HiddenPubStruct')]" -//@ has "$.index[*][?(@.inner.impl)]" -//@ has "$.index[*][?(@.name=='PubTrait')]" +//@ has "$.index[?(@.name == 'HiddenPubStruct')]" +//@ has "$.index[?(@.inner.impl)]" +//@ has "$.index[?(@.name=='PubTrait')]" pub trait PubTrait {} #[doc(hidden)] diff --git a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id.rs b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id.rs index a3f058188429..7fc3f70fe5a6 100644 --- a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id.rs +++ b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id.rs @@ -1,21 +1,21 @@ -//@ has "$.index[*][?(@.name=='PubTrait')]" +//@ has "$.index[?(@.name=='PubTrait')]" pub trait PubTrait {} #[doc(hidden)] pub mod hidden { - //@ !has "$.index[*][?(@.name == 'HiddenPubStruct')]" + //@ !has "$.index[?(@.name == 'HiddenPubStruct')]" pub struct HiddenPubStruct; - //@ !has "$.index[*][?(@.docs == 'Not Here')]" + //@ !has "$.index[?(@.docs == 'Not Here')]" /// Not Here impl crate::PubTrait for HiddenPubStruct {} } pub mod not_hidden { - //@ has "$.index[*][?(@.name == 'NotHiddenPubStruct')]" + //@ has "$.index[?(@.name == 'NotHiddenPubStruct')]" pub struct NotHiddenPubStruct; - //@ has "$.index[*][?(@.docs == 'Here')]" + //@ has "$.index[?(@.docs == 'Here')]" /// Here impl crate::PubTrait for NotHiddenPubStruct {} } diff --git a/tests/rustdoc-json/impls/local_for_foreign.rs b/tests/rustdoc-json/impls/local_for_foreign.rs index cd89c4753488..86c72a580b2e 100644 --- a/tests/rustdoc-json/impls/local_for_foreign.rs +++ b/tests/rustdoc-json/impls/local_for_foreign.rs @@ -3,16 +3,16 @@ extern crate foreign_struct; /// ForeignStruct id hack pub use foreign_struct::ForeignStruct as _; -//@ set ForeignStruct = "$.index[*][?(@.docs=='ForeignStruct id hack')].inner.use.id" +//@ set ForeignStruct = "$.index[?(@.docs=='ForeignStruct id hack')].inner.use.id" pub trait LocalTrait {} -//@ set LocalTrait = "$.index[*][?(@.name=='LocalTrait')].id" +//@ set LocalTrait = "$.index[?(@.name=='LocalTrait')].id" /// local for foreign impl LocalTrait for foreign_struct::ForeignStruct {} -//@ set impl = "$.index[*][?(@.docs=='local for foreign')].id" -//@ is "$.index[*][?(@.docs=='local for foreign')].inner.impl.trait.id" $LocalTrait -//@ is "$.index[*][?(@.docs=='local for foreign')].inner.impl.for.resolved_path.id" $ForeignStruct +//@ set impl = "$.index[?(@.docs=='local for foreign')].id" +//@ is "$.index[?(@.docs=='local for foreign')].inner.impl.trait.id" $LocalTrait +//@ is "$.index[?(@.docs=='local for foreign')].inner.impl.for.resolved_path.id" $ForeignStruct -//@ is "$.index[*][?(@.name=='LocalTrait')].inner.trait.implementations[*]" $impl +//@ is "$.index[?(@.name=='LocalTrait')].inner.trait.implementations[*]" $impl diff --git a/tests/rustdoc-json/impls/local_for_local.rs b/tests/rustdoc-json/impls/local_for_local.rs index 1d141d6e4de3..876a7912f09b 100644 --- a/tests/rustdoc-json/impls/local_for_local.rs +++ b/tests/rustdoc-json/impls/local_for_local.rs @@ -1,12 +1,12 @@ -//@ set struct = "$.index[*][?(@.name=='Struct')].id" +//@ set struct = "$.index[?(@.name=='Struct')].id" pub struct Struct; -//@ set trait = "$.index[*][?(@.name=='Trait')].id" +//@ set trait = "$.index[?(@.name=='Trait')].id" pub trait Trait {} -//@ set impl = "$.index[*][?(@.docs=='impl')].id" +//@ set impl = "$.index[?(@.docs=='impl')].id" /// impl impl Trait for Struct {} -//@ has "$.index[*][?(@.name=='Struct')].inner.struct.impls[*]" $impl -//@ is "$.index[*][?(@.name=='Trait')].inner.trait.implementations[*]" $impl -//@ is "$.index[*][?(@.docs=='impl')].inner.impl.trait.id" $trait -//@ is "$.index[*][?(@.docs=='impl')].inner.impl.for.resolved_path.id" $struct +//@ has "$.index[?(@.name=='Struct')].inner.struct.impls[*]" $impl +//@ is "$.index[?(@.name=='Trait')].inner.trait.implementations[*]" $impl +//@ is "$.index[?(@.docs=='impl')].inner.impl.trait.id" $trait +//@ is "$.index[?(@.docs=='impl')].inner.impl.for.resolved_path.id" $struct diff --git a/tests/rustdoc-json/impls/local_for_local_primitive.rs b/tests/rustdoc-json/impls/local_for_local_primitive.rs index 8c1eb044eae7..859c0cb8ec82 100644 --- a/tests/rustdoc-json/impls/local_for_local_primitive.rs +++ b/tests/rustdoc-json/impls/local_for_local_primitive.rs @@ -1,18 +1,18 @@ #![feature(rustc_attrs)] -//@ set Local = "$.index[*][?(@.name=='Local')].id" +//@ set Local = "$.index[?(@.name=='Local')].id" pub trait Local {} -//@ is "$.index[*][?(@.docs=='Local for bool')].inner.impl.trait.id" $Local -//@ is "$.index[*][?(@.docs=='Local for bool')].inner.impl.for.primitive" '"bool"' +//@ is "$.index[?(@.docs=='Local for bool')].inner.impl.trait.id" $Local +//@ is "$.index[?(@.docs=='Local for bool')].inner.impl.for.primitive" '"bool"' /// Local for bool impl Local for bool {} -//@ set impl = "$.index[*][?(@.docs=='Local for bool')].id" -//@ is "$.index[*][?(@.name=='Local')].inner.trait.implementations[*]" $impl +//@ set impl = "$.index[?(@.docs=='Local for bool')].id" +//@ is "$.index[?(@.name=='Local')].inner.trait.implementations[*]" $impl // FIXME(#101695): Test bool's `impls` include "Local for bool" -//@ has "$.index[*][?(@.name=='bool')]" +//@ has "$.index[?(@.name=='bool')]" #[rustc_doc_primitive = "bool"] /// Boolean docs mod prim_bool {} diff --git a/tests/rustdoc-json/impls/local_for_primitive.rs b/tests/rustdoc-json/impls/local_for_primitive.rs index 56d930ca5c4f..a5ab3ec8a1b7 100644 --- a/tests/rustdoc-json/impls/local_for_primitive.rs +++ b/tests/rustdoc-json/impls/local_for_primitive.rs @@ -1,7 +1,7 @@ -//@ set local = "$.index[*][?(@.name=='Local')]" +//@ set local = "$.index[?(@.name=='Local')]" pub trait Local {} -//@ set impl = "$.index[*][?(@.docs=='local for bool')].id" -//@ is "$.index[*][?(@.name=='Local')].inner.trait.implementations[*]" $impl +//@ set impl = "$.index[?(@.docs=='local for bool')].id" +//@ is "$.index[?(@.name=='Local')].inner.trait.implementations[*]" $impl /// local for bool impl Local for bool {} diff --git a/tests/rustdoc-json/impls/pub_for_hidden_private.rs b/tests/rustdoc-json/impls/pub_for_hidden_private.rs index 261ffbfeb4a4..eb89219022c7 100644 --- a/tests/rustdoc-json/impls/pub_for_hidden_private.rs +++ b/tests/rustdoc-json/impls/pub_for_hidden_private.rs @@ -5,6 +5,6 @@ pub trait TheTrait {} #[doc(hidden)] struct Value {} -//@ has '$.index[*][?(@.docs=="THE IMPL")]' +//@ has '$.index[?(@.docs=="THE IMPL")]' /// THE IMPL impl TheTrait for Value {} diff --git a/tests/rustdoc-json/impls/trait-for-dyn-trait.rs b/tests/rustdoc-json/impls/trait-for-dyn-trait.rs index 0fbb4df00284..17cb07f3571d 100644 --- a/tests/rustdoc-json/impls/trait-for-dyn-trait.rs +++ b/tests/rustdoc-json/impls/trait-for-dyn-trait.rs @@ -1,15 +1,15 @@ -//@ set t1 = '$.index[*][?(@.name=="T1")].id' +//@ set t1 = '$.index[?(@.name=="T1")].id' pub trait T1 {} -//@ set t2 = '$.index[*][?(@.name=="T2")].id' +//@ set t2 = '$.index[?(@.name=="T2")].id' pub trait T2 {} /// Fun impl impl T1 for dyn T2 {} -//@ set impl = '$.index[*][?(@.docs=="Fun impl")].id' -//@ is '$.index[*][?(@.name=="T1")].inner.trait.implementations[*]' $impl -//@ is '$.index[*][?(@.name=="T2")].inner.trait.implementations' [] +//@ set impl = '$.index[?(@.docs=="Fun impl")].id' +//@ is '$.index[?(@.name=="T1")].inner.trait.implementations[*]' $impl +//@ is '$.index[?(@.name=="T2")].inner.trait.implementations' [] -//@ is '$.index[*][?(@.docs=="Fun impl")].inner.impl.trait.id' $t1 -//@ is '$.index[*][?(@.docs=="Fun impl")].inner.impl.for.dyn_trait.traits[*].trait.id' $t2 +//@ is '$.index[?(@.docs=="Fun impl")].inner.impl.trait.id' $t1 +//@ is '$.index[?(@.docs=="Fun impl")].inner.impl.for.dyn_trait.traits[*].trait.id' $t2 diff --git a/tests/rustdoc-json/intra-doc-links/foreign_variant.rs b/tests/rustdoc-json/intra-doc-links/foreign_variant.rs index 251c4884fbb5..b3e6f51d23c1 100644 --- a/tests/rustdoc-json/intra-doc-links/foreign_variant.rs +++ b/tests/rustdoc-json/intra-doc-links/foreign_variant.rs @@ -8,6 +8,6 @@ pub struct Local; /// local impl impl enum_variant_in_trait_method::Trait for Local {} -//@ !has "$.index[*][?(@.name == 'Trait')]" -//@ !has "$.index[*][?(@.name == 'method')]" -//@ count "$.index[*][?(@.docs == 'local impl')].inner.items[*]" 0 +//@ !has "$.index[?(@.name == 'Trait')]" +//@ !has "$.index[?(@.name == 'method')]" +//@ count "$.index[?(@.docs == 'local impl')].inner.items[*]" 0 diff --git a/tests/rustdoc-json/intra-doc-links/non_page.rs b/tests/rustdoc-json/intra-doc-links/non_page.rs index 00987d93c1e9..e2d00ee64e9c 100644 --- a/tests/rustdoc-json/intra-doc-links/non_page.rs +++ b/tests/rustdoc-json/intra-doc-links/non_page.rs @@ -7,17 +7,17 @@ //! [`Trait::ASSOC_CONST`] //! [`Trait::method`] -//@ set struct_field = "$.index[*][?(@.name=='struct_field')].id" -//@ set Variant = "$.index[*][?(@.name=='Variant')].id" -//@ set AssocType = "$.index[*][?(@.name=='AssocType')].id" -//@ set ASSOC_CONST = "$.index[*][?(@.name=='ASSOC_CONST')].id" -//@ set method = "$.index[*][?(@.name=='method')].id" +//@ set struct_field = "$.index[?(@.name=='struct_field')].id" +//@ set Variant = "$.index[?(@.name=='Variant')].id" +//@ set AssocType = "$.index[?(@.name=='AssocType')].id" +//@ set ASSOC_CONST = "$.index[?(@.name=='ASSOC_CONST')].id" +//@ set method = "$.index[?(@.name=='method')].id" -//@ is "$.index[*][?(@.name=='non_page')].links['`Struct::struct_field`']" $struct_field -//@ is "$.index[*][?(@.name=='non_page')].links['`Enum::Variant`']" $Variant -//@ is "$.index[*][?(@.name=='non_page')].links['`Trait::AssocType`']" $AssocType -//@ is "$.index[*][?(@.name=='non_page')].links['`Trait::ASSOC_CONST`']" $ASSOC_CONST -//@ is "$.index[*][?(@.name=='non_page')].links['`Trait::method`']" $method +//@ is "$.index[?(@.name=='non_page')].links['`Struct::struct_field`']" $struct_field +//@ is "$.index[?(@.name=='non_page')].links['`Enum::Variant`']" $Variant +//@ is "$.index[?(@.name=='non_page')].links['`Trait::AssocType`']" $AssocType +//@ is "$.index[?(@.name=='non_page')].links['`Trait::ASSOC_CONST`']" $ASSOC_CONST +//@ is "$.index[?(@.name=='non_page')].links['`Trait::method`']" $method pub struct Struct { pub struct_field: i32, diff --git a/tests/rustdoc-json/intra-doc-links/user_written.rs b/tests/rustdoc-json/intra-doc-links/user_written.rs index c3f9df95a8fa..97a643490e6c 100644 --- a/tests/rustdoc-json/intra-doc-links/user_written.rs +++ b/tests/rustdoc-json/intra-doc-links/user_written.rs @@ -4,5 +4,5 @@ /// To test rustdoc json pub fn foo() {} -//@ set foo = "$.index[*][?(@.name=='foo')].id" -//@ is "$.index[*][?(@.name=='user_written')].links['foo#reasons']" $foo +//@ set foo = "$.index[?(@.name=='foo')].id" +//@ is "$.index[?(@.name=='user_written')].links['foo#reasons']" $foo diff --git a/tests/rustdoc-json/keyword.rs b/tests/rustdoc-json/keyword.rs index 8a2130f19783..566b2c68bd5d 100644 --- a/tests/rustdoc-json/keyword.rs +++ b/tests/rustdoc-json/keyword.rs @@ -6,15 +6,15 @@ #![feature(rustdoc_internals)] #![no_std] -//@ !has "$.index[*][?(@.name=='match')]" -//@ has "$.index[*][?(@.name=='foo')]" +//@ !has "$.index[?(@.name=='match')]" +//@ has "$.index[?(@.name=='foo')]" #[doc(keyword = "match")] /// this is a test! pub mod foo {} -//@ !has "$.index[*][?(@.name=='break')]" -//@ !has "$.index[*][?(@.name=='bar')]" +//@ !has "$.index[?(@.name=='break')]" +//@ !has "$.index[?(@.name=='bar')]" #[doc(keyword = "break")] /// hello mod bar {} diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs index 2a13bf10d5d6..fea546c9fb60 100644 --- a/tests/rustdoc-json/keyword_private.rs +++ b/tests/rustdoc-json/keyword_private.rs @@ -3,18 +3,18 @@ //@ compile-flags: --document-private-items #![feature(rustdoc_internals)] -//@ !has "$.index[*][?(@.name=='match')]" -//@ has "$.index[*][?(@.name=='foo')]" -//@ is "$.index[*][?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' -//@ is "$.index[*][?(@.name=='foo')].docs" '"this is a test!"' +//@ !has "$.index[?(@.name=='match')]" +//@ has "$.index[?(@.name=='foo')]" +//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' +//@ is "$.index[?(@.name=='foo')].docs" '"this is a test!"' #[doc(keyword = "match")] /// this is a test! pub mod foo {} -//@ !has "$.index[*][?(@.name=='break')]" -//@ has "$.index[*][?(@.name=='bar')]" -//@ is "$.index[*][?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]' -//@ is "$.index[*][?(@.name=='bar')].docs" '"hello"' +//@ !has "$.index[?(@.name=='break')]" +//@ has "$.index[?(@.name=='bar')]" +//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]' +//@ is "$.index[?(@.name=='bar')].docs" '"hello"' #[doc(keyword = "break")] /// hello mod bar {} diff --git a/tests/rustdoc-json/lifetime/longest.rs b/tests/rustdoc-json/lifetime/longest.rs index 2d4e098d696b..50cf084c3987 100644 --- a/tests/rustdoc-json/lifetime/longest.rs +++ b/tests/rustdoc-json/lifetime/longest.rs @@ -1,24 +1,24 @@ -//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].name" \"\'a\" -//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' -//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' -//@ count "$.index[*][?(@.name=='longest')].inner.function.generics.params[*]" 1 -//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.where_predicates" [] +//@ is "$.index[?(@.name=='longest')].inner.function.generics.params[0].name" \"\'a\" +//@ is "$.index[?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' +//@ is "$.index[?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' +//@ count "$.index[?(@.name=='longest')].inner.function.generics.params[*]" 1 +//@ is "$.index[?(@.name=='longest')].inner.function.generics.where_predicates" [] -//@ count "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[*]" 2 -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[0][0]" '"l"' -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[1][0]" '"r"' +//@ count "$.index[?(@.name=='longest')].inner.function.sig.inputs[*]" 2 +//@ is "$.index[?(@.name=='longest')].inner.function.sig.inputs[0][0]" '"l"' +//@ is "$.index[?(@.name=='longest')].inner.function.sig.inputs[1][0]" '"r"' -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.lifetime" \"\'a\" -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable" false -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.type.primitive" \"str\" +//@ is "$.index[?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable" false +//@ is "$.index[?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.type.primitive" \"str\" -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.lifetime" \"\'a\" -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.is_mutable" false -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.type.primitive" \"str\" +//@ is "$.index[?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.is_mutable" false +//@ is "$.index[?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.type.primitive" \"str\" -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.output.borrowed_ref.lifetime" \"\'a\" -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.output.borrowed_ref.is_mutable" false -//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.output.borrowed_ref.type.primitive" \"str\" +//@ is "$.index[?(@.name=='longest')].inner.function.sig.output.borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[?(@.name=='longest')].inner.function.sig.output.borrowed_ref.is_mutable" false +//@ is "$.index[?(@.name=='longest')].inner.function.sig.output.borrowed_ref.type.primitive" \"str\" pub fn longest<'a>(l: &'a str, r: &'a str) -> &'a str { if l.len() > r.len() { l } else { r } diff --git a/tests/rustdoc-json/lifetime/outlives.rs b/tests/rustdoc-json/lifetime/outlives.rs index 257e43985ac3..f191b386c6ca 100644 --- a/tests/rustdoc-json/lifetime/outlives.rs +++ b/tests/rustdoc-json/lifetime/outlives.rs @@ -1,16 +1,16 @@ -//@ count "$.index[*][?(@.name=='foo')].inner.function.generics.params[*]" 3 -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates" [] -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].name" \"\'a\" -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[1].name" \"\'b\" -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].name" '"T"' -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].kind.lifetime.outlives" [] -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[1].kind.lifetime.outlives" [\"\'a\"] -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.default" null -//@ count "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[*]" 1 -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[0].outlives" \"\'b\" -//@ is "$.index[*][?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.lifetime" \"\'a\" -//@ is "$.index[*][?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable" false -//@ is "$.index[*][?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.type.borrowed_ref.lifetime" \"\'b\" -//@ is "$.index[*][?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.type.borrowed_ref.is_mutable" false -//@ is "$.index[*][?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.type.borrowed_ref.type.generic" \"T\" +//@ count "$.index[?(@.name=='foo')].inner.function.generics.params[*]" 3 +//@ is "$.index[?(@.name=='foo')].inner.function.generics.where_predicates" [] +//@ is "$.index[?(@.name=='foo')].inner.function.generics.params[0].name" \"\'a\" +//@ is "$.index[?(@.name=='foo')].inner.function.generics.params[1].name" \"\'b\" +//@ is "$.index[?(@.name=='foo')].inner.function.generics.params[2].name" '"T"' +//@ is "$.index[?(@.name=='foo')].inner.function.generics.params[0].kind.lifetime.outlives" [] +//@ is "$.index[?(@.name=='foo')].inner.function.generics.params[1].kind.lifetime.outlives" [\"\'a\"] +//@ is "$.index[?(@.name=='foo')].inner.function.generics.params[2].kind.type.default" null +//@ count "$.index[?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[*]" 1 +//@ is "$.index[?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[0].outlives" \"\'b\" +//@ is "$.index[?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable" false +//@ is "$.index[?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.type.borrowed_ref.lifetime" \"\'b\" +//@ is "$.index[?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.type.borrowed_ref.is_mutable" false +//@ is "$.index[?(@.name=='foo')].inner.function.sig.inputs[0][1].borrowed_ref.type.borrowed_ref.type.generic" \"T\" pub fn foo<'a, 'b: 'a, T: 'b>(_: &'a &'b T) {} diff --git a/tests/rustdoc-json/lifetime/outlives_in_param.rs b/tests/rustdoc-json/lifetime/outlives_in_param.rs index 55ff52505415..dc9f57ff8a10 100644 --- a/tests/rustdoc-json/lifetime/outlives_in_param.rs +++ b/tests/rustdoc-json/lifetime/outlives_in_param.rs @@ -1,6 +1,6 @@ -//@ count '$.index[*][?(@.name=="outlives")].inner.function.generics.params[*]' 2 -//@ is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].name' \"\'a\" -//@ is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].kind.lifetime.outlives' [] -//@ is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].name' '"T"' -//@ is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].kind.type.bounds' '[{"outlives": "'\''a"}]' +//@ count '$.index[?(@.name=="outlives")].inner.function.generics.params[*]' 2 +//@ is '$.index[?(@.name=="outlives")].inner.function.generics.params[0].name' \"\'a\" +//@ is '$.index[?(@.name=="outlives")].inner.function.generics.params[0].kind.lifetime.outlives' [] +//@ is '$.index[?(@.name=="outlives")].inner.function.generics.params[1].name' '"T"' +//@ is '$.index[?(@.name=="outlives")].inner.function.generics.params[1].kind.type.bounds' '[{"outlives": "'\''a"}]' pub fn outlives<'a, T: 'a>() {} diff --git a/tests/rustdoc-json/lifetime/outlives_in_where.rs b/tests/rustdoc-json/lifetime/outlives_in_where.rs index 5158ff118a07..48faf8ff8306 100644 --- a/tests/rustdoc-json/lifetime/outlives_in_where.rs +++ b/tests/rustdoc-json/lifetime/outlives_in_where.rs @@ -1,20 +1,20 @@ -//@ is '$.index[*][?(@.name=="on_lifetimes")].inner.function.generics.where_predicates' '[{"lifetime_predicate": {"lifetime": "'\''all", "outlives": ["'\''a", "'\''b", "'\''c"]}}]' +//@ is '$.index[?(@.name=="on_lifetimes")].inner.function.generics.where_predicates' '[{"lifetime_predicate": {"lifetime": "'\''all", "outlives": ["'\''a", "'\''b", "'\''c"]}}]' pub fn on_lifetimes<'a, 'b, 'c, 'all>() where 'all: 'a + 'b + 'c, { } -//@ count '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[*]' 2 -//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].name' \"\'a\" -//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].kind.lifetime.outlives' [] -//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].name' '"T"' -//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] -//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] -//@ count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[*]' 1 -//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.type.generic' '"T"' -//@ count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]' 1 -//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].outlives' \"\'a\" +//@ count '$.index[?(@.name=="on_trait")].inner.function.generics.params[*]' 2 +//@ is '$.index[?(@.name=="on_trait")].inner.function.generics.params[0].name' \"\'a\" +//@ is '$.index[?(@.name=="on_trait")].inner.function.generics.params[0].kind.lifetime.outlives' [] +//@ is '$.index[?(@.name=="on_trait")].inner.function.generics.params[1].name' '"T"' +//@ is '$.index[?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] +//@ is '$.index[?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] +//@ count '$.index[?(@.name=="on_trait")].inner.function.generics.where_predicates[*]' 1 +//@ is '$.index[?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.type.generic' '"T"' +//@ count '$.index[?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]' 1 +//@ is '$.index[?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].outlives' \"\'a\" pub fn on_trait<'a, T>() where T: 'a, diff --git a/tests/rustdoc-json/methods/abi.rs b/tests/rustdoc-json/methods/abi.rs index dac02a6ce3ca..fa2387ddf67a 100644 --- a/tests/rustdoc-json/methods/abi.rs +++ b/tests/rustdoc-json/methods/abi.rs @@ -1,50 +1,50 @@ #![feature(abi_vectorcall)] -//@ has "$.index[*][?(@.name=='Foo')]" +//@ has "$.index[?(@.name=='Foo')]" pub struct Foo; impl Foo { - //@ is "$.index[*][?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" + //@ is "$.index[?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" pub fn abi_rust() {} - //@ is "$.index[*][?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' + //@ is "$.index[?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' pub extern "C" fn abi_c() {} - //@ is "$.index[*][?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' + //@ is "$.index[?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' pub extern "system" fn abi_system() {} - //@ is "$.index[*][?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' + //@ is "$.index[?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' pub extern "C-unwind" fn abi_c_unwind() {} - //@ is "$.index[*][?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' + //@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} - //@ is "$.index[*][?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' + //@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' pub extern "vectorcall" fn abi_vectorcall() {} - //@ is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' + //@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} } pub trait Bar { - //@ is "$.index[*][?(@.name=='trait_abi_rust')].inner.function.header.abi" \"Rust\" + //@ is "$.index[?(@.name=='trait_abi_rust')].inner.function.header.abi" \"Rust\" fn trait_abi_rust() {} - //@ is "$.index[*][?(@.name=='trait_abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' + //@ is "$.index[?(@.name=='trait_abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' extern "C" fn trait_abi_c() {} - //@ is "$.index[*][?(@.name=='trait_abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' + //@ is "$.index[?(@.name=='trait_abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' extern "system" fn trait_abi_system() {} - //@ is "$.index[*][?(@.name=='trait_abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' + //@ is "$.index[?(@.name=='trait_abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' extern "C-unwind" fn trait_abi_c_unwind() {} - //@ is "$.index[*][?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' + //@ is "$.index[?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' extern "system-unwind" fn trait_abi_system_unwind() {} - //@ is "$.index[*][?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' + //@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' extern "vectorcall" fn trait_abi_vectorcall() {} - //@ is "$.index[*][?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' + //@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {} } diff --git a/tests/rustdoc-json/methods/qualifiers.rs b/tests/rustdoc-json/methods/qualifiers.rs index ba7c2e60936b..b1d9f0c1af3a 100644 --- a/tests/rustdoc-json/methods/qualifiers.rs +++ b/tests/rustdoc-json/methods/qualifiers.rs @@ -3,34 +3,34 @@ pub struct Foo; impl Foo { - //@ is "$.index[*][?(@.name=='const_meth')].inner.function.header.is_async" false - //@ is "$.index[*][?(@.name=='const_meth')].inner.function.header.is_const" true - //@ is "$.index[*][?(@.name=='const_meth')].inner.function.header.is_unsafe" false + //@ is "$.index[?(@.name=='const_meth')].inner.function.header.is_async" false + //@ is "$.index[?(@.name=='const_meth')].inner.function.header.is_const" true + //@ is "$.index[?(@.name=='const_meth')].inner.function.header.is_unsafe" false pub const fn const_meth() {} - //@ is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.is_async" false - //@ is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.is_const" false - //@ is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.is_unsafe" false + //@ is "$.index[?(@.name=='nothing_meth')].inner.function.header.is_async" false + //@ is "$.index[?(@.name=='nothing_meth')].inner.function.header.is_const" false + //@ is "$.index[?(@.name=='nothing_meth')].inner.function.header.is_unsafe" false pub fn nothing_meth() {} - //@ is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.is_async" false - //@ is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.is_const" false - //@ is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='unsafe_meth')].inner.function.header.is_async" false + //@ is "$.index[?(@.name=='unsafe_meth')].inner.function.header.is_const" false + //@ is "$.index[?(@.name=='unsafe_meth')].inner.function.header.is_unsafe" true pub unsafe fn unsafe_meth() {} - //@ is "$.index[*][?(@.name=='async_meth')].inner.function.header.is_async" true - //@ is "$.index[*][?(@.name=='async_meth')].inner.function.header.is_const" false - //@ is "$.index[*][?(@.name=='async_meth')].inner.function.header.is_unsafe" false + //@ is "$.index[?(@.name=='async_meth')].inner.function.header.is_async" true + //@ is "$.index[?(@.name=='async_meth')].inner.function.header.is_const" false + //@ is "$.index[?(@.name=='async_meth')].inner.function.header.is_unsafe" false pub async fn async_meth() {} - //@ is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.is_async" true - //@ is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.is_const" false - //@ is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='async_unsafe_meth')].inner.function.header.is_async" true + //@ is "$.index[?(@.name=='async_unsafe_meth')].inner.function.header.is_const" false + //@ is "$.index[?(@.name=='async_unsafe_meth')].inner.function.header.is_unsafe" true pub async unsafe fn async_unsafe_meth() {} - //@ is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.is_async" false - //@ is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.is_const" true - //@ is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='const_unsafe_meth')].inner.function.header.is_async" false + //@ is "$.index[?(@.name=='const_unsafe_meth')].inner.function.header.is_const" true + //@ is "$.index[?(@.name=='const_unsafe_meth')].inner.function.header.is_unsafe" true pub const unsafe fn const_unsafe_meth() {} // It's impossible for a method to be both const and async, so no test for that diff --git a/tests/rustdoc-json/nested.rs b/tests/rustdoc-json/nested.rs index 10ec2831c212..8cc564706d61 100644 --- a/tests/rustdoc-json/nested.rs +++ b/tests/rustdoc-json/nested.rs @@ -2,31 +2,31 @@ //@ compile-flags: --crate-version 1.0.0 //@ is "$.crate_version" \"1.0.0\" -//@ has "$.index[*][?(@.name=='nested')].inner.module" -//@ is "$.index[*][?(@.name=='nested')].inner.module.is_crate" true +//@ has "$.index[?(@.name=='nested')].inner.module" +//@ is "$.index[?(@.name=='nested')].inner.module.is_crate" true -//@ set l1_id = "$.index[*][?(@.name=='l1')].id" -//@ ismany "$.index[*][?(@.name=='nested')].inner.module.items[*]" $l1_id +//@ set l1_id = "$.index[?(@.name=='l1')].id" +//@ ismany "$.index[?(@.name=='nested')].inner.module.items[*]" $l1_id -//@ has "$.index[*][?(@.name=='l1')].inner.module" -//@ is "$.index[*][?(@.name=='l1')].inner.module.is_crate" false +//@ has "$.index[?(@.name=='l1')].inner.module" +//@ is "$.index[?(@.name=='l1')].inner.module.is_crate" false pub mod l1 { - //@ has "$.index[*][?(@.name=='l3')].inner.module" - //@ is "$.index[*][?(@.name=='l3')].inner.module.is_crate" false - //@ set l3_id = "$.index[*][?(@.name=='l3')].id" + //@ has "$.index[?(@.name=='l3')].inner.module" + //@ is "$.index[?(@.name=='l3')].inner.module.is_crate" false + //@ set l3_id = "$.index[?(@.name=='l3')].id" pub mod l3 { - //@ has "$.index[*][?(@.name=='L4')].inner.struct" - //@ is "$.index[*][?(@.name=='L4')].inner.struct.kind" '"unit"' - //@ set l4_id = "$.index[*][?(@.name=='L4')].id" - //@ ismany "$.index[*][?(@.name=='l3')].inner.module.items[*]" $l4_id + //@ has "$.index[?(@.name=='L4')].inner.struct" + //@ is "$.index[?(@.name=='L4')].inner.struct.kind" '"unit"' + //@ set l4_id = "$.index[?(@.name=='L4')].id" + //@ ismany "$.index[?(@.name=='l3')].inner.module.items[*]" $l4_id pub struct L4; } - //@ is "$.index[*][?(@.inner.use)].inner.use.is_glob" false - //@ is "$.index[*][?(@.inner.use)].inner.use.source" '"l3::L4"' - //@ is "$.index[*][?(@.inner.use)].inner.use.is_glob" false - //@ is "$.index[*][?(@.inner.use)].inner.use.id" $l4_id - //@ set l4_use_id = "$.index[*][?(@.inner.use)].id" + //@ is "$.index[?(@.inner.use)].inner.use.is_glob" false + //@ is "$.index[?(@.inner.use)].inner.use.source" '"l3::L4"' + //@ is "$.index[?(@.inner.use)].inner.use.is_glob" false + //@ is "$.index[?(@.inner.use)].inner.use.id" $l4_id + //@ set l4_use_id = "$.index[?(@.inner.use)].id" pub use l3::L4; } -//@ ismany "$.index[*][?(@.name=='l1')].inner.module.items[*]" $l3_id $l4_use_id +//@ ismany "$.index[?(@.name=='l1')].inner.module.items[*]" $l3_id $l4_use_id diff --git a/tests/rustdoc-json/non_lifetime_binders.rs b/tests/rustdoc-json/non_lifetime_binders.rs index 7c518a8f5a7b..84318821c508 100644 --- a/tests/rustdoc-json/non_lifetime_binders.rs +++ b/tests/rustdoc-json/non_lifetime_binders.rs @@ -5,11 +5,11 @@ pub trait Trait {} pub struct Wrapper(std::marker::PhantomData); -//@ count "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[*]" 2 -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].name" \"\'a\" -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].name" \"T\" -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].kind" '{ "type": { "bounds": [], "default": null, "is_synthetic": false } }' +//@ count "$.index[?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[*]" 2 +//@ is "$.index[?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].name" \"\'a\" +//@ is "$.index[?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +//@ is "$.index[?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].name" \"T\" +//@ is "$.index[?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].kind" '{ "type": { "bounds": [], "default": null, "is_synthetic": false } }' pub fn foo() where for<'a, T> &'a Wrapper: Trait, diff --git a/tests/rustdoc-json/output_generics.rs b/tests/rustdoc-json/output_generics.rs index 3454f421636c..4d4339ceb239 100644 --- a/tests/rustdoc-json/output_generics.rs +++ b/tests/rustdoc-json/output_generics.rs @@ -2,11 +2,11 @@ // This is a regression test for #98009. -//@ has "$.index[*][?(@.name=='this_compiles')]" -//@ has "$.index[*][?(@.name=='this_does_not')]" -//@ has "$.index[*][?(@.name=='Events')]" -//@ has "$.index[*][?(@.name=='Other')]" -//@ has "$.index[*][?(@.name=='Trait')]" +//@ has "$.index[?(@.name=='this_compiles')]" +//@ has "$.index[?(@.name=='this_does_not')]" +//@ has "$.index[?(@.name=='Events')]" +//@ has "$.index[?(@.name=='Other')]" +//@ has "$.index[?(@.name=='Trait')]" struct Events(R); diff --git a/tests/rustdoc-json/path_name.rs b/tests/rustdoc-json/path_name.rs index a1b3ae294fa9..116b2bee5086 100644 --- a/tests/rustdoc-json/path_name.rs +++ b/tests/rustdoc-json/path_name.rs @@ -19,22 +19,22 @@ pub use priv_mod::{InPrivMod, InPrivMod as InPrivMod2}; use pub_mod::InPubMod as InPubMod3; pub use pub_mod::{InPubMod, InPubMod as InPubMod2}; -//@ is "$.index[*][?(@.name=='T0')].inner.type_alias.type.resolved_path.path" '"priv_mod::InPrivMod"' +//@ is "$.index[?(@.name=='T0')].inner.type_alias.type.resolved_path.path" '"priv_mod::InPrivMod"' pub type T0 = priv_mod::InPrivMod; -//@ is "$.index[*][?(@.name=='T1')].inner.type_alias.type.resolved_path.path" '"InPrivMod"' +//@ is "$.index[?(@.name=='T1')].inner.type_alias.type.resolved_path.path" '"InPrivMod"' pub type T1 = InPrivMod; -//@ is "$.index[*][?(@.name=='T2')].inner.type_alias.type.resolved_path.path" '"InPrivMod2"' +//@ is "$.index[?(@.name=='T2')].inner.type_alias.type.resolved_path.path" '"InPrivMod2"' pub type T2 = InPrivMod2; -//@ is "$.index[*][?(@.name=='T3')].inner.type_alias.type.resolved_path.path" '"priv_mod::InPrivMod"' +//@ is "$.index[?(@.name=='T3')].inner.type_alias.type.resolved_path.path" '"priv_mod::InPrivMod"' pub type T3 = InPrivMod3; -//@ is "$.index[*][?(@.name=='U0')].inner.type_alias.type.resolved_path.path" '"pub_mod::InPubMod"' +//@ is "$.index[?(@.name=='U0')].inner.type_alias.type.resolved_path.path" '"pub_mod::InPubMod"' pub type U0 = pub_mod::InPubMod; -//@ is "$.index[*][?(@.name=='U1')].inner.type_alias.type.resolved_path.path" '"InPubMod"' +//@ is "$.index[?(@.name=='U1')].inner.type_alias.type.resolved_path.path" '"InPubMod"' pub type U1 = InPubMod; -//@ is "$.index[*][?(@.name=='U2')].inner.type_alias.type.resolved_path.path" '"InPubMod2"' +//@ is "$.index[?(@.name=='U2')].inner.type_alias.type.resolved_path.path" '"InPubMod2"' pub type U2 = InPubMod2; -//@ is "$.index[*][?(@.name=='U3')].inner.type_alias.type.resolved_path.path" '"pub_mod::InPubMod"' +//@ is "$.index[?(@.name=='U3')].inner.type_alias.type.resolved_path.path" '"pub_mod::InPubMod"' pub type U3 = InPubMod3; // Check we only have paths for structs at their original path @@ -43,25 +43,25 @@ pub type U3 = InPubMod3; pub use defines_and_reexports::{InPrivMod as XPrivMod, InPubMod as XPubMod}; use defines_and_reexports::{InPrivMod as XPrivMod2, InPubMod as XPubMod2}; -//@ is "$.index[*][?(@.name=='X0')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::m1::InPubMod"' +//@ is "$.index[?(@.name=='X0')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::m1::InPubMod"' pub type X0 = defines_and_reexports::m1::InPubMod; -//@ is "$.index[*][?(@.name=='X1')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod"' +//@ is "$.index[?(@.name=='X1')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod"' pub type X1 = defines_and_reexports::InPubMod; -//@ is "$.index[*][?(@.name=='X2')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod2"' +//@ is "$.index[?(@.name=='X2')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod2"' pub type X2 = defines_and_reexports::InPubMod2; -//@ is "$.index[*][?(@.name=='X3')].inner.type_alias.type.resolved_path.path" '"XPubMod"' +//@ is "$.index[?(@.name=='X3')].inner.type_alias.type.resolved_path.path" '"XPubMod"' pub type X3 = XPubMod; // N.B. This isn't the path as used *or* the original path! -//@ is "$.index[*][?(@.name=='X4')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod"' +//@ is "$.index[?(@.name=='X4')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod"' pub type X4 = XPubMod2; -//@ is "$.index[*][?(@.name=='Y1')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod"' +//@ is "$.index[?(@.name=='Y1')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod"' pub type Y1 = defines_and_reexports::InPrivMod; -//@ is "$.index[*][?(@.name=='Y2')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod2"' +//@ is "$.index[?(@.name=='Y2')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod2"' pub type Y2 = defines_and_reexports::InPrivMod2; -//@ is "$.index[*][?(@.name=='Y3')].inner.type_alias.type.resolved_path.path" '"XPrivMod"' +//@ is "$.index[?(@.name=='Y3')].inner.type_alias.type.resolved_path.path" '"XPrivMod"' pub type Y3 = XPrivMod; -//@ is "$.index[*][?(@.name=='Y4')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod"' +//@ is "$.index[?(@.name=='Y4')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod"' pub type Y4 = XPrivMod2; // For foreign items, $.paths contains the *origional* path, even if it's not publicly @@ -74,9 +74,9 @@ pub type Y4 = XPrivMod2; // Tests for the example in the docs of Path::name. // If these change, chage the docs. -//@ is "$.index[*][?(@.name=='Vec1')].inner.type_alias.type.resolved_path.path" '"std::vec::Vec"' +//@ is "$.index[?(@.name=='Vec1')].inner.type_alias.type.resolved_path.path" '"std::vec::Vec"' pub type Vec1 = std::vec::Vec; -//@ is "$.index[*][?(@.name=='Vec2')].inner.type_alias.type.resolved_path.path" '"Vec"' +//@ is "$.index[?(@.name=='Vec2')].inner.type_alias.type.resolved_path.path" '"Vec"' pub type Vec2 = Vec; -//@ is "$.index[*][?(@.name=='Vec3')].inner.type_alias.type.resolved_path.path" '"std::prelude::v1::Vec"' +//@ is "$.index[?(@.name=='Vec3')].inner.type_alias.type.resolved_path.path" '"std::prelude::v1::Vec"' pub type Vec3 = std::prelude::v1::Vec; diff --git a/tests/rustdoc-json/primitives/local_primitive.rs b/tests/rustdoc-json/primitives/local_primitive.rs index b10ae45f3ec0..b58120bae052 100644 --- a/tests/rustdoc-json/primitives/local_primitive.rs +++ b/tests/rustdoc-json/primitives/local_primitive.rs @@ -11,11 +11,11 @@ #[rustc_doc_primitive = "i32"] mod prim_i32 {} -//@ set local_i32 = "$.index[*][?(@.name=='i32')].id" +//@ set local_i32 = "$.index[?(@.name=='i32')].id" -//@ has "$.index[*][?(@.name=='local_primitive')]" -//@ ismany "$.index[*][?(@.name=='local_primitive')].inner.module.items[*]" $local_i32 -//@ is "$.index[*][?(@.name=='local_primitive')].links['prim@i32']" $local_i32 +//@ has "$.index[?(@.name=='local_primitive')]" +//@ ismany "$.index[?(@.name=='local_primitive')].inner.module.items[*]" $local_i32 +//@ is "$.index[?(@.name=='local_primitive')].links['prim@i32']" $local_i32 // Let's ensure the `prim_i32` module isn't present in the output JSON: -//@ !has "$.index[*][?(@.name=='prim_i32')]" +//@ !has "$.index[?(@.name=='prim_i32')]" diff --git a/tests/rustdoc-json/primitives/primitive_impls.rs b/tests/rustdoc-json/primitives/primitive_impls.rs index 58c222ce4f0b..a1f0ebd11b63 100644 --- a/tests/rustdoc-json/primitives/primitive_impls.rs +++ b/tests/rustdoc-json/primitives/primitive_impls.rs @@ -4,26 +4,26 @@ #![no_core] #![rustc_coherence_is_core] -//@ set impl_i32 = "$.index[*][?(@.docs=='Only core can do this')].id" +//@ set impl_i32 = "$.index[?(@.docs=='Only core can do this')].id" #[lang = "sized"] trait Sized {} /// Only core can do this impl i32 { - //@ set identity = "$.index[*][?(@.docs=='Do Nothing')].id" + //@ set identity = "$.index[?(@.docs=='Do Nothing')].id" /// Do Nothing pub fn identity(self) -> Self { self } - //@ is "$.index[*][?(@.docs=='Only core can do this')].inner.impl.items[*]" $identity + //@ is "$.index[?(@.docs=='Only core can do this')].inner.impl.items[*]" $identity } -//@ set Trait = "$.index[*][?(@.name=='Trait')].id" +//@ set Trait = "$.index[?(@.name=='Trait')].id" pub trait Trait {} -//@ set impl_trait_for_i32 = "$.index[*][?(@.docs=='impl Trait for i32')].id" +//@ set impl_trait_for_i32 = "$.index[?(@.docs=='impl Trait for i32')].id" /// impl Trait for i32 impl Trait for i32 {} @@ -31,7 +31,7 @@ impl Trait for i32 {} #[rustc_doc_primitive = "i32"] mod prim_i32 {} -//@ set i32 = "$.index[*][?(@.docs=='i32')].id" -//@ is "$.index[*][?(@.docs=='i32')].name" '"i32"' -//@ is "$.index[*][?(@.docs=='i32')].inner.primitive.name" '"i32"' -//@ ismany "$.index[*][?(@.docs=='i32')].inner.primitive.impls[*]" $impl_i32 $impl_trait_for_i32 +//@ set i32 = "$.index[?(@.docs=='i32')].id" +//@ is "$.index[?(@.docs=='i32')].name" '"i32"' +//@ is "$.index[?(@.docs=='i32')].inner.primitive.name" '"i32"' +//@ ismany "$.index[?(@.docs=='i32')].inner.primitive.impls[*]" $impl_i32 $impl_trait_for_i32 diff --git a/tests/rustdoc-json/primitives/primitive_overloading.rs b/tests/rustdoc-json/primitives/primitive_overloading.rs index 5e5f3974ab3c..ae0306843c56 100644 --- a/tests/rustdoc-json/primitives/primitive_overloading.rs +++ b/tests/rustdoc-json/primitives/primitive_overloading.rs @@ -4,8 +4,8 @@ #![feature(rustc_attrs)] -//@ has "$.index[*][?(@.name=='usize')]" -//@ has "$.index[*][?(@.name=='prim')]" +//@ has "$.index[?(@.name=='usize')]" +//@ has "$.index[?(@.name=='prim')]" #[rustc_doc_primitive = "usize"] /// This is the built-in type `usize`. diff --git a/tests/rustdoc-json/primitives/primitive_type.rs b/tests/rustdoc-json/primitives/primitive_type.rs index 21ef5ab7196f..a0d34218b805 100644 --- a/tests/rustdoc-json/primitives/primitive_type.rs +++ b/tests/rustdoc-json/primitives/primitive_type.rs @@ -1,17 +1,17 @@ #![feature(never_type)] -//@ is "$.index[*][?(@.name=='PrimNever')].visibility" \"public\" -//@ is "$.index[*][?(@.name=='PrimNever')].inner.type_alias.type.primitive" \"never\" +//@ is "$.index[?(@.name=='PrimNever')].visibility" \"public\" +//@ is "$.index[?(@.name=='PrimNever')].inner.type_alias.type.primitive" \"never\" pub type PrimNever = !; -//@ is "$.index[*][?(@.name=='PrimStr')].inner.type_alias.type.primitive" \"str\" +//@ is "$.index[?(@.name=='PrimStr')].inner.type_alias.type.primitive" \"str\" pub type PrimStr = str; -//@ is "$.index[*][?(@.name=='PrimBool')].inner.type_alias.type.primitive" \"bool\" +//@ is "$.index[?(@.name=='PrimBool')].inner.type_alias.type.primitive" \"bool\" pub type PrimBool = bool; -//@ is "$.index[*][?(@.name=='PrimChar')].inner.type_alias.type.primitive" \"char\" +//@ is "$.index[?(@.name=='PrimChar')].inner.type_alias.type.primitive" \"char\" pub type PrimChar = char; -//@ is "$.index[*][?(@.name=='PrimU8')].inner.type_alias.type.primitive" \"u8\" +//@ is "$.index[?(@.name=='PrimU8')].inner.type_alias.type.primitive" \"u8\" pub type PrimU8 = u8; diff --git a/tests/rustdoc-json/primitives/use_primitive.rs b/tests/rustdoc-json/primitives/use_primitive.rs index d4cdef84de84..9213229c4bb1 100644 --- a/tests/rustdoc-json/primitives/use_primitive.rs +++ b/tests/rustdoc-json/primitives/use_primitive.rs @@ -5,13 +5,13 @@ #[rustc_doc_primitive = "usize"] mod usize {} -//@ set local_crate_id = "$.index[*][?(@.name=='use_primitive')].crate_id" +//@ set local_crate_id = "$.index[?(@.name=='use_primitive')].crate_id" -//@ has "$.index[*][?(@.name=='ilog10')]" -//@ !is "$.index[*][?(@.name=='ilog10')].crate_id" $local_crate_id -//@ has "$.index[*][?(@.name=='checked_add')]" -//@ !is "$.index[*][?(@.name=='checked_add')]" $local_crate_id -//@ !has "$.index[*][?(@.name=='is_ascii_uppercase')]" +//@ has "$.index[?(@.name=='ilog10')]" +//@ !is "$.index[?(@.name=='ilog10')].crate_id" $local_crate_id +//@ has "$.index[?(@.name=='checked_add')]" +//@ !is "$.index[?(@.name=='checked_add')]" $local_crate_id +//@ !has "$.index[?(@.name=='is_ascii_uppercase')]" //@ is "$.index[*].inner.use[?(@.name=='my_i32')].id" null pub use i32 as my_i32; diff --git a/tests/rustdoc-json/pub_mod_in_private_mod.rs b/tests/rustdoc-json/pub_mod_in_private_mod.rs index 112ab9c68f00..8b31ad0bcfe2 100644 --- a/tests/rustdoc-json/pub_mod_in_private_mod.rs +++ b/tests/rustdoc-json/pub_mod_in_private_mod.rs @@ -1,6 +1,6 @@ // See https://github.com/rust-lang/rust/issues/101105 -//@ !has "$.index[*][?(@.name=='nucleus')]" +//@ !has "$.index[?(@.name=='nucleus')]" mod corpus { pub mod nucleus {} } diff --git a/tests/rustdoc-json/reexport/doc_inline_external_crate.rs b/tests/rustdoc-json/reexport/doc_inline_external_crate.rs index 4debd395496b..f7067857ddf4 100644 --- a/tests/rustdoc-json/reexport/doc_inline_external_crate.rs +++ b/tests/rustdoc-json/reexport/doc_inline_external_crate.rs @@ -4,7 +4,7 @@ #[doc(inline)] pub extern crate enum_with_discriminant; -//@ !has '$.index[*][?(@.docs == "Should not be inlined")]' -//@ has '$.index[*][?(@.name == "enum_with_discriminant")].inner.extern_crate' -//@ set enum_with_discriminant = '$.index[*][?(@.name == "enum_with_discriminant")].id' -//@ is '$.index[*][?(@.name == "doc_inline_external_crate")].inner.module.items[*]' $enum_with_discriminant +//@ !has '$.index[?(@.docs == "Should not be inlined")]' +//@ has '$.index[?(@.name == "enum_with_discriminant")].inner.extern_crate' +//@ set enum_with_discriminant = '$.index[?(@.name == "enum_with_discriminant")].id' +//@ is '$.index[?(@.name == "doc_inline_external_crate")].inner.module.items[*]' $enum_with_discriminant diff --git a/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs b/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs index 4efacd283ef7..746749e02042 100644 --- a/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs +++ b/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs @@ -2,5 +2,5 @@ #![crate_name = "export_extern_crate_as_self"] -//@ is "$.index[*][?(@.inner.module)].name" \"export_extern_crate_as_self\" +//@ is "$.index[?(@.inner.module)].name" \"export_extern_crate_as_self\" pub extern crate self as export_extern_crate_as_self; // Must be the same name as the crate already has diff --git a/tests/rustdoc-json/reexport/extern_crate_glob.rs b/tests/rustdoc-json/reexport/extern_crate_glob.rs index dfe6e7a03b15..8a4388feaca6 100644 --- a/tests/rustdoc-json/reexport/extern_crate_glob.rs +++ b/tests/rustdoc-json/reexport/extern_crate_glob.rs @@ -5,7 +5,7 @@ extern crate enum_with_discriminant; #[doc(inline)] pub use enum_with_discriminant::*; -//@ !has '$.index[*][?(@.docs == "Should not be inlined")]' -//@ is '$.index[*][?(@.inner.use)].inner.use.name' \"enum_with_discriminant\" -//@ set use = '$.index[*][?(@.inner.use)].id' -//@ is '$.index[*][?(@.name == "extern_crate_glob")].inner.module.items[*]' $use +//@ !has '$.index[?(@.docs == "Should not be inlined")]' +//@ is '$.index[?(@.inner.use)].inner.use.name' \"enum_with_discriminant\" +//@ set use = '$.index[?(@.inner.use)].id' +//@ is '$.index[?(@.name == "extern_crate_glob")].inner.module.items[*]' $use diff --git a/tests/rustdoc-json/reexport/glob_collision.rs b/tests/rustdoc-json/reexport/glob_collision.rs index 8142c35f4c71..b077bc1e47c1 100644 --- a/tests/rustdoc-json/reexport/glob_collision.rs +++ b/tests/rustdoc-json/reexport/glob_collision.rs @@ -1,24 +1,24 @@ // Regression test for https://github.com/rust-lang/rust/issues/100973 -//@ set m1 = "$.index[*][?(@.name == 'm1' && @.inner.module)].id" -//@ is "$.index[*][?(@.name == 'm1')].inner.module.items" [] -//@ is "$.index[*][?(@.name == 'm1')].inner.module.is_stripped" true +//@ set m1 = "$.index[?(@.name == 'm1' && @.inner.module)].id" +//@ is "$.index[?(@.name == 'm1')].inner.module.items" [] +//@ is "$.index[?(@.name == 'm1')].inner.module.is_stripped" true mod m1 { pub fn f() {} } -//@ set m2 = "$.index[*][?(@.name == 'm2' && @.inner.module)].id" -//@ is "$.index[*][?(@.name == 'm2')].inner.module.items" [] -//@ is "$.index[*][?(@.name == 'm2')].inner.module.is_stripped" true +//@ set m2 = "$.index[?(@.name == 'm2' && @.inner.module)].id" +//@ is "$.index[?(@.name == 'm2')].inner.module.items" [] +//@ is "$.index[?(@.name == 'm2')].inner.module.is_stripped" true mod m2 { pub fn f(_: u8) {} } -//@ set m1_use = "$.index[*][?(@.docs=='m1 re-export')].id" +//@ set m1_use = "$.index[?(@.docs=='m1 re-export')].id" //@ is "$.index[*].inner.use[?(@.name=='m1')].id" $m1 //@ is "$.index[*].inner.use[?(@.name=='m1')].is_glob" true /// m1 re-export pub use m1::*; -//@ set m2_use = "$.index[*][?(@.docs=='m2 re-export')].id" +//@ set m2_use = "$.index[?(@.docs=='m2 re-export')].id" //@ is "$.index[*].inner.use[?(@.name=='m2')].id" $m2 //@ is "$.index[*].inner.use[?(@.name=='m2')].is_glob" true /// m2 re-export diff --git a/tests/rustdoc-json/reexport/glob_empty_mod.rs b/tests/rustdoc-json/reexport/glob_empty_mod.rs index ee1779407f40..69c0c0e6d5f3 100644 --- a/tests/rustdoc-json/reexport/glob_empty_mod.rs +++ b/tests/rustdoc-json/reexport/glob_empty_mod.rs @@ -1,8 +1,8 @@ // Regression test for https://github.com/rust-lang/rust/issues/100973 -//@ is "$.index[*][?(@.name=='m1' && @.inner.module)].inner.module.is_stripped" true -//@ set m1 = "$.index[*][?(@.name=='m1')].id" +//@ is "$.index[?(@.name=='m1' && @.inner.module)].inner.module.is_stripped" true +//@ set m1 = "$.index[?(@.name=='m1')].id" mod m1 {} -//@ is "$.index[*][?(@.inner.use)].inner.use.id" $m1 +//@ is "$.index[?(@.inner.use)].inner.use.id" $m1 pub use m1::*; diff --git a/tests/rustdoc-json/reexport/glob_extern.rs b/tests/rustdoc-json/reexport/glob_extern.rs index 98be47739413..ccc6faffc8ed 100644 --- a/tests/rustdoc-json/reexport/glob_extern.rs +++ b/tests/rustdoc-json/reexport/glob_extern.rs @@ -1,19 +1,19 @@ //@ edition:2018 -//@ is "$.index[*][?(@.name=='mod1')].inner.module.is_stripped" "true" +//@ is "$.index[?(@.name=='mod1')].inner.module.is_stripped" "true" mod mod1 { extern "C" { - //@ set public_fn_id = "$.index[*][?(@.name=='public_fn')].id" + //@ set public_fn_id = "$.index[?(@.name=='public_fn')].id" pub fn public_fn(); - //@ !has "$.index[*][?(@.name=='private_fn')]" + //@ !has "$.index[?(@.name=='private_fn')]" fn private_fn(); } - //@ ismany "$.index[*][?(@.name=='mod1')].inner.module.items[*]" $public_fn_id - //@ set mod1_id = "$.index[*][?(@.name=='mod1')].id" + //@ ismany "$.index[?(@.name=='mod1')].inner.module.items[*]" $public_fn_id + //@ set mod1_id = "$.index[?(@.name=='mod1')].id" } -//@ is "$.index[*][?(@.inner.use)].inner.use.is_glob" true -//@ is "$.index[*][?(@.inner.use)].inner.use.id" $mod1_id -//@ set use_id = "$.index[*][?(@.inner.use)].id" -//@ ismany "$.index[*][?(@.name=='glob_extern')].inner.module.items[*]" $use_id +//@ is "$.index[?(@.inner.use)].inner.use.is_glob" true +//@ is "$.index[?(@.inner.use)].inner.use.id" $mod1_id +//@ set use_id = "$.index[?(@.inner.use)].id" +//@ ismany "$.index[?(@.name=='glob_extern')].inner.module.items[*]" $use_id pub use mod1::*; diff --git a/tests/rustdoc-json/reexport/glob_private.rs b/tests/rustdoc-json/reexport/glob_private.rs index 2084ffc356e2..f232914787b2 100644 --- a/tests/rustdoc-json/reexport/glob_private.rs +++ b/tests/rustdoc-json/reexport/glob_private.rs @@ -1,32 +1,32 @@ //@ edition:2018 -//@ is "$.index[*][?(@.name=='mod1')].inner.module.is_stripped" "true" +//@ is "$.index[?(@.name=='mod1')].inner.module.is_stripped" "true" mod mod1 { - //@ is "$.index[*][?(@.name=='mod2')].inner.module.is_stripped" "true" + //@ is "$.index[?(@.name=='mod2')].inner.module.is_stripped" "true" mod mod2 { - //@ set m2pub_id = "$.index[*][?(@.name=='Mod2Public')].id" + //@ set m2pub_id = "$.index[?(@.name=='Mod2Public')].id" pub struct Mod2Public; - //@ !has "$.index[*][?(@.name=='Mod2Private')]" + //@ !has "$.index[?(@.name=='Mod2Private')]" struct Mod2Private; } - //@ set mod2_use_id = "$.index[*][?(@.docs=='Mod2 re-export')].id" - //@ is "$.index[*][?(@.docs=='Mod2 re-export')].inner.use.name" \"mod2\" + //@ set mod2_use_id = "$.index[?(@.docs=='Mod2 re-export')].id" + //@ is "$.index[?(@.docs=='Mod2 re-export')].inner.use.name" \"mod2\" /// Mod2 re-export pub use self::mod2::*; - //@ set m1pub_id = "$.index[*][?(@.name=='Mod1Public')].id" + //@ set m1pub_id = "$.index[?(@.name=='Mod1Public')].id" pub struct Mod1Public; - //@ !has "$.index[*][?(@.name=='Mod1Private')]" + //@ !has "$.index[?(@.name=='Mod1Private')]" struct Mod1Private; } -//@ set mod1_use_id = "$.index[*][?(@.docs=='Mod1 re-export')].id" -//@ is "$.index[*][?(@.docs=='Mod1 re-export')].inner.use.name" \"mod1\" +//@ set mod1_use_id = "$.index[?(@.docs=='Mod1 re-export')].id" +//@ is "$.index[?(@.docs=='Mod1 re-export')].inner.use.name" \"mod1\" /// Mod1 re-export pub use mod1::*; -//@ ismany "$.index[*][?(@.name=='mod2')].inner.module.items[*]" $m2pub_id -//@ ismany "$.index[*][?(@.name=='mod1')].inner.module.items[*]" $m1pub_id $mod2_use_id -//@ ismany "$.index[*][?(@.name=='glob_private')].inner.module.items[*]" $mod1_use_id +//@ ismany "$.index[?(@.name=='mod2')].inner.module.items[*]" $m2pub_id +//@ ismany "$.index[?(@.name=='mod1')].inner.module.items[*]" $m1pub_id $mod2_use_id +//@ ismany "$.index[?(@.name=='glob_private')].inner.module.items[*]" $mod1_use_id diff --git a/tests/rustdoc-json/reexport/in_root_and_mod.rs b/tests/rustdoc-json/reexport/in_root_and_mod.rs index a1d2080c0688..e0c54f9d7fd7 100644 --- a/tests/rustdoc-json/reexport/in_root_and_mod.rs +++ b/tests/rustdoc-json/reexport/in_root_and_mod.rs @@ -1,6 +1,6 @@ -//@ !has "$.index[*][?(@.name=='foo')]" +//@ !has "$.index[?(@.name=='foo')]" mod foo { - //@ has "$.index[*][?(@.name=='Foo')]" + //@ has "$.index[?(@.name=='Foo')]" pub struct Foo; } diff --git a/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs b/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs index 7d26d2a970d4..5780b2082794 100644 --- a/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs +++ b/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs @@ -1,19 +1,19 @@ pub mod foo { - //@ set bar_id = "$.index[*][?(@.name=='Bar')].id" - //@ ismany "$.index[*][?(@.name=='foo')].inner.module.items[*]" $bar_id + //@ set bar_id = "$.index[?(@.name=='Bar')].id" + //@ ismany "$.index[?(@.name=='foo')].inner.module.items[*]" $bar_id pub struct Bar; } -//@ set root_import_id = "$.index[*][?(@.docs=='Outer re-export')].id" +//@ set root_import_id = "$.index[?(@.docs=='Outer re-export')].id" //@ is "$.index[*].inner[?(@.use.source=='foo::Bar')].use.id" $bar_id -//@ has "$.index[*][?(@.name=='in_root_and_mod_pub')].inner.module.items[*]" $root_import_id +//@ has "$.index[?(@.name=='in_root_and_mod_pub')].inner.module.items[*]" $root_import_id /// Outer re-export pub use foo::Bar; pub mod baz { - //@ set baz_import_id = "$.index[*][?(@.docs=='Inner re-export')].id" + //@ set baz_import_id = "$.index[?(@.docs=='Inner re-export')].id" //@ is "$.index[*].inner[?(@.use.source=='crate::foo::Bar')].use.id" $bar_id - //@ ismany "$.index[*][?(@.name=='baz')].inner.module.items[*]" $baz_import_id + //@ ismany "$.index[?(@.name=='baz')].inner.module.items[*]" $baz_import_id /// Inner re-export pub use crate::foo::Bar; } diff --git a/tests/rustdoc-json/reexport/macro.rs b/tests/rustdoc-json/reexport/macro.rs index f182208c3417..0bd37768255b 100644 --- a/tests/rustdoc-json/reexport/macro.rs +++ b/tests/rustdoc-json/reexport/macro.rs @@ -1,13 +1,13 @@ //@ edition:2018 -//@ set repro_id = "$.index[*][?(@.name=='repro')].id" +//@ set repro_id = "$.index[?(@.name=='repro')].id" #[macro_export] macro_rules! repro { () => {}; } -//@ set repro2_id = "$.index[*][?(@.docs=='Re-export')].id" +//@ set repro2_id = "$.index[?(@.docs=='Re-export')].id" /// Re-export pub use crate::repro as repro2; -//@ ismany "$.index[*][?(@.name=='macro')].inner.module.items[*]" $repro_id $repro2_id +//@ ismany "$.index[?(@.name=='macro')].inner.module.items[*]" $repro_id $repro2_id diff --git a/tests/rustdoc-json/reexport/mod_not_included.rs b/tests/rustdoc-json/reexport/mod_not_included.rs index d0ce95749f1b..a2ac543a94cb 100644 --- a/tests/rustdoc-json/reexport/mod_not_included.rs +++ b/tests/rustdoc-json/reexport/mod_not_included.rs @@ -6,6 +6,6 @@ mod m1 { pub use m1::x; -//@ has "$.index[*][?(@.name=='x' && @.inner.function)]" +//@ has "$.index[?(@.name=='x' && @.inner.function)]" //@ has "$.index[*].inner[?(@.use.name=='x')].use.source" '"m1::x"' -//@ !has "$.index[*][?(@.name=='m1')]" +//@ !has "$.index[?(@.name=='m1')]" diff --git a/tests/rustdoc-json/reexport/private_twice_one_inline.rs b/tests/rustdoc-json/reexport/private_twice_one_inline.rs index fdf8cda103bf..6b5d03e207eb 100644 --- a/tests/rustdoc-json/reexport/private_twice_one_inline.rs +++ b/tests/rustdoc-json/reexport/private_twice_one_inline.rs @@ -5,19 +5,19 @@ extern crate pub_struct as foo; #[doc(inline)] -//@ set crate_use_id = "$.index[*][?(@.docs=='Hack A')].id" -//@ set foo_id = "$.index[*][?(@.docs=='Hack A')].inner.use.id" +//@ set crate_use_id = "$.index[?(@.docs=='Hack A')].id" +//@ set foo_id = "$.index[?(@.docs=='Hack A')].inner.use.id" /// Hack A pub use foo::Foo; -//@ set bar_id = "$.index[*][?(@.name=='bar')].id" +//@ set bar_id = "$.index[?(@.name=='bar')].id" pub mod bar { - //@ is "$.index[*][?(@.docs=='Hack B')].inner.use.id" $foo_id - //@ set bar_use_id = "$.index[*][?(@.docs=='Hack B')].id" - //@ ismany "$.index[*][?(@.name=='bar')].inner.module.items[*]" $bar_use_id + //@ is "$.index[?(@.docs=='Hack B')].inner.use.id" $foo_id + //@ set bar_use_id = "$.index[?(@.docs=='Hack B')].id" + //@ ismany "$.index[?(@.name=='bar')].inner.module.items[*]" $bar_use_id /// Hack B pub use foo::Foo; } -//@ ismany "$.index[*][?(@.inner.use)].id" $crate_use_id $bar_use_id -//@ ismany "$.index[*][?(@.name=='private_twice_one_inline')].inner.module.items[*]" $bar_id $crate_use_id +//@ ismany "$.index[?(@.inner.use)].id" $crate_use_id $bar_use_id +//@ ismany "$.index[?(@.name=='private_twice_one_inline')].inner.module.items[*]" $bar_id $crate_use_id diff --git a/tests/rustdoc-json/reexport/private_two_names.rs b/tests/rustdoc-json/reexport/private_two_names.rs index 049100d7f497..79af40b83a4f 100644 --- a/tests/rustdoc-json/reexport/private_two_names.rs +++ b/tests/rustdoc-json/reexport/private_two_names.rs @@ -1,21 +1,21 @@ // Test for the ICE in https://github.com/rust-lang/rust/issues/83720 // A pub-in-private type re-exported under two different names shouldn't cause an error -//@ !has "$.index[*][?(@.name=='style')]" +//@ !has "$.index[?(@.name=='style')]" mod style { - //@ set color_struct_id = "$.index[*][?(@.inner.struct && @.name=='Color')].id" + //@ set color_struct_id = "$.index[?(@.inner.struct && @.name=='Color')].id" pub struct Color; } -//@ is "$.index[*][?(@.docs=='First re-export')].inner.use.id" $color_struct_id -//@ is "$.index[*][?(@.docs=='First re-export')].inner.use.name" \"Color\" -//@ set color_export_id = "$.index[*][?(@.docs=='First re-export')].id" +//@ is "$.index[?(@.docs=='First re-export')].inner.use.id" $color_struct_id +//@ is "$.index[?(@.docs=='First re-export')].inner.use.name" \"Color\" +//@ set color_export_id = "$.index[?(@.docs=='First re-export')].id" /// First re-export pub use style::Color; -//@ is "$.index[*][?(@.docs=='Second re-export')].inner.use.id" $color_struct_id -//@ is "$.index[*][?(@.docs=='Second re-export')].inner.use.name" \"Colour\" -//@ set colour_export_id = "$.index[*][?(@.docs=='Second re-export')].id" +//@ is "$.index[?(@.docs=='Second re-export')].inner.use.id" $color_struct_id +//@ is "$.index[?(@.docs=='Second re-export')].inner.use.name" \"Colour\" +//@ set colour_export_id = "$.index[?(@.docs=='Second re-export')].id" /// Second re-export pub use style::Color as Colour; -//@ ismany "$.index[*][?(@.name=='private_two_names')].inner.module.items[*]" $color_export_id $colour_export_id +//@ ismany "$.index[?(@.name=='private_two_names')].inner.module.items[*]" $color_export_id $colour_export_id diff --git a/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs b/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs index e021b51ab4be..129ccb7e2ebe 100644 --- a/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs +++ b/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs @@ -9,5 +9,5 @@ mod repeat_n { /// not here pub use repeat_n::RepeatN; -//@ count "$.index[*][?(@.name=='pub_use_doc_hidden')].inner.items[*]" 0 -//@ !has "$.index[*][?(@.docs == 'not here')]" +//@ count "$.index[?(@.name=='pub_use_doc_hidden')].inner.items[*]" 0 +//@ !has "$.index[?(@.docs == 'not here')]" diff --git a/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs b/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs index 25edd5dbb280..56922340a6fb 100644 --- a/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs +++ b/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs @@ -1,11 +1,11 @@ // Regression test for . -//@ set impl_S = "$.index[*][?(@.docs=='impl S')].id" -//@ has "$.index[*][?(@.name=='S')].inner.struct.impls[*]" $impl_S -//@ set is_present = "$.index[*][?(@.name=='is_present')].id" -//@ is "$.index[*][?(@.docs=='impl S')].inner.impl.items[*]" $is_present -//@ !has "$.index[*][?(@.name=='hidden_impl')]" -//@ !has "$.index[*][?(@.name=='hidden_fn')]" +//@ set impl_S = "$.index[?(@.docs=='impl S')].id" +//@ has "$.index[?(@.name=='S')].inner.struct.impls[*]" $impl_S +//@ set is_present = "$.index[?(@.name=='is_present')].id" +//@ is "$.index[?(@.docs=='impl S')].inner.impl.items[*]" $is_present +//@ !has "$.index[?(@.name=='hidden_impl')]" +//@ !has "$.index[?(@.name=='hidden_fn')]" #![no_std] diff --git a/tests/rustdoc-json/reexport/reexport_of_hidden.rs b/tests/rustdoc-json/reexport/reexport_of_hidden.rs index 80f171da888e..fd9f57115c65 100644 --- a/tests/rustdoc-json/reexport/reexport_of_hidden.rs +++ b/tests/rustdoc-json/reexport/reexport_of_hidden.rs @@ -1,7 +1,7 @@ //@ compile-flags: --document-hidden-items //@ has "$.index[*].inner[?(@.use.name=='UsedHidden')]" -//@ has "$.index[*][?(@.name=='Hidden')]" +//@ has "$.index[?(@.name=='Hidden')]" pub mod submodule { #[doc(hidden)] pub struct Hidden {} diff --git a/tests/rustdoc-json/reexport/rename_private.rs b/tests/rustdoc-json/reexport/rename_private.rs index 3f13f305d644..0494dff5bca2 100644 --- a/tests/rustdoc-json/reexport/rename_private.rs +++ b/tests/rustdoc-json/reexport/rename_private.rs @@ -1,10 +1,10 @@ //@ edition:2018 -//@ !has "$.index[*][?(@.name=='inner')]" +//@ !has "$.index[?(@.name=='inner')]" mod inner { - //@ has "$.index[*][?(@.name=='Public')]" + //@ has "$.index[?(@.name=='Public')]" pub struct Public; } -//@ is "$.index[*][?(@.inner.use)].inner.use.name" \"NewName\" +//@ is "$.index[?(@.inner.use)].inner.use.name" \"NewName\" pub use inner::Public as NewName; diff --git a/tests/rustdoc-json/reexport/rename_public.rs b/tests/rustdoc-json/reexport/rename_public.rs index 81c003a51c4a..c0676b5875d2 100644 --- a/tests/rustdoc-json/reexport/rename_public.rs +++ b/tests/rustdoc-json/reexport/rename_public.rs @@ -1,15 +1,15 @@ //@ edition:2018 -//@ set inner_id = "$.index[*][?(@.name=='inner')].id" +//@ set inner_id = "$.index[?(@.name=='inner')].id" pub mod inner { - //@ set public_id = "$.index[*][?(@.name=='Public')].id" - //@ ismany "$.index[*][?(@.name=='inner')].inner.module.items[*]" $public_id + //@ set public_id = "$.index[?(@.name=='Public')].id" + //@ ismany "$.index[?(@.name=='inner')].inner.module.items[*]" $public_id pub struct Public; } -//@ set import_id = "$.index[*][?(@.docs=='Re-export')].id" +//@ set import_id = "$.index[?(@.docs=='Re-export')].id" //@ !has "$.index[*].inner[?(@.use.name=='Public')]" //@ is "$.index[*].inner[?(@.use.name=='NewName')].use.source" \"inner::Public\" /// Re-export pub use inner::Public as NewName; -//@ ismany "$.index[*][?(@.name=='rename_public')].inner.module.items[*]" $inner_id $import_id +//@ ismany "$.index[?(@.name=='rename_public')].inner.module.items[*]" $inner_id $import_id diff --git a/tests/rustdoc-json/reexport/same_name_different_types.rs b/tests/rustdoc-json/reexport/same_name_different_types.rs index 760e2c6f7750..a707abafe883 100644 --- a/tests/rustdoc-json/reexport/same_name_different_types.rs +++ b/tests/rustdoc-json/reexport/same_name_different_types.rs @@ -1,12 +1,12 @@ // Regression test for . pub mod nested { - //@ set foo_struct = "$.index[*][?(@.docs == 'Foo the struct')].id" + //@ set foo_struct = "$.index[?(@.docs == 'Foo the struct')].id" /// Foo the struct pub struct Foo {} - //@ set foo_fn = "$.index[*][?(@.docs == 'Foo the function')].id" + //@ set foo_fn = "$.index[?(@.docs == 'Foo the function')].id" #[allow(non_snake_case)] /// Foo the function diff --git a/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs index f313171afa59..9ba69a4aa72c 100644 --- a/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs +++ b/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs @@ -3,17 +3,17 @@ #![no_std] mod inner { - //@ set trait_id = "$.index[*][?(@.name=='Trait')].id" + //@ set trait_id = "$.index[?(@.name=='Trait')].id" pub trait Trait {} } -//@ set export_id = "$.index[*][?(@.docs=='First re-export')].id" +//@ set export_id = "$.index[?(@.docs=='First re-export')].id" //@ is "$.index[*].inner[?(@.use.name=='Trait')].use.id" $trait_id /// First re-export pub use inner::Trait; -//@ set reexport_id = "$.index[*][?(@.docs=='Second re-export')].id" +//@ set reexport_id = "$.index[?(@.docs=='Second re-export')].id" //@ is "$.index[*].inner[?(@.use.name=='Reexport')].use.id" $trait_id /// Second re-export pub use inner::Trait as Reexport; -//@ ismany "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.module.items[*]" $reexport_id $export_id +//@ ismany "$.index[?(@.name=='same_type_reexported_more_than_once')].inner.module.items[*]" $reexport_id $export_id diff --git a/tests/rustdoc-json/reexport/simple_private.rs b/tests/rustdoc-json/reexport/simple_private.rs index 405d57d342e4..85da90cf48c4 100644 --- a/tests/rustdoc-json/reexport/simple_private.rs +++ b/tests/rustdoc-json/reexport/simple_private.rs @@ -1,17 +1,17 @@ //@ edition:2018 -//@ !has "$.index[*][?(@.name=='inner')]" +//@ !has "$.index[?(@.name=='inner')]" mod inner { - //@ set pub_id = "$.index[*][?(@.name=='Public')].id" + //@ set pub_id = "$.index[?(@.name=='Public')].id" pub struct Public; } -//@ is "$.index[*][?(@.inner.use)].inner.use.name" \"Public\" -//@ is "$.index[*][?(@.inner.use)].inner.use.id" $pub_id -//@ set use_id = "$.index[*][?(@.inner.use)].id" +//@ is "$.index[?(@.inner.use)].inner.use.name" \"Public\" +//@ is "$.index[?(@.inner.use)].inner.use.id" $pub_id +//@ set use_id = "$.index[?(@.inner.use)].id" pub use inner::Public; -//@ ismany "$.index[*][?(@.name=='simple_private')].inner.module.items[*]" $use_id +//@ ismany "$.index[?(@.name=='simple_private')].inner.module.items[*]" $use_id // Test for https://github.com/rust-lang/rust/issues/135309 //@ has "$.paths[*][?(@.kind=='module')].path" '["simple_private"]' diff --git a/tests/rustdoc-json/reexport/simple_public.rs b/tests/rustdoc-json/reexport/simple_public.rs index f13358283140..3dcfe900d735 100644 --- a/tests/rustdoc-json/reexport/simple_public.rs +++ b/tests/rustdoc-json/reexport/simple_public.rs @@ -1,19 +1,19 @@ //@ edition:2018 -//@ set inner_id = "$.index[*][?(@.name=='inner')].id" +//@ set inner_id = "$.index[?(@.name=='inner')].id" pub mod inner { - //@ set public_id = "$.index[*][?(@.name=='Public')].id" - //@ ismany "$.index[*][?(@.name=='inner')].inner.module.items[*]" $public_id + //@ set public_id = "$.index[?(@.name=='Public')].id" + //@ ismany "$.index[?(@.name=='inner')].inner.module.items[*]" $public_id pub struct Public; } -//@ set import_id = "$.index[*][?(@.docs=='Outer')].id" -//@ is "$.index[*][?(@.docs=='Outer')].inner.use.source" \"inner::Public\" +//@ set import_id = "$.index[?(@.docs=='Outer')].id" +//@ is "$.index[?(@.docs=='Outer')].inner.use.source" \"inner::Public\" /// Outer pub use inner::Public; -//@ ismany "$.index[*][?(@.name=='simple_public')].inner.module.items[*]" $import_id $inner_id +//@ ismany "$.index[?(@.name=='simple_public')].inner.module.items[*]" $import_id $inner_id //@ has "$.paths[*][?(@.kind=='module')].path" '["simple_public"]' //@ has "$.paths[*][?(@.kind=='module')].path" '["simple_public", "inner"]' diff --git a/tests/rustdoc-json/reexport/synthesize_trait_with_docs.rs b/tests/rustdoc-json/reexport/synthesize_trait_with_docs.rs index 59699e4861b4..89591690bcaf 100644 --- a/tests/rustdoc-json/reexport/synthesize_trait_with_docs.rs +++ b/tests/rustdoc-json/reexport/synthesize_trait_with_docs.rs @@ -7,4 +7,4 @@ pub struct Local; impl trait_with_docs::HasDocs for Local {} -//@ !has "$.index[*][?(@.name == 'HasDocs')]" +//@ !has "$.index[?(@.name == 'HasDocs')]" diff --git a/tests/rustdoc-json/return-type-notation.rs b/tests/rustdoc-json/return-type-notation.rs index 2219642bfc51..7943991616b9 100644 --- a/tests/rustdoc-json/return-type-notation.rs +++ b/tests/rustdoc-json/return-type-notation.rs @@ -8,8 +8,8 @@ pub trait Foo { async fn bar(); } -//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.args.angle_bracketed.constraints[0].args" '"return_type_notation"' -//@ ismany "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[*].bound_predicate.type.qualified_path.args" '"return_type_notation"' '"return_type_notation"' +//@ is "$.index[?(@.name=='foo')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.args.angle_bracketed.constraints[0].args" '"return_type_notation"' +//@ ismany "$.index[?(@.name=='foo')].inner.function.generics.where_predicates[*].bound_predicate.type.qualified_path.args" '"return_type_notation"' '"return_type_notation"' pub fn foo>() where ::bar(..): 'static, diff --git a/tests/rustdoc-json/return_private.rs b/tests/rustdoc-json/return_private.rs index 214fda14acad..8fbdb6be5c91 100644 --- a/tests/rustdoc-json/return_private.rs +++ b/tests/rustdoc-json/return_private.rs @@ -1,13 +1,13 @@ // Regression test for . mod secret { - //@ set struct_secret = "$.index[*][?(@.name == 'Secret' && @.inner.struct)].id" + //@ set struct_secret = "$.index[?(@.name == 'Secret' && @.inner.struct)].id" pub struct Secret; } -//@ has "$.index[*][?(@.name=='get_secret')].inner.function" -//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.path" '"secret::Secret"' -//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.id" $struct_secret +//@ has "$.index[?(@.name=='get_secret')].inner.function" +//@ is "$.index[?(@.name=='get_secret')].inner.function.sig.output.resolved_path.path" '"secret::Secret"' +//@ is "$.index[?(@.name=='get_secret')].inner.function.sig.output.resolved_path.id" $struct_secret pub fn get_secret() -> secret::Secret { secret::Secret } diff --git a/tests/rustdoc-json/statics/extern.rs b/tests/rustdoc-json/statics/extern.rs index 9e0265da8e2e..5be13c8b8fc4 100644 --- a/tests/rustdoc-json/statics/extern.rs +++ b/tests/rustdoc-json/statics/extern.rs @@ -1,38 +1,38 @@ //@ edition: 2021 extern "C" { - //@ is '$.index[*][?(@.name=="A")].inner.static.is_unsafe' true - //@ is '$.index[*][?(@.name=="A")].inner.static.is_mutable' false + //@ is '$.index[?(@.name=="A")].inner.static.is_unsafe' true + //@ is '$.index[?(@.name=="A")].inner.static.is_mutable' false pub static A: i32; - //@ is '$.index[*][?(@.name=="B")].inner.static.is_unsafe' true - //@ is '$.index[*][?(@.name=="B")].inner.static.is_mutable' true + //@ is '$.index[?(@.name=="B")].inner.static.is_unsafe' true + //@ is '$.index[?(@.name=="B")].inner.static.is_mutable' true pub static mut B: i32; // items in unadorned `extern` blocks cannot have safety qualifiers } unsafe extern "C" { - //@ is '$.index[*][?(@.name=="C")].inner.static.is_unsafe' true - //@ is '$.index[*][?(@.name=="C")].inner.static.is_mutable' false + //@ is '$.index[?(@.name=="C")].inner.static.is_unsafe' true + //@ is '$.index[?(@.name=="C")].inner.static.is_mutable' false pub static C: i32; - //@ is '$.index[*][?(@.name=="D")].inner.static.is_unsafe' true - //@ is '$.index[*][?(@.name=="D")].inner.static.is_mutable' true + //@ is '$.index[?(@.name=="D")].inner.static.is_unsafe' true + //@ is '$.index[?(@.name=="D")].inner.static.is_mutable' true pub static mut D: i32; - //@ is '$.index[*][?(@.name=="E")].inner.static.is_unsafe' false - //@ is '$.index[*][?(@.name=="E")].inner.static.is_mutable' false + //@ is '$.index[?(@.name=="E")].inner.static.is_unsafe' false + //@ is '$.index[?(@.name=="E")].inner.static.is_mutable' false pub safe static E: i32; - //@ is '$.index[*][?(@.name=="F")].inner.static.is_unsafe' false - //@ is '$.index[*][?(@.name=="F")].inner.static.is_mutable' true + //@ is '$.index[?(@.name=="F")].inner.static.is_unsafe' false + //@ is '$.index[?(@.name=="F")].inner.static.is_mutable' true pub safe static mut F: i32; - //@ is '$.index[*][?(@.name=="G")].inner.static.is_unsafe' true - //@ is '$.index[*][?(@.name=="G")].inner.static.is_mutable' false + //@ is '$.index[?(@.name=="G")].inner.static.is_unsafe' true + //@ is '$.index[?(@.name=="G")].inner.static.is_mutable' false pub unsafe static G: i32; - //@ is '$.index[*][?(@.name=="H")].inner.static.is_unsafe' true - //@ is '$.index[*][?(@.name=="H")].inner.static.is_mutable' true + //@ is '$.index[?(@.name=="H")].inner.static.is_unsafe' true + //@ is '$.index[?(@.name=="H")].inner.static.is_mutable' true pub unsafe static mut H: i32; } -//@ ismany '$.index[*][?(@.inner.static)].inner.static.expr' '""' '""' '""' '""' '""' '""' '""' '""' -//@ ismany '$.index[*][?(@.inner.static)].inner.static.type.primitive' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' +//@ ismany '$.index[?(@.inner.static)].inner.static.expr' '""' '""' '""' '""' '""' '""' '""' '""' +//@ ismany '$.index[?(@.inner.static)].inner.static.type.primitive' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' diff --git a/tests/rustdoc-json/statics/statics.rs b/tests/rustdoc-json/statics/statics.rs index a8af23cc87dc..497a134c503d 100644 --- a/tests/rustdoc-json/statics/statics.rs +++ b/tests/rustdoc-json/statics/statics.rs @@ -1,12 +1,12 @@ -//@ is '$.index[*][?(@.name=="A")].inner.static.type.primitive' '"i32"' -//@ is '$.index[*][?(@.name=="A")].inner.static.is_mutable' false -//@ is '$.index[*][?(@.name=="A")].inner.static.expr' '"5"' -//@ is '$.index[*][?(@.name=="A")].inner.static.is_unsafe' false +//@ is '$.index[?(@.name=="A")].inner.static.type.primitive' '"i32"' +//@ is '$.index[?(@.name=="A")].inner.static.is_mutable' false +//@ is '$.index[?(@.name=="A")].inner.static.expr' '"5"' +//@ is '$.index[?(@.name=="A")].inner.static.is_unsafe' false pub static A: i32 = 5; -//@ is '$.index[*][?(@.name=="B")].inner.static.type.primitive' '"u32"' -//@ is '$.index[*][?(@.name=="B")].inner.static.is_mutable' true +//@ is '$.index[?(@.name=="B")].inner.static.type.primitive' '"u32"' +//@ is '$.index[?(@.name=="B")].inner.static.is_mutable' true // Expr value isn't gaurenteed, it'd be fine to change it. -//@ is '$.index[*][?(@.name=="B")].inner.static.expr' '"_"' -//@ is '$.index[*][?(@.name=="B")].inner.static.is_unsafe' false +//@ is '$.index[?(@.name=="B")].inner.static.expr' '"_"' +//@ is '$.index[?(@.name=="B")].inner.static.is_unsafe' false pub static mut B: u32 = 2 + 3; diff --git a/tests/rustdoc-json/stripped_modules.rs b/tests/rustdoc-json/stripped_modules.rs index d0db9c6588b0..ba6644190a2d 100644 --- a/tests/rustdoc-json/stripped_modules.rs +++ b/tests/rustdoc-json/stripped_modules.rs @@ -1,17 +1,17 @@ -//@ !has "$.index[*][?(@.name=='no_pub_inner')]" +//@ !has "$.index[?(@.name=='no_pub_inner')]" mod no_pub_inner { fn priv_inner() {} } -//@ !has "$.index[*][?(@.name=='pub_inner_unreachable')]" +//@ !has "$.index[?(@.name=='pub_inner_unreachable')]" mod pub_inner_unreachable { - //@ !has "$.index[*][?(@.name=='pub_inner_1')]" + //@ !has "$.index[?(@.name=='pub_inner_1')]" pub fn pub_inner_1() {} } -//@ !has "$.index[*][?(@.name=='pub_inner_reachable')]" +//@ !has "$.index[?(@.name=='pub_inner_reachable')]" mod pub_inner_reachable { - //@ has "$.index[*][?(@.name=='pub_inner_2')]" + //@ has "$.index[?(@.name=='pub_inner_2')]" pub fn pub_inner_2() {} } diff --git a/tests/rustdoc-json/structs/field_order.rs b/tests/rustdoc-json/structs/field_order.rs index 7e556df777f4..eb1740676a67 100644 --- a/tests/rustdoc-json/structs/field_order.rs +++ b/tests/rustdoc-json/structs/field_order.rs @@ -15,24 +15,24 @@ pub struct Foo { pub vll_9: i32, } -//@ set 0 = '$.index[*][?(@.name == "ews_0")].id' -//@ set 1 = '$.index[*][?(@.name == "dik_1")].id' -//@ set 2 = '$.index[*][?(@.name == "hsk_2")].id' -//@ set 3 = '$.index[*][?(@.name == "djt_3")].id' -//@ set 4 = '$.index[*][?(@.name == "jnr_4")].id' -//@ set 5 = '$.index[*][?(@.name == "dfs_5")].id' -//@ set 6 = '$.index[*][?(@.name == "bja_6")].id' -//@ set 7 = '$.index[*][?(@.name == "lyc_7")].id' -//@ set 8 = '$.index[*][?(@.name == "yqd_8")].id' -//@ set 9 = '$.index[*][?(@.name == "vll_9")].id' +//@ set 0 = '$.index[?(@.name == "ews_0")].id' +//@ set 1 = '$.index[?(@.name == "dik_1")].id' +//@ set 2 = '$.index[?(@.name == "hsk_2")].id' +//@ set 3 = '$.index[?(@.name == "djt_3")].id' +//@ set 4 = '$.index[?(@.name == "jnr_4")].id' +//@ set 5 = '$.index[?(@.name == "dfs_5")].id' +//@ set 6 = '$.index[?(@.name == "bja_6")].id' +//@ set 7 = '$.index[?(@.name == "lyc_7")].id' +//@ set 8 = '$.index[?(@.name == "yqd_8")].id' +//@ set 9 = '$.index[?(@.name == "vll_9")].id' -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[0]' $0 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[1]' $1 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[2]' $2 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[3]' $3 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[4]' $4 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[5]' $5 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[6]' $6 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[7]' $7 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[8]' $8 -//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[9]' $9 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[0]' $0 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[1]' $1 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[2]' $2 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[3]' $3 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[4]' $4 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[5]' $5 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[6]' $6 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[7]' $7 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[8]' $8 +//@ is '$.index[?(@.name == "Foo")].inner.struct.kind.plain.fields[9]' $9 diff --git a/tests/rustdoc-json/structs/plain_all_pub.rs b/tests/rustdoc-json/structs/plain_all_pub.rs index 67d2a4a7a8cf..501044f62cc5 100644 --- a/tests/rustdoc-json/structs/plain_all_pub.rs +++ b/tests/rustdoc-json/structs/plain_all_pub.rs @@ -3,9 +3,9 @@ pub struct Demo { pub y: i32, } -//@ set x = "$.index[*][?(@.name=='x')].id" -//@ set y = "$.index[*][?(@.name=='y')].id" -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[1]" $y -//@ count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 2 -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.has_stripped_fields" false +//@ set x = "$.index[?(@.name=='x')].id" +//@ set y = "$.index[?(@.name=='y')].id" +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.plain.fields[1]" $y +//@ count "$.index[?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 2 +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.plain.has_stripped_fields" false diff --git a/tests/rustdoc-json/structs/plain_doc_hidden.rs b/tests/rustdoc-json/structs/plain_doc_hidden.rs index 4573adc73fa1..e62fb27ae86a 100644 --- a/tests/rustdoc-json/structs/plain_doc_hidden.rs +++ b/tests/rustdoc-json/structs/plain_doc_hidden.rs @@ -4,8 +4,8 @@ pub struct Demo { pub y: i32, } -//@ set x = "$.index[*][?(@.name=='x')].id" -//@ !has "$.index[*][?(@.name=='y')].id" -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x -//@ count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.has_stripped_fields" true +//@ set x = "$.index[?(@.name=='x')].id" +//@ !has "$.index[?(@.name=='y')].id" +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +//@ count "$.index[?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.plain.has_stripped_fields" true diff --git a/tests/rustdoc-json/structs/plain_empty.rs b/tests/rustdoc-json/structs/plain_empty.rs index 30013021abef..127f9ed19721 100644 --- a/tests/rustdoc-json/structs/plain_empty.rs +++ b/tests/rustdoc-json/structs/plain_empty.rs @@ -1,5 +1,5 @@ -//@ is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='PlainEmpty')].inner.struct" -//@ is "$.index[*][?(@.name=='PlainEmpty')].inner.struct.kind.plain.has_stripped_fields" false -//@ is "$.index[*][?(@.name=='PlainEmpty')].inner.struct.kind.plain.fields" [] +//@ is "$.index[?(@.name=='PlainEmpty')].visibility" \"public\" +//@ has "$.index[?(@.name=='PlainEmpty')].inner.struct" +//@ is "$.index[?(@.name=='PlainEmpty')].inner.struct.kind.plain.has_stripped_fields" false +//@ is "$.index[?(@.name=='PlainEmpty')].inner.struct.kind.plain.fields" [] pub struct PlainEmpty {} diff --git a/tests/rustdoc-json/structs/plain_pub_priv.rs b/tests/rustdoc-json/structs/plain_pub_priv.rs index 91079a30d42e..181d5ea0de28 100644 --- a/tests/rustdoc-json/structs/plain_pub_priv.rs +++ b/tests/rustdoc-json/structs/plain_pub_priv.rs @@ -3,7 +3,7 @@ pub struct Demo { y: i32, } -//@ set x = "$.index[*][?(@.name=='x')].id" -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x -//@ count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.has_stripped_fields" true +//@ set x = "$.index[?(@.name=='x')].id" +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +//@ count "$.index[?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.plain.has_stripped_fields" true diff --git a/tests/rustdoc-json/structs/tuple.rs b/tests/rustdoc-json/structs/tuple.rs index 6c8dc79dfe22..115ce29bd703 100644 --- a/tests/rustdoc-json/structs/tuple.rs +++ b/tests/rustdoc-json/structs/tuple.rs @@ -1,4 +1,4 @@ -//@ is "$.index[*][?(@.name=='Tuple')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='Tuple')].inner.struct" -//@ is "$.index[*][?(@.name=='Tuple')].inner.struct.kind.tuple" '[null, null]' +//@ is "$.index[?(@.name=='Tuple')].visibility" \"public\" +//@ has "$.index[?(@.name=='Tuple')].inner.struct" +//@ is "$.index[?(@.name=='Tuple')].inner.struct.kind.tuple" '[null, null]' pub struct Tuple(u32, String); diff --git a/tests/rustdoc-json/structs/tuple_empty.rs b/tests/rustdoc-json/structs/tuple_empty.rs index 137915e6c054..af5b57fb133b 100644 --- a/tests/rustdoc-json/structs/tuple_empty.rs +++ b/tests/rustdoc-json/structs/tuple_empty.rs @@ -1,2 +1,2 @@ -//@ is "$.index[*][?(@.name=='TupleUnit')].inner.struct.kind.tuple" [] +//@ is "$.index[?(@.name=='TupleUnit')].inner.struct.kind.tuple" [] pub struct TupleUnit(); diff --git a/tests/rustdoc-json/structs/tuple_pub_priv.rs b/tests/rustdoc-json/structs/tuple_pub_priv.rs index 11af26e6ea3a..b97a17cc46ac 100644 --- a/tests/rustdoc-json/structs/tuple_pub_priv.rs +++ b/tests/rustdoc-json/structs/tuple_pub_priv.rs @@ -5,9 +5,9 @@ pub struct Demo( #[doc(hidden)] i32, ); -//@ set field = "$.index[*][?(@.docs=='field')].id" +//@ set field = "$.index[?(@.docs=='field')].id" -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[0]" null -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[1]" $field -//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[2]" null -//@ count "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[*]" 3 +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.tuple[0]" null +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.tuple[1]" $field +//@ is "$.index[?(@.name=='Demo')].inner.struct.kind.tuple[2]" null +//@ count "$.index[?(@.name=='Demo')].inner.struct.kind.tuple[*]" 3 diff --git a/tests/rustdoc-json/structs/unit.rs b/tests/rustdoc-json/structs/unit.rs index ad6af65c0e0b..6a9617252064 100644 --- a/tests/rustdoc-json/structs/unit.rs +++ b/tests/rustdoc-json/structs/unit.rs @@ -1,4 +1,4 @@ -//@ is "$.index[*][?(@.name=='Unit')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='Unit')].inner.struct" -//@ is "$.index[*][?(@.name=='Unit')].inner.struct.kind" \"unit\" +//@ is "$.index[?(@.name=='Unit')].visibility" \"public\" +//@ has "$.index[?(@.name=='Unit')].inner.struct" +//@ is "$.index[?(@.name=='Unit')].inner.struct.kind" \"unit\" pub struct Unit; diff --git a/tests/rustdoc-json/structs/with_generics.rs b/tests/rustdoc-json/structs/with_generics.rs index 3e7f175a5a1a..979b002d0eee 100644 --- a/tests/rustdoc-json/structs/with_generics.rs +++ b/tests/rustdoc-json/structs/with_generics.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; -//@ is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='WithGenerics')].inner.struct" -//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[0].name" \"T\" -//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[0].kind.type.bounds" [] -//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[1].name" \"U\" -//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[1].kind.type.bounds" [] -//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.kind.plain.has_stripped_fields" true -//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.kind.plain.fields" [] +//@ is "$.index[?(@.name=='WithGenerics')].visibility" \"public\" +//@ has "$.index[?(@.name=='WithGenerics')].inner.struct" +//@ is "$.index[?(@.name=='WithGenerics')].inner.struct.generics.params[0].name" \"T\" +//@ is "$.index[?(@.name=='WithGenerics')].inner.struct.generics.params[0].kind.type.bounds" [] +//@ is "$.index[?(@.name=='WithGenerics')].inner.struct.generics.params[1].name" \"U\" +//@ is "$.index[?(@.name=='WithGenerics')].inner.struct.generics.params[1].kind.type.bounds" [] +//@ is "$.index[?(@.name=='WithGenerics')].inner.struct.kind.plain.has_stripped_fields" true +//@ is "$.index[?(@.name=='WithGenerics')].inner.struct.kind.plain.fields" [] pub struct WithGenerics { stuff: Vec, things: HashMap, diff --git a/tests/rustdoc-json/structs/with_primitives.rs b/tests/rustdoc-json/structs/with_primitives.rs index fe99292456d6..4e856bda296c 100644 --- a/tests/rustdoc-json/structs/with_primitives.rs +++ b/tests/rustdoc-json/structs/with_primitives.rs @@ -1,9 +1,9 @@ -//@ is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='WithPrimitives')].inner.struct" -//@ is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.generics.params[0].name" \"\'a\" -//@ is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.generics.params[0].kind.lifetime.outlives" [] -//@ is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.kind.plain.has_stripped_fields" true -//@ is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.kind.plain.fields" [] +//@ is "$.index[?(@.name=='WithPrimitives')].visibility" \"public\" +//@ has "$.index[?(@.name=='WithPrimitives')].inner.struct" +//@ is "$.index[?(@.name=='WithPrimitives')].inner.struct.generics.params[0].name" \"\'a\" +//@ is "$.index[?(@.name=='WithPrimitives')].inner.struct.generics.params[0].kind.lifetime.outlives" [] +//@ is "$.index[?(@.name=='WithPrimitives')].inner.struct.kind.plain.has_stripped_fields" true +//@ is "$.index[?(@.name=='WithPrimitives')].inner.struct.kind.plain.fields" [] pub struct WithPrimitives<'a> { num: u32, s: &'a str, diff --git a/tests/rustdoc-json/trait_alias.rs b/tests/rustdoc-json/trait_alias.rs index d9ef256b106f..e7a586ee95a3 100644 --- a/tests/rustdoc-json/trait_alias.rs +++ b/tests/rustdoc-json/trait_alias.rs @@ -1,17 +1,17 @@ #![feature(trait_alias)] -//@ set StrLike = "$.index[*][?(@.name=='StrLike')].id" -//@ is "$.index[*][?(@.name=='StrLike')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='StrLike')].inner.trait_alias" -//@ is "$.index[*][?(@.name=='StrLike')].span.filename" $FILE +//@ set StrLike = "$.index[?(@.name=='StrLike')].id" +//@ is "$.index[?(@.name=='StrLike')].visibility" \"public\" +//@ has "$.index[?(@.name=='StrLike')].inner.trait_alias" +//@ is "$.index[?(@.name=='StrLike')].span.filename" $FILE pub trait StrLike = AsRef; -//@ is "$.index[*][?(@.name=='f')].inner.function.sig.output.impl_trait[0].trait_bound.trait.id" $StrLike +//@ is "$.index[?(@.name=='f')].inner.function.sig.output.impl_trait[0].trait_bound.trait.id" $StrLike pub fn f() -> impl StrLike { "heya" } -//@ !is "$.index[*][?(@.name=='g')].inner.function.sig.output.impl_trait[0].trait_bound.trait.id" $StrLike +//@ !is "$.index[?(@.name=='g')].inner.function.sig.output.impl_trait[0].trait_bound.trait.id" $StrLike pub fn g() -> impl AsRef { "heya" } diff --git a/tests/rustdoc-json/traits/has_body.rs b/tests/rustdoc-json/traits/has_body.rs index 95e0f97b52cc..d17988474f92 100644 --- a/tests/rustdoc-json/traits/has_body.rs +++ b/tests/rustdoc-json/traits/has_body.rs @@ -1,21 +1,21 @@ -//@ has "$.index[*][?(@.name=='Foo')]" +//@ has "$.index[?(@.name=='Foo')]" pub trait Foo { - //@ is "$.index[*][?(@.name=='no_self')].inner.function.has_body" false + //@ is "$.index[?(@.name=='no_self')].inner.function.has_body" false fn no_self(); - //@ is "$.index[*][?(@.name=='move_self')].inner.function.has_body" false + //@ is "$.index[?(@.name=='move_self')].inner.function.has_body" false fn move_self(self); - //@ is "$.index[*][?(@.name=='ref_self')].inner.function.has_body" false + //@ is "$.index[?(@.name=='ref_self')].inner.function.has_body" false fn ref_self(&self); - //@ is "$.index[*][?(@.name=='no_self_def')].inner.function.has_body" true + //@ is "$.index[?(@.name=='no_self_def')].inner.function.has_body" true fn no_self_def() {} - //@ is "$.index[*][?(@.name=='move_self_def')].inner.function.has_body" true + //@ is "$.index[?(@.name=='move_self_def')].inner.function.has_body" true fn move_self_def(self) {} - //@ is "$.index[*][?(@.name=='ref_self_def')].inner.function.has_body" true + //@ is "$.index[?(@.name=='ref_self_def')].inner.function.has_body" true fn ref_self_def(&self) {} } pub trait Bar: Clone { - //@ is "$.index[*][?(@.name=='method')].inner.function.has_body" false + //@ is "$.index[?(@.name=='method')].inner.function.has_body" false fn method(&self, param: usize); } diff --git a/tests/rustdoc-json/traits/implementors.rs b/tests/rustdoc-json/traits/implementors.rs index 9fdb763b61ee..499acefedb77 100644 --- a/tests/rustdoc-json/traits/implementors.rs +++ b/tests/rustdoc-json/traits/implementors.rs @@ -5,14 +5,14 @@ pub struct GeorgeMichael {} impl Wham for GeorgeMichael {} // Find IDs. -//@ set wham = "$.index[*][?(@.name=='Wham')].id" -//@ set gmWham = "$.index[*][?(@.docs=='Wham for George Michael')].id" -//@ set gm = "$.index[*][?(@.name=='GeorgeMichael')].id" +//@ set wham = "$.index[?(@.name=='Wham')].id" +//@ set gmWham = "$.index[?(@.docs=='Wham for George Michael')].id" +//@ set gm = "$.index[?(@.name=='GeorgeMichael')].id" // Both struct and trait point to impl. -//@ has "$.index[*][?(@.name=='GeorgeMichael')].inner.struct.impls[*]" $gmWham -//@ is "$.index[*][?(@.name=='Wham')].inner.trait.implementations[*]" $gmWham +//@ has "$.index[?(@.name=='GeorgeMichael')].inner.struct.impls[*]" $gmWham +//@ is "$.index[?(@.name=='Wham')].inner.trait.implementations[*]" $gmWham // Impl points to both struct and trait. -//@ is "$.index[*][?(@.docs == 'Wham for George Michael')].inner.impl.trait.id" $wham -//@ is "$.index[*][?(@.docs == 'Wham for George Michael')].inner.impl.for.resolved_path.id" $gm +//@ is "$.index[?(@.docs == 'Wham for George Michael')].inner.impl.trait.id" $wham +//@ is "$.index[?(@.docs == 'Wham for George Michael')].inner.impl.for.resolved_path.id" $gm diff --git a/tests/rustdoc-json/traits/is_dyn_compatible.rs b/tests/rustdoc-json/traits/is_dyn_compatible.rs index bccf94d17d60..b172b53807b6 100644 --- a/tests/rustdoc-json/traits/is_dyn_compatible.rs +++ b/tests/rustdoc-json/traits/is_dyn_compatible.rs @@ -1,19 +1,19 @@ #![no_std] -//@ has "$.index[*][?(@.name=='FooDynIncompatible')]" -//@ is "$.index[*][?(@.name=='FooDynIncompatible')].inner.trait.is_dyn_compatible" false +//@ has "$.index[?(@.name=='FooDynIncompatible')]" +//@ is "$.index[?(@.name=='FooDynIncompatible')].inner.trait.is_dyn_compatible" false pub trait FooDynIncompatible { fn foo() -> Self; } -//@ has "$.index[*][?(@.name=='BarDynIncompatible')]" -//@ is "$.index[*][?(@.name=='BarDynIncompatible')].inner.trait.is_dyn_compatible" false +//@ has "$.index[?(@.name=='BarDynIncompatible')]" +//@ is "$.index[?(@.name=='BarDynIncompatible')].inner.trait.is_dyn_compatible" false pub trait BarDynIncompatible { fn foo(i: T); } -//@ has "$.index[*][?(@.name=='FooDynCompatible')]" -//@ is "$.index[*][?(@.name=='FooDynCompatible')].inner.trait.is_dyn_compatible" true +//@ has "$.index[?(@.name=='FooDynCompatible')]" +//@ is "$.index[?(@.name=='FooDynCompatible')].inner.trait.is_dyn_compatible" true pub trait FooDynCompatible { fn foo(&self); } diff --git a/tests/rustdoc-json/traits/private_supertrait.rs b/tests/rustdoc-json/traits/private_supertrait.rs index ce0642278e08..1e11abaecdf5 100644 --- a/tests/rustdoc-json/traits/private_supertrait.rs +++ b/tests/rustdoc-json/traits/private_supertrait.rs @@ -1,9 +1,9 @@ -//@ !has "$.index[*][?(@.name == 'sealed')]" +//@ !has "$.index[?(@.name == 'sealed')]" mod sealed { - //@ set sealed_id = "$.index[*][?(@.name=='Sealed')].id" + //@ set sealed_id = "$.index[?(@.name=='Sealed')].id" pub trait Sealed {} } -//@ count "$.index[*][?(@.name=='Trait')].inner.trait.bounds[*]" 1 -//@ is "$.index[*][?(@.name=='Trait')].inner.trait.bounds[0].trait_bound.trait.id" $sealed_id +//@ count "$.index[?(@.name=='Trait')].inner.trait.bounds[*]" 1 +//@ is "$.index[?(@.name=='Trait')].inner.trait.bounds[0].trait_bound.trait.id" $sealed_id pub trait Trait: sealed::Sealed {} diff --git a/tests/rustdoc-json/traits/self.rs b/tests/rustdoc-json/traits/self.rs index efd9efd556fa..018bda9cc3c5 100644 --- a/tests/rustdoc-json/traits/self.rs +++ b/tests/rustdoc-json/traits/self.rs @@ -7,29 +7,29 @@ pub struct Foo; // Each assertion matches 3 times, and should be the same each time. impl Foo { - //@ ismany '$.index[*][?(@.name=="by_ref")].inner.function.sig.inputs[0][0]' '"self"' '"self"' '"self"' - //@ ismany '$.index[*][?(@.name=="by_ref")].inner.function.sig.inputs[0][1].borrowed_ref.type.generic' '"Self"' '"Self"' '"Self"' - //@ ismany '$.index[*][?(@.name=="by_ref")].inner.function.sig.inputs[0][1].borrowed_ref.lifetime' null null null - //@ ismany '$.index[*][?(@.name=="by_ref")].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable' false false false + //@ ismany '$.index[?(@.name=="by_ref")].inner.function.sig.inputs[0][0]' '"self"' '"self"' '"self"' + //@ ismany '$.index[?(@.name=="by_ref")].inner.function.sig.inputs[0][1].borrowed_ref.type.generic' '"Self"' '"Self"' '"Self"' + //@ ismany '$.index[?(@.name=="by_ref")].inner.function.sig.inputs[0][1].borrowed_ref.lifetime' null null null + //@ ismany '$.index[?(@.name=="by_ref")].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable' false false false pub fn by_ref(&self) {} - //@ ismany '$.index[*][?(@.name=="by_exclusive_ref")].inner.function.sig.inputs[0][0]' '"self"' '"self"' '"self"' - //@ ismany '$.index[*][?(@.name=="by_exclusive_ref")].inner.function.sig.inputs[0][1].borrowed_ref.type.generic' '"Self"' '"Self"' '"Self"' - //@ ismany '$.index[*][?(@.name=="by_exclusive_ref")].inner.function.sig.inputs[0][1].borrowed_ref.lifetime' null null null - //@ ismany '$.index[*][?(@.name=="by_exclusive_ref")].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable' true true true + //@ ismany '$.index[?(@.name=="by_exclusive_ref")].inner.function.sig.inputs[0][0]' '"self"' '"self"' '"self"' + //@ ismany '$.index[?(@.name=="by_exclusive_ref")].inner.function.sig.inputs[0][1].borrowed_ref.type.generic' '"Self"' '"Self"' '"Self"' + //@ ismany '$.index[?(@.name=="by_exclusive_ref")].inner.function.sig.inputs[0][1].borrowed_ref.lifetime' null null null + //@ ismany '$.index[?(@.name=="by_exclusive_ref")].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable' true true true pub fn by_exclusive_ref(&mut self) {} - //@ ismany '$.index[*][?(@.name=="by_value")].inner.function.sig.inputs[0][0]' '"self"' '"self"' '"self"' - //@ ismany '$.index[*][?(@.name=="by_value")].inner.function.sig.inputs[0][1].generic' '"Self"' '"Self"' '"Self"' + //@ ismany '$.index[?(@.name=="by_value")].inner.function.sig.inputs[0][0]' '"self"' '"self"' '"self"' + //@ ismany '$.index[?(@.name=="by_value")].inner.function.sig.inputs[0][1].generic' '"Self"' '"Self"' '"Self"' pub fn by_value(self) {} - //@ ismany '$.index[*][?(@.name=="with_lifetime")].inner.function.sig.inputs[0][0]' '"self"' '"self"' '"self"' - //@ ismany '$.index[*][?(@.name=="with_lifetime")].inner.function.sig.inputs[0][1].borrowed_ref.type.generic' '"Self"' '"Self"' '"Self"' - //@ ismany '$.index[*][?(@.name=="with_lifetime")].inner.function.sig.inputs[0][1].borrowed_ref.lifetime' \"\'a\" \"\'a\" \"\'a\" - //@ ismany '$.index[*][?(@.name=="with_lifetime")].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable' false false false + //@ ismany '$.index[?(@.name=="with_lifetime")].inner.function.sig.inputs[0][0]' '"self"' '"self"' '"self"' + //@ ismany '$.index[?(@.name=="with_lifetime")].inner.function.sig.inputs[0][1].borrowed_ref.type.generic' '"Self"' '"Self"' '"Self"' + //@ ismany '$.index[?(@.name=="with_lifetime")].inner.function.sig.inputs[0][1].borrowed_ref.lifetime' \"\'a\" \"\'a\" \"\'a\" + //@ ismany '$.index[?(@.name=="with_lifetime")].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable' false false false pub fn with_lifetime<'a>(&'a self) {} - //@ ismany '$.index[*][?(@.name=="build")].inner.function.sig.output.generic' '"Self"' '"Self"' '"Self"' + //@ ismany '$.index[?(@.name=="build")].inner.function.sig.output.generic' '"Self"' '"Self"' '"Self"' pub fn build() -> Self { Self } diff --git a/tests/rustdoc-json/traits/supertrait.rs b/tests/rustdoc-json/traits/supertrait.rs index 4b6199d4b26f..3accb0ff8581 100644 --- a/tests/rustdoc-json/traits/supertrait.rs +++ b/tests/rustdoc-json/traits/supertrait.rs @@ -1,20 +1,20 @@ -//@ set loud_id = "$.index[*][?(@.name=='Loud')].id" +//@ set loud_id = "$.index[?(@.name=='Loud')].id" pub trait Loud {} -//@ set very_loud_id = "$.index[*][?(@.name=='VeryLoud')].id" -//@ count "$.index[*][?(@.name=='VeryLoud')].inner.trait.bounds[*]" 1 -//@ is "$.index[*][?(@.name=='VeryLoud')].inner.trait.bounds[0].trait_bound.trait.id" $loud_id +//@ set very_loud_id = "$.index[?(@.name=='VeryLoud')].id" +//@ count "$.index[?(@.name=='VeryLoud')].inner.trait.bounds[*]" 1 +//@ is "$.index[?(@.name=='VeryLoud')].inner.trait.bounds[0].trait_bound.trait.id" $loud_id pub trait VeryLoud: Loud {} -//@ set sounds_good_id = "$.index[*][?(@.name=='SoundsGood')].id" +//@ set sounds_good_id = "$.index[?(@.name=='SoundsGood')].id" pub trait SoundsGood {} -//@ count "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[*]" 2 -//@ is "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[0].trait_bound.trait.id" $very_loud_id -//@ is "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[1].trait_bound.trait.id" $sounds_good_id +//@ count "$.index[?(@.name=='MetalBand')].inner.trait.bounds[*]" 2 +//@ is "$.index[?(@.name=='MetalBand')].inner.trait.bounds[0].trait_bound.trait.id" $very_loud_id +//@ is "$.index[?(@.name=='MetalBand')].inner.trait.bounds[1].trait_bound.trait.id" $sounds_good_id pub trait MetalBand: VeryLoud + SoundsGood {} -//@ count "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[*]" 2 -//@ is "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[1].trait_bound.trait.id" $very_loud_id -//@ is "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[0].trait_bound.trait.id" $sounds_good_id +//@ count "$.index[?(@.name=='DnabLatem')].inner.trait.bounds[*]" 2 +//@ is "$.index[?(@.name=='DnabLatem')].inner.trait.bounds[1].trait_bound.trait.id" $very_loud_id +//@ is "$.index[?(@.name=='DnabLatem')].inner.trait.bounds[0].trait_bound.trait.id" $sounds_good_id pub trait DnabLatem: SoundsGood + VeryLoud {} diff --git a/tests/rustdoc-json/traits/trait_alias.rs b/tests/rustdoc-json/traits/trait_alias.rs index 137b8947e239..497930a67c83 100644 --- a/tests/rustdoc-json/traits/trait_alias.rs +++ b/tests/rustdoc-json/traits/trait_alias.rs @@ -2,25 +2,25 @@ #![feature(trait_alias)] -//@ set Orig = "$.index[*][?(@.name == 'Orig')].id" -//@ has "$.index[*][?(@.name == 'Orig')].inner.trait" +//@ set Orig = "$.index[?(@.name == 'Orig')].id" +//@ has "$.index[?(@.name == 'Orig')].inner.trait" pub trait Orig {} -//@ set Alias = "$.index[*][?(@.name == 'Alias')].id" -//@ has "$.index[*][?(@.name == 'Alias')].inner.trait_alias" -//@ is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.generics" '{"params": [], "where_predicates": []}' -//@ count "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[*]" 1 -//@ is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.id" $Orig -//@ is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.args.angle_bracketed.args[0].type.primitive" '"i32"' +//@ set Alias = "$.index[?(@.name == 'Alias')].id" +//@ has "$.index[?(@.name == 'Alias')].inner.trait_alias" +//@ is "$.index[?(@.name == 'Alias')].inner.trait_alias.generics" '{"params": [], "where_predicates": []}' +//@ count "$.index[?(@.name == 'Alias')].inner.trait_alias.params[*]" 1 +//@ is "$.index[?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.id" $Orig +//@ is "$.index[?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.args.angle_bracketed.args[0].type.primitive" '"i32"' pub trait Alias = Orig; pub struct Struct; impl Orig for Struct {} -//@ has "$.index[*][?(@.name=='takes_alias')].inner.function.sig.inputs[0][1].impl_trait" -//@ is "$.index[*][?(@.name=='takes_alias')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.id" $Alias -//@ is "$.index[*][?(@.name=='takes_alias')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $Alias +//@ has "$.index[?(@.name=='takes_alias')].inner.function.sig.inputs[0][1].impl_trait" +//@ is "$.index[?(@.name=='takes_alias')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.id" $Alias +//@ is "$.index[?(@.name=='takes_alias')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $Alias pub fn takes_alias(_: impl Alias) {} // FIXME: Should the trait be mentioned in both the decl and generics? diff --git a/tests/rustdoc-json/traits/uses_extern_trait.rs b/tests/rustdoc-json/traits/uses_extern_trait.rs index 3a93bcaefd4b..52983527f08c 100644 --- a/tests/rustdoc-json/traits/uses_extern_trait.rs +++ b/tests/rustdoc-json/traits/uses_extern_trait.rs @@ -1,5 +1,5 @@ #![no_std] pub fn drop_default(_x: T) {} -//@ !has "$.index[*][?(@.name=='Debug')]" -//@ !has "$.index[*][?(@.name=='Default')]" +//@ !has "$.index[?(@.name=='Debug')]" +//@ !has "$.index[?(@.name=='Default')]" diff --git a/tests/rustdoc-json/type/dyn.rs b/tests/rustdoc-json/type/dyn.rs index d8686d4e2fb1..4e533a67f8b4 100644 --- a/tests/rustdoc-json/type/dyn.rs +++ b/tests/rustdoc-json/type/dyn.rs @@ -1,45 +1,45 @@ use std::fmt::Debug; -//@ count "$.index[*][?(@.name=='dyn')].inner.module.items[*]" 3 -//@ set sync_int_gen = "$.index[*][?(@.name=='SyncIntGen')].id" -//@ set ref_fn = "$.index[*][?(@.name=='RefFn')].id" -//@ set weird_order = "$.index[*][?(@.name=='WeirdOrder')].id" -//@ ismany "$.index[*][?(@.name=='dyn')].inner.module.items[*]" $sync_int_gen $ref_fn $weird_order +//@ count "$.index[?(@.name=='dyn')].inner.module.items[*]" 3 +//@ set sync_int_gen = "$.index[?(@.name=='SyncIntGen')].id" +//@ set ref_fn = "$.index[?(@.name=='RefFn')].id" +//@ set weird_order = "$.index[?(@.name=='WeirdOrder')].id" +//@ ismany "$.index[?(@.name=='dyn')].inner.module.items[*]" $sync_int_gen $ref_fn $weird_order -//@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias" -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.generics" '{"params": [], "where_predicates": []}' -//@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path" -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.path" \"Box\" -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.constraints" [] -//@ count "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args" 1 -//@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait" -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.lifetime" \"\'static\" -//@ count "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[*]" 3 -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].generic_params" [] -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].generic_params" [] -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].generic_params" [] -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.path" '"Fn"' -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.path" '"Send"' -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.path" '"Sync"' -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.args" '{"parenthesized": {"inputs": [],"output": {"primitive": "i32"}}}' +//@ has "$.index[?(@.name=='SyncIntGen')].inner.type_alias" +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.generics" '{"params": [], "where_predicates": []}' +//@ has "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path" +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.path" \"Box\" +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.constraints" [] +//@ count "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args" 1 +//@ has "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait" +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.lifetime" \"\'static\" +//@ count "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[*]" 3 +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].generic_params" [] +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].generic_params" [] +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].generic_params" [] +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.path" '"Fn"' +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.path" '"Send"' +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.path" '"Sync"' +//@ is "$.index[?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.args" '{"parenthesized": {"inputs": [],"output": {"primitive": "i32"}}}' pub type SyncIntGen = Box i32 + Send + Sync + 'static>; -//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias" -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}' -//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref" -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.is_mutable" 'false' -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.lifetime" "\"'a\"" -//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait" -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.lifetime" null -//@ count "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[*]" 1 -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.path" '"Fn"' -//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref" -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref.lifetime" "\"'b\"" -//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref" -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref.lifetime" "\"'b\"" +//@ has "$.index[?(@.name=='RefFn')].inner.type_alias" +//@ is "$.index[?(@.name=='RefFn')].inner.type_alias.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}' +//@ has "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref" +//@ is "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.is_mutable" 'false' +//@ is "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.lifetime" "\"'a\"" +//@ has "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait" +//@ is "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.lifetime" null +//@ count "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[*]" 1 +//@ is "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +//@ is "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.path" '"Fn"' +//@ has "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref" +//@ is "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref.lifetime" "\"'b\"" +//@ has "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref" +//@ is "$.index[?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref.lifetime" "\"'b\"" pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32; -//@ is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.path" '"Send"' -//@ is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.path" '"Debug"' +//@ is "$.index[?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.path" '"Send"' +//@ is "$.index[?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.path" '"Debug"' pub type WeirdOrder = Box; diff --git a/tests/rustdoc-json/type/extern.rs b/tests/rustdoc-json/type/extern.rs index 97e1c3760ee5..7963690e4484 100644 --- a/tests/rustdoc-json/type/extern.rs +++ b/tests/rustdoc-json/type/extern.rs @@ -5,5 +5,5 @@ extern "C" { pub type Foo; } -//@ is "$.index[*][?(@.docs=='No inner information')].name" '"Foo"' -//@ is "$.index[*][?(@.docs=='No inner information')].inner" \"extern_type\" +//@ is "$.index[?(@.docs=='No inner information')].name" '"Foo"' +//@ is "$.index[?(@.docs=='No inner information')].inner" \"extern_type\" diff --git a/tests/rustdoc-json/type/fn_lifetime.rs b/tests/rustdoc-json/type/fn_lifetime.rs index aaa716bf11fd..10e95cc5e562 100644 --- a/tests/rustdoc-json/type/fn_lifetime.rs +++ b/tests/rustdoc-json/type/fn_lifetime.rs @@ -1,24 +1,24 @@ -//@ has "$.index[*][?(@.name=='GenericFn')].inner.type_alias" +//@ has "$.index[?(@.name=='GenericFn')].inner.type_alias" -//@ ismany "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].name" \"\'a\" -//@ has "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].kind.lifetime" -//@ count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].kind.lifetime.outlives[*]" 0 -//@ count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.where_predicates[*]" 0 -//@ count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.generic_params[*]" 0 -//@ count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.sig.inputs[*]" 1 -//@ is "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.sig.inputs[*][1].borrowed_ref.lifetime" \"\'a\" -//@ is "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.sig.output.borrowed_ref.lifetime" \"\'a\" +//@ ismany "$.index[?(@.name=='GenericFn')].inner.type_alias.generics.params[*].name" \"\'a\" +//@ has "$.index[?(@.name=='GenericFn')].inner.type_alias.generics.params[*].kind.lifetime" +//@ count "$.index[?(@.name=='GenericFn')].inner.type_alias.generics.params[*].kind.lifetime.outlives[*]" 0 +//@ count "$.index[?(@.name=='GenericFn')].inner.type_alias.generics.where_predicates[*]" 0 +//@ count "$.index[?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.generic_params[*]" 0 +//@ count "$.index[?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.sig.inputs[*]" 1 +//@ is "$.index[?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.sig.inputs[*][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.sig.output.borrowed_ref.lifetime" \"\'a\" pub type GenericFn<'a> = fn(&'a i32) -> &'a i32; -//@ has "$.index[*][?(@.name=='ForAll')].inner.type_alias" -//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.generics.params[*]" 0 -//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.generics.where_predicates[*]" 0 -//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*]" 1 -//@ is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].name" \"\'a\" -//@ has "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].kind.lifetime" -//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].kind.lifetime.outlives[*]" 0 -//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.sig.inputs[*]" 1 -//@ is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.sig.inputs[*][1].borrowed_ref.lifetime" \"\'a\" -//@ is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.sig.output.borrowed_ref.lifetime" \"\'a\" +//@ has "$.index[?(@.name=='ForAll')].inner.type_alias" +//@ count "$.index[?(@.name=='ForAll')].inner.type_alias.generics.params[*]" 0 +//@ count "$.index[?(@.name=='ForAll')].inner.type_alias.generics.where_predicates[*]" 0 +//@ count "$.index[?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*]" 1 +//@ is "$.index[?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].name" \"\'a\" +//@ has "$.index[?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].kind.lifetime" +//@ count "$.index[?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].kind.lifetime.outlives[*]" 0 +//@ count "$.index[?(@.name=='ForAll')].inner.type_alias.type.function_pointer.sig.inputs[*]" 1 +//@ is "$.index[?(@.name=='ForAll')].inner.type_alias.type.function_pointer.sig.inputs[*][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[?(@.name=='ForAll')].inner.type_alias.type.function_pointer.sig.output.borrowed_ref.lifetime" \"\'a\" pub type ForAll = for<'a> fn(&'a i32) -> &'a i32; diff --git a/tests/rustdoc-json/type/generic_default.rs b/tests/rustdoc-json/type/generic_default.rs index 2d2ce9cd1033..26a232a1562b 100644 --- a/tests/rustdoc-json/type/generic_default.rs +++ b/tests/rustdoc-json/type/generic_default.rs @@ -1,31 +1,31 @@ -//@ set result = "$.index[*][?(@.name=='Result')].id" +//@ set result = "$.index[?(@.name=='Result')].id" pub enum Result { Ok(T), Err(E), } -//@ set my_error = "$.index[*][?(@.name=='MyError')].id" +//@ set my_error = "$.index[?(@.name=='MyError')].id" pub struct MyError {} -//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias" -//@ count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.where_predicates[*]" 0 -//@ count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[*]" 2 -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].name" \"T\" -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].name" \"E\" -//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type" -//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type" -//@ count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.bounds[*]" 0 -//@ count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.bounds[*]" 0 -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.default" null -//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path" -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.id" $my_error -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.path" \"MyError\" -//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path" -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.id" $result -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.path" \"Result\" -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.constraints" [] -//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" -//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" \"T\" -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" \"E\" +//@ has "$.index[?(@.name=='MyResult')].inner.type_alias" +//@ count "$.index[?(@.name=='MyResult')].inner.type_alias.generics.where_predicates[*]" 0 +//@ count "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[*]" 2 +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[0].name" \"T\" +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[1].name" \"E\" +//@ has "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type" +//@ has "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type" +//@ count "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.bounds[*]" 0 +//@ count "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.bounds[*]" 0 +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.default" null +//@ has "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path" +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.id" $my_error +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.path" \"MyError\" +//@ has "$.index[?(@.name=='MyResult')].inner.type_alias.type.resolved_path" +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.type.resolved_path.id" $result +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.type.resolved_path.path" \"Result\" +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.constraints" [] +//@ has "$.index[?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" +//@ has "$.index[?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" \"T\" +//@ is "$.index[?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" \"E\" pub type MyResult = Result; diff --git a/tests/rustdoc-json/type/hrtb.rs b/tests/rustdoc-json/type/hrtb.rs index 08b35b90a2b1..68b7a556a69a 100644 --- a/tests/rustdoc-json/type/hrtb.rs +++ b/tests/rustdoc-json/type/hrtb.rs @@ -1,5 +1,5 @@ -//@ is "$.index[*][?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.type" '{"generic": "F"}' -//@ is "$.index[*][?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +//@ is "$.index[?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.type" '{"generic": "F"}' +//@ is "$.index[?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' pub fn genfn(f: F) where for<'a, 'b> F: Fn(&'a i32, &'b i32), @@ -8,12 +8,12 @@ where f(&zero, &zero); } -//@ is "$.index[*][?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' -//@ is "$.index[*][?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' -//@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.lifetime" null -//@ count "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[*]" 1 -//@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' -//@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.path" '"Fn"' +//@ is "$.index[?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' +//@ is "$.index[?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' +//@ is "$.index[?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.lifetime" null +//@ count "$.index[?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[*]" 1 +//@ is "$.index[?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +//@ is "$.index[?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.path" '"Fn"' pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) { let zero = 0; f(&zero, &zero); diff --git a/tests/rustdoc-json/type/inherent_associated_type.rs b/tests/rustdoc-json/type/inherent_associated_type.rs index e26f8f7c651b..e96a92f7cfb4 100644 --- a/tests/rustdoc-json/type/inherent_associated_type.rs +++ b/tests/rustdoc-json/type/inherent_associated_type.rs @@ -1,23 +1,23 @@ #![feature(inherent_associated_types)] #![allow(incomplete_features)] -//@ set OwnerMetadata = '$.index[*][?(@.name=="OwnerMetadata")].id' +//@ set OwnerMetadata = '$.index[?(@.name=="OwnerMetadata")].id' pub struct OwnerMetadata; -//@ set Owner = '$.index[*][?(@.name=="Owner")].id' +//@ set Owner = '$.index[?(@.name=="Owner")].id' pub struct Owner; pub fn create() -> Owner::Metadata { OwnerMetadata } -//@ is '$.index[*][?(@.name=="create")].inner.function.sig.output.qualified_path.name' '"Metadata"' -//@ is '$.index[*][?(@.name=="create")].inner.function.sig.output.qualified_path.trait' null -//@ is '$.index[*][?(@.name=="create")].inner.function.sig.output.qualified_path.self_type.resolved_path.id' $Owner +//@ is '$.index[?(@.name=="create")].inner.function.sig.output.qualified_path.name' '"Metadata"' +//@ is '$.index[?(@.name=="create")].inner.function.sig.output.qualified_path.trait' null +//@ is '$.index[?(@.name=="create")].inner.function.sig.output.qualified_path.self_type.resolved_path.id' $Owner /// impl impl Owner { /// iat pub type Metadata = OwnerMetadata; } -//@ set iat = '$.index[*][?(@.docs=="iat")].id' -//@ is '$.index[*][?(@.docs=="impl")].inner.impl.items[*]' $iat -//@ is '$.index[*][?(@.docs=="iat")].inner.assoc_type.type.resolved_path.id' $OwnerMetadata +//@ set iat = '$.index[?(@.docs=="iat")].id' +//@ is '$.index[?(@.docs=="impl")].inner.impl.items[*]' $iat +//@ is '$.index[?(@.docs=="iat")].inner.assoc_type.type.resolved_path.id' $OwnerMetadata diff --git a/tests/rustdoc-json/type/inherent_associated_type_bound.rs b/tests/rustdoc-json/type/inherent_associated_type_bound.rs index 22c9c9c1149a..20354909f8ec 100644 --- a/tests/rustdoc-json/type/inherent_associated_type_bound.rs +++ b/tests/rustdoc-json/type/inherent_associated_type_bound.rs @@ -1,17 +1,17 @@ #![feature(inherent_associated_types)] #![allow(incomplete_features)] -//@ set Carrier = '$.index[*][?(@.name=="Carrier")].id' +//@ set Carrier = '$.index[?(@.name=="Carrier")].id' pub struct Carrier<'a>(&'a ()); -//@ count "$.index[*][?(@.name=='user')].inner.function.sig.inputs[*]" 1 -//@ is "$.index[*][?(@.name=='user')].inner.function.sig.inputs[0][0]" '"_"' -//@ is '$.index[*][?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\" -//@ is '$.index[*][?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier -//@ is '$.index[*][?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\" -//@ is '$.index[*][?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.name' '"Focus"' -//@ is '$.index[*][?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.trait' null -//@ is '$.index[*][?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"' +//@ count "$.index[?(@.name=='user')].inner.function.sig.inputs[*]" 1 +//@ is "$.index[?(@.name=='user')].inner.function.sig.inputs[0][0]" '"_"' +//@ is '$.index[?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\" +//@ is '$.index[?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier +//@ is '$.index[?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\" +//@ is '$.index[?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.name' '"Focus"' +//@ is '$.index[?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.trait' null +//@ is '$.index[?(@.name=="user")].inner.function.sig.inputs[0][1].function_pointer.sig.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"' pub fn user(_: for<'b> fn(Carrier<'b>::Focus)) {} impl<'a> Carrier<'a> { diff --git a/tests/rustdoc-json/type/inherent_associated_type_projections.rs b/tests/rustdoc-json/type/inherent_associated_type_projections.rs index 501694dce8b6..934daba11bb1 100644 --- a/tests/rustdoc-json/type/inherent_associated_type_projections.rs +++ b/tests/rustdoc-json/type/inherent_associated_type_projections.rs @@ -1,15 +1,15 @@ #![feature(inherent_associated_types)] #![allow(incomplete_features)] -//@ set Parametrized = '$.index[*][?(@.name=="Parametrized")].id' +//@ set Parametrized = '$.index[?(@.name=="Parametrized")].id' pub struct Parametrized(T); -//@ count "$.index[*][?(@.name=='test')].inner.function.sig.inputs[*]" 1 -//@ is "$.index[*][?(@.name=='test')].inner.function.sig.inputs[0][0]" '"_"' -//@ is '$.index[*][?(@.name=="test")].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.id' $Parametrized -//@ is '$.index[*][?(@.name=="test")].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\" -//@ is '$.index[*][?(@.name=="test")].inner.function.sig.inputs[0][1].qualified_path.name' '"Proj"' -//@ is '$.index[*][?(@.name=="test")].inner.function.sig.inputs[0][1].qualified_path.trait' null +//@ count "$.index[?(@.name=='test')].inner.function.sig.inputs[*]" 1 +//@ is "$.index[?(@.name=='test')].inner.function.sig.inputs[0][0]" '"_"' +//@ is '$.index[?(@.name=="test")].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.id' $Parametrized +//@ is '$.index[?(@.name=="test")].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\" +//@ is '$.index[?(@.name=="test")].inner.function.sig.inputs[0][1].qualified_path.name' '"Proj"' +//@ is '$.index[?(@.name=="test")].inner.function.sig.inputs[0][1].qualified_path.trait' null pub fn test(_: Parametrized::Proj) {} /// param_bool @@ -24,10 +24,10 @@ impl Parametrized { pub type Proj = String; } -//@ set param_bool = '$.index[*][?(@.docs=="param_bool")].id' -//@ set param_i32 = '$.index[*][?(@.docs=="param_i32")].id' -//@ set param_bool_proj = '$.index[*][?(@.docs=="param_bool_proj")].id' -//@ set param_i32_proj = '$.index[*][?(@.docs=="param_i32_proj")].id' +//@ set param_bool = '$.index[?(@.docs=="param_bool")].id' +//@ set param_i32 = '$.index[?(@.docs=="param_i32")].id' +//@ set param_bool_proj = '$.index[?(@.docs=="param_bool_proj")].id' +//@ set param_i32_proj = '$.index[?(@.docs=="param_i32_proj")].id' -//@ is '$.index[*][?(@.docs=="param_bool")].inner.impl.items[*]' $param_bool_proj -//@ is '$.index[*][?(@.docs=="param_i32")].inner.impl.items[*]' $param_i32_proj +//@ is '$.index[?(@.docs=="param_bool")].inner.impl.items[*]' $param_bool_proj +//@ is '$.index[?(@.docs=="param_i32")].inner.impl.items[*]' $param_i32_proj diff --git a/tests/rustdoc-json/type_alias.rs b/tests/rustdoc-json/type_alias.rs index 2f2b4c42d441..7fd23a48040d 100644 --- a/tests/rustdoc-json/type_alias.rs +++ b/tests/rustdoc-json/type_alias.rs @@ -1,15 +1,15 @@ -//@ set IntVec = "$.index[*][?(@.name=='IntVec')].id" -//@ is "$.index[*][?(@.name=='IntVec')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='IntVec')].inner.type_alias" -//@ is "$.index[*][?(@.name=='IntVec')].span.filename" $FILE +//@ set IntVec = "$.index[?(@.name=='IntVec')].id" +//@ is "$.index[?(@.name=='IntVec')].visibility" \"public\" +//@ has "$.index[?(@.name=='IntVec')].inner.type_alias" +//@ is "$.index[?(@.name=='IntVec')].span.filename" $FILE pub type IntVec = Vec; -//@ is "$.index[*][?(@.name=='f')].inner.function.sig.output.resolved_path.id" $IntVec +//@ is "$.index[?(@.name=='f')].inner.function.sig.output.resolved_path.id" $IntVec pub fn f() -> IntVec { vec![0; 32] } -//@ !is "$.index[*][?(@.name=='g')].inner.function.sig.output.resolved_path.id" $IntVec +//@ !is "$.index[?(@.name=='g')].inner.function.sig.output.resolved_path.id" $IntVec pub fn g() -> Vec { vec![0; 32] } diff --git a/tests/rustdoc-json/unions/field_order.rs b/tests/rustdoc-json/unions/field_order.rs index a1616f627513..b3a07a13bc81 100644 --- a/tests/rustdoc-json/unions/field_order.rs +++ b/tests/rustdoc-json/unions/field_order.rs @@ -15,24 +15,24 @@ pub union Foo { pub vll_9: i32, } -//@ set 0 = '$.index[*][?(@.name == "ews_0")].id' -//@ set 1 = '$.index[*][?(@.name == "dik_1")].id' -//@ set 2 = '$.index[*][?(@.name == "hsk_2")].id' -//@ set 3 = '$.index[*][?(@.name == "djt_3")].id' -//@ set 4 = '$.index[*][?(@.name == "jnr_4")].id' -//@ set 5 = '$.index[*][?(@.name == "dfs_5")].id' -//@ set 6 = '$.index[*][?(@.name == "bja_6")].id' -//@ set 7 = '$.index[*][?(@.name == "lyc_7")].id' -//@ set 8 = '$.index[*][?(@.name == "yqd_8")].id' -//@ set 9 = '$.index[*][?(@.name == "vll_9")].id' +//@ set 0 = '$.index[?(@.name == "ews_0")].id' +//@ set 1 = '$.index[?(@.name == "dik_1")].id' +//@ set 2 = '$.index[?(@.name == "hsk_2")].id' +//@ set 3 = '$.index[?(@.name == "djt_3")].id' +//@ set 4 = '$.index[?(@.name == "jnr_4")].id' +//@ set 5 = '$.index[?(@.name == "dfs_5")].id' +//@ set 6 = '$.index[?(@.name == "bja_6")].id' +//@ set 7 = '$.index[?(@.name == "lyc_7")].id' +//@ set 8 = '$.index[?(@.name == "yqd_8")].id' +//@ set 9 = '$.index[?(@.name == "vll_9")].id' -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[0]' $0 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[1]' $1 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[2]' $2 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[3]' $3 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[4]' $4 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[5]' $5 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[6]' $6 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[7]' $7 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[8]' $8 -//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[9]' $9 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[0]' $0 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[1]' $1 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[2]' $2 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[3]' $3 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[4]' $4 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[5]' $5 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[6]' $6 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[7]' $7 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[8]' $8 +//@ is '$.index[?(@.name == "Foo")].inner.union.fields[9]' $9 diff --git a/tests/rustdoc-json/unions/impl.rs b/tests/rustdoc-json/unions/impl.rs index 989a025f6690..6f398cc23f68 100644 --- a/tests/rustdoc-json/unions/impl.rs +++ b/tests/rustdoc-json/unions/impl.rs @@ -1,15 +1,15 @@ #![no_std] -//@ is "$.index[*][?(@.name=='Ux')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='Ux')].inner.union" +//@ is "$.index[?(@.name=='Ux')].visibility" \"public\" +//@ has "$.index[?(@.name=='Ux')].inner.union" pub union Ux { a: u32, b: u64, } -//@ is "$.index[*][?(@.name=='Num')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='Num')].inner.trait" +//@ is "$.index[?(@.name=='Num')].visibility" \"public\" +//@ has "$.index[?(@.name=='Num')].inner.trait" pub trait Num {} -//@ count "$.index[*][?(@.name=='Ux')].inner.union.impls" 1 +//@ count "$.index[?(@.name=='Ux')].inner.union.impls" 1 impl Num for Ux {} diff --git a/tests/rustdoc-json/unions/union.rs b/tests/rustdoc-json/unions/union.rs index 7f135a72dec6..24ee47f19573 100644 --- a/tests/rustdoc-json/unions/union.rs +++ b/tests/rustdoc-json/unions/union.rs @@ -1,14 +1,14 @@ -//@ has "$.index[*][?(@.name=='Union')].visibility" \"public\" -//@ has "$.index[*][?(@.name=='Union')].inner.union" -//@ !has "$.index[*][?(@.name=='Union')].inner.union.struct_type" -//@ set Union = "$.index[*][?(@.name=='Union')].id" +//@ has "$.index[?(@.name=='Union')].visibility" \"public\" +//@ has "$.index[?(@.name=='Union')].inner.union" +//@ !has "$.index[?(@.name=='Union')].inner.union.struct_type" +//@ set Union = "$.index[?(@.name=='Union')].id" pub union Union { int: i32, float: f32, } -//@ has "$.index[*][?(@.name=='make_int_union')].inner.function.sig.output.resolved_path" -//@ is "$.index[*][?(@.name=='make_int_union')].inner.function.sig.output.resolved_path.id" $Union +//@ has "$.index[?(@.name=='make_int_union')].inner.function.sig.output.resolved_path" +//@ is "$.index[?(@.name=='make_int_union')].inner.function.sig.output.resolved_path.id" $Union pub fn make_int_union(int: i32) -> Union { Union { int } } From 42631d80272a27957dcbcb6cb56327038aaa9784 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Thu, 20 Mar 2025 23:02:39 +0000 Subject: [PATCH 164/546] tests/rustdoc-json: replace `$.paths[*][?` with `$.paths[?` This fixes all 3 of these tests. Done automatically in VSCode. --- tests/rustdoc-json/path_name.rs | 2 +- tests/rustdoc-json/reexport/simple_private.rs | 4 ++-- tests/rustdoc-json/reexport/simple_public.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/rustdoc-json/path_name.rs b/tests/rustdoc-json/path_name.rs index 116b2bee5086..dcfaa0607c4c 100644 --- a/tests/rustdoc-json/path_name.rs +++ b/tests/rustdoc-json/path_name.rs @@ -38,7 +38,7 @@ pub type U2 = InPubMod2; pub type U3 = InPubMod3; // Check we only have paths for structs at their original path -//@ ismany "$.paths[*][?(@.crate_id==0 && @.kind=='struct')].path" '["path_name", "priv_mod", "InPrivMod"]' '["path_name", "pub_mod", "InPubMod"]' +//@ ismany "$.paths[?(@.crate_id==0 && @.kind=='struct')].path" '["path_name", "priv_mod", "InPrivMod"]' '["path_name", "pub_mod", "InPubMod"]' pub use defines_and_reexports::{InPrivMod as XPrivMod, InPubMod as XPubMod}; use defines_and_reexports::{InPrivMod as XPrivMod2, InPubMod as XPubMod2}; diff --git a/tests/rustdoc-json/reexport/simple_private.rs b/tests/rustdoc-json/reexport/simple_private.rs index 85da90cf48c4..40be1708dc69 100644 --- a/tests/rustdoc-json/reexport/simple_private.rs +++ b/tests/rustdoc-json/reexport/simple_private.rs @@ -14,7 +14,7 @@ pub use inner::Public; //@ ismany "$.index[?(@.name=='simple_private')].inner.module.items[*]" $use_id // Test for https://github.com/rust-lang/rust/issues/135309 -//@ has "$.paths[*][?(@.kind=='module')].path" '["simple_private"]' +//@ has "$.paths[?(@.kind=='module')].path" '["simple_private"]' //@ !has "$.paths[*].path" '["simple_private", "inner"]' -//@ has "$.paths[*][?(@.kind=='struct')].path" '["simple_private", "inner", "Public"]' +//@ has "$.paths[?(@.kind=='struct')].path" '["simple_private", "inner", "Public"]' //@ !has "$.paths[*].path" '["simple_private", "Public"]' diff --git a/tests/rustdoc-json/reexport/simple_public.rs b/tests/rustdoc-json/reexport/simple_public.rs index 3dcfe900d735..cdb6c0dc88a3 100644 --- a/tests/rustdoc-json/reexport/simple_public.rs +++ b/tests/rustdoc-json/reexport/simple_public.rs @@ -15,7 +15,7 @@ pub use inner::Public; //@ ismany "$.index[?(@.name=='simple_public')].inner.module.items[*]" $import_id $inner_id -//@ has "$.paths[*][?(@.kind=='module')].path" '["simple_public"]' -//@ has "$.paths[*][?(@.kind=='module')].path" '["simple_public", "inner"]' -//@ has "$.paths[*][?(@.kind=='struct')].path" '["simple_public", "inner", "Public"]' +//@ has "$.paths[?(@.kind=='module')].path" '["simple_public"]' +//@ has "$.paths[?(@.kind=='module')].path" '["simple_public", "inner"]' +//@ has "$.paths[?(@.kind=='struct')].path" '["simple_public", "inner", "Public"]' //@ !has "$.paths[*].path" '["simple_public", "Public"]' From 13335e313c96fecd30e4ec28dececda046b6304b Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 21 Mar 2025 00:16:41 +0000 Subject: [PATCH 165/546] tests/rustdoc-json: change assertions to use RFC 9535 jsonpath --- tests/rustdoc-json/enums/use_variant_foreign.rs | 2 +- tests/rustdoc-json/primitives/use_primitive.rs | 4 ++-- tests/rustdoc-json/reexport/glob_collision.rs | 10 +++++----- tests/rustdoc-json/reexport/in_root_and_mod.rs | 8 ++++---- tests/rustdoc-json/reexport/in_root_and_mod_pub.rs | 4 ++-- tests/rustdoc-json/reexport/mod_not_included.rs | 2 +- tests/rustdoc-json/reexport/reexport_of_hidden.rs | 4 ++-- tests/rustdoc-json/reexport/rename_public.rs | 4 ++-- .../rustdoc-json/reexport/same_name_different_types.rs | 8 ++++---- .../reexport/same_type_reexported_more_than_once.rs | 4 ++-- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/rustdoc-json/enums/use_variant_foreign.rs b/tests/rustdoc-json/enums/use_variant_foreign.rs index 844dd758680c..14e07b4123e6 100644 --- a/tests/rustdoc-json/enums/use_variant_foreign.rs +++ b/tests/rustdoc-json/enums/use_variant_foreign.rs @@ -2,7 +2,7 @@ extern crate color; -//@ has "$.index[*].inner.use[?(@.name == 'Red')]" +//@ has "$.index[?(@.inner.use.name == 'Red')]" pub use color::Color::Red; //@ !has "$.index[?(@.name == 'Red')]" diff --git a/tests/rustdoc-json/primitives/use_primitive.rs b/tests/rustdoc-json/primitives/use_primitive.rs index 9213229c4bb1..2991cc1e47c2 100644 --- a/tests/rustdoc-json/primitives/use_primitive.rs +++ b/tests/rustdoc-json/primitives/use_primitive.rs @@ -13,7 +13,7 @@ mod usize {} //@ !is "$.index[?(@.name=='checked_add')]" $local_crate_id //@ !has "$.index[?(@.name=='is_ascii_uppercase')]" -//@ is "$.index[*].inner.use[?(@.name=='my_i32')].id" null +//@ is "$.index[?(@.inner.use.name=='my_i32')].inner.use.id" null pub use i32 as my_i32; -//@ is "$.index[*].inner.use[?(@.name=='u32')].id" null +//@ is "$.index[?(@.inner.use.name=='u32')].inner.use.id" null pub use u32; diff --git a/tests/rustdoc-json/reexport/glob_collision.rs b/tests/rustdoc-json/reexport/glob_collision.rs index b077bc1e47c1..48de1b5e7721 100644 --- a/tests/rustdoc-json/reexport/glob_collision.rs +++ b/tests/rustdoc-json/reexport/glob_collision.rs @@ -14,14 +14,14 @@ mod m2 { } //@ set m1_use = "$.index[?(@.docs=='m1 re-export')].id" -//@ is "$.index[*].inner.use[?(@.name=='m1')].id" $m1 -//@ is "$.index[*].inner.use[?(@.name=='m1')].is_glob" true +//@ is "$.index[?(@.inner.use.name=='m1')].inner.use.id" $m1 +//@ is "$.index[?(@.inner.use.name=='m1')].inner.use.is_glob" true /// m1 re-export pub use m1::*; //@ set m2_use = "$.index[?(@.docs=='m2 re-export')].id" -//@ is "$.index[*].inner.use[?(@.name=='m2')].id" $m2 -//@ is "$.index[*].inner.use[?(@.name=='m2')].is_glob" true +//@ is "$.index[?(@.inner.use.name=='m2')].inner.use.id" $m2 +//@ is "$.index[?(@.inner.use.name=='m2')].inner.use.is_glob" true /// m2 re-export pub use m2::*; -//@ ismany "$.index[*].inner.module[?(@.is_crate==true)].items[*]" $m1_use $m2_use +//@ ismany "$.index[?(@.name=='glob_collision')].inner.module.items[*]" $m1_use $m2_use diff --git a/tests/rustdoc-json/reexport/in_root_and_mod.rs b/tests/rustdoc-json/reexport/in_root_and_mod.rs index e0c54f9d7fd7..005004e3b868 100644 --- a/tests/rustdoc-json/reexport/in_root_and_mod.rs +++ b/tests/rustdoc-json/reexport/in_root_and_mod.rs @@ -1,13 +1,13 @@ -//@ !has "$.index[?(@.name=='foo')]" +//@ !has "$.index[*].name" '"foo"' mod foo { - //@ has "$.index[?(@.name=='Foo')]" + //@ has "$.index[*].name" '"Foo"' pub struct Foo; } -//@ has "$.index[*].inner[?(@.use.source=='foo::Foo')]" +//@ has "$.index[*].inner.use.source" '"foo::Foo"' pub use foo::Foo; pub mod bar { - //@ has "$.index[*].inner[?(@.use.source=='crate::foo::Foo')]" + //@ has "$.index[*].inner.use.source" '"crate::foo::Foo"' pub use crate::foo::Foo; } diff --git a/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs b/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs index 5780b2082794..54dda2a3cd09 100644 --- a/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs +++ b/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs @@ -5,14 +5,14 @@ pub mod foo { } //@ set root_import_id = "$.index[?(@.docs=='Outer re-export')].id" -//@ is "$.index[*].inner[?(@.use.source=='foo::Bar')].use.id" $bar_id +//@ is "$.index[?(@.inner.use.source=='foo::Bar')].inner.use.id" $bar_id //@ has "$.index[?(@.name=='in_root_and_mod_pub')].inner.module.items[*]" $root_import_id /// Outer re-export pub use foo::Bar; pub mod baz { //@ set baz_import_id = "$.index[?(@.docs=='Inner re-export')].id" - //@ is "$.index[*].inner[?(@.use.source=='crate::foo::Bar')].use.id" $bar_id + //@ is "$.index[?(@.inner.use.source=='crate::foo::Bar')].inner.use.id" $bar_id //@ ismany "$.index[?(@.name=='baz')].inner.module.items[*]" $baz_import_id /// Inner re-export pub use crate::foo::Bar; diff --git a/tests/rustdoc-json/reexport/mod_not_included.rs b/tests/rustdoc-json/reexport/mod_not_included.rs index a2ac543a94cb..59e5fff59c98 100644 --- a/tests/rustdoc-json/reexport/mod_not_included.rs +++ b/tests/rustdoc-json/reexport/mod_not_included.rs @@ -7,5 +7,5 @@ mod m1 { pub use m1::x; //@ has "$.index[?(@.name=='x' && @.inner.function)]" -//@ has "$.index[*].inner[?(@.use.name=='x')].use.source" '"m1::x"' +//@ has "$.index[?(@.inner.use.name=='x')].inner.use.source" '"m1::x"' //@ !has "$.index[?(@.name=='m1')]" diff --git a/tests/rustdoc-json/reexport/reexport_of_hidden.rs b/tests/rustdoc-json/reexport/reexport_of_hidden.rs index fd9f57115c65..119e699d8156 100644 --- a/tests/rustdoc-json/reexport/reexport_of_hidden.rs +++ b/tests/rustdoc-json/reexport/reexport_of_hidden.rs @@ -1,7 +1,7 @@ //@ compile-flags: --document-hidden-items -//@ has "$.index[*].inner[?(@.use.name=='UsedHidden')]" -//@ has "$.index[?(@.name=='Hidden')]" +//@ has "$.index[*].inner.use.name" '"UsedHidden"' +//@ has "$.index[*].name" '"Hidden"' pub mod submodule { #[doc(hidden)] pub struct Hidden {} diff --git a/tests/rustdoc-json/reexport/rename_public.rs b/tests/rustdoc-json/reexport/rename_public.rs index c0676b5875d2..a3d712358f22 100644 --- a/tests/rustdoc-json/reexport/rename_public.rs +++ b/tests/rustdoc-json/reexport/rename_public.rs @@ -7,8 +7,8 @@ pub mod inner { pub struct Public; } //@ set import_id = "$.index[?(@.docs=='Re-export')].id" -//@ !has "$.index[*].inner[?(@.use.name=='Public')]" -//@ is "$.index[*].inner[?(@.use.name=='NewName')].use.source" \"inner::Public\" +//@ !has "$.index[?(@.inner.use.name=='Public')]" +//@ is "$.index[?(@.inner.use.name=='NewName')].inner.use.source" \"inner::Public\" /// Re-export pub use inner::Public as NewName; diff --git a/tests/rustdoc-json/reexport/same_name_different_types.rs b/tests/rustdoc-json/reexport/same_name_different_types.rs index a707abafe883..6e7ad3393e5d 100644 --- a/tests/rustdoc-json/reexport/same_name_different_types.rs +++ b/tests/rustdoc-json/reexport/same_name_different_types.rs @@ -13,10 +13,10 @@ pub mod nested { pub fn Foo() {} } -//@ ismany "$.index[*].inner[?(@.use.name == 'Foo')].use.id" $foo_fn $foo_struct -//@ ismany "$.index[*].inner[?(@.use.name == 'Bar')].use.id" $foo_fn $foo_struct +//@ ismany "$.index[?(@.inner.use.name == 'Foo')].inner.use.id" $foo_fn $foo_struct +//@ ismany "$.index[?(@.inner.use.name == 'Bar')].inner.use.id" $foo_fn $foo_struct -//@ count "$.index[*].inner[?(@.use.name == 'Foo')]" 2 -//@ count "$.index[*].inner[?(@.use.name == 'Bar')]" 2 +//@ count "$.index[?(@.inner.use.name == 'Foo')]" 2 +//@ count "$.index[?(@.inner.use.name == 'Bar')]" 2 pub use Foo as Bar; pub use nested::Foo; diff --git a/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs index 9ba69a4aa72c..05b55c7b12a0 100644 --- a/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs +++ b/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs @@ -8,11 +8,11 @@ mod inner { } //@ set export_id = "$.index[?(@.docs=='First re-export')].id" -//@ is "$.index[*].inner[?(@.use.name=='Trait')].use.id" $trait_id +//@ is "$.index[?(@.inner.use.name=='Trait')].inner.use.id" $trait_id /// First re-export pub use inner::Trait; //@ set reexport_id = "$.index[?(@.docs=='Second re-export')].id" -//@ is "$.index[*].inner[?(@.use.name=='Reexport')].use.id" $trait_id +//@ is "$.index[?(@.inner.use.name=='Reexport')].inner.use.id" $trait_id /// Second re-export pub use inner::Trait as Reexport; From e5fc7d6a55fd3318f7e457bb27df0de3089dcc0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 21 Mar 2025 12:50:27 +0800 Subject: [PATCH 166/546] Fix Thread::set_name on cygwin --- library/std/src/sys/pal/unix/thread.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index bffe25362998..bb34c2fabe55 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -143,8 +143,8 @@ impl Thread { pub fn set_name(name: &CStr) { unsafe { cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - // Linux limits the allowed length of the name. + if #[cfg(any(target_os = "linux", target_os = "cygwin"))] { + // Linux and Cygwin limits the allowed length of the name. const TASK_COMM_LEN: usize = 16; let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); } else { @@ -346,6 +346,7 @@ impl Drop for Thread { target_os = "solaris", target_os = "illumos", target_os = "vxworks", + target_os = "cygwin", target_vendor = "apple", ))] fn truncate_cstr(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { From 077b8d5c370391d428dbb4d3d037f6e51b1349a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 16 Mar 2025 23:59:10 +0100 Subject: [PATCH 167/546] Abort in deadlock handler if we fail to get a query map --- compiler/rustc_interface/src/util.rs | 13 +++++++++++-- compiler/rustc_query_impl/src/plumbing.rs | 15 +++++++++------ compiler/rustc_query_system/src/query/job.rs | 2 +- compiler/rustc_query_system/src/query/mod.rs | 2 +- compiler/rustc_query_system/src/query/plumbing.rs | 5 +++-- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 5cccab893bb3..0904795529e3 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -192,7 +192,16 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, // `TyCtxt` TLS reference here. let query_map = current_gcx2.access(|gcx| { tls::enter_context(&tls::ImplicitCtxt::new(gcx), || { - tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs()) + tls::with(|tcx| { + let (query_map, complete) = QueryCtxt::new(tcx).collect_active_jobs(); + if !complete { + eprintln!("internal compiler error: failed to get query map in deadlock handler, aborting process"); + // We need to abort here as we failed to resolve the deadlock, + // otherwise the compiler could just hang, + process::abort(); + } + query_map + }) }) }); let query_map = FromDyn::from(query_map); @@ -201,7 +210,7 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, .name("rustc query cycle handler".to_string()) .spawn(move || { let on_panic = defer(|| { - eprintln!("query cycle handler thread panicked, aborting process"); + eprintln!("internal compiler error: query cycle handler thread panicked, aborting process"); // We need to abort here as we failed to resolve the deadlock, // otherwise the compiler could just hang, process::abort(); diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 2b8457ace8ee..85abb77e53c7 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -79,14 +79,15 @@ impl QueryContext for QueryCtxt<'_> { tls::with_related_context(self.tcx, |icx| icx.query) } - fn collect_active_jobs(self) -> QueryMap { + fn collect_active_jobs(self) -> (QueryMap, bool) { let mut jobs = QueryMap::default(); + let mut complete = true; for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() { - collect(self.tcx, &mut jobs); + collect(self.tcx, &mut jobs, &mut complete); } - jobs + (jobs, complete) } // Interactions with on_disk_cache @@ -139,7 +140,8 @@ impl QueryContext for QueryCtxt<'_> { } fn depth_limit_error(self, job: QueryJobId) { - let (info, depth) = job.find_dep_kind_root(self.collect_active_jobs()); + // FIXME: `collect_active_jobs` expects no locks to be held, which doesn't hold for this call. + let (info, depth) = job.find_dep_kind_root(self.collect_active_jobs().0); let suggested_limit = match self.recursion_limit() { Limit(0) => Limit(2), @@ -677,7 +679,7 @@ macro_rules! define_queries { } } - pub(crate) fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) { + pub(crate) fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap, complete: &mut bool) { let make_query = |tcx, key| { let kind = rustc_middle::dep_graph::dep_kinds::$name; let name = stringify!($name); @@ -692,6 +694,7 @@ macro_rules! define_queries { // don't `unwrap()` here, just manually check for `None` and do best-effort error // reporting. if res.is_none() { + *complete = false; tracing::warn!( "Failed to collect active jobs for query with name `{}`!", stringify!($name) @@ -756,7 +759,7 @@ macro_rules! define_queries { // These arrays are used for iteration and can't be indexed by `DepKind`. - const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap)] = + const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap, &mut bool)] = &[$(query_impl::$name::try_collect_active_jobs),*]; const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[ diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 37b305d0a8b5..44f9325dce26 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -588,7 +588,7 @@ pub fn print_query_stack( // state if it was responsible for triggering the panic. let mut count_printed = 0; let mut count_total = 0; - let query_map = qcx.collect_active_jobs(); + let query_map = qcx.collect_active_jobs().0; if let Some(ref mut file) = file { let _ = writeln!(file, "\n\nquery stack during panic:"); diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 2ed0c810b751..3728691a6f9a 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -86,7 +86,7 @@ pub trait QueryContext: HasDepContext { /// Get the query information from the TLS context. fn current_query_job(self) -> Option; - fn collect_active_jobs(self) -> QueryMap; + fn collect_active_jobs(self) -> (QueryMap, bool); /// Load a side effect associated to the node in the previous session. fn load_side_effect( diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 7578cb5e2aeb..68590854343e 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -250,8 +250,9 @@ where Q: QueryConfig, Qcx: QueryContext, { - let error = - try_execute.find_cycle_in_stack(qcx.collect_active_jobs(), &qcx.current_query_job(), span); + let (query_map, complete) = qcx.collect_active_jobs(); + assert!(complete, "failed to collect active queries"); + let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span); (mk_cycle(query, qcx, error), None) } From 157008d7117ec9ca13b70c38058639524437112f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 14:36:28 +0100 Subject: [PATCH 168/546] Update comments --- compiler/rustc_interface/src/util.rs | 5 +++-- compiler/rustc_query_impl/src/plumbing.rs | 2 ++ compiler/rustc_query_system/src/query/plumbing.rs | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 0904795529e3..249b80bb31d9 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -195,9 +195,10 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, tls::with(|tcx| { let (query_map, complete) = QueryCtxt::new(tcx).collect_active_jobs(); if !complete { + // There was an unexpected error collecting all active jobs, which we need + // to find cycles to break. + // We want to avoid panicking in the deadlock handler, so we abort instead. eprintln!("internal compiler error: failed to get query map in deadlock handler, aborting process"); - // We need to abort here as we failed to resolve the deadlock, - // otherwise the compiler could just hang, process::abort(); } query_map diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 85abb77e53c7..301bcac4ca79 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -79,6 +79,8 @@ impl QueryContext for QueryCtxt<'_> { tls::with_related_context(self.tcx, |icx| icx.query) } + /// Returns a query map representing active query jobs and a bool being false + /// if there was an error constructing the map. fn collect_active_jobs(self) -> (QueryMap, bool) { let mut jobs = QueryMap::default(); let mut complete = true; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 68590854343e..dc1d6f760fac 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -251,7 +251,10 @@ where Qcx: QueryContext, { let (query_map, complete) = qcx.collect_active_jobs(); + // Ensure there was no errors collecting all active jobs. + // We need the complete map to ensure we find a cycle to break. assert!(complete, "failed to collect active queries"); + let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span); (mk_cycle(query, qcx, error), None) } From fcd3349d14af8b217b849f030e5d8ffd5e99f0d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 16 Aug 2023 17:50:40 +0200 Subject: [PATCH 169/546] Optimize hash map operations in the query system --- Cargo.lock | 2 - compiler/rustc_data_structures/Cargo.toml | 5 -- compiler/rustc_data_structures/src/lib.rs | 2 + compiler/rustc_data_structures/src/sharded.rs | 2 +- compiler/rustc_query_system/src/lib.rs | 2 + .../rustc_query_system/src/query/plumbing.rs | 70 +++++++++++-------- 6 files changed, 46 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a8dea0b1051..e5bd55538bd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1491,7 +1491,6 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "allocator-api2", "foldhash", "serde", ] @@ -3480,7 +3479,6 @@ dependencies = [ "either", "elsa", "ena", - "hashbrown 0.15.2", "indexmap", "jobserver", "libc", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index fcaf2750507d..df3bee6ee9cc 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -29,11 +29,6 @@ thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end -[dependencies.hashbrown] -version = "0.15.2" -default-features = false -features = ["nightly"] # for may_dangle - [dependencies.parking_lot] version = "0.12" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 865424fd6bbd..244997f56115 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -38,6 +38,8 @@ #![feature(unwrap_infallible)] // tidy-alphabetical-end +extern crate hashbrown; + use std::fmt; pub use atomic_ref::AtomicRef; diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 49cafcb17a03..5de9413cf15d 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -256,7 +256,7 @@ impl ShardedHashMap { } #[inline] -fn make_hash(val: &K) -> u64 { +pub fn make_hash(val: &K) -> u64 { let mut state = FxHasher::default(); val.hash(&mut state); state.finish() diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 2aedd365adc8..85e41a390726 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -7,6 +7,8 @@ #![feature(min_specialization)] // tidy-alphabetical-end +extern crate hashbrown; + pub mod cache; pub mod dep_graph; mod error; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 7578cb5e2aeb..d6b90fbc09f8 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -3,14 +3,13 @@ //! manage the caches, and so forth. use std::cell::Cell; -use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::mem; +use hashbrown::hash_table::Entry; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sharded::Sharded; +use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::{outline, sync}; use rustc_errors::{Diag, FatalError, StashKey}; @@ -25,8 +24,13 @@ use crate::query::caches::QueryCache; use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, report_cycle}; use crate::query::{QueryContext, QueryMap, QueryStackFrame, SerializedDepNodeIndex}; +#[inline] +fn equivalent_key(k: &K) -> impl Fn(&(K, V)) -> bool + '_ { + move |x| x.0 == *k +} + pub struct QueryState { - active: Sharded>, + active: Sharded>, } /// Indicates the state of a query for a given key in a query map. @@ -159,7 +163,7 @@ where { /// Completes the query by updating the query cache with the `result`, /// signals the waiter and forgets the JobOwner, so it won't poison the query - fn complete(self, cache: &C, result: C::Value, dep_node_index: DepNodeIndex) + fn complete(self, cache: &C, key_hash: u64, result: C::Value, dep_node_index: DepNodeIndex) where C: QueryCache, { @@ -174,16 +178,17 @@ where cache.complete(key, result, dep_node_index); let job = { - let val = { - // don't keep the lock during the `unwrap()` of the retrieved value, or we taint the - // underlying shard. - // since unwinding also wants to look at this map, this can also prevent a double - // panic. - let mut lock = state.active.lock_shard_by_value(&key); - lock.remove(&key) - }; - val.unwrap().expect_job() + // don't keep the lock during the `unwrap()` of the retrieved value, or we taint the + // underlying shard. + // since unwinding also wants to look at this map, this can also prevent a double + // panic. + let mut shard = state.active.lock_shard_by_hash(key_hash); + match shard.find_entry(key_hash, equivalent_key(&key)) { + Err(_) => None, + Ok(occupied) => Some(occupied.remove().0.1), + } }; + let job = job.expect("active query job entry").expect_job(); job.signal_complete(); } @@ -199,11 +204,16 @@ where // Poison the query so jobs waiting on it panic. let state = self.state; let job = { - let mut shard = state.active.lock_shard_by_value(&self.key); - let job = shard.remove(&self.key).unwrap().expect_job(); - - shard.insert(self.key, QueryResult::Poisoned); - job + let key_hash = sharded::make_hash(&self.key); + let mut shard = state.active.lock_shard_by_hash(key_hash); + match shard.find_entry(key_hash, equivalent_key(&self.key)) { + Err(_) => panic!(), + Ok(occupied) => { + let ((key, value), vacant) = occupied.remove(); + vacant.insert((key, QueryResult::Poisoned)); + value.expect_job() + } + } }; // Also signal the completion of the job, so waiters // will continue execution. @@ -283,11 +293,11 @@ where outline(|| { // We didn't find the query result in the query cache. Check if it was // poisoned due to a panic instead. - let lock = query.query_state(qcx).active.get_shard_by_value(&key).lock(); - - match lock.get(&key) { + let key_hash = sharded::make_hash(&key); + let shard = query.query_state(qcx).active.lock_shard_by_hash(key_hash); + match shard.find(key_hash, equivalent_key(&key)) { // The query we waited on panicked. Continue unwinding here. - Some(QueryResult::Poisoned) => FatalError.raise(), + Some((_, QueryResult::Poisoned)) => FatalError.raise(), _ => panic!( "query '{}' result must be in the cache or the query must be poisoned after a wait", query.name() @@ -318,7 +328,8 @@ where Qcx: QueryContext, { let state = query.query_state(qcx); - let mut state_lock = state.active.lock_shard_by_value(&key); + let key_hash = sharded::make_hash(&key); + let mut state_lock = state.active.lock_shard_by_hash(key_hash); // For the parallel compiler we need to check both the query cache and query state structures // while holding the state lock to ensure that 1) the query has not yet completed and 2) the @@ -335,21 +346,21 @@ where let current_job_id = qcx.current_query_job(); - match state_lock.entry(key) { + match state_lock.entry(key_hash, equivalent_key(&key), |(k, _)| sharded::make_hash(k)) { Entry::Vacant(entry) => { // Nothing has computed or is computing the query, so we start a new job and insert it in the // state map. let id = qcx.next_job_id(); let job = QueryJob::new(id, span, current_job_id); - entry.insert(QueryResult::Started(job)); + entry.insert((key, QueryResult::Started(job))); // Drop the lock before we start executing the query drop(state_lock); - execute_job::<_, _, INCR>(query, qcx, state, key, id, dep_node) + execute_job::<_, _, INCR>(query, qcx, state, key, key_hash, id, dep_node) } Entry::Occupied(mut entry) => { - match entry.get_mut() { + match &mut entry.get_mut().1 { QueryResult::Started(job) => { if sync::is_dyn_thread_safe() { // Get the latch out @@ -380,6 +391,7 @@ fn execute_job( qcx: Qcx, state: &QueryState, key: Q::Key, + key_hash: u64, id: QueryJobId, dep_node: Option, ) -> (Q::Value, Option) @@ -440,7 +452,7 @@ where } } } - job_owner.complete(cache, result, dep_node_index); + job_owner.complete(cache, key_hash, result, dep_node_index); (result, Some(dep_node_index)) } From ea99e81485ff5d82cabba9af5d1c21293737cc16 Mon Sep 17 00:00:00 2001 From: Bardi Harborow Date: Fri, 21 Mar 2025 17:53:29 +1100 Subject: [PATCH 170/546] Recognise new IPv6 non-global range from RFC9602 This commit adds the 5f00::/16 range defined by RFC9602 to those ranges which Ipv6Addr::is_global recognises as a non-global IP. This range is used for Segment Routing (SRv6) SIDs. --- library/core/src/net/ip_addr.rs | 2 ++ library/coretests/tests/net/ip_addr.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 7aa5ed60d046..2f027be69286 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1623,6 +1623,8 @@ impl Ipv6Addr { // IANA says N/A. || matches!(self.segments(), [0x2002, _, _, _, _, _, _, _]) || self.is_documentation() + // Segment Routing (SRv6) SIDs (`5f00::/16`) + || matches!(self.segments(), [0x5f00, ..]) || self.is_unique_local() || self.is_unicast_link_local()) } diff --git a/library/coretests/tests/net/ip_addr.rs b/library/coretests/tests/net/ip_addr.rs index f01b43282ec4..3fec59d67b74 100644 --- a/library/coretests/tests/net/ip_addr.rs +++ b/library/coretests/tests/net/ip_addr.rs @@ -689,6 +689,8 @@ fn ipv6_properties() { check!("2002::", &[0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + check!("5f00::", &[0x5f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); check!( From 93bfe39ba574cff3f1d1df448f0b512e32578e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 21 Mar 2025 07:54:06 +0100 Subject: [PATCH 171/546] Use hashbrown from crates.io --- Cargo.lock | 3 +++ compiler/rustc_data_structures/Cargo.toml | 5 +++++ compiler/rustc_data_structures/src/lib.rs | 2 -- compiler/rustc_query_system/Cargo.toml | 5 +++++ compiler/rustc_query_system/src/lib.rs | 2 -- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5bd55538bd1..9db0232b736f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1491,6 +1491,7 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ + "allocator-api2", "foldhash", "serde", ] @@ -3479,6 +3480,7 @@ dependencies = [ "either", "elsa", "ena", + "hashbrown 0.15.2", "indexmap", "jobserver", "libc", @@ -4257,6 +4259,7 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ + "hashbrown 0.15.2", "parking_lot", "rustc-rayon-core", "rustc_abi", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index df3bee6ee9cc..fcaf2750507d 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -29,6 +29,11 @@ thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end +[dependencies.hashbrown] +version = "0.15.2" +default-features = false +features = ["nightly"] # for may_dangle + [dependencies.parking_lot] version = "0.12" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 244997f56115..865424fd6bbd 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -38,8 +38,6 @@ #![feature(unwrap_infallible)] // tidy-alphabetical-end -extern crate hashbrown; - use std::fmt; pub use atomic_ref::AtomicRef; diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 78710efb7a93..7db06953aeb6 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -24,3 +24,8 @@ rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end + +[dependencies.hashbrown] +version = "0.15.2" +default-features = false +features = ["nightly"] # for may_dangle diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 85e41a390726..2aedd365adc8 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -7,8 +7,6 @@ #![feature(min_specialization)] // tidy-alphabetical-end -extern crate hashbrown; - pub mod cache; pub mod dep_graph; mod error; From 34244c1477e4b485c51872fc3c6d846b4a3c6ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 21 Mar 2025 08:09:42 +0100 Subject: [PATCH 172/546] Address comments --- compiler/rustc_interface/src/util.rs | 17 +++++++------ compiler/rustc_query_impl/src/plumbing.rs | 25 ++++++++++++------- compiler/rustc_query_system/src/query/job.rs | 7 +++++- compiler/rustc_query_system/src/query/mod.rs | 2 +- .../rustc_query_system/src/query/plumbing.rs | 3 +-- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 249b80bb31d9..333786f0ca38 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -193,15 +193,16 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, let query_map = current_gcx2.access(|gcx| { tls::enter_context(&tls::ImplicitCtxt::new(gcx), || { tls::with(|tcx| { - let (query_map, complete) = QueryCtxt::new(tcx).collect_active_jobs(); - if !complete { - // There was an unexpected error collecting all active jobs, which we need - // to find cycles to break. - // We want to avoid panicking in the deadlock handler, so we abort instead. - eprintln!("internal compiler error: failed to get query map in deadlock handler, aborting process"); - process::abort(); + match QueryCtxt::new(tcx).collect_active_jobs() { + Ok(query_map) => query_map, + Err(_) => { + // There was an unexpected error collecting all active jobs, which we need + // to find cycles to break. + // We want to avoid panicking in the deadlock handler, so we abort instead. + eprintln!("internal compiler error: failed to get query map in deadlock handler, aborting process"); + process::abort(); + } } - query_map }) }) }); diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 301bcac4ca79..cafe16ce77b9 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -79,17 +79,20 @@ impl QueryContext for QueryCtxt<'_> { tls::with_related_context(self.tcx, |icx| icx.query) } - /// Returns a query map representing active query jobs and a bool being false - /// if there was an error constructing the map. - fn collect_active_jobs(self) -> (QueryMap, bool) { + /// Returns a query map representing active query jobs. + /// It returns an incomplete map as an error if it fails + /// to take locks. + fn collect_active_jobs(self) -> Result { let mut jobs = QueryMap::default(); let mut complete = true; for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() { - collect(self.tcx, &mut jobs, &mut complete); + if collect(self.tcx, &mut jobs).is_none() { + complete = false; + } } - (jobs, complete) + if complete { Ok(jobs) } else { Err(jobs) } } // Interactions with on_disk_cache @@ -143,7 +146,11 @@ impl QueryContext for QueryCtxt<'_> { fn depth_limit_error(self, job: QueryJobId) { // FIXME: `collect_active_jobs` expects no locks to be held, which doesn't hold for this call. - let (info, depth) = job.find_dep_kind_root(self.collect_active_jobs().0); + let query_map = match self.collect_active_jobs() { + Ok(query_map) => query_map, + Err(query_map) => query_map, + }; + let (info, depth) = job.find_dep_kind_root(query_map); let suggested_limit = match self.recursion_limit() { Limit(0) => Limit(2), @@ -681,7 +688,7 @@ macro_rules! define_queries { } } - pub(crate) fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap, complete: &mut bool) { + pub(crate) fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) -> Option<()> { let make_query = |tcx, key| { let kind = rustc_middle::dep_graph::dep_kinds::$name; let name = stringify!($name); @@ -696,12 +703,12 @@ macro_rules! define_queries { // don't `unwrap()` here, just manually check for `None` and do best-effort error // reporting. if res.is_none() { - *complete = false; tracing::warn!( "Failed to collect active jobs for query with name `{}`!", stringify!($name) ); } + res } pub(crate) fn alloc_self_profile_query_strings<'tcx>( @@ -761,7 +768,7 @@ macro_rules! define_queries { // These arrays are used for iteration and can't be indexed by `DepKind`. - const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap, &mut bool)] = + const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap) -> Option<()>] = &[$(query_impl::$name::try_collect_active_jobs),*]; const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[ diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 44f9325dce26..f0cb378f471e 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -588,7 +588,12 @@ pub fn print_query_stack( // state if it was responsible for triggering the panic. let mut count_printed = 0; let mut count_total = 0; - let query_map = qcx.collect_active_jobs().0; + + // Make use of a partial query map if we fail to take locks collecting active queries. + let query_map = match qcx.collect_active_jobs() { + Ok(query_map) => query_map, + Err(query_map) => query_map, + }; if let Some(ref mut file) = file { let _ = writeln!(file, "\n\nquery stack during panic:"); diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 3728691a6f9a..0d0c66aa978e 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -86,7 +86,7 @@ pub trait QueryContext: HasDepContext { /// Get the query information from the TLS context. fn current_query_job(self) -> Option; - fn collect_active_jobs(self) -> (QueryMap, bool); + fn collect_active_jobs(self) -> Result; /// Load a side effect associated to the node in the previous session. fn load_side_effect( diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index dc1d6f760fac..a5ecc50421e7 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -250,10 +250,9 @@ where Q: QueryConfig, Qcx: QueryContext, { - let (query_map, complete) = qcx.collect_active_jobs(); // Ensure there was no errors collecting all active jobs. // We need the complete map to ensure we find a cycle to break. - assert!(complete, "failed to collect active queries"); + let query_map = qcx.collect_active_jobs().expect("failed to collect active queries"); let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span); (mk_cycle(query, qcx, error), None) From d4b8fa9e4c04f3afb7daad03d6719605a8c4bb90 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 14 Mar 2025 12:47:08 +0100 Subject: [PATCH 173/546] remove `feature(inline_const_pat)` --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 - compiler/rustc_feature/src/removed.rs | 3 + compiler/rustc_feature/src/unstable.rs | 2 - compiler/rustc_parse/messages.ftl | 2 - compiler/rustc_parse/src/errors.rs | 11 -- compiler/rustc_parse/src/parser/mod.rs | 15 ++- compiler/rustc_parse/src/parser/pat.rs | 9 -- .../src/language-features/inline-const-pat.md | 22 ---- .../src/matches/redundant_guards.rs | 1 - src/tools/tidy/src/issues.txt | 1 - .../invalid-inline-const-in-match-arm.rs | 9 -- .../invalid-inline-const-in-match-arm.stderr | 18 --- .../feature-gate-inline_const_pat.rs | 4 - .../feature-gate-inline_const_pat.stderr | 13 -- .../range_pat_interactions0.rs | 5 +- .../range_pat_interactions1.rs | 2 - .../range_pat_interactions1.stderr | 19 +-- .../range_pat_interactions2.rs | 22 ---- .../range_pat_interactions2.stderr | 43 ------- .../range_pat_interactions3.rs | 19 --- .../range_pat_interactions3.stderr | 13 -- .../ui/inline-const/collect-scopes-in-pat.rs | 16 --- .../inline-const/const-block-pat-liveness.rs | 18 --- .../inline-const/const-match-pat-generic.rs | 28 ----- .../const-match-pat-generic.stderr | 15 --- .../inline-const/const-match-pat-inference.rs | 11 -- .../const-match-pat-lifetime-err.rs | 47 ------- .../const-match-pat-lifetime-err.stderr | 28 ----- .../inline-const/const-match-pat-lifetime.rs | 34 ----- .../ui/inline-const/const-match-pat-range.rs | 38 ------ tests/ui/inline-const/const-match-pat.rs | 20 --- tests/ui/inline-const/in-pat-recovery.rs | 11 ++ tests/ui/inline-const/in-pat-recovery.stderr | 10 ++ tests/ui/inline-const/pat-match-fndef.rs | 12 -- tests/ui/inline-const/pat-match-fndef.stderr | 8 -- tests/ui/inline-const/pat-unsafe-err.rs | 22 ---- tests/ui/inline-const/pat-unsafe-err.stderr | 19 --- tests/ui/inline-const/pat-unsafe.rs | 29 ----- tests/ui/inline-const/pat-unsafe.stderr | 20 --- tests/ui/lint/dead-code/anon-const-in-pat.rs | 44 ------- tests/ui/match/issue-112438.rs | 10 -- tests/ui/match/validate-range-endpoints.rs | 3 - .../ui/match/validate-range-endpoints.stderr | 28 ++--- tests/ui/parser/issues/issue-24375.stderr | 4 - .../parser/recover/recover-pat-exprs.stderr | 116 ------------------ .../parser/recover/recover-pat-issues.stderr | 24 ---- .../ui/parser/recover/recover-pat-lets.stderr | 8 -- .../parser/recover/recover-pat-ranges.stderr | 24 ---- .../recover/recover-pat-wildcards.stderr | 4 - .../ui/pattern/non-structural-match-types.rs | 31 +++-- .../pattern/non-structural-match-types.stderr | 48 ++++++-- tests/ui/type/pattern_types/const_block.rs | 10 -- .../unsafe/const_pat_in_layout_restricted.rs | 23 ---- 53 files changed, 110 insertions(+), 887 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/inline-const-pat.md delete mode 100644 tests/ui/consts/invalid-inline-const-in-match-arm.rs delete mode 100644 tests/ui/consts/invalid-inline-const-in-match-arm.stderr delete mode 100644 tests/ui/feature-gates/feature-gate-inline_const_pat.rs delete mode 100644 tests/ui/feature-gates/feature-gate-inline_const_pat.stderr delete mode 100644 tests/ui/half-open-range-patterns/range_pat_interactions2.rs delete mode 100644 tests/ui/half-open-range-patterns/range_pat_interactions2.stderr delete mode 100644 tests/ui/half-open-range-patterns/range_pat_interactions3.rs delete mode 100644 tests/ui/half-open-range-patterns/range_pat_interactions3.stderr delete mode 100644 tests/ui/inline-const/collect-scopes-in-pat.rs delete mode 100644 tests/ui/inline-const/const-block-pat-liveness.rs delete mode 100644 tests/ui/inline-const/const-match-pat-generic.rs delete mode 100644 tests/ui/inline-const/const-match-pat-generic.stderr delete mode 100644 tests/ui/inline-const/const-match-pat-inference.rs delete mode 100644 tests/ui/inline-const/const-match-pat-lifetime-err.rs delete mode 100644 tests/ui/inline-const/const-match-pat-lifetime-err.stderr delete mode 100644 tests/ui/inline-const/const-match-pat-lifetime.rs delete mode 100644 tests/ui/inline-const/const-match-pat-range.rs delete mode 100644 tests/ui/inline-const/const-match-pat.rs create mode 100644 tests/ui/inline-const/in-pat-recovery.rs create mode 100644 tests/ui/inline-const/in-pat-recovery.stderr delete mode 100644 tests/ui/inline-const/pat-match-fndef.rs delete mode 100644 tests/ui/inline-const/pat-match-fndef.stderr delete mode 100644 tests/ui/inline-const/pat-unsafe-err.rs delete mode 100644 tests/ui/inline-const/pat-unsafe-err.stderr delete mode 100644 tests/ui/inline-const/pat-unsafe.rs delete mode 100644 tests/ui/inline-const/pat-unsafe.stderr delete mode 100644 tests/ui/lint/dead-code/anon-const-in-pat.rs delete mode 100644 tests/ui/match/issue-112438.rs delete mode 100644 tests/ui/type/pattern_types/const_block.rs delete mode 100644 tests/ui/unsafe/const_pat_in_layout_restricted.rs diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 31ff102c127a..cbe5f8e338f6 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -483,7 +483,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { half_open_range_patterns_in_slices, "half-open range patterns in slices are unstable" ); - gate_all!(inline_const_pat, "inline-const in pattern position is experimental"); gate_all!(associated_const_equality, "associated const equality is incomplete"); gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(dyn_star, "`dyn*` trait objects are experimental"); diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 47e4f9a2fe88..6ba7b22a0dff 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -142,6 +142,9 @@ declare_features! ( /// Allows inferring `'static` outlives requirements (RFC 2093). (removed, infer_static_outlives_requirements, "1.63.0", Some(54185), Some("removed as it caused some confusion and discussion was inactive for years")), + /// Allow anonymous constants from an inline `const` block in pattern position + (removed, inline_const_pat, "CURRENT_RUSTC_VERSION", Some(76001), + Some("removed due to implementation concerns as it requires significant refactorings")), /// Lazily evaluate constants. This allows constants to depend on type parameters. (removed, lazy_normalization_consts, "1.46.0", Some(72219), Some("superseded by `generic_const_exprs`")), /// Changes `impl Trait` to capture all lifetimes in scope. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3b75c69132c2..85bf0d319db6 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -531,8 +531,6 @@ declare_features! ( (unstable, import_trait_associated_functions, "1.86.0", Some(134691)), /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995)), - /// Allow anonymous constants from an inline `const` block in pattern position - (unstable, inline_const_pat, "1.58.0", Some(76001)), /// Allows using `pointer` and `reference` in intra-doc links (unstable, intra_doc_pointers, "1.51.0", Some(80896)), // Allows using the `kl` and `widekl` target features and the associated intrinsics diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 6d4308cda1a6..0ef3d6bc3765 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -842,8 +842,6 @@ parse_unexpected_expr_in_pat_const_sugg = consider extracting the expression int parse_unexpected_expr_in_pat_create_guard_sugg = consider moving the expression to a match arm guard -parse_unexpected_expr_in_pat_inline_const_sugg = consider wrapping the expression in an inline `const` (requires `{"#"}![feature(inline_const_pat)]`) - parse_unexpected_expr_in_pat_update_guard_sugg = consider moving the expression to the match arm guard parse_unexpected_if_with_if = unexpected `if` in the condition expression diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e090d9cf7600..7f3208126586 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2787,17 +2787,6 @@ pub(crate) enum UnexpectedExpressionInPatternSugg { /// The statement's block's indentation. indentation: String, }, - - #[multipart_suggestion( - parse_unexpected_expr_in_pat_inline_const_sugg, - applicability = "maybe-incorrect" - )] - InlineConst { - #[suggestion_part(code = "const {{ ")] - start_span: Span, - #[suggestion_part(code = " }}")] - end_span: Span, - }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index a79b40482883..d865fd427641 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1370,9 +1370,6 @@ impl<'a> Parser<'a> { /// Parses inline const expressions. fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P> { - if pat { - self.psess.gated_spans.gate(sym::inline_const_pat, span); - } self.expect_keyword(exp!(Const))?; let (attrs, blk) = self.parse_inner_attrs_and_block(None)?; let anon_const = AnonConst { @@ -1380,7 +1377,17 @@ impl<'a> Parser<'a> { value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), }; let blk_span = anon_const.value.span; - Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs)) + let kind = if pat { + let guar = self + .dcx() + .struct_span_err(blk_span, "`inline_const_pat` has been removed") + .with_help("use a named `const`-item or an `if`-guard instead") + .emit(); + ExprKind::Err(guar) + } else { + ExprKind::ConstBlock(anon_const) + }; + Ok(self.mk_expr_with_attrs(span.to(blk_span), kind, attrs)) } /// Parses mutability (`mut` or nothing). diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index ec14c5718da5..174cc929fa70 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -631,15 +631,6 @@ impl<'a> Parser<'a> { ident, indentation, }); - - // help: wrap the expr in a `const { expr }` - // FIXME(inline_const_pat): once stabilized, remove this check and remove the `(requires #[feature(inline_const_pat)])` note from the message - if self.parser.psess.unstable_features.is_nightly_build() { - err.subdiagnostic(UnexpectedExpressionInPatternSugg::InlineConst { - start_span: expr_span.shrink_to_lo(), - end_span: expr_span.shrink_to_hi(), - }); - } }, ); } diff --git a/src/doc/unstable-book/src/language-features/inline-const-pat.md b/src/doc/unstable-book/src/language-features/inline-const-pat.md deleted file mode 100644 index c6f54d79cfce..000000000000 --- a/src/doc/unstable-book/src/language-features/inline-const-pat.md +++ /dev/null @@ -1,22 +0,0 @@ -# `inline_const_pat` - -The tracking issue for this feature is: [#76001] - ------- - -This feature allows you to use inline constant expressions in pattern position: - -```rust -#![feature(inline_const_pat)] - -const fn one() -> i32 { 1 } - -let some_int = 3; -match some_int { - const { 1 + 2 } => println!("Matched 1 + 2"), - const { one() } => println!("Matched const fn returning 1"), - _ => println!("Didn't match anything :("), -} -``` - -[#76001]: https://github.com/rust-lang/rust/issues/76001 diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index ab53ad98572e..9bbef8da0a46 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -246,7 +246,6 @@ fn emit_redundant_guards<'tcx>( fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { for_each_expr_without_closures(expr, |expr| { if match expr.kind { - ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat(), ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => { // Allow ctors matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..)) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 2b9ae1954785..c20d67051084 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2876,7 +2876,6 @@ ui/macros/rfc-3086-metavar-expr/issue-111904.rs ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs ui/malformed/issue-69341-malformed-derive-inert.rs ui/marker_trait_attr/issue-61651-type-mismatch.rs -ui/match/issue-112438.rs ui/match/issue-113012.rs ui/match/issue-11319.rs ui/match/issue-114691.rs diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.rs b/tests/ui/consts/invalid-inline-const-in-match-arm.rs deleted file mode 100644 index 4fe4b0d33c88..000000000000 --- a/tests/ui/consts/invalid-inline-const-in-match-arm.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(inline_const_pat)] - -fn main() { - match () { - const { (|| {})() } => {} - //~^ ERROR cannot call non-const closure in constants - //~| ERROR could not evaluate constant pattern - } -} diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr deleted file mode 100644 index b22f99f40d35..000000000000 --- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0015]: cannot call non-const closure in constants - --> $DIR/invalid-inline-const-in-match-arm.rs:5:17 - | -LL | const { (|| {})() } => {} - | ^^^^^^^^^ - | - = note: closures need an RFC before allowed to be called in constants - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error: could not evaluate constant pattern - --> $DIR/invalid-inline-const-in-match-arm.rs:5:9 - | -LL | const { (|| {})() } => {} - | ^^^^^^^^^^^^^^^^^^^ could not evaluate constant - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/feature-gates/feature-gate-inline_const_pat.rs b/tests/ui/feature-gates/feature-gate-inline_const_pat.rs deleted file mode 100644 index 3d0df289fb74..000000000000 --- a/tests/ui/feature-gates/feature-gate-inline_const_pat.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let const { () } = (); - //~^ ERROR inline-const in pattern position is experimental [E0658] -} diff --git a/tests/ui/feature-gates/feature-gate-inline_const_pat.stderr b/tests/ui/feature-gates/feature-gate-inline_const_pat.stderr deleted file mode 100644 index 7d7376fa818b..000000000000 --- a/tests/ui/feature-gates/feature-gate-inline_const_pat.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: inline-const in pattern position is experimental - --> $DIR/feature-gate-inline_const_pat.rs:2:9 - | -LL | let const { () } = (); - | ^^^^^ - | - = note: see issue #76001 for more information - = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions0.rs b/tests/ui/half-open-range-patterns/range_pat_interactions0.rs index f943ea0271da..f79001ff1f17 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions0.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions0.rs @@ -1,7 +1,5 @@ //@ run-pass #![allow(non_contiguous_range_endpoints)] -#![feature(inline_const_pat)] - fn main() { let mut if_lettable = vec![]; let mut first_or = vec![]; @@ -16,7 +14,6 @@ fn main() { match x { 1 | -3..0 => first_or.push(x), y @ (0..5 | 6) => or_two.push(y), - y @ 0..const { 5 + 1 } => assert_eq!(y, 5), y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), y => bottom.push(y), @@ -25,6 +22,6 @@ fn main() { assert_eq!(if_lettable, [-1, 0, 2, 4]); assert_eq!(first_or, [-3, -2, -1, 1]); assert_eq!(or_two, [0, 2, 3, 4, 6]); - assert_eq!(range_from, [-5, -4, 7]); + assert_eq!(range_from, [-5, -4, 5, 7]); assert_eq!(bottom, [-7, -6]); } diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs index 4d7c9f10261f..c5705d5db60f 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs @@ -18,8 +18,6 @@ fn main() { //~^ error: expected a pattern range bound, found an expression 1 | -3..0 => first_or.push(x), y @ (0..5 | 6) => or_two.push(y), - y @ 0..const { 5 + 1 } => assert_eq!(y, 5), - //~^ error: inline-const in pattern position is experimental [E0658] y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), y => bottom.push(y), diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr index 62be2ef7a4d8..5cd98faa8abb 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -11,10 +11,6 @@ LL + const VAL: /* Type */ = 5+1; LL ~ match x as i32 { LL ~ 0..VAL => errors_only.push(x), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | 0..const { 5+1 } => errors_only.push(x), - | +++++++ + error[E0408]: variable `n` is not bound in all patterns --> $DIR/range_pat_interactions1.rs:10:25 @@ -24,17 +20,6 @@ LL | if let n @ 2..3|4 = x { | | | variable not in all patterns -error[E0658]: inline-const in pattern position is experimental - --> $DIR/range_pat_interactions1.rs:21:20 - | -LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), - | ^^^^^ - | - = note: see issue #76001 for more information - = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: aborting due to 2 previous errors -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0408, E0658. -For more information about an error, try `rustc --explain E0408`. +For more information about this error, try `rustc --explain E0408`. diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs deleted file mode 100644 index 0dbdb8fe7b6e..000000000000 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs +++ /dev/null @@ -1,22 +0,0 @@ -fn main() { - let mut first_or = Vec::::new(); - let mut or_two = Vec::::new(); - let mut range_from = Vec::::new(); - let mut bottom = Vec::::new(); - let mut errors_only = Vec::::new(); - - for x in -9 + 1..=(9 - 2) { - match x as i32 { - 0..=(5+1) => errors_only.push(x), - //~^ error: expected a pattern range bound, found an expression - //~| error: range pattern bounds cannot have parentheses - 1 | -3..0 => first_or.push(x), - y @ (0..5 | 6) => or_two.push(y), - y @ 0..const { 5 + 1 } => assert_eq!(y, 5), - //~^ error: inline-const in pattern position is experimental - y @ -5.. => range_from.push(y), - y @ ..-7 => assert_eq!(y, -8), - y => bottom.push(y), - } - } -} diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr deleted file mode 100644 index dbe7f4482eed..000000000000 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error: range pattern bounds cannot have parentheses - --> $DIR/range_pat_interactions2.rs:10:17 - | -LL | 0..=(5+1) => errors_only.push(x), - | ^ ^ - | -help: remove these parentheses - | -LL - 0..=(5+1) => errors_only.push(x), -LL + 0..=5+1 => errors_only.push(x), - | - -error: expected a pattern range bound, found an expression - --> $DIR/range_pat_interactions2.rs:10:18 - | -LL | 0..=(5+1) => errors_only.push(x), - | ^^^ not a pattern - | - = note: arbitrary expressions are not allowed in patterns: -help: consider extracting the expression into a `const` - | -LL + const VAL: /* Type */ = 5+1; -LL ~ match x as i32 { -LL ~ 0..=(VAL) => errors_only.push(x), - | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | 0..=(const { 5+1 }) => errors_only.push(x), - | +++++++ + - -error[E0658]: inline-const in pattern position is experimental - --> $DIR/range_pat_interactions2.rs:15:20 - | -LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), - | ^^^^^ - | - = note: see issue #76001 for more information - = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions3.rs b/tests/ui/half-open-range-patterns/range_pat_interactions3.rs deleted file mode 100644 index 2f2778095cf4..000000000000 --- a/tests/ui/half-open-range-patterns/range_pat_interactions3.rs +++ /dev/null @@ -1,19 +0,0 @@ -fn main() { - let mut first_or = Vec::::new(); - let mut or_two = Vec::::new(); - let mut range_from = Vec::::new(); - let mut bottom = Vec::::new(); - - for x in -9 + 1..=(9 - 2) { - match x as i32 { - 8.. => bottom.push(x), - 1 | -3..0 => first_or.push(x), - y @ (0..5 | 6) => or_two.push(y), - y @ 0..const { 5 + 1 } => assert_eq!(y, 5), - //~^ inline-const in pattern position is experimental - y @ -5.. => range_from.push(y), - y @ ..-7 => assert_eq!(y, -8), - y => bottom.push(y), - } - } -} diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr deleted file mode 100644 index dc7dc0efa7a2..000000000000 --- a/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: inline-const in pattern position is experimental - --> $DIR/range_pat_interactions3.rs:12:20 - | -LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), - | ^^^^^ - | - = note: see issue #76001 for more information - = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/inline-const/collect-scopes-in-pat.rs b/tests/ui/inline-const/collect-scopes-in-pat.rs deleted file mode 100644 index 16baf920f584..000000000000 --- a/tests/ui/inline-const/collect-scopes-in-pat.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: -Zlint-mir -//@ check-pass - -#![feature(inline_const_pat)] - -fn main() { - match 1 { - const { - || match 0 { - x => 0, - }; - 0 - } => (), - _ => (), - } -} diff --git a/tests/ui/inline-const/const-block-pat-liveness.rs b/tests/ui/inline-const/const-block-pat-liveness.rs deleted file mode 100644 index 26393a4f65b8..000000000000 --- a/tests/ui/inline-const/const-block-pat-liveness.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! This test used to ICE because const blocks didn't have a body -//! anymore, making a lot of logic very fragile around handling the -//! HIR of a const block. -//! https://github.com/rust-lang/rust/issues/125846 - -//@ check-pass - -#![feature(inline_const_pat)] - -fn main() { - match 0 { - const { - let a = 10_usize; - *&a - } - | _ => {} - } -} diff --git a/tests/ui/inline-const/const-match-pat-generic.rs b/tests/ui/inline-const/const-match-pat-generic.rs deleted file mode 100644 index 889c015e9acb..000000000000 --- a/tests/ui/inline-const/const-match-pat-generic.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![feature(inline_const_pat)] - -// rust-lang/rust#82518: ICE with inline-const in match referencing const-generic parameter - -fn foo() { - match 0 { - const { V } => {}, - //~^ ERROR constant pattern cannot depend on generic parameters - _ => {}, - } -} - -const fn f(x: usize) -> usize { - x + 1 -} - -fn bar() { - match 0 { - const { f(V) } => {}, - //~^ ERROR constant pattern cannot depend on generic parameters - _ => {}, - } -} - -fn main() { - foo::<1>(); - bar::<1>(); -} diff --git a/tests/ui/inline-const/const-match-pat-generic.stderr b/tests/ui/inline-const/const-match-pat-generic.stderr deleted file mode 100644 index 7d9e1d9e407e..000000000000 --- a/tests/ui/inline-const/const-match-pat-generic.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0158]: constant pattern cannot depend on generic parameters - --> $DIR/const-match-pat-generic.rs:7:9 - | -LL | const { V } => {}, - | ^^^^^^^^^^^ `const` depends on a generic parameter - -error[E0158]: constant pattern cannot depend on generic parameters - --> $DIR/const-match-pat-generic.rs:19:9 - | -LL | const { f(V) } => {}, - | ^^^^^^^^^^^^^^ `const` depends on a generic parameter - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/inline-const/const-match-pat-inference.rs b/tests/ui/inline-const/const-match-pat-inference.rs deleted file mode 100644 index 3d3533839bc7..000000000000 --- a/tests/ui/inline-const/const-match-pat-inference.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ check-pass - -#![feature(inline_const_pat)] - -fn main() { - match 1u64 { - 0 => (), - const { 0 + 1 } => (), - const { 2 - 1 } ..= const { u64::MAX } => (), - } -} diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.rs b/tests/ui/inline-const/const-match-pat-lifetime-err.rs deleted file mode 100644 index 7f450ebe6fcc..000000000000 --- a/tests/ui/inline-const/const-match-pat-lifetime-err.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![feature(inline_const_pat)] - -use std::marker::PhantomData; - -#[derive(PartialEq, Eq)] -pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); - -#[derive(PartialEq, Eq)] -pub struct CovariantRef<'a, T: ?Sized>(&'a T); - -impl<'a, T: ?Sized> InvariantRef<'a, T> { - pub const fn new(r: &'a T) -> Self { - InvariantRef(r, PhantomData) - } -} - -impl<'a> InvariantRef<'a, ()> { - pub const NEW: Self = InvariantRef::new(&()); -} - -impl<'a> CovariantRef<'a, ()> { - pub const NEW: Self = CovariantRef(&()); -} - -fn match_invariant_ref<'a>() { - let y = (); - match InvariantRef::new(&y) { - //~^ ERROR `y` does not live long enough [E0597] - const { InvariantRef::<'a>::NEW } => (), - } -} - -fn match_covariant_ref<'a>() { - // Unclear if we should error here (should we be able to subtype the type of - // `y.0`), but using the associated const directly in the pattern also - // errors. - let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),); - //~^ ERROR lifetime may not live long enough - match y.0 { - const { CovariantRef::<'a>::NEW } => (), - } -} - -fn main() { - match_invariant_ref(); - match_covariant_ref(); -} diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr deleted file mode 100644 index 7eea1846057a..000000000000 --- a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0597]: `y` does not live long enough - --> $DIR/const-match-pat-lifetime-err.rs:27:29 - | -LL | fn match_invariant_ref<'a>() { - | -- lifetime `'a` defined here -LL | let y = (); - | - binding `y` declared here -LL | match InvariantRef::new(&y) { - | ^^ borrowed value does not live long enough -LL | -LL | const { InvariantRef::<'a>::NEW } => (), - | ----------------------- using this value as a constant requires that `y` is borrowed for `'a` -LL | } -LL | } - | - `y` dropped here while still borrowed - -error: lifetime may not live long enough - --> $DIR/const-match-pat-lifetime-err.rs:37:12 - | -LL | fn match_covariant_ref<'a>() { - | -- lifetime `'a` defined here -... -LL | let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/inline-const/const-match-pat-lifetime.rs b/tests/ui/inline-const/const-match-pat-lifetime.rs deleted file mode 100644 index 7f1011ea2400..000000000000 --- a/tests/ui/inline-const/const-match-pat-lifetime.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ run-pass - -#![feature(inline_const_pat)] - -use std::marker::PhantomData; - -// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid" -fn issue_78174() { - match "foo" { - const { concat!("fo", "o") } => (), - _ => unreachable!(), - } -} - -#[derive(PartialEq, Eq)] -pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); - -impl<'a, T: ?Sized> InvariantRef<'a, T> { - pub const fn new(r: &'a T) -> Self { - InvariantRef(r, PhantomData) - } -} - -fn match_invariant_ref<'a>() { - match const { InvariantRef::<'a, _>::new(&()) } { - const { InvariantRef::<'a, ()>::new(&()) } => { - } - } -} - -fn main() { - issue_78174(); - match_invariant_ref(); -} diff --git a/tests/ui/inline-const/const-match-pat-range.rs b/tests/ui/inline-const/const-match-pat-range.rs deleted file mode 100644 index 7202c0c04521..000000000000 --- a/tests/ui/inline-const/const-match-pat-range.rs +++ /dev/null @@ -1,38 +0,0 @@ -//@ build-pass - -#![feature(inline_const_pat)] - -fn main() { - const N: u32 = 10; - let x: u32 = 3; - - match x { - 1 ..= const { N + 1 } => {}, - _ => {}, - } - - match x { - const { N - 1 } ..= 10 => {}, - _ => {}, - } - - match x { - const { N - 1 } ..= const { N + 1 } => {}, - _ => {}, - } - - match x { - .. const { N + 1 } => {}, - _ => {}, - } - - match x { - const { N - 1 } .. => {}, - _ => {}, - } - - match x { - ..= const { N + 1 } => {}, - _ => {} - } -} diff --git a/tests/ui/inline-const/const-match-pat.rs b/tests/ui/inline-const/const-match-pat.rs deleted file mode 100644 index 1580ef258129..000000000000 --- a/tests/ui/inline-const/const-match-pat.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ run-pass - -#![feature(inline_const_pat)] -const MMIO_BIT1: u8 = 4; -const MMIO_BIT2: u8 = 5; - -fn main() { - let s = match read_mmio() { - 0 => "FOO", - const { 1 << MMIO_BIT1 } => "BAR", - const { 1 << MMIO_BIT2 } => "BAZ", - _ => unreachable!(), - }; - - assert_eq!("BAZ", s); -} - -fn read_mmio() -> i32 { - 1 << 5 -} diff --git a/tests/ui/inline-const/in-pat-recovery.rs b/tests/ui/inline-const/in-pat-recovery.rs new file mode 100644 index 000000000000..0d912af09811 --- /dev/null +++ b/tests/ui/inline-const/in-pat-recovery.rs @@ -0,0 +1,11 @@ +// While `feature(inline_const_pat)` has been removed from the +// compiler, we should still make sure that the resulting error +// message is acceptable. +fn main() { + match 1 { + const { 1 + 7 } => {} + //~^ `inline_const_pat` has been removed + 2 => {} + _ => {} + } +} diff --git a/tests/ui/inline-const/in-pat-recovery.stderr b/tests/ui/inline-const/in-pat-recovery.stderr new file mode 100644 index 000000000000..e1f2e681e77f --- /dev/null +++ b/tests/ui/inline-const/in-pat-recovery.stderr @@ -0,0 +1,10 @@ +error: `inline_const_pat` has been removed + --> $DIR/in-pat-recovery.rs:6:15 + | +LL | const { 1 + 7 } => {} + | ^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard instead + +error: aborting due to 1 previous error + diff --git a/tests/ui/inline-const/pat-match-fndef.rs b/tests/ui/inline-const/pat-match-fndef.rs deleted file mode 100644 index 013a4a675610..000000000000 --- a/tests/ui/inline-const/pat-match-fndef.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![feature(inline_const_pat)] - -fn uwu() {} - -fn main() { - let x = []; - match x[123] { - const { uwu } => {} - //~^ ERROR `fn() {uwu}` cannot be used in patterns - _ => {} - } -} diff --git a/tests/ui/inline-const/pat-match-fndef.stderr b/tests/ui/inline-const/pat-match-fndef.stderr deleted file mode 100644 index 220437a0491a..000000000000 --- a/tests/ui/inline-const/pat-match-fndef.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fn item `fn() {uwu}` cannot be used in patterns - --> $DIR/pat-match-fndef.rs:8:9 - | -LL | const { uwu } => {} - | ^^^^^^^^^^^^^ fn item can't be used in patterns - -error: aborting due to 1 previous error - diff --git a/tests/ui/inline-const/pat-unsafe-err.rs b/tests/ui/inline-const/pat-unsafe-err.rs deleted file mode 100644 index b906def70295..000000000000 --- a/tests/ui/inline-const/pat-unsafe-err.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![feature(inline_const_pat)] - -const unsafe fn require_unsafe() -> usize { - 1 -} - -fn main() { - match () { - const { - require_unsafe(); - //~^ ERROR [E0133] - } => (), - } - - match 1 { - const { - require_unsafe() - //~^ ERROR [E0133] - }..=4 => (), - _ => (), - } -} diff --git a/tests/ui/inline-const/pat-unsafe-err.stderr b/tests/ui/inline-const/pat-unsafe-err.stderr deleted file mode 100644 index 786c7f31ccce..000000000000 --- a/tests/ui/inline-const/pat-unsafe-err.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block - --> $DIR/pat-unsafe-err.rs:10:13 - | -LL | require_unsafe(); - | ^^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block - --> $DIR/pat-unsafe-err.rs:17:13 - | -LL | require_unsafe() - | ^^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/inline-const/pat-unsafe.rs b/tests/ui/inline-const/pat-unsafe.rs deleted file mode 100644 index 4b05f3a1cddd..000000000000 --- a/tests/ui/inline-const/pat-unsafe.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ check-pass - -#![warn(unused_unsafe)] -#![feature(inline_const_pat)] - -const unsafe fn require_unsafe() -> usize { - 1 -} - -fn main() { - unsafe { - match () { - const { - require_unsafe(); - unsafe {} - //~^ WARNING unnecessary `unsafe` block - } => (), - } - - match 1 { - const { - unsafe {} - //~^ WARNING unnecessary `unsafe` block - require_unsafe() - }..=4 => (), - _ => (), - } - } -} diff --git a/tests/ui/inline-const/pat-unsafe.stderr b/tests/ui/inline-const/pat-unsafe.stderr deleted file mode 100644 index 59460271ac01..000000000000 --- a/tests/ui/inline-const/pat-unsafe.stderr +++ /dev/null @@ -1,20 +0,0 @@ -warning: unnecessary `unsafe` block - --> $DIR/pat-unsafe.rs:15:17 - | -LL | unsafe {} - | ^^^^^^ unnecessary `unsafe` block - | -note: the lint level is defined here - --> $DIR/pat-unsafe.rs:3:9 - | -LL | #![warn(unused_unsafe)] - | ^^^^^^^^^^^^^ - -warning: unnecessary `unsafe` block - --> $DIR/pat-unsafe.rs:22:17 - | -LL | unsafe {} - | ^^^^^^ unnecessary `unsafe` block - -warning: 2 warnings emitted - diff --git a/tests/ui/lint/dead-code/anon-const-in-pat.rs b/tests/ui/lint/dead-code/anon-const-in-pat.rs deleted file mode 100644 index e2d8c90edcca..000000000000 --- a/tests/ui/lint/dead-code/anon-const-in-pat.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@ check-pass -#![feature(inline_const_pat)] -#![deny(dead_code)] - -const fn one() -> i32 { - 1 -} - -const fn two() -> i32 { - 2 -} - -const fn three() -> i32 { - 3 -} - -fn inline_const() { - // rust-lang/rust#78171: dead_code lint triggers even though function is used in const pattern - match 1 { - const { one() } => {} - _ => {} - } -} - -fn inline_const_range() { - match 1 { - 1 ..= const { two() } => {} - _ => {} - } -} - -struct S; - -fn const_generic_arg() { - match S::<3> { - S::<{three()}> => {} - } -} - -fn main() { - inline_const(); - inline_const_range(); - const_generic_arg(); -} diff --git a/tests/ui/match/issue-112438.rs b/tests/ui/match/issue-112438.rs deleted file mode 100644 index b2febe292105..000000000000 --- a/tests/ui/match/issue-112438.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -#![feature(inline_const_pat)] -#![allow(dead_code)] -fn foo() { - match 0 { - const { 1 << 5 } | _ => {} - } -} - -fn main() {} diff --git a/tests/ui/match/validate-range-endpoints.rs b/tests/ui/match/validate-range-endpoints.rs index 46d4239886d3..678cedf016b9 100644 --- a/tests/ui/match/validate-range-endpoints.rs +++ b/tests/ui/match/validate-range-endpoints.rs @@ -1,4 +1,3 @@ -#![feature(inline_const_pat)] #![allow(overlapping_range_endpoints)] fn main() { @@ -17,8 +16,6 @@ fn main() { // There isn't really a way to detect these 1..=TOO_BIG => {} //~^ ERROR lower range bound must be less than or equal to upper - 1..=const { 256 } => {} - //~^ ERROR lower range bound must be less than or equal to upper _ => {} } diff --git a/tests/ui/match/validate-range-endpoints.stderr b/tests/ui/match/validate-range-endpoints.stderr index 2d0538804a37..6a8a81a1cc64 100644 --- a/tests/ui/match/validate-range-endpoints.stderr +++ b/tests/ui/match/validate-range-endpoints.stderr @@ -1,59 +1,53 @@ error: literal out of range for `u8` - --> $DIR/validate-range-endpoints.rs:7:12 + --> $DIR/validate-range-endpoints.rs:6:12 | LL | 1..257 => {} | ^^^ this value does not fit into the type `u8` whose range is `0..=255` error: literal out of range for `u8` - --> $DIR/validate-range-endpoints.rs:9:13 + --> $DIR/validate-range-endpoints.rs:8:13 | LL | 1..=256 => {} | ^^^ this value does not fit into the type `u8` whose range is `0..=255` error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/validate-range-endpoints.rs:18:9 + --> $DIR/validate-range-endpoints.rs:17:9 | LL | 1..=TOO_BIG => {} | ^^^^^^^^^^^ lower bound larger than upper bound -error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/validate-range-endpoints.rs:20:9 - | -LL | 1..=const { 256 } => {} - | ^^^^^^^^^^^^^^^^^ lower bound larger than upper bound - error: literal out of range for `u64` - --> $DIR/validate-range-endpoints.rs:26:32 + --> $DIR/validate-range-endpoints.rs:23:32 | LL | 10000000000000000000..=99999999999999999999 => {} | ^^^^^^^^^^^^^^^^^^^^ this value does not fit into the type `u64` whose range is `0..=18446744073709551615` error: literal out of range for `i8` - --> $DIR/validate-range-endpoints.rs:32:12 + --> $DIR/validate-range-endpoints.rs:29:12 | LL | 0..129 => {} | ^^^ this value does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` - --> $DIR/validate-range-endpoints.rs:34:13 + --> $DIR/validate-range-endpoints.rs:31:13 | LL | 0..=128 => {} | ^^^ this value does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` - --> $DIR/validate-range-endpoints.rs:36:9 + --> $DIR/validate-range-endpoints.rs:33:9 | LL | -129..0 => {} | ^^^^ this value does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` - --> $DIR/validate-range-endpoints.rs:38:9 + --> $DIR/validate-range-endpoints.rs:35:9 | LL | -10000..=-20 => {} | ^^^^^^ this value does not fit into the type `i8` whose range is `-128..=127` error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered - --> $DIR/validate-range-endpoints.rs:49:11 + --> $DIR/validate-range-endpoints.rs:46:11 | LL | match 0i8 { | ^^^ patterns `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered @@ -66,7 +60,7 @@ LL + i8::MIN..=-17_i8 | 1_i8..=i8::MAX => todo!() | error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` not covered - --> $DIR/validate-range-endpoints.rs:53:11 + --> $DIR/validate-range-endpoints.rs:50:11 | LL | match 0i8 { | ^^^ pattern `i8::MIN..=-17_i8` not covered @@ -78,7 +72,7 @@ LL ~ -10000.. => {}, LL + i8::MIN..=-17_i8 => todo!() | -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0004, E0030. For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index 2af57a52035c..e96c004fb351 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -16,10 +16,6 @@ LL + const VAL: /* Type */ = tmp[0]; LL ~ match z { LL ~ VAL => {} | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { tmp[0] } => {} - | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr index dcc1945d569c..69bc5107ccaf 100644 --- a/tests/ui/parser/recover/recover-pat-exprs.stderr +++ b/tests/ui/parser/recover/recover-pat-exprs.stderr @@ -17,10 +17,6 @@ LL ~ match 0 { LL | x => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.y } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:6:9 @@ -42,10 +38,6 @@ LL | x => (), LL | x.y => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.0 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:7:9 @@ -68,10 +60,6 @@ LL | x.y => (), LL | x.0 => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x._0 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:8:9 @@ -94,10 +82,6 @@ LL | x => (), LL | x._0 => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.0.1 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:9:9 @@ -120,10 +104,6 @@ LL | x => (), LL | x.0.1 => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.4.y.17.__z } => (), - | +++++++ + error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` --> $DIR/recover-pat-exprs.rs:12:12 @@ -173,10 +153,6 @@ LL + const VAL: /* Type */ = x[0]; LL ~ match 0 { LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x[0] } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:24:9 @@ -197,10 +173,6 @@ LL ~ match 0 { LL | x[0] => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x[..] } => (), - | +++++++ + error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/recover-pat-exprs.rs:27:12 @@ -247,10 +219,6 @@ LL + const VAL: /* Type */ = x.f(); LL ~ match 0 { LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.f() } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:38:9 @@ -271,10 +239,6 @@ LL ~ match 0 { LL | x.f() => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x._f() } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:39:9 @@ -296,10 +260,6 @@ LL | x.f() => (), LL | x._f() => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x? } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:40:9 @@ -322,10 +282,6 @@ LL | x._f() => (), LL | x? => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { ().f() } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:41:9 @@ -348,10 +304,6 @@ LL | x.f() => (), LL | ().f() => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { (0, x)?.f() } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:42:9 @@ -374,10 +326,6 @@ LL | x.f() => (), LL | (0, x)?.f() => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.f().g() } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:43:9 @@ -400,10 +348,6 @@ LL | x.f() => (), LL | x.f().g() => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { 0.f()?.g()?? } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:50:9 @@ -423,10 +367,6 @@ LL + const VAL: /* Type */ = x as usize; LL ~ match 0 { LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x as usize } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:51:9 @@ -447,10 +387,6 @@ LL ~ match 0 { LL | x as usize => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { 0 as usize } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:52:9 @@ -472,10 +408,6 @@ LL | x as usize => (), LL | 0 as usize => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.f().0.4 as f32 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:59:9 @@ -495,10 +427,6 @@ LL + const VAL: /* Type */ = 1 + 1; LL ~ match 0 { LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { 1 + 1 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:60:9 @@ -519,10 +447,6 @@ LL ~ match 0 { LL | 1 + 1 => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { (1 + 2) * 3 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:63:9 @@ -545,10 +469,6 @@ LL | 1 + 1 => (), LL | LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.0 > 2 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:64:9 @@ -571,10 +491,6 @@ LL | 1 + 1 => (), LL | x.0 > 2 => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { x.0 == 2 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:69:13 @@ -594,10 +510,6 @@ LL + const VAL: /* Type */ = y.0 > 2; LL ~ match (0, 0) { LL ~ (x, VAL) if x != 0 => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | (x, const { y.0 > 2 }) if x != 0 => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:70:13 @@ -618,10 +530,6 @@ LL ~ match (0, 0) { LL | (x, y.0 > 2) if x != 0 => (), LL ~ (x, VAL) if x != 0 || x != 1 => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | (x, const { y.0 > 2 }) if x != 0 || x != 1 => (), - | +++++++ + error: left-hand side of `@` must be a binding --> $DIR/recover-pat-exprs.rs:83:9 @@ -658,10 +566,6 @@ LL + const VAL: /* Type */ = u8::MAX.abs(); LL ~ match u8::MAX { LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { u8::MAX.abs() } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:86:17 @@ -684,10 +588,6 @@ LL | u8::MAX.abs() => (), LL | LL ~ z @ w @ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | z @ w @ const { v.u() } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:88:9 @@ -710,10 +610,6 @@ LL | u8::MAX.abs() => (), LL | LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { y.ilog(3) } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:90:9 @@ -736,10 +632,6 @@ LL | u8::MAX.abs() => (), LL | LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { n + 1 } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:92:10 @@ -762,10 +654,6 @@ LL | u8::MAX.abs() => (), LL | LL ~ (VAL) => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | (const { "".f() + 14 * 8 }) => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:95:9 @@ -788,10 +676,6 @@ LL | u8::MAX.abs() => (), LL | 0 | ((1) | 2) | 3 => (), LL ~ VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { f?() } => (), - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:101:9 diff --git a/tests/ui/parser/recover/recover-pat-issues.stderr b/tests/ui/parser/recover/recover-pat-issues.stderr index 0c65b16dd951..ec7fcda3497f 100644 --- a/tests/ui/parser/recover/recover-pat-issues.stderr +++ b/tests/ui/parser/recover/recover-pat-issues.stderr @@ -16,10 +16,6 @@ LL + const VAL: /* Type */ = "hi".to_owned(); LL ~ match foo { LL ~ Foo(VAL) => true, | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | Foo(const { "hi".to_owned() }) => true, - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:14:20 @@ -39,10 +35,6 @@ LL + const BAZ: /* Type */ = "hi".to_owned(); LL ~ match bar { LL ~ Bar { baz: BAZ } => true, | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | Bar { baz: const { "hi".to_owned() } } => true, - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:25:11 @@ -62,10 +54,6 @@ LL + const VAL: /* Type */ = "foo".to_string(); LL ~ match foo.as_slice() { LL ~ &[VAL] => {} | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | &[const { "foo".to_string() }] => {} - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:36:17 @@ -79,10 +67,6 @@ help: consider extracting the expression into a `const` LL + const VAL: /* Type */ = MAGIC.0 as usize; LL ~ if let Some(VAL) = None:: {} | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | if let Some(const { MAGIC.0 as usize }) = None:: {} - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:41:13 @@ -96,10 +80,6 @@ help: consider extracting the expression into a `const` LL + const VAL: /* Type */ = -1.some(4); LL ~ if let (VAL) = (0, Some(4)) {} | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | if let (const { -1.some(4) }) = (0, Some(4)) {} - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:44:13 @@ -113,10 +93,6 @@ help: consider extracting the expression into a `const` LL + const VAL: /* Type */ = -1.Some(4); LL ~ if let (VAL) = (0, Some(4)) {} | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | if let (const { -1.Some(4) }) = (0, Some(4)) {} - | +++++++ + error: aborting due to 6 previous errors diff --git a/tests/ui/parser/recover/recover-pat-lets.stderr b/tests/ui/parser/recover/recover-pat-lets.stderr index 55252729d7ba..ab79e4ebcaeb 100644 --- a/tests/ui/parser/recover/recover-pat-lets.stderr +++ b/tests/ui/parser/recover/recover-pat-lets.stderr @@ -34,10 +34,6 @@ help: consider extracting the expression into a `const` LL + const VAL: /* Type */ = 1 + 1; LL ~ let Some(VAL) = x else { | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | let Some(const { 1 + 1 }) = x else { - | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:17:17 @@ -51,10 +47,6 @@ help: consider extracting the expression into a `const` LL + const VAL: /* Type */ = 1 + 1; LL ~ if let Some(VAL) = x { | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | if let Some(const { 1 + 1 }) = x { - | +++++++ + error: aborting due to 5 previous errors diff --git a/tests/ui/parser/recover/recover-pat-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr index e8f323596d0f..6c17182618b5 100644 --- a/tests/ui/parser/recover/recover-pat-ranges.stderr +++ b/tests/ui/parser/recover/recover-pat-ranges.stderr @@ -98,10 +98,6 @@ LL | 0..=1 => (), LL | LL ~ ..=VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | ..=const { 1 + 2 } => (), - | +++++++ + error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:15:10 @@ -119,10 +115,6 @@ LL | 0..=1 => (), LL | LL ~ (VAL).. => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | (const { -4 + 0 }).. => (), - | +++++++ + error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:18:10 @@ -140,10 +132,6 @@ LL | 0..=1 => (), LL | LL ~ (VAL)...1 * 2 => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | (const { 1 + 4 })...1 * 2 => (), - | +++++++ + error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:18:19 @@ -161,10 +149,6 @@ LL | 0..=1 => (), LL | LL ~ (1 + 4)...VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | (1 + 4)...const { 1 * 2 } => (), - | +++++++ + error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:24:9 @@ -182,10 +166,6 @@ LL | 0..=1 => (), LL | LL ~ VAL..="y".z() => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | const { 0.x() }..="y".z() => (), - | +++++++ + error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:24:17 @@ -203,10 +183,6 @@ LL | 0..=1 => (), LL | LL ~ 0.x()..=VAL => (), | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | 0.x()..=const { "y".z() } => (), - | +++++++ + warning: `...` range patterns are deprecated --> $DIR/recover-pat-ranges.rs:18:16 diff --git a/tests/ui/parser/recover/recover-pat-wildcards.stderr b/tests/ui/parser/recover/recover-pat-wildcards.stderr index f939e5133700..ebc1cbf7d591 100644 --- a/tests/ui/parser/recover/recover-pat-wildcards.stderr +++ b/tests/ui/parser/recover/recover-pat-wildcards.stderr @@ -84,10 +84,6 @@ LL + const VAL: /* Type */ = 2 + _; LL ~ match 9 { LL ~ 4..=(VAL) => () | -help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) - | -LL | 4..=(const { 2 + _ }) => () - | +++++++ + error: aborting due to 11 previous errors diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs index dde44dfee9c3..5869767c936b 100644 --- a/tests/ui/pattern/non-structural-match-types.rs +++ b/tests/ui/pattern/non-structural-match-types.rs @@ -1,14 +1,29 @@ //@ edition:2021 - -#![allow(unreachable_code)] #![feature(const_async_blocks)] -#![feature(inline_const_pat)] -fn main() { - match loop {} { - const { || {} } => {} //~ ERROR cannot be used in patterns +struct AnyOption(T); +impl AnyOption { + const NONE: Option = None; +} + +fn uwu() {} +fn defines() { + match Some(uwu) { + AnyOption::<_>::NONE => {} + //~^ ERROR constant of non-structural type + _ => {} } - match loop {} { - const { async {} } => {} //~ ERROR cannot be used in patterns + + match Some(|| {}) { + AnyOption::<_>::NONE => {} + //~^ ERROR constant of non-structural type + _ => {} + } + + match Some(async {}) { + AnyOption::<_>::NONE => {} + //~^ ERROR constant of non-structural type + _ => {} } } +fn main() {} diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr index 3588751bf668..da675a9f3ff5 100644 --- a/tests/ui/pattern/non-structural-match-types.stderr +++ b/tests/ui/pattern/non-structural-match-types.stderr @@ -1,14 +1,42 @@ -error: closure `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns - --> $DIR/non-structural-match-types.rs:9:9 - | -LL | const { || {} } => {} - | ^^^^^^^^^^^^^^^ closure can't be used in patterns - -error: `async` block `{async block@$DIR/non-structural-match-types.rs:12:17: 12:22}` cannot be used in patterns +error: constant of non-structural type `Option` in a pattern --> $DIR/non-structural-match-types.rs:12:9 | -LL | const { async {} } => {} - | ^^^^^^^^^^^^^^^^^^ `async` block can't be used in patterns +LL | impl AnyOption { + | -------------------- +LL | const NONE: Option = None; + | --------------------- constant defined here +... +LL | AnyOption::<_>::NONE => {} + | ^^^^^^^^^^^^^^^^^^^^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -error: aborting due to 2 previous errors +error: constant of non-structural type `Option<{closure@$DIR/non-structural-match-types.rs:17:16: 17:18}>` in a pattern + --> $DIR/non-structural-match-types.rs:18:9 + | +LL | impl AnyOption { + | -------------------- +LL | const NONE: Option = None; + | --------------------- constant defined here +... +LL | AnyOption::<_>::NONE => {} + | ^^^^^^^^^^^^^^^^^^^^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + +error: constant of non-structural type `Option<{async block@$DIR/non-structural-match-types.rs:23:16: 23:21}>` in a pattern + --> $DIR/non-structural-match-types.rs:24:9 + | +LL | impl AnyOption { + | -------------------- +LL | const NONE: Option = None; + | --------------------- constant defined here +... +LL | AnyOption::<_>::NONE => {} + | ^^^^^^^^^^^^^^^^^^^^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + = note: `ResumeTy` must be annotated with `#[derive(PartialEq)]` to be usable in patterns + +error: aborting due to 3 previous errors diff --git a/tests/ui/type/pattern_types/const_block.rs b/tests/ui/type/pattern_types/const_block.rs deleted file mode 100644 index ed19b10671af..000000000000 --- a/tests/ui/type/pattern_types/const_block.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(pattern_types)] -#![feature(pattern_type_macro)] -#![feature(inline_const_pat)] -//@ check-pass - -use std::pat::pattern_type; - -fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - -fn main() {} diff --git a/tests/ui/unsafe/const_pat_in_layout_restricted.rs b/tests/ui/unsafe/const_pat_in_layout_restricted.rs deleted file mode 100644 index 2ba173ee4996..000000000000 --- a/tests/ui/unsafe/const_pat_in_layout_restricted.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Check that ref mut patterns within a const pattern don't get considered -// unsafe because they're within a pattern for a layout constrained stuct. -//@ check-pass - -#![feature(rustc_attrs)] -#![feature(inline_const_pat)] - -#[rustc_layout_scalar_valid_range_start(3)] -struct Gt2(i32); - -fn main() { - match unsafe { Gt2(5) } { - Gt2( - const { - || match () { - ref mut y => (), - }; - 4 - }, - ) => (), - _ => (), - } -} From 75935624b383f142f952fa94790a7a88f6ce80b0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 14 Mar 2025 15:37:14 +0100 Subject: [PATCH 174/546] fix pretty test --- tests/pretty/stmt_expr_attributes.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/pretty/stmt_expr_attributes.rs b/tests/pretty/stmt_expr_attributes.rs index 01a503ce7eea..90d2b2f5e1e6 100644 --- a/tests/pretty/stmt_expr_attributes.rs +++ b/tests/pretty/stmt_expr_attributes.rs @@ -1,6 +1,5 @@ //@ pp-exact -#![feature(inline_const_pat)] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] @@ -206,9 +205,7 @@ fn _11() { let _ = (); () }; - let const { - #![rustc_dummy] - } = + let _ = #[rustc_dummy] const { #![rustc_dummy] }; From 8b2daac8d371c341b92fbdc00876706355b2f69d Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 20 Mar 2025 15:10:42 +0100 Subject: [PATCH 175/546] coretests stop relying on `inline_const_pat` --- library/coretests/tests/lib.rs | 10 +- library/coretests/tests/num/int_macros.rs | 695 +++++++++++---------- library/coretests/tests/num/uint_macros.rs | 495 +++++++-------- 3 files changed, 604 insertions(+), 596 deletions(-) diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 79022fec8a20..7ad154796f64 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -39,7 +39,6 @@ #![feature(generic_assert_internals)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] -#![feature(inline_const_pat)] #![feature(int_roundings)] #![feature(ip)] #![feature(ip_from)] @@ -95,16 +94,17 @@ /// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. macro_rules! assert_eq_const_safe { - ($left:expr, $right:expr) => { - assert_eq_const_safe!($left, $right, concat!(stringify!($left), " == ", stringify!($right))); + ($t:ty: $left:expr, $right:expr) => { + assert_eq_const_safe!($t: $left, $right, concat!(stringify!($left), " == ", stringify!($right))); }; - ($left:expr, $right:expr$(, $($arg:tt)+)?) => { + ($t:ty: $left:expr, $right:expr$(, $($arg:tt)+)?) => { { fn runtime() { assert_eq!($left, $right, $($($arg)*),*); } const fn compiletime() { - assert!(matches!($left, const { $right })); + const PAT: $t = $right; + assert!(matches!($left, PAT), $($($arg)*),*); } core::intrinsics::const_eval_select((), compiletime, runtime) } diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index bbf19d2b444f..0d9fb9e797e1 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -1,5 +1,6 @@ macro_rules! int_module { ($T:ident, $U:ident) => { + use core::num::ParseIntError; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T::*; @@ -32,20 +33,20 @@ macro_rules! int_module { test_runtime_and_compiletime! { fn test_rem_euclid() { - assert_eq_const_safe!((-1 as $T).rem_euclid(MIN), MAX); + assert_eq_const_safe!($T: (-1 as $T).rem_euclid(MIN), MAX); } fn test_abs() { - assert_eq_const_safe!((1 as $T).abs(), 1 as $T); - assert_eq_const_safe!((0 as $T).abs(), 0 as $T); - assert_eq_const_safe!((-1 as $T).abs(), 1 as $T); + assert_eq_const_safe!($T: (1 as $T).abs(), 1 as $T); + assert_eq_const_safe!($T: (0 as $T).abs(), 0 as $T); + assert_eq_const_safe!($T: (-1 as $T).abs(), 1 as $T); } fn test_signum() { - assert_eq_const_safe!((1 as $T).signum(), 1 as $T); - assert_eq_const_safe!((0 as $T).signum(), 0 as $T); - assert_eq_const_safe!((-0 as $T).signum(), 0 as $T); - assert_eq_const_safe!((-1 as $T).signum(), -1 as $T); + assert_eq_const_safe!($T: (1 as $T).signum(), 1 as $T); + assert_eq_const_safe!($T: (0 as $T).signum(), 0 as $T); + assert_eq_const_safe!($T: (-0 as $T).signum(), 0 as $T); + assert_eq_const_safe!($T: (-1 as $T).signum(), -1 as $T); } fn test_is_positive() { @@ -72,123 +73,123 @@ macro_rules! int_module { test_runtime_and_compiletime! { fn test_count_ones() { - assert_eq_const_safe!(A.count_ones(), 3); - assert_eq_const_safe!(B.count_ones(), 2); - assert_eq_const_safe!(C.count_ones(), 5); + assert_eq_const_safe!(u32: A.count_ones(), 3); + assert_eq_const_safe!(u32: B.count_ones(), 2); + assert_eq_const_safe!(u32: C.count_ones(), 5); } fn test_count_zeros() { - assert_eq_const_safe!(A.count_zeros(), $T::BITS - 3); - assert_eq_const_safe!(B.count_zeros(), $T::BITS - 2); - assert_eq_const_safe!(C.count_zeros(), $T::BITS - 5); + assert_eq_const_safe!(u32: A.count_zeros(), $T::BITS - 3); + assert_eq_const_safe!(u32: B.count_zeros(), $T::BITS - 2); + assert_eq_const_safe!(u32: C.count_zeros(), $T::BITS - 5); } fn test_leading_trailing_ones() { const A: $T = 0b0101_1111; - assert_eq_const_safe!(A.trailing_ones(), 5); - assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); + assert_eq_const_safe!(u32: A.trailing_ones(), 5); + assert_eq_const_safe!(u32: (!A).leading_ones(), $T::BITS - 7); - assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); + assert_eq_const_safe!(u32: A.reverse_bits().leading_ones(), 5); - assert_eq_const_safe!(_1.leading_ones(), $T::BITS); - assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); + assert_eq_const_safe!(u32: _1.leading_ones(), $T::BITS); + assert_eq_const_safe!(u32: _1.trailing_ones(), $T::BITS); - assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); - assert_eq_const_safe!(MAX.leading_ones(), 0); + assert_eq_const_safe!(u32: (_1 << 1).trailing_ones(), 0); + assert_eq_const_safe!(u32: MAX.leading_ones(), 0); - assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); - assert_eq_const_safe!(MAX.trailing_ones(), $T::BITS - 1); + assert_eq_const_safe!(u32: (_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq_const_safe!(u32: MAX.trailing_ones(), $T::BITS - 1); - assert_eq_const_safe!(_0.leading_ones(), 0); - assert_eq_const_safe!(_0.trailing_ones(), 0); + assert_eq_const_safe!(u32: _0.leading_ones(), 0); + assert_eq_const_safe!(u32: _0.trailing_ones(), 0); const X: $T = 0b0010_1100; - assert_eq_const_safe!(X.leading_ones(), 0); - assert_eq_const_safe!(X.trailing_ones(), 0); + assert_eq_const_safe!(u32: X.leading_ones(), 0); + assert_eq_const_safe!(u32: X.trailing_ones(), 0); } fn test_rotate() { - assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); - assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); - assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + assert_eq_const_safe!($T: A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq_const_safe!($T: B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq_const_safe!($T: C.rotate_left(6).rotate_right(2).rotate_right(4), C); // Rotating these should make no difference // // We test using 124 bits because to ensure that overlong bit shifts do // not cause undefined behavior. See #10183. - assert_eq_const_safe!(_0.rotate_left(124), _0); - assert_eq_const_safe!(_1.rotate_left(124), _1); - assert_eq_const_safe!(_0.rotate_right(124), _0); - assert_eq_const_safe!(_1.rotate_right(124), _1); + assert_eq_const_safe!($T: _0.rotate_left(124), _0); + assert_eq_const_safe!($T: _1.rotate_left(124), _1); + assert_eq_const_safe!($T: _0.rotate_right(124), _0); + assert_eq_const_safe!($T: _1.rotate_right(124), _1); // Rotating by 0 should have no effect - assert_eq_const_safe!(A.rotate_left(0), A); - assert_eq_const_safe!(B.rotate_left(0), B); - assert_eq_const_safe!(C.rotate_left(0), C); + assert_eq_const_safe!($T: A.rotate_left(0), A); + assert_eq_const_safe!($T: B.rotate_left(0), B); + assert_eq_const_safe!($T: C.rotate_left(0), C); // Rotating by a multiple of word size should also have no effect - assert_eq_const_safe!(A.rotate_left(128), A); - assert_eq_const_safe!(B.rotate_left(128), B); - assert_eq_const_safe!(C.rotate_left(128), C); + assert_eq_const_safe!($T: A.rotate_left(128), A); + assert_eq_const_safe!($T: B.rotate_left(128), B); + assert_eq_const_safe!($T: C.rotate_left(128), C); } fn test_swap_bytes() { - assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); - assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); - assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); + assert_eq_const_safe!($T: A.swap_bytes().swap_bytes(), A); + assert_eq_const_safe!($T: B.swap_bytes().swap_bytes(), B); + assert_eq_const_safe!($T: C.swap_bytes().swap_bytes(), C); // Swapping these should make no difference - assert_eq_const_safe!(_0.swap_bytes(), _0); - assert_eq_const_safe!(_1.swap_bytes(), _1); + assert_eq_const_safe!($T: _0.swap_bytes(), _0); + assert_eq_const_safe!($T: _1.swap_bytes(), _1); } fn test_le() { - assert_eq_const_safe!($T::from_le(A.to_le()), A); - assert_eq_const_safe!($T::from_le(B.to_le()), B); - assert_eq_const_safe!($T::from_le(C.to_le()), C); - assert_eq_const_safe!($T::from_le(_0), _0); - assert_eq_const_safe!($T::from_le(_1), _1); - assert_eq_const_safe!(_0.to_le(), _0); - assert_eq_const_safe!(_1.to_le(), _1); + assert_eq_const_safe!($T: $T::from_le(A.to_le()), A); + assert_eq_const_safe!($T: $T::from_le(B.to_le()), B); + assert_eq_const_safe!($T: $T::from_le(C.to_le()), C); + assert_eq_const_safe!($T: $T::from_le(_0), _0); + assert_eq_const_safe!($T: $T::from_le(_1), _1); + assert_eq_const_safe!($T: _0.to_le(), _0); + assert_eq_const_safe!($T: _1.to_le(), _1); } fn test_be() { - assert_eq_const_safe!($T::from_be(A.to_be()), A); - assert_eq_const_safe!($T::from_be(B.to_be()), B); - assert_eq_const_safe!($T::from_be(C.to_be()), C); - assert_eq_const_safe!($T::from_be(_0), _0); - assert_eq_const_safe!($T::from_be(_1), _1); - assert_eq_const_safe!(_0.to_be(), _0); - assert_eq_const_safe!(_1.to_be(), _1); + assert_eq_const_safe!($T: $T::from_be(A.to_be()), A); + assert_eq_const_safe!($T: $T::from_be(B.to_be()), B); + assert_eq_const_safe!($T: $T::from_be(C.to_be()), C); + assert_eq_const_safe!($T: $T::from_be(_0), _0); + assert_eq_const_safe!($T: $T::from_be(_1), _1); + assert_eq_const_safe!($T: _0.to_be(), _0); + assert_eq_const_safe!($T: _1.to_be(), _1); } fn test_signed_checked_div() { - assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); - assert_eq_const_safe!((5 as $T).checked_div(0), None); - assert_eq_const_safe!(isize::MIN.checked_div(-1), None); + assert_eq_const_safe!(Option<$T>: (10 as $T).checked_div(2), Some(5)); + assert_eq_const_safe!(Option<$T>: (5 as $T).checked_div(0), None); + assert_eq_const_safe!(Option<$T>: $T::MIN.checked_div(-1), None); } fn test_saturating_abs() { - assert_eq_const_safe!((0 as $T).saturating_abs(), 0); - assert_eq_const_safe!((123 as $T).saturating_abs(), 123); - assert_eq_const_safe!((-123 as $T).saturating_abs(), 123); - assert_eq_const_safe!((MAX - 2).saturating_abs(), MAX - 2); - assert_eq_const_safe!((MAX - 1).saturating_abs(), MAX - 1); - assert_eq_const_safe!(MAX.saturating_abs(), MAX); - assert_eq_const_safe!((MIN + 2).saturating_abs(), MAX - 1); - assert_eq_const_safe!((MIN + 1).saturating_abs(), MAX); - assert_eq_const_safe!(MIN.saturating_abs(), MAX); + assert_eq_const_safe!($T: (0 as $T).saturating_abs(), 0); + assert_eq_const_safe!($T: (123 as $T).saturating_abs(), 123); + assert_eq_const_safe!($T: (-123 as $T).saturating_abs(), 123); + assert_eq_const_safe!($T: (MAX - 2).saturating_abs(), MAX - 2); + assert_eq_const_safe!($T: (MAX - 1).saturating_abs(), MAX - 1); + assert_eq_const_safe!($T: MAX.saturating_abs(), MAX); + assert_eq_const_safe!($T: (MIN + 2).saturating_abs(), MAX - 1); + assert_eq_const_safe!($T: (MIN + 1).saturating_abs(), MAX); + assert_eq_const_safe!($T: MIN.saturating_abs(), MAX); } fn test_saturating_neg() { - assert_eq_const_safe!((0 as $T).saturating_neg(), 0); - assert_eq_const_safe!((123 as $T).saturating_neg(), -123); - assert_eq_const_safe!((-123 as $T).saturating_neg(), 123); - assert_eq_const_safe!((MAX - 2).saturating_neg(), MIN + 3); - assert_eq_const_safe!((MAX - 1).saturating_neg(), MIN + 2); - assert_eq_const_safe!(MAX.saturating_neg(), MIN + 1); - assert_eq_const_safe!((MIN + 2).saturating_neg(), MAX - 1); - assert_eq_const_safe!((MIN + 1).saturating_neg(), MAX); - assert_eq_const_safe!(MIN.saturating_neg(), MAX); + assert_eq_const_safe!($T: (0 as $T).saturating_neg(), 0); + assert_eq_const_safe!($T: (123 as $T).saturating_neg(), -123); + assert_eq_const_safe!($T: (-123 as $T).saturating_neg(), 123); + assert_eq_const_safe!($T: (MAX - 2).saturating_neg(), MIN + 3); + assert_eq_const_safe!($T: (MAX - 1).saturating_neg(), MIN + 2); + assert_eq_const_safe!($T: MAX.saturating_neg(), MIN + 1); + assert_eq_const_safe!($T: (MIN + 2).saturating_neg(), MAX - 1); + assert_eq_const_safe!($T: (MIN + 1).saturating_neg(), MAX); + assert_eq_const_safe!($T: MIN.saturating_neg(), MAX); } } @@ -250,23 +251,23 @@ macro_rules! int_module { test_runtime_and_compiletime! { fn test_from_str_radix() { - assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq_const_safe!(i32::from_str_radix("123", 16), Ok(291 as i32)); - assert_eq_const_safe!(i32::from_str_radix("ffff", 16), Ok(65535 as i32)); - assert_eq_const_safe!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); - assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); - assert_eq_const_safe!($T::from_str_radix("Z", 36), Ok(35 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq_const_safe!(Result: i32::from_str_radix("123", 16), Ok(291 as i32)); + assert_eq_const_safe!(Result: i32::from_str_radix("ffff", 16), Ok(65535 as i32)); + assert_eq_const_safe!(Result: i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("z", 36), Ok(35 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("Z", 36), Ok(35 as $T)); - assert_eq_const_safe!($T::from_str_radix("-123", 10), Ok(-123 as $T)); - assert_eq_const_safe!($T::from_str_radix("-1001", 2), Ok(-9 as $T)); - assert_eq_const_safe!($T::from_str_radix("-123", 8), Ok(-83 as $T)); - assert_eq_const_safe!(i32::from_str_radix("-123", 16), Ok(-291 as i32)); - assert_eq_const_safe!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); - assert_eq_const_safe!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); - assert_eq_const_safe!($T::from_str_radix("-z", 36), Ok(-35 as $T)); - assert_eq_const_safe!($T::from_str_radix("-Z", 36), Ok(-35 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("-123", 10), Ok(-123 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("-1001", 2), Ok(-9 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("-123", 8), Ok(-83 as $T)); + assert_eq_const_safe!(Result: i32::from_str_radix("-123", 16), Ok(-291 as i32)); + assert_eq_const_safe!(Result: i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); + assert_eq_const_safe!(Result: i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("-z", 36), Ok(-35 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("-Z", 36), Ok(-35 as $T)); assert!($T::from_str_radix("Z", 35).is_err()); assert!($T::from_str_radix("-9", 2).is_err()); @@ -277,16 +278,16 @@ macro_rules! int_module { fn test_pow() { { const R: $T = 2; - assert_eq_const_safe!(R.pow(2), 4 as $T); - assert_eq_const_safe!(R.pow(0), 1 as $T); - assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); - assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); - assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); - assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); - assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); - assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); - assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + assert_eq_const_safe!($T: R.pow(2), 4 as $T); + assert_eq_const_safe!($T: R.pow(0), 1 as $T); + assert_eq_const_safe!($T: R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!($T: R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(Option<$T>: R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(Option<$T>: R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!($T: R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!($T: R.saturating_pow(0), 1 as $T); } { @@ -295,221 +296,227 @@ macro_rules! int_module { // if itest::MAX == 2^j-1, then itest is a `j` bit int, // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, // thussaturating_pow the overflowing result is exactly 1. - assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), None); - assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); - assert_eq_const_safe!(R.saturating_pow(2), MAX); + assert_eq_const_safe!($T: R.wrapping_pow(2), 1 as $T); + assert_eq_const_safe!(Option<$T>: R.checked_pow(2), None); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(2), (1 as $T, true)); + assert_eq_const_safe!($T: R.saturating_pow(2), MAX); } { // test for negative exponent. const R: $T = -2; - assert_eq_const_safe!(R.pow(2), 4 as $T); - assert_eq_const_safe!(R.pow(3), -8 as $T); - assert_eq_const_safe!(R.pow(0), 1 as $T); - assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); - assert_eq_const_safe!(R.wrapping_pow(3), -8 as $T); - assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); - assert_eq_const_safe!(R.checked_pow(3), Some(-8 as $T)); - assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); - assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); - assert_eq_const_safe!(R.overflowing_pow(3), (-8 as $T, false)); - assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); - assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); - assert_eq_const_safe!(R.saturating_pow(3), -8 as $T); - assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + assert_eq_const_safe!($T: R.pow(2), 4 as $T); + assert_eq_const_safe!($T: R.pow(3), -8 as $T); + assert_eq_const_safe!($T: R.pow(0), 1 as $T); + assert_eq_const_safe!($T: R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!($T: R.wrapping_pow(3), -8 as $T); + assert_eq_const_safe!($T: R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(Option<$T>: R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(Option<$T>: R.checked_pow(3), Some(-8 as $T)); + assert_eq_const_safe!(Option<$T>: R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(3), (-8 as $T, false)); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!($T: R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!($T: R.saturating_pow(3), -8 as $T); + assert_eq_const_safe!($T: R.saturating_pow(0), 1 as $T); } } fn test_div_floor() { const A: $T = 8; const B: $T = 3; - assert_eq_const_safe!(A.div_floor(B), 2); - assert_eq_const_safe!(A.div_floor(-B), -3); - assert_eq_const_safe!((-A).div_floor(B), -3); - assert_eq_const_safe!((-A).div_floor(-B), 2); + assert_eq_const_safe!($T: A.div_floor(B), 2); + assert_eq_const_safe!($T: A.div_floor(-B), -3); + assert_eq_const_safe!($T: (-A).div_floor(B), -3); + assert_eq_const_safe!($T: (-A).div_floor(-B), 2); } fn test_div_ceil() { const A: $T = 8; const B: $T = 3; - assert_eq_const_safe!(A.div_ceil(B), 3); - assert_eq_const_safe!(A.div_ceil(-B), -2); - assert_eq_const_safe!((-A).div_ceil(B), -2); - assert_eq_const_safe!((-A).div_ceil(-B), 3); + assert_eq_const_safe!($T: A.div_ceil(B), 3); + assert_eq_const_safe!($T: A.div_ceil(-B), -2); + assert_eq_const_safe!($T: (-A).div_ceil(B), -2); + assert_eq_const_safe!($T: (-A).div_ceil(-B), 3); } fn test_next_multiple_of() { - assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); - assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); - assert_eq_const_safe!((16 as $T).next_multiple_of(-8), 16); - assert_eq_const_safe!((23 as $T).next_multiple_of(-8), 16); - assert_eq_const_safe!((-16 as $T).next_multiple_of(8), -16); - assert_eq_const_safe!((-23 as $T).next_multiple_of(8), -16); - assert_eq_const_safe!((-16 as $T).next_multiple_of(-8), -16); - assert_eq_const_safe!((-23 as $T).next_multiple_of(-8), -24); - assert_eq_const_safe!(MIN.next_multiple_of(-1), MIN); + assert_eq_const_safe!($T: (16 as $T).next_multiple_of(8), 16); + assert_eq_const_safe!($T: (23 as $T).next_multiple_of(8), 24); + assert_eq_const_safe!($T: (16 as $T).next_multiple_of(-8), 16); + assert_eq_const_safe!($T: (23 as $T).next_multiple_of(-8), 16); + assert_eq_const_safe!($T: (-16 as $T).next_multiple_of(8), -16); + assert_eq_const_safe!($T: (-23 as $T).next_multiple_of(8), -16); + assert_eq_const_safe!($T: (-16 as $T).next_multiple_of(-8), -16); + assert_eq_const_safe!($T: (-23 as $T).next_multiple_of(-8), -24); + assert_eq_const_safe!($T: MIN.next_multiple_of(-1), MIN); } fn test_checked_next_multiple_of() { - assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); - assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); - assert_eq_const_safe!((16 as $T).checked_next_multiple_of(-8), Some(16)); - assert_eq_const_safe!((23 as $T).checked_next_multiple_of(-8), Some(16)); - assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(8), Some(-16)); - assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(8), Some(-16)); - assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(-8), Some(-16)); - assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(-8), Some(-24)); - assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); - assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); - assert_eq_const_safe!(MIN.checked_next_multiple_of(-3), None); - assert_eq_const_safe!(MIN.checked_next_multiple_of(-1), Some(MIN)); + assert_eq_const_safe!(Option<$T>: (16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq_const_safe!(Option<$T>: (23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq_const_safe!(Option<$T>: (16 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq_const_safe!(Option<$T>: (23 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq_const_safe!(Option<$T>: (-16 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq_const_safe!(Option<$T>: (-23 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq_const_safe!(Option<$T>: (-16 as $T).checked_next_multiple_of(-8), Some(-16)); + assert_eq_const_safe!(Option<$T>: (-23 as $T).checked_next_multiple_of(-8), Some(-24)); + assert_eq_const_safe!(Option<$T>: (1 as $T).checked_next_multiple_of(0), None); + assert_eq_const_safe!(Option<$T>: MAX.checked_next_multiple_of(2), None); + assert_eq_const_safe!(Option<$T>: MIN.checked_next_multiple_of(-3), None); + assert_eq_const_safe!(Option<$T>: MIN.checked_next_multiple_of(-1), Some(MIN)); } fn test_carrying_add() { - assert_eq_const_safe!(MAX.carrying_add(1, false), (MIN, true)); - assert_eq_const_safe!(MAX.carrying_add(0, true), (MIN, true)); - assert_eq_const_safe!(MAX.carrying_add(1, true), (MIN + 1, true)); - assert_eq_const_safe!(MAX.carrying_add(-1, false), (MAX - 1, false)); - assert_eq_const_safe!(MAX.carrying_add(-1, true), (MAX, false)); // no intermediate overflow - assert_eq_const_safe!(MIN.carrying_add(-1, false), (MAX, true)); - assert_eq_const_safe!(MIN.carrying_add(-1, true), (MIN, false)); // no intermediate overflow - assert_eq_const_safe!((0 as $T).carrying_add(MAX, true), (MIN, true)); - assert_eq_const_safe!((0 as $T).carrying_add(MIN, true), (MIN + 1, false)); + assert_eq_const_safe!(($T, bool): MAX.carrying_add(1, false), (MIN, true)); + assert_eq_const_safe!(($T, bool): MAX.carrying_add(0, true), (MIN, true)); + assert_eq_const_safe!(($T, bool): MAX.carrying_add(1, true), (MIN + 1, true)); + assert_eq_const_safe!(($T, bool): MAX.carrying_add(-1, false), (MAX - 1, false)); + assert_eq_const_safe!(($T, bool): MAX.carrying_add(-1, true), (MAX, false)); // no intermediate overflow + assert_eq_const_safe!(($T, bool): MIN.carrying_add(-1, false), (MAX, true)); + assert_eq_const_safe!(($T, bool): MIN.carrying_add(-1, true), (MIN, false)); // no intermediate overflow + assert_eq_const_safe!(($T, bool): (0 as $T).carrying_add(MAX, true), (MIN, true)); + assert_eq_const_safe!(($T, bool): (0 as $T).carrying_add(MIN, true), (MIN + 1, false)); } fn test_borrowing_sub() { - assert_eq_const_safe!(MIN.borrowing_sub(1, false), (MAX, true)); - assert_eq_const_safe!(MIN.borrowing_sub(0, true), (MAX, true)); - assert_eq_const_safe!(MIN.borrowing_sub(1, true), (MAX - 1, true)); - assert_eq_const_safe!(MIN.borrowing_sub(-1, false), (MIN + 1, false)); - assert_eq_const_safe!(MIN.borrowing_sub(-1, true), (MIN, false)); // no intermediate overflow - assert_eq_const_safe!(MAX.borrowing_sub(-1, false), (MIN, true)); - assert_eq_const_safe!(MAX.borrowing_sub(-1, true), (MAX, false)); // no intermediate overflow - assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, false), (MIN, true)); - assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, true), (MAX, false)); + assert_eq_const_safe!(($T, bool): MIN.borrowing_sub(1, false), (MAX, true)); + assert_eq_const_safe!(($T, bool): MIN.borrowing_sub(0, true), (MAX, true)); + assert_eq_const_safe!(($T, bool): MIN.borrowing_sub(1, true), (MAX - 1, true)); + assert_eq_const_safe!(($T, bool): MIN.borrowing_sub(-1, false), (MIN + 1, false)); + assert_eq_const_safe!(($T, bool): MIN.borrowing_sub(-1, true), (MIN, false)); // no intermediate overflow + assert_eq_const_safe!(($T, bool): MAX.borrowing_sub(-1, false), (MIN, true)); + assert_eq_const_safe!(($T, bool): MAX.borrowing_sub(-1, true), (MAX, false)); // no intermediate overflow + assert_eq_const_safe!(($T, bool): (0 as $T).borrowing_sub(MIN, false), (MIN, true)); + assert_eq_const_safe!(($T, bool): (0 as $T).borrowing_sub(MIN, true), (MAX, false)); } fn test_widening_mul() { - assert_eq_const_safe!(MAX.widening_mul(MAX), (1, MAX / 2)); - assert_eq_const_safe!(MIN.widening_mul(MAX), (MIN as $U, MIN / 2)); - assert_eq_const_safe!(MIN.widening_mul(MIN), (0, MAX / 2 + 1)); + assert_eq_const_safe!(($U, $T): MAX.widening_mul(MAX), (1, MAX / 2)); + assert_eq_const_safe!(($U, $T): MIN.widening_mul(MAX), (MIN as $U, MIN / 2)); + assert_eq_const_safe!(($U, $T): MIN.widening_mul(MIN), (0, MAX / 2 + 1)); } fn test_carrying_mul() { - assert_eq_const_safe!(MAX.carrying_mul(MAX, 0), (1, MAX / 2)); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MAX.carrying_mul(MAX, 0), (1, MAX / 2)); + assert_eq_const_safe!(($U, $T): MAX.carrying_mul(MAX, MAX), (UMAX / 2 + 1, MAX / 2) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MAX.carrying_mul(MAX, MIN), (UMAX / 2 + 2, MAX / 2 - 1) ); - assert_eq_const_safe!(MIN.carrying_mul(MAX, 0), (MIN as $U, MIN / 2)); - assert_eq_const_safe!(MIN.carrying_mul(MAX, MAX), (UMAX, MIN / 2)); - assert_eq_const_safe!(MIN.carrying_mul(MAX, MIN), (0, MIN / 2)); - assert_eq_const_safe!(MIN.carrying_mul(MIN, 0), (0, MAX / 2 + 1)); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul(MAX, 0), (MIN as $U, MIN / 2)); + assert_eq_const_safe!(($U, $T): MIN.carrying_mul(MAX, MAX), (UMAX, MIN / 2)); + assert_eq_const_safe!(($U, $T): MIN.carrying_mul(MAX, MIN), (0, MIN / 2)); + assert_eq_const_safe!(($U, $T): MIN.carrying_mul(MIN, 0), (0, MAX / 2 + 1)); + assert_eq_const_safe!(($U, $T): MIN.carrying_mul(MIN, MAX), (UMAX / 2, MAX / 2 + 1) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul(MIN, MIN), (UMAX / 2 + 1, MAX / 2) ); } fn test_carrying_mul_add() { - assert_eq_const_safe!(MAX.carrying_mul_add(MAX, 0, 0), (1, MAX / 2)); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MAX.carrying_mul_add(MAX, 0, 0), (1, MAX / 2)); + assert_eq_const_safe!(($U, $T): MAX.carrying_mul_add(MAX, MAX, 0), (UMAX / 2 + 1, MAX / 2) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MAX.carrying_mul_add(MAX, MIN, 0), (UMAX / 2 + 2, MAX / 2 - 1) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MAX.carrying_mul_add(MAX, MAX, MAX), (UMAX, MAX / 2) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MAX.carrying_mul_add(MAX, MAX, MIN), (0, MAX / 2) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MAX.carrying_mul_add(MAX, MIN, MIN), (1, MAX / 2 - 1) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MAX, 0, 0), (MIN as $U, MIN / 2) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MAX, MAX, 0), (UMAX, MIN / 2) ); - assert_eq_const_safe!(MIN.carrying_mul_add(MAX, MIN, 0), (0, MIN / 2)); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): + MIN.carrying_mul_add(MAX, MIN, 0), + (0, MIN / 2) + ); + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MAX, MAX, MAX), (UMAX / 2 - 1, MIN / 2 + 1) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MAX, MAX, MIN), (UMAX / 2, MIN / 2) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MAX, MIN, MIN), (UMAX / 2 + 1, MIN / 2 - 1) ); - assert_eq_const_safe!(MIN.carrying_mul_add(MIN, 0, 0), (0, MAX / 2 + 1)); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): + MIN.carrying_mul_add(MIN, 0, 0), + (0, MAX / 2 + 1) + ); + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MIN, MAX, 0), (UMAX / 2, MAX / 2 + 1) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MIN, MIN, 0), (UMAX / 2 + 1, MAX / 2) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MIN, MAX, MAX), (UMAX - 1, MAX / 2 + 1) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MIN, MAX, MIN), (UMAX, MAX / 2) ); - assert_eq_const_safe!( + assert_eq_const_safe!(($U, $T): MIN.carrying_mul_add(MIN, MIN, MIN), (0, MAX / 2) ); } fn test_midpoint() { - assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); - assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); + assert_eq_const_safe!($T: <$T>::midpoint(1, 3), 2); + assert_eq_const_safe!($T: <$T>::midpoint(3, 1), 2); - assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); - assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); - assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); - assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); + assert_eq_const_safe!($T: <$T>::midpoint(0, 0), 0); + assert_eq_const_safe!($T: <$T>::midpoint(0, 2), 1); + assert_eq_const_safe!($T: <$T>::midpoint(2, 0), 1); + assert_eq_const_safe!($T: <$T>::midpoint(2, 2), 2); - assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); - assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); - assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); - assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); + assert_eq_const_safe!($T: <$T>::midpoint(1, 4), 2); + assert_eq_const_safe!($T: <$T>::midpoint(4, 1), 2); + assert_eq_const_safe!($T: <$T>::midpoint(3, 4), 3); + assert_eq_const_safe!($T: <$T>::midpoint(4, 3), 3); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), 0); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), 0); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MIN, <$T>::MAX), 0); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MAX, <$T>::MIN), 0); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq_const_safe!($T: <$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); + assert_eq_const_safe!($T: <$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); } } @@ -526,154 +533,154 @@ macro_rules! int_module { test_runtime_and_compiletime! { fn test_unbounded_shl() { // <$T>::MIN - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); // <$T>::MAX - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); // 1 - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, 1), (1 << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, 3), (1 << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, 5), (1 << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0); // -1 - assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_ONE), (-1 << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_TWO), (-1 << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_THREE), (-1 << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, 1), (-1 << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, 3), (-1 << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, 5), (-1 << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_ONE), (-1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_TWO), (-1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_THREE), (-1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, 1), (-1 << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, 3), (-1 << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, 5), (-1 << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW3), 0); // 8 - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, 1), (8 << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, 3), (8 << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, 5), (8 << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0); // 17 - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, 1), (17 << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, 3), (17 << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, 5), (17 << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0); } fn test_unbounded_shr() { // <$T>::MIN - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), -1); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), -1); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), -1); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), -1); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), -1); // <$T>::MAX - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); // 1 - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, 1), (1 >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, 3), (1 >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, 5), (1 >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0); // -1 - assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_ONE), (-1 >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_TWO), (-1 >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_THREE), (-1 >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, 1), (-1 >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, 3), (-1 >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, 5), (-1 >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW2), -1); - assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW3), -1); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_ONE), (-1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_TWO), (-1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_THREE), (-1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, 1), (-1 >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, 3), (-1 >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, 5), (-1 >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW2), -1); + assert_eq_const_safe!($T: <$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW3), -1); // 8 - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, 1), (8 >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, 3), (8 >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, 5), (8 >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0); // 17 - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, 1), (17 >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, 3), (17 >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, 5), (17 >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); } } }; diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index d09eb97b17e0..2e35e8bf5342 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -1,5 +1,6 @@ macro_rules! uint_module { ($T:ident) => { + use core::num::ParseIntError; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T::*; @@ -49,95 +50,95 @@ macro_rules! uint_module { fn test_leading_trailing_ones() { const A: $T = 0b0101_1111; - assert_eq_const_safe!(A.trailing_ones(), 5); - assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); + assert_eq_const_safe!(u32: A.trailing_ones(), 5); + assert_eq_const_safe!(u32: (!A).leading_ones(), $T::BITS - 7); - assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); + assert_eq_const_safe!(u32: A.reverse_bits().leading_ones(), 5); - assert_eq_const_safe!(_1.leading_ones(), $T::BITS); - assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); + assert_eq_const_safe!(u32: _1.leading_ones(), $T::BITS); + assert_eq_const_safe!(u32: _1.trailing_ones(), $T::BITS); - assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); - assert_eq_const_safe!((_1 >> 1).leading_ones(), 0); + assert_eq_const_safe!(u32: (_1 << 1).trailing_ones(), 0); + assert_eq_const_safe!(u32: (_1 >> 1).leading_ones(), 0); - assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); - assert_eq_const_safe!((_1 >> 1).trailing_ones(), $T::BITS - 1); + assert_eq_const_safe!(u32: (_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq_const_safe!(u32: (_1 >> 1).trailing_ones(), $T::BITS - 1); - assert_eq_const_safe!(_0.leading_ones(), 0); - assert_eq_const_safe!(_0.trailing_ones(), 0); + assert_eq_const_safe!(u32: _0.leading_ones(), 0); + assert_eq_const_safe!(u32: _0.trailing_ones(), 0); const X: $T = 0b0010_1100; - assert_eq_const_safe!(X.leading_ones(), 0); - assert_eq_const_safe!(X.trailing_ones(), 0); + assert_eq_const_safe!(u32: X.leading_ones(), 0); + assert_eq_const_safe!(u32: X.trailing_ones(), 0); } fn test_rotate() { - assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); - assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); - assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + assert_eq_const_safe!($T: A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq_const_safe!($T: B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq_const_safe!($T: C.rotate_left(6).rotate_right(2).rotate_right(4), C); // Rotating these should make no difference // // We test using 124 bits because to ensure that overlong bit shifts do // not cause undefined behavior. See #10183. - assert_eq_const_safe!(_0.rotate_left(124), _0); - assert_eq_const_safe!(_1.rotate_left(124), _1); - assert_eq_const_safe!(_0.rotate_right(124), _0); - assert_eq_const_safe!(_1.rotate_right(124), _1); + assert_eq_const_safe!($T: _0.rotate_left(124), _0); + assert_eq_const_safe!($T: _1.rotate_left(124), _1); + assert_eq_const_safe!($T: _0.rotate_right(124), _0); + assert_eq_const_safe!($T: _1.rotate_right(124), _1); // Rotating by 0 should have no effect - assert_eq_const_safe!(A.rotate_left(0), A); - assert_eq_const_safe!(B.rotate_left(0), B); - assert_eq_const_safe!(C.rotate_left(0), C); + assert_eq_const_safe!($T: A.rotate_left(0), A); + assert_eq_const_safe!($T: B.rotate_left(0), B); + assert_eq_const_safe!($T: C.rotate_left(0), C); // Rotating by a multiple of word size should also have no effect - assert_eq_const_safe!(A.rotate_left(128), A); - assert_eq_const_safe!(B.rotate_left(128), B); - assert_eq_const_safe!(C.rotate_left(128), C); + assert_eq_const_safe!($T: A.rotate_left(128), A); + assert_eq_const_safe!($T: B.rotate_left(128), B); + assert_eq_const_safe!($T: C.rotate_left(128), C); } fn test_swap_bytes() { - assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); - assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); - assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); + assert_eq_const_safe!($T: A.swap_bytes().swap_bytes(), A); + assert_eq_const_safe!($T: B.swap_bytes().swap_bytes(), B); + assert_eq_const_safe!($T: C.swap_bytes().swap_bytes(), C); // Swapping these should make no difference - assert_eq_const_safe!(_0.swap_bytes(), _0); - assert_eq_const_safe!(_1.swap_bytes(), _1); + assert_eq_const_safe!($T: _0.swap_bytes(), _0); + assert_eq_const_safe!($T: _1.swap_bytes(), _1); } fn test_reverse_bits() { - assert_eq_const_safe!(A.reverse_bits().reverse_bits(), A); - assert_eq_const_safe!(B.reverse_bits().reverse_bits(), B); - assert_eq_const_safe!(C.reverse_bits().reverse_bits(), C); + assert_eq_const_safe!($T: A.reverse_bits().reverse_bits(), A); + assert_eq_const_safe!($T: B.reverse_bits().reverse_bits(), B); + assert_eq_const_safe!($T: C.reverse_bits().reverse_bits(), C); // Swapping these should make no difference - assert_eq_const_safe!(_0.reverse_bits(), _0); - assert_eq_const_safe!(_1.reverse_bits(), _1); + assert_eq_const_safe!($T: _0.reverse_bits(), _0); + assert_eq_const_safe!($T: _1.reverse_bits(), _1); } fn test_le() { - assert_eq_const_safe!($T::from_le(A.to_le()), A); - assert_eq_const_safe!($T::from_le(B.to_le()), B); - assert_eq_const_safe!($T::from_le(C.to_le()), C); - assert_eq_const_safe!($T::from_le(_0), _0); - assert_eq_const_safe!($T::from_le(_1), _1); - assert_eq_const_safe!(_0.to_le(), _0); - assert_eq_const_safe!(_1.to_le(), _1); + assert_eq_const_safe!($T: $T::from_le(A.to_le()), A); + assert_eq_const_safe!($T: $T::from_le(B.to_le()), B); + assert_eq_const_safe!($T: $T::from_le(C.to_le()), C); + assert_eq_const_safe!($T: $T::from_le(_0), _0); + assert_eq_const_safe!($T: $T::from_le(_1), _1); + assert_eq_const_safe!($T: _0.to_le(), _0); + assert_eq_const_safe!($T: _1.to_le(), _1); } fn test_be() { - assert_eq_const_safe!($T::from_be(A.to_be()), A); - assert_eq_const_safe!($T::from_be(B.to_be()), B); - assert_eq_const_safe!($T::from_be(C.to_be()), C); - assert_eq_const_safe!($T::from_be(_0), _0); - assert_eq_const_safe!($T::from_be(_1), _1); - assert_eq_const_safe!(_0.to_be(), _0); - assert_eq_const_safe!(_1.to_be(), _1); + assert_eq_const_safe!($T: $T::from_be(A.to_be()), A); + assert_eq_const_safe!($T: $T::from_be(B.to_be()), B); + assert_eq_const_safe!($T: $T::from_be(C.to_be()), C); + assert_eq_const_safe!($T: $T::from_be(_0), _0); + assert_eq_const_safe!($T: $T::from_be(_1), _1); + assert_eq_const_safe!($T: _0.to_be(), _0); + assert_eq_const_safe!($T: _1.to_be(), _1); } fn test_unsigned_checked_div() { - assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); - assert_eq_const_safe!((5 as $T).checked_div(0), None); + assert_eq_const_safe!(Option<$T>: (10 as $T).checked_div(2), Some(5)); + assert_eq_const_safe!(Option<$T>: (5 as $T).checked_div(0), None); } } @@ -194,12 +195,12 @@ macro_rules! uint_module { test_runtime_and_compiletime! { fn test_parse_bytes() { - assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq_const_safe!(u16::from_str_radix("123", 16), Ok(291 as u16)); - assert_eq_const_safe!(u16::from_str_radix("ffff", 16), Ok(65535 as u16)); - assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq_const_safe!(Result: u16::from_str_radix("123", 16), Ok(291 as u16)); + assert_eq_const_safe!(Result: u16::from_str_radix("ffff", 16), Ok(65535 as u16)); + assert_eq_const_safe!(Result<$T, ParseIntError>: $T::from_str_radix("z", 36), Ok(35 as $T)); assert!($T::from_str_radix("Z", 10).is_err()); assert!($T::from_str_radix("_", 2).is_err()); @@ -208,16 +209,16 @@ macro_rules! uint_module { fn test_pow() { { const R: $T = 2; - assert_eq_const_safe!(R.pow(2), 4 as $T); - assert_eq_const_safe!(R.pow(0), 1 as $T); - assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); - assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); - assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); - assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); - assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); - assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); - assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + assert_eq_const_safe!($T: R.pow(2), 4 as $T); + assert_eq_const_safe!($T: R.pow(0), 1 as $T); + assert_eq_const_safe!($T: R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!($T: R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(Option<$T>: R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(Option<$T>: R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!($T: R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!($T: R.saturating_pow(0), 1 as $T); } { @@ -226,20 +227,20 @@ macro_rules! uint_module { // if itest::MAX == 2^j-1, then itest is a `j` bit int, // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, // thussaturating_pow the overflowing result is exactly 1. - assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), None); - assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); - assert_eq_const_safe!(R.saturating_pow(2), MAX); + assert_eq_const_safe!($T: R.wrapping_pow(2), 1 as $T); + assert_eq_const_safe!(Option<$T>: R.checked_pow(2), None); + assert_eq_const_safe!(($T, bool): R.overflowing_pow(2), (1 as $T, true)); + assert_eq_const_safe!($T: R.saturating_pow(2), MAX); } } fn test_isqrt() { - assert_eq_const_safe!((0 as $T).isqrt(), 0 as $T); - assert_eq_const_safe!((1 as $T).isqrt(), 1 as $T); - assert_eq_const_safe!((2 as $T).isqrt(), 1 as $T); - assert_eq_const_safe!((99 as $T).isqrt(), 9 as $T); - assert_eq_const_safe!((100 as $T).isqrt(), 10 as $T); - assert_eq_const_safe!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); + assert_eq_const_safe!($T: (0 as $T).isqrt(), 0 as $T); + assert_eq_const_safe!($T: (1 as $T).isqrt(), 1 as $T); + assert_eq_const_safe!($T: (2 as $T).isqrt(), 1 as $T); + assert_eq_const_safe!($T: (99 as $T).isqrt(), 9 as $T); + assert_eq_const_safe!($T: (100 as $T).isqrt(), 10 as $T); + assert_eq_const_safe!($T: $T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); } } @@ -264,24 +265,24 @@ macro_rules! uint_module { test_runtime_and_compiletime! { fn test_div_floor() { - assert_eq_const_safe!((8 as $T).div_floor(3), 2); + assert_eq_const_safe!($T: (8 as $T).div_floor(3), 2); } fn test_div_ceil() { - assert_eq_const_safe!((8 as $T).div_ceil(3), 3); + assert_eq_const_safe!($T: (8 as $T).div_ceil(3), 3); } fn test_next_multiple_of() { - assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); - assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); - assert_eq_const_safe!(MAX.next_multiple_of(1), MAX); + assert_eq_const_safe!($T: (16 as $T).next_multiple_of(8), 16); + assert_eq_const_safe!($T: (23 as $T).next_multiple_of(8), 24); + assert_eq_const_safe!($T: MAX.next_multiple_of(1), MAX); } fn test_checked_next_multiple_of() { - assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); - assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); - assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); - assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); + assert_eq_const_safe!(Option<$T>: (16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq_const_safe!(Option<$T>: (23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq_const_safe!(Option<$T>: (1 as $T).checked_next_multiple_of(0), None); + assert_eq_const_safe!(Option<$T>: MAX.checked_next_multiple_of(2), None); } fn test_is_next_multiple_of() { @@ -292,63 +293,63 @@ macro_rules! uint_module { } fn test_carrying_add() { - assert_eq_const_safe!($T::MAX.carrying_add(1, false), (0, true)); - assert_eq_const_safe!($T::MAX.carrying_add(0, true), (0, true)); - assert_eq_const_safe!($T::MAX.carrying_add(1, true), (1, true)); + assert_eq_const_safe!(($T, bool): $T::MAX.carrying_add(1, false), (0, true)); + assert_eq_const_safe!(($T, bool): $T::MAX.carrying_add(0, true), (0, true)); + assert_eq_const_safe!(($T, bool): $T::MAX.carrying_add(1, true), (1, true)); - assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); - assert_eq_const_safe!($T::MIN.carrying_add(0, true), (1, false)); - assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, true), (0, true)); + assert_eq_const_safe!(($T, bool): $T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); + assert_eq_const_safe!(($T, bool): $T::MIN.carrying_add(0, true), (1, false)); + assert_eq_const_safe!(($T, bool): $T::MIN.carrying_add($T::MAX, true), (0, true)); } fn test_borrowing_sub() { - assert_eq_const_safe!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); - assert_eq_const_safe!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); - assert_eq_const_safe!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + assert_eq_const_safe!(($T, bool): $T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq_const_safe!(($T, bool): $T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq_const_safe!(($T, bool): $T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); - assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); - assert_eq_const_safe!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); - assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); + assert_eq_const_safe!(($T, bool): $T::MAX.borrowing_sub($T::MAX, false), (0, false)); + assert_eq_const_safe!(($T, bool): $T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); + assert_eq_const_safe!(($T, bool): $T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); } fn test_widening_mul() { - assert_eq_const_safe!($T::MAX.widening_mul($T::MAX), (1, $T::MAX - 1)); + assert_eq_const_safe!(($T, $T): $T::MAX.widening_mul($T::MAX), (1, $T::MAX - 1)); } fn test_carrying_mul() { - assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, 0), (1, $T::MAX - 1)); - assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, $T::MAX), (0, $T::MAX)); + assert_eq_const_safe!(($T, $T): $T::MAX.carrying_mul($T::MAX, 0), (1, $T::MAX - 1)); + assert_eq_const_safe!(($T, $T): $T::MAX.carrying_mul($T::MAX, $T::MAX), (0, $T::MAX)); } fn test_carrying_mul_add() { - assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, 0, 0), (1, $T::MAX - 1)); - assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, 0), (0, $T::MAX)); - assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, $T::MAX), ($T::MAX, $T::MAX)); + assert_eq_const_safe!(($T, $T): $T::MAX.carrying_mul_add($T::MAX, 0, 0), (1, $T::MAX - 1)); + assert_eq_const_safe!(($T, $T): $T::MAX.carrying_mul_add($T::MAX, $T::MAX, 0), (0, $T::MAX)); + assert_eq_const_safe!(($T, $T): $T::MAX.carrying_mul_add($T::MAX, $T::MAX, $T::MAX), ($T::MAX, $T::MAX)); } fn test_midpoint() { - assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); - assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); + assert_eq_const_safe!($T: <$T>::midpoint(1, 3), 2); + assert_eq_const_safe!($T: <$T>::midpoint(3, 1), 2); - assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); - assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); - assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); - assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); + assert_eq_const_safe!($T: <$T>::midpoint(0, 0), 0); + assert_eq_const_safe!($T: <$T>::midpoint(0, 2), 1); + assert_eq_const_safe!($T: <$T>::midpoint(2, 0), 1); + assert_eq_const_safe!($T: <$T>::midpoint(2, 2), 2); - assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); - assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); - assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); - assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); + assert_eq_const_safe!($T: <$T>::midpoint(1, 4), 2); + assert_eq_const_safe!($T: <$T>::midpoint(4, 1), 2); + assert_eq_const_safe!($T: <$T>::midpoint(3, 4), 3); + assert_eq_const_safe!($T: <$T>::midpoint(4, 3), 3); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq_const_safe!($T: <$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq_const_safe!($T: <$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); + assert_eq_const_safe!($T: <$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); } } @@ -365,154 +366,154 @@ macro_rules! uint_module { test_runtime_and_compiletime! { fn test_unbounded_shl() { // <$T>::MIN - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); // <$T>::MAX - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); // 1 - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, 1), (1 << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, 3), (1 << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, 5), (1 << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0); // !0 - assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_ONE), (!0 << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_TWO), (!0 << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_THREE), (!0 << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, 1), (!0 << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, 3), (!0 << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, 5), (!0 << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_ONE), (!0 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_TWO), (!0 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_THREE), (!0 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, 1), (!0 << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, 3), (!0 << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, 5), (!0 << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW3), 0); // 8 - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, 1), (8 << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, 3), (8 << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, 5), (8 << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0); // 17 - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5)); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, 1), (17 << 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, 3), (17 << 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, 5), (17 << 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0); } fn test_unbounded_shr() { // <$T>::MIN - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); // <$T>::MAX - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); // 1 - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, 1), (1 >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, 3), (1 >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, 5), (1 >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0); // !0 - assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_ONE), (!0 >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_TWO), (!0 >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_THREE), (!0 >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, 1), (!0 >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, 3), (!0 >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, 5), (!0 >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_ONE), (!0 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_TWO), (!0 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_THREE), (!0 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, 1), (!0 >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, 3), (!0 >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, 5), (!0 >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW3), 0); // 8 - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, 1), (8 >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, 3), (8 >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, 5), (8 >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0); // 17 - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5)); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0); - assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, 1), (17 >> 1)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, 3), (17 >> 3)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, 5), (17 >> 5)); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); } } }; From a3b7990b9a3c42a4bf479ea27604927c45fd7172 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 21 Mar 2025 09:35:22 +0100 Subject: [PATCH 176/546] update rustfmt test --- src/tools/rustfmt/tests/source/pattern.rs | 2 +- src/tools/rustfmt/tests/target/pattern.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rustfmt/tests/source/pattern.rs b/src/tools/rustfmt/tests/source/pattern.rs index ed6ad690fa98..0e5abb52394d 100644 --- a/src/tools/rustfmt/tests/source/pattern.rs +++ b/src/tools/rustfmt/tests/source/pattern.rs @@ -91,7 +91,7 @@ fn issue3728() { fn literals() { match 42 { - const { 1 + 2 } | 4 + 1 | 2 | 4 | 6 => {} 10 | 11 | 12 | 13 | 14 => {} diff --git a/src/tools/rustfmt/tests/target/pattern.rs b/src/tools/rustfmt/tests/target/pattern.rs index e867f65929dd..483725f95c48 100644 --- a/src/tools/rustfmt/tests/target/pattern.rs +++ b/src/tools/rustfmt/tests/target/pattern.rs @@ -99,7 +99,7 @@ fn issue3728() { fn literals() { match 42 { - const { 1 + 2 } | 4 | 6 => {} + 1 | 2 | 4 | 6 => {} 10 | 11 | 12 | 13 | 14 => {} _ => {} } From 244e92ba5c6e8031da1471229151abd44f383eb9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Mar 2025 10:33:47 +0100 Subject: [PATCH 177/546] catch_unwind intrinsic: document return value --- library/core/src/intrinsics/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index cf03c07b6a56..81e59a1f349e 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3002,6 +3002,7 @@ pub const fn discriminant_value(v: &T) -> ::Discrimina /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. +/// Returns `1` if unwinding occurred and `catch_fn` was called; returns `0` otherwise. /// /// `catch_fn` must not unwind. /// From 91ae8651ae0bc6fcc3b3f4e9c0cfaeef1d9342d4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 21 Mar 2025 09:52:08 +0000 Subject: [PATCH 178/546] Rustup to rustc 1.87.0-nightly (78948ac25 2025-03-20) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 1b2751c86e3c..cbed84253fbe 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-18" +channel = "nightly-2025-03-21" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 83b56eb059d9e47864191fc13783f44f04cb42b4 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 4 Mar 2025 14:17:16 +1100 Subject: [PATCH 179/546] coverage: Separate span-extraction from unexpansion --- .../rustc_mir_transform/src/coverage/spans.rs | 36 +++++- .../src/coverage/spans/from_mir.rs | 105 ++++++------------ 2 files changed, 66 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index b9ed6984ddb2..f63ccff8decf 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -6,10 +6,8 @@ use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; use tracing::{debug, debug_span, instrument}; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; -use crate::coverage::spans::from_mir::{ - ExtractedCovspans, Hole, SpanFromMir, extract_covspans_from_mir, -}; -use crate::coverage::{ExtractedHirInfo, mappings}; +use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; +use crate::coverage::{ExtractedHirInfo, mappings, unexpand}; mod from_mir; @@ -19,7 +17,35 @@ pub(super) fn extract_refined_covspans( graph: &CoverageGraph, code_mappings: &mut impl Extend, ) { - let ExtractedCovspans { mut covspans } = extract_covspans_from_mir(mir_body, hir_info, graph); + let &ExtractedHirInfo { body_span, .. } = hir_info; + + let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph); + let mut covspans = raw_spans + .into_iter() + .filter_map(|RawSpanFromMir { raw_span, bcb }| try { + let (span, expn_kind) = + unexpand::unexpand_into_body_span_with_expn_kind(raw_span, body_span)?; + // Discard any spans that fill the entire body, because they tend + // to represent compiler-inserted code, e.g. implicitly returning `()`. + if span.source_equal(body_span) { + return None; + }; + SpanFromMir { span, expn_kind, bcb } + }) + .collect::>(); + + // Only proceed if we found at least one usable span. + if covspans.is_empty() { + return; + } + + // Also add the adjusted function signature span, if available. + // Otherwise, add a fake span at the start of the body, to avoid an ugly + // gap between the start of the body and the first real span. + // FIXME: Find a more principled way to solve this problem. + covspans.push(SpanFromMir::for_fn_sig( + hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()), + )); // First, perform the passes that need macro information. covspans.sort_by(|a, b| graph.cmp_in_dominator_order(a.bcb, b.bcb)); diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 73b68d7155cf..1faa2171c0b0 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,3 +1,5 @@ +use std::iter; + use rustc_middle::bug; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{ @@ -5,87 +7,50 @@ use rustc_middle::mir::{ }; use rustc_span::{ExpnKind, Span}; -use crate::coverage::ExtractedHirInfo; -use crate::coverage::graph::{ - BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, -}; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; use crate::coverage::spans::Covspan; -use crate::coverage::unexpand::unexpand_into_body_span_with_expn_kind; -pub(crate) struct ExtractedCovspans { - pub(crate) covspans: Vec, +#[derive(Debug)] +pub(crate) struct RawSpanFromMir { + /// A span that has been extracted from a MIR statement/terminator, but + /// hasn't been "unexpanded", so it might not lie within the function body + /// span and might be part of an expansion with a different context. + pub(crate) raw_span: Span, + pub(crate) bcb: BasicCoverageBlock, } -/// Traverses the MIR body to produce an initial collection of coverage-relevant -/// spans, each associated with a node in the coverage graph (BCB) and possibly -/// other metadata. -pub(crate) fn extract_covspans_from_mir( - mir_body: &mir::Body<'_>, - hir_info: &ExtractedHirInfo, +/// Generates an initial set of coverage spans from the statements and +/// terminators in the function's MIR body, each associated with its +/// corresponding node in the coverage graph. +/// +/// This is necessarily an inexact process, because MIR isn't designed to +/// capture source spans at the level of detail we would want for coverage, +/// but it's good enough to be better than nothing. +pub(crate) fn extract_raw_spans_from_mir<'tcx>( + mir_body: &mir::Body<'tcx>, graph: &CoverageGraph, -) -> ExtractedCovspans { - let &ExtractedHirInfo { body_span, .. } = hir_info; - - let mut covspans = vec![]; +) -> Vec { + let mut raw_spans = vec![]; + // We only care about blocks that are part of the coverage graph. for (bcb, bcb_data) in graph.iter_enumerated() { - bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data, &mut covspans); - } + let make_raw_span = |raw_span: Span| RawSpanFromMir { raw_span, bcb }; - // Only add the signature span if we found at least one span in the body. - if !covspans.is_empty() { - // If there is no usable signature span, add a fake one (before refinement) - // to avoid an ugly gap between the body start and the first real span. - // FIXME: Find a more principled way to solve this problem. - let fn_sig_span = hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()); - covspans.push(SpanFromMir::for_fn_sig(fn_sig_span)); - } + // A coverage graph node can consist of multiple basic blocks. + for &bb in &bcb_data.basic_blocks { + let bb_data = &mir_body[bb]; - ExtractedCovspans { covspans } -} + let statements = bb_data.statements.iter(); + raw_spans.extend(statements.filter_map(filtered_statement_span).map(make_raw_span)); -// Generate a set of coverage spans from the filtered set of `Statement`s and `Terminator`s of -// the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One coverage span is generated -// for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will -// merge some coverage spans, at which point a coverage span may represent multiple -// `Statement`s and/or `Terminator`s.) -fn bcb_to_initial_coverage_spans<'a, 'tcx>( - mir_body: &'a mir::Body<'tcx>, - body_span: Span, - bcb: BasicCoverageBlock, - bcb_data: &'a BasicCoverageBlockData, - initial_covspans: &mut Vec, -) { - for &bb in &bcb_data.basic_blocks { - let data = &mir_body[bb]; - - let unexpand = move |expn_span| { - unexpand_into_body_span_with_expn_kind(expn_span, body_span) - // Discard any spans that fill the entire body, because they tend - // to represent compiler-inserted code, e.g. implicitly returning `()`. - .filter(|(span, _)| !span.source_equal(body_span)) - }; - - let mut extract_statement_span = |statement| { - let expn_span = filtered_statement_span(statement)?; - let (span, expn_kind) = unexpand(expn_span)?; - - initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb)); - Some(()) - }; - for statement in data.statements.iter() { - extract_statement_span(statement); + // There's only one terminator, but wrap it in an iterator to + // mirror the handling of statements. + let terminator = iter::once(bb_data.terminator()); + raw_spans.extend(terminator.filter_map(filtered_terminator_span).map(make_raw_span)); } - - let mut extract_terminator_span = |terminator| { - let expn_span = filtered_terminator_span(terminator)?; - let (span, expn_kind) = unexpand(expn_span)?; - - initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb)); - Some(()) - }; - extract_terminator_span(data.terminator()); } + + raw_spans } /// If the MIR `Statement` has a span contributive to computing coverage spans, @@ -219,7 +184,7 @@ pub(crate) struct SpanFromMir { } impl SpanFromMir { - fn for_fn_sig(fn_sig_span: Span) -> Self { + pub(crate) fn for_fn_sig(fn_sig_span: Span) -> Self { Self::new(fn_sig_span, None, START_BCB) } From 7fdac5eef09a11fd4f35ab272d83f5ea08b15320 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 4 Mar 2025 13:53:24 +1100 Subject: [PATCH 180/546] coverage: Defer the filtering of hole spans --- .../rustc_mir_transform/src/coverage/mod.rs | 21 +++++++------------ .../rustc_mir_transform/src/coverage/spans.rs | 9 +++++++- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 572dbae8fd20..aa4c0ef1e1f9 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -273,8 +273,9 @@ struct ExtractedHirInfo { /// Must have the same context and filename as the body span. fn_sig_span_extended: Option, body_span: Span, - /// "Holes" are regions within the body span that should not be included in - /// coverage spans for this function (e.g. closures and nested items). + /// "Holes" are regions within the function body (or its expansions) that + /// should not be included in coverage spans for this function + /// (e.g. closures and nested items). hole_spans: Vec, } @@ -323,7 +324,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir let function_source_hash = hash_mir_source(tcx, hir_body); - let hole_spans = extract_hole_spans_from_hir(tcx, body_span, hir_body); + let hole_spans = extract_hole_spans_from_hir(tcx, hir_body); ExtractedHirInfo { function_source_hash, @@ -340,14 +341,9 @@ fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> tcx.hir_owner_nodes(owner).opt_hash_including_bodies.unwrap().to_smaller_hash().as_u64() } -fn extract_hole_spans_from_hir<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, // Usually `hir_body.value.span`, but not always - hir_body: &hir::Body<'tcx>, -) -> Vec { +fn extract_hole_spans_from_hir<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &hir::Body<'tcx>) -> Vec { struct HolesVisitor<'tcx> { tcx: TyCtxt<'tcx>, - body_span: Span, hole_spans: Vec, } @@ -387,14 +383,11 @@ fn extract_hole_spans_from_hir<'tcx>( } impl HolesVisitor<'_> { fn visit_hole_span(&mut self, hole_span: Span) { - // Discard any holes that aren't directly visible within the body span. - if self.body_span.contains(hole_span) && self.body_span.eq_ctxt(hole_span) { - self.hole_spans.push(hole_span); - } + self.hole_spans.push(hole_span); } } - let mut visitor = HolesVisitor { tcx, body_span, hole_spans: vec![] }; + let mut visitor = HolesVisitor { tcx, hole_spans: vec![] }; visitor.visit_body(hir_body); visitor.hole_spans diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index f63ccff8decf..8befe9c5d8dd 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -69,7 +69,14 @@ pub(super) fn extract_refined_covspans( covspans.dedup_by(|b, a| a.span.source_equal(b.span)); // Sort the holes, and merge overlapping/adjacent holes. - let mut holes = hir_info.hole_spans.iter().map(|&span| Hole { span }).collect::>(); + let mut holes = hir_info + .hole_spans + .iter() + .copied() + // Discard any holes that aren't directly visible within the body span. + .filter(|&hole_span| body_span.contains(hole_span) && body_span.eq_ctxt(hole_span)) + .map(|span| Hole { span }) + .collect::>(); holes.sort_by(|a, b| compare_spans(a.span, b.span)); holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); From 80a5adf871c30e8bfdd696d22595b70a584cce3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 19 Mar 2025 14:31:15 +0100 Subject: [PATCH 181/546] Unify LLVM invalidation path handling Before it was using a different set of paths in different call-sites. --- src/bootstrap/src/core/build_steps/gcc.rs | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 21 ++++++++++----------- src/bootstrap/src/core/config/config.rs | 5 +++-- src/bootstrap/src/core/config/tests.rs | 3 ++- src/build_helper/src/git.rs | 4 ++-- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index b88a5f2bbf13..48bb5cb8e876 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -273,7 +273,7 @@ fn detect_gcc_sha(config: &crate::Config, is_git: bool) -> String { get_closest_merge_commit( Some(&config.src), &config.git_config(), - &[config.src.join("src/gcc"), config.src.join("src/bootstrap/download-ci-gcc-stamp")], + &["src/gcc", "src/bootstrap/download-ci-gcc-stamp"], ) .unwrap() } else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 0ae5256a18fd..efecca6ebddd 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -174,20 +174,19 @@ pub fn prebuilt_llvm_config( LlvmBuildStatus::ShouldBuild(Meta { stamp, res, out_dir, root: root.into() }) } +/// Paths whose changes invalidate LLVM downloads. +pub const LLVM_INVALIDATION_PATHS: &[&str] = &[ + "src/llvm-project", + "src/bootstrap/download-ci-llvm-stamp", + // the LLVM shared object file is named `LLVM--rust-{version}-nightly` + "src/version", +]; + /// This retrieves the LLVM sha we *want* to use, according to git history. pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { let llvm_sha = if is_git { - get_closest_merge_commit( - Some(&config.src), - &config.git_config(), - &[ - config.src.join("src/llvm-project"), - config.src.join("src/bootstrap/download-ci-llvm-stamp"), - // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` - config.src.join("src/version"), - ], - ) - .unwrap() + get_closest_merge_commit(Some(&config.src), &config.git_config(), LLVM_INVALIDATION_PATHS) + .unwrap() } else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) { info.sha.trim().to_owned() } else { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 2b8c1f49afbe..dfd64c3246d2 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -23,6 +23,7 @@ use tracing::{instrument, span}; use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::llvm; +use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; pub use crate::core::config::flags::Subcommand; use crate::core::config::flags::{Color, Flags, Warnings}; use crate::core::download::is_download_ci_available; @@ -3109,9 +3110,9 @@ impl Config { #[cfg(not(test))] self.update_submodule("src/llvm-project"); - // Check for untracked changes in `src/llvm-project`. + // Check for untracked changes in `src/llvm-project` and other important places. let has_changes = self - .last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true) + .last_modified_commit(LLVM_INVALIDATION_PATHS, "download-ci-llvm", true) .is_none(); // Return false if there are untracked changes, otherwise check if CI LLVM is available. diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index fb2c52966ebb..6f21016ea744 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -12,6 +12,7 @@ use super::flags::Flags; use super::{ChangeIdWrapper, Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm; +use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig}; pub(crate) fn parse(config: &str) -> Config { @@ -41,7 +42,7 @@ fn download_ci_llvm() { let if_unchanged_config = parse("llvm.download-ci-llvm = \"if-unchanged\""); if if_unchanged_config.llvm_from_ci { let has_changes = if_unchanged_config - .last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true) + .last_modified_commit(LLVM_INVALIDATION_PATHS, "download-ci-llvm", true) .is_none(); assert!( diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 9f778a2fd774..bdec54a77414 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use std::process::{Command, Stdio}; use crate::ci::CiEnv; @@ -121,7 +121,7 @@ fn git_upstream_merge_base( pub fn get_closest_merge_commit( git_dir: Option<&Path>, config: &GitConfig<'_>, - target_paths: &[PathBuf], + target_paths: &[&str], ) -> Result { let mut git = Command::new("git"); From 9c05758ed47166d14bf073e6941dc95020ff7713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 19 Mar 2025 14:39:16 +0100 Subject: [PATCH 182/546] Remove duplicated check for LLVM modifications and disable `download-ci-llvm=true` on CI --- src/bootstrap/src/core/build_steps/llvm.rs | 40 ++-------------------- src/bootstrap/src/core/config/config.rs | 11 ++++-- src/bootstrap/src/core/config/tests.rs | 14 ++++++-- 3 files changed, 23 insertions(+), 42 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index efecca6ebddd..28a8afd9c04a 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -14,7 +14,6 @@ use std::path::{Path, PathBuf}; use std::sync::OnceLock; use std::{env, fs}; -use build_helper::ci::CiEnv; use build_helper::git::get_closest_merge_commit; #[cfg(feature = "tracing")] use tracing::instrument; @@ -206,10 +205,9 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { /// Returns whether the CI-found LLVM is currently usable. /// -/// This checks both the build triple platform to confirm we're usable at all, -/// and then verifies if the current HEAD matches the detected LLVM SHA head, -/// in which case LLVM is indicated as not available. -pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { +/// This checks the build triple platform to confirm we're usable at all, and if LLVM +/// with/without assertions is available. +pub(crate) fn is_ci_llvm_available_for_target(config: &Config, asserts: bool) -> bool { // This is currently all tier 1 targets and tier 2 targets with host tools // (since others may not have CI artifacts) // https://doc.rust-lang.org/rustc/platform-support.html#tier-1 @@ -254,41 +252,9 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { return false; } - if is_ci_llvm_modified(config) { - eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change"); - return false; - } - true } -/// Returns true if we're running in CI with modified LLVM (and thus can't download it) -pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { - // If not running in a CI environment, return false. - if !config.is_running_on_ci { - return false; - } - - // In rust-lang/rust managed CI, assert the existence of the LLVM submodule. - if CiEnv::is_rust_lang_managed_ci_job() { - assert!( - config.in_tree_llvm_info.is_managed_git_subrepository(), - "LLVM submodule must be fetched in rust-lang/rust managed CI builders." - ); - } - // If LLVM submodule isn't present, skip the change check as it won't work. - else if !config.in_tree_llvm_info.is_managed_git_subrepository() { - return false; - } - - let llvm_sha = detect_llvm_sha(config, true); - let head_sha = crate::output( - helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").as_command_mut(), - ); - let head_sha = head_sha.trim(); - llvm_sha == head_sha -} - #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Llvm { pub target: TargetSelection, diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index dfd64c3246d2..b8068373c73f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -3116,7 +3116,7 @@ impl Config { .is_none(); // Return false if there are untracked changes, otherwise check if CI LLVM is available. - if has_changes { false } else { llvm::is_ci_llvm_available(self, asserts) } + if has_changes { false } else { llvm::is_ci_llvm_available_for_target(self, asserts) } }; match download_ci_llvm { @@ -3127,8 +3127,15 @@ impl Config { ); } + if b && self.is_running_on_ci { + // On CI, we must always rebuild LLVM if there were any modifications to it + panic!( + "`llvm.download-ci-llvm` cannot be set to `true` on CI. Use `if-unchanged` instead." + ); + } + // If download-ci-llvm=true we also want to check that CI llvm is available - b && llvm::is_ci_llvm_available(self, asserts) + b && llvm::is_ci_llvm_available_for_target(self, asserts) } StringOrBool::String(s) if s == "if-unchanged" => if_unchanged(), StringOrBool::String(other) => { diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 6f21016ea744..068e237c2cdc 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -25,13 +25,21 @@ pub(crate) fn parse(config: &str) -> Config { #[test] fn download_ci_llvm() { let config = parse(""); - let is_available = llvm::is_ci_llvm_available(&config, config.llvm_assertions); + let is_available = llvm::is_ci_llvm_available_for_target(&config, config.llvm_assertions); if is_available { assert!(config.llvm_from_ci); } - let config = parse("llvm.download-ci-llvm = true"); - let is_available = llvm::is_ci_llvm_available(&config, config.llvm_assertions); + let config = Config::parse_inner( + Flags::parse(&[ + "check".to_string(), + "--config=/does/not/exist".to_string(), + "--ci".to_string(), + "false".to_string(), + ]), + |&_| toml::from_str("llvm.download-ci-llvm = true"), + ); + let is_available = llvm::is_ci_llvm_available_for_target(&config, config.llvm_assertions); if is_available { assert!(config.llvm_from_ci); } From 68aaa8d103f8d17dc9fc721a80ceb45d2ec9585d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 19 Mar 2025 14:40:38 +0100 Subject: [PATCH 183/546] Allow unused code in tests To avoid working around some code being unused in tests due to it being stubbed out with `#[cfg(test)]`. --- src/bootstrap/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 1fba17dcf308..ec5c0c53baa6 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -15,6 +15,7 @@ //! //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. +#![cfg_attr(test, allow(unused))] use std::cell::{Cell, RefCell}; use std::collections::{BTreeSet, HashMap, HashSet}; From f53acd17cb172c02bd8ec24aadd4475579ee0b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 20 Mar 2025 10:06:51 +0100 Subject: [PATCH 184/546] Set `if-unchanged` as the default value for `download-ci-llvm` when we're on CI. --- src/bootstrap/src/core/config/config.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index b8068373c73f..ffa3c2ddb6d0 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -3097,7 +3097,14 @@ impl Config { download_ci_llvm: Option, asserts: bool, ) -> bool { - let download_ci_llvm = download_ci_llvm.unwrap_or(StringOrBool::Bool(true)); + // We don't ever want to use `true` on CI, as we should not + // download upstream artifacts if there are any local modifications. + let default = if self.is_running_on_ci { + StringOrBool::String("if-unchanged".to_string()) + } else { + StringOrBool::Bool(true) + }; + let download_ci_llvm = download_ci_llvm.unwrap_or(default); let if_unchanged = || { if self.rust_info.is_from_tarball() { From e288faa4b015676829f96f83dc5e124ee7c0b3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 20 Mar 2025 13:43:21 +0100 Subject: [PATCH 185/546] Disable CI mode when checking default bootstrap profiles --- .../host-x86_64/mingw-check/check-default-config-profiles.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/mingw-check/check-default-config-profiles.sh b/src/ci/docker/host-x86_64/mingw-check/check-default-config-profiles.sh index d706927d6d95..0c85d4b449db 100755 --- a/src/ci/docker/host-x86_64/mingw-check/check-default-config-profiles.sh +++ b/src/ci/docker/host-x86_64/mingw-check/check-default-config-profiles.sh @@ -8,5 +8,6 @@ config_dir="../src/bootstrap/defaults" # Loop through each configuration file in the directory for config_file in "$config_dir"/*.toml; do - python3 ../x.py check --config $config_file --dry-run + # Disable CI mode, because it is not compatible with all profiles + python3 ../x.py check --config $config_file --dry-run --ci=false done From f5c59a444f45e32772f393358c2c28c5346f49a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 21 Mar 2025 12:23:44 +0100 Subject: [PATCH 186/546] Fix test using `download-ci-llvm=true` on CI --- src/bootstrap/src/core/builder/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b7a51a33dbd2..fd3b28e4e6ab 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1074,7 +1074,7 @@ fn test_prebuilt_llvm_config_path_resolution() { let config = configure( r#" [llvm] - download-ci-llvm = true + download-ci-llvm = "if-unchanged" "#, ); From 2c77a0775c8e398296b14798504f40c968eaf55d Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Fri, 21 Mar 2025 12:36:01 +0100 Subject: [PATCH 187/546] test(ui): add tuple-struct-where-clause-suggestion ui test for #91520 --- ...le-struct-where-clause-suggestion-91520.rs | 17 +++++++++++++++ ...truct-where-clause-suggestion-91520.stderr | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/ui/suggestions/tuple-struct-where-clause-suggestion-91520.rs create mode 100644 tests/ui/suggestions/tuple-struct-where-clause-suggestion-91520.stderr diff --git a/tests/ui/suggestions/tuple-struct-where-clause-suggestion-91520.rs b/tests/ui/suggestions/tuple-struct-where-clause-suggestion-91520.rs new file mode 100644 index 000000000000..b7086325d5f8 --- /dev/null +++ b/tests/ui/suggestions/tuple-struct-where-clause-suggestion-91520.rs @@ -0,0 +1,17 @@ +// Verify that the `where` clause suggestion is in the correct place +// Previously, the suggestion to add `where` clause was placed inside the derive +// like `#[derive(Clone where Inner: Clone)]` +// instead of `struct Outer(Inner) where Inner: Clone` + +#![crate_type = "lib"] + +struct Inner(T); +//~^ HELP consider annotating `Inner` with `#[derive(Clone)]` +impl Clone for Inner<()> { + fn clone(&self) -> Self { todo!() } +} + +#[derive(Clone)] +struct Outer(Inner); +//~^ ERROR the trait bound `Inner: Clone` is not satisfied [E0277] +//~| HELP consider introducing a `where` clause diff --git a/tests/ui/suggestions/tuple-struct-where-clause-suggestion-91520.stderr b/tests/ui/suggestions/tuple-struct-where-clause-suggestion-91520.stderr new file mode 100644 index 000000000000..577b090ce1b4 --- /dev/null +++ b/tests/ui/suggestions/tuple-struct-where-clause-suggestion-91520.stderr @@ -0,0 +1,21 @@ +error[E0277]: the trait bound `Inner: Clone` is not satisfied + --> $DIR/tuple-struct-where-clause-suggestion-91520.rs:15:17 + | +LL | #[derive(Clone)] + | ----- in this derive macro expansion +LL | struct Outer(Inner); + | ^^^^^^^^ the trait `Clone` is not implemented for `Inner` + | +help: consider annotating `Inner` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Inner(T); + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | struct Outer(Inner) where Inner: Clone; + | +++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 521d0c4a30083dd447fcf397e8b1de278acb81af Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 21 Mar 2025 12:30:25 +0000 Subject: [PATCH 188/546] Cache current_dll_path output Computing the current dll path is somewhat expensive relative to other work when compiling `fn main() {}` as `dladdr` needs to iterate over the symbol table of librustc_driver.so until it finds a match. --- compiler/rustc_session/src/filesearch.rs | 118 ++++++++++++----------- 1 file changed, 64 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 50f09c57107e..bdeca91eb64a 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -60,66 +60,76 @@ pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf { #[cfg(unix)] fn current_dll_path() -> Result { - use std::ffi::{CStr, OsStr}; - use std::os::unix::prelude::*; + use std::sync::OnceLock; - #[cfg(not(target_os = "aix"))] - unsafe { - let addr = current_dll_path as usize as *mut _; - let mut info = std::mem::zeroed(); - if libc::dladdr(addr, &mut info) == 0 { - return Err("dladdr failed".into()); - } - if info.dli_fname.is_null() { - return Err("dladdr returned null pointer".into()); - } - let bytes = CStr::from_ptr(info.dli_fname).to_bytes(); - let os = OsStr::from_bytes(bytes); - Ok(PathBuf::from(os)) - } + // This is somewhat expensive relative to other work when compiling `fn main() {}` as `dladdr` + // needs to iterate over the symbol table of librustc_driver.so until it finds a match. + // As such cache this to avoid recomputing if we try to get the sysroot in multiple places. + static CURRENT_DLL_PATH: OnceLock> = OnceLock::new(); + CURRENT_DLL_PATH + .get_or_init(|| { + use std::ffi::{CStr, OsStr}; + use std::os::unix::prelude::*; - #[cfg(target_os = "aix")] - unsafe { - // On AIX, the symbol `current_dll_path` references a function descriptor. - // A function descriptor is consisted of (See https://reviews.llvm.org/D62532) - // * The address of the entry point of the function. - // * The TOC base address for the function. - // * The environment pointer. - // The function descriptor is in the data section. - let addr = current_dll_path as u64; - let mut buffer = vec![std::mem::zeroed::(); 64]; - loop { - if libc::loadquery( - libc::L_GETINFO, - buffer.as_mut_ptr() as *mut u8, - (size_of::() * buffer.len()) as u32, - ) >= 0 - { - break; - } else { - if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM { - return Err("loadquery failed".into()); + #[cfg(not(target_os = "aix"))] + unsafe { + let addr = current_dll_path as usize as *mut _; + let mut info = std::mem::zeroed(); + if libc::dladdr(addr, &mut info) == 0 { + return Err("dladdr failed".into()); } - buffer.resize(buffer.len() * 2, std::mem::zeroed::()); - } - } - let mut current = buffer.as_mut_ptr() as *mut libc::ld_info; - loop { - let data_base = (*current).ldinfo_dataorg as u64; - let data_end = data_base + (*current).ldinfo_datasize; - if (data_base..data_end).contains(&addr) { - let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes(); + if info.dli_fname.is_null() { + return Err("dladdr returned null pointer".into()); + } + let bytes = CStr::from_ptr(info.dli_fname).to_bytes(); let os = OsStr::from_bytes(bytes); - return Ok(PathBuf::from(os)); + Ok(PathBuf::from(os)) } - if (*current).ldinfo_next == 0 { - break; + + #[cfg(target_os = "aix")] + unsafe { + // On AIX, the symbol `current_dll_path` references a function descriptor. + // A function descriptor is consisted of (See https://reviews.llvm.org/D62532) + // * The address of the entry point of the function. + // * The TOC base address for the function. + // * The environment pointer. + // The function descriptor is in the data section. + let addr = current_dll_path as u64; + let mut buffer = vec![std::mem::zeroed::(); 64]; + loop { + if libc::loadquery( + libc::L_GETINFO, + buffer.as_mut_ptr() as *mut u8, + (size_of::() * buffer.len()) as u32, + ) >= 0 + { + break; + } else { + if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM { + return Err("loadquery failed".into()); + } + buffer.resize(buffer.len() * 2, std::mem::zeroed::()); + } + } + let mut current = buffer.as_mut_ptr() as *mut libc::ld_info; + loop { + let data_base = (*current).ldinfo_dataorg as u64; + let data_end = data_base + (*current).ldinfo_datasize; + if (data_base..data_end).contains(&addr) { + let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes(); + let os = OsStr::from_bytes(bytes); + return Ok(PathBuf::from(os)); + } + if (*current).ldinfo_next == 0 { + break; + } + current = (current as *mut i8).offset((*current).ldinfo_next as isize) + as *mut libc::ld_info; + } + return Err(format!("current dll's address {} is not in the load map", addr)); } - current = - (current as *mut i8).offset((*current).ldinfo_next as isize) as *mut libc::ld_info; - } - return Err(format!("current dll's address {} is not in the load map", addr)); - } + }) + .clone() } #[cfg(windows)] From 7d3965e0cdc1614335e2c3d18234963bb0827160 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Feb 2025 14:37:09 +0000 Subject: [PATCH 189/546] Move make_input call --- compiler/rustc_driver_impl/src/lib.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 8ede6e413368..4a3037bb9714 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -243,12 +243,17 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) return; } + let input = make_input(&default_early_dcx, &matches.free); + let has_input = input.is_some(); let (odir, ofile) = make_output(&matches); + + drop(default_early_dcx); + let mut config = interface::Config { opts: sopts, crate_cfg: matches.opt_strs("cfg"), crate_check_cfg: matches.opt_strs("check-cfg"), - input: Input::File(PathBuf::new()), + input: input.unwrap_or(Input::File(PathBuf::new())), output_file: ofile, output_dir: odir, ice_file, @@ -265,16 +270,6 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) expanded_args: args, }; - let has_input = match make_input(&default_early_dcx, &matches.free) { - Some(input) => { - config.input = input; - true // has input: normal compilation - } - None => false, // no input: we will exit early - }; - - drop(default_early_dcx); - callbacks.config(&mut config); let registered_lints = config.register_lints.is_some(); @@ -407,7 +402,7 @@ fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) { } } -// Extract output directory and file from matches. +/// Extract output directory and file from matches. fn make_output(matches: &getopts::Matches) -> (Option, Option) { let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); let ofile = matches.opt_str("o").map(|o| match o.as_str() { From 41f1ed11c2ef656737af2b15a9f58e84421424bb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:23:54 +0000 Subject: [PATCH 190/546] Move some calls to before calling codegen_crate `--emit mir`, `#[rustc_symbol_name]` and `#[rustc_def_path]` now run before codegen and thus work even if codegen fails. This can help with debugging. --- compiler/rustc_driver_impl/messages.ftl | 2 ++ compiler/rustc_driver_impl/src/lib.rs | 8 ++++++- .../src/session_diagnostics.rs | 6 +++++ compiler/rustc_interface/messages.ftl | 3 --- compiler/rustc_interface/src/errors.rs | 6 ----- compiler/rustc_interface/src/passes.rs | 24 +++++++------------ 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 05e11c4527f8..2c6a0291ac29 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -1,3 +1,5 @@ +driver_impl_cant_emit_mir = could not emit MIR: {$error} + driver_impl_ice = the compiler unexpectedly panicked. this is a bug. driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 4a3037bb9714..4ba076c64e10 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -108,7 +108,7 @@ mod signal_handler { } use crate::session_diagnostics::{ - RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch, + CantEmitMIR, RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch, RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead, UnstableFeatureUsage, }; @@ -374,6 +374,12 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) return early_exit(); } + if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { + if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) { + tcx.dcx().emit_fatal(CantEmitMIR { error }); + } + } + Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)) }); diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index e06c56539d1c..774221fd396a 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -2,6 +2,12 @@ use std::error::Error; use rustc_macros::{Diagnostic, Subdiagnostic}; +#[derive(Diagnostic)] +#[diag(driver_impl_cant_emit_mir)] +pub struct CantEmitMIR { + pub error: std::io::Error, +} + #[derive(Diagnostic)] #[diag(driver_impl_rlink_unable_to_read)] pub(crate) struct RlinkUnableToRead { diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index adc7ed54e147..ffbe708ba8da 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -3,9 +3,6 @@ interface_abi_required_feature = .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! interface_abi_required_feature_issue = for more information, see issue #116344 -interface_cant_emit_mir = - could not emit MIR: {$error} - interface_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$crate_name}` != `{$attr_crate_name}` interface_crate_name_invalid = crate names cannot start with a `-`, but `{$crate_name}` has a leading hyphen diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index eed729a1777f..ef0235b5577f 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -73,12 +73,6 @@ pub struct TempsDirError; #[diag(interface_out_dir_error)] pub struct OutDirError; -#[derive(Diagnostic)] -#[diag(interface_cant_emit_mir)] -pub struct CantEmitMIR { - pub error: io::Error, -} - #[derive(Diagnostic)] #[diag(interface_rustc_error_fatal)] pub struct RustcErrorFatal { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e47385d08994..3d6b6a594a2b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1078,6 +1078,15 @@ pub(crate) fn start_codegen<'tcx>( codegen_backend: &dyn CodegenBackend, tcx: TyCtxt<'tcx>, ) -> Box { + // Hook for UI tests. + check_for_rustc_errors_attr(tcx); + + // Don't run this test assertions when not doing codegen. Compiletest tries to build + // build-fail tests in check mode first and expects it to not give an error in that case. + if tcx.sess.opts.output_types.should_codegen() { + rustc_symbol_mangling::test::report_symbol_names(tcx); + } + // Don't do code generation if there were any errors. Likewise if // there were any delayed bugs, because codegen will likely cause // more ICEs, obscuring the original problem. @@ -1085,9 +1094,6 @@ pub(crate) fn start_codegen<'tcx>( guar.raise_fatal(); } - // Hook for UI tests. - check_for_rustc_errors_attr(tcx); - info!("Pre-codegen\n{:?}", tcx.debug_stats()); let (metadata, need_metadata_module) = rustc_metadata::fs::encode_and_write_metadata(tcx); @@ -1096,20 +1102,8 @@ pub(crate) fn start_codegen<'tcx>( codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) }); - // Don't run this test assertions when not doing codegen. Compiletest tries to build - // build-fail tests in check mode first and expects it to not give an error in that case. - if tcx.sess.opts.output_types.should_codegen() { - rustc_symbol_mangling::test::report_symbol_names(tcx); - } - info!("Post-codegen\n{:?}", tcx.debug_stats()); - if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) { - tcx.dcx().emit_fatal(errors::CantEmitMIR { error }); - } - } - // This must run after monomorphization so that all generic types // have been instantiated. if tcx.sess.opts.unstable_opts.print_type_sizes { From cd929bfccb60cfae7624c7ae1a00efb6df069337 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 27 Feb 2025 16:36:20 +0000 Subject: [PATCH 191/546] Fix lint name in unused linker_messages warning --- compiler/rustc_passes/messages.ftl | 4 ++-- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/errors.rs | 4 ++-- tests/ui/lint/linker-warning.stderr | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index ed498d9d3442..06398dd4f725 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -811,8 +811,8 @@ passes_unused_duplicate = passes_unused_empty_lints_note = attribute `{$name}` with an empty list has no effect -passes_unused_linker_warnings_note = - the `linker_warnings` lint can only be controlled at the root of a crate that needs to be linked +passes_unused_linker_messages_note = + the `linker_messages` lint can only be controlled at the root of a crate that needs to be linked passes_unused_multiple = multiple `{$name}` attributes diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e0739c342df2..ff01e72f6c77 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2388,7 +2388,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .iter() .all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib)); if never_needs_link { - errors::UnusedNote::LinkerWarningsBinaryCrateOnly + errors::UnusedNote::LinkerMessagesBinaryCrateOnly } else { return; } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b8359c27e538..a72f40cd843a 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -770,8 +770,8 @@ pub(crate) enum UnusedNote { NoLints { name: Symbol }, #[note(passes_unused_default_method_body_const_note)] DefaultMethodBodyConst, - #[note(passes_unused_linker_warnings_note)] - LinkerWarningsBinaryCrateOnly, + #[note(passes_unused_linker_messages_note)] + LinkerMessagesBinaryCrateOnly, } #[derive(LintDiagnostic)] diff --git a/tests/ui/lint/linker-warning.stderr b/tests/ui/lint/linker-warning.stderr index 3a2c392fd031..c678562ab546 100644 --- a/tests/ui/lint/linker-warning.stderr +++ b/tests/ui/lint/linker-warning.stderr @@ -16,7 +16,7 @@ warning: unused attribute LL | #![allow(linker_messages)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | - = note: the `linker_warnings` lint can only be controlled at the root of a crate that needs to be linked + = note: the `linker_messages` lint can only be controlled at the root of a crate that needs to be linked warning: 2 warnings emitted From 63cfd47cb10940e593f6755a54c12438f7fced8f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 27 Feb 2025 16:35:57 +0000 Subject: [PATCH 192/546] Don't attempt to export compiler-builtins symbols from rust dylibs They are marked with hidden visibility to prevent them from getting exported, so we shouldn't ask the linker to export them anyway. The only thing that does it cause a warning on macOS. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index e2a59c6efb88..7df2d128d2fb 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1782,7 +1782,10 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) - let mut symbols = Vec::new(); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { - if info.level.is_below_threshold(export_threshold) { + // Do not export mangled symbols from cdylibs and don't attempt to export compiler-builtins + // from any cdylib. The latter doesn't work anyway as we use hidden visibility for + // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning. + if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) { symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate( tcx, symbol, cnum, )); From 530ab61c0eca891773bb71716849e3e934e84e9f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:06:34 +0000 Subject: [PATCH 193/546] Also check for compiler-builtins in linked_symbols Otherwise the linker complains about EC symbols missing when compiling for arm64ec. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 7df2d128d2fb..3f5e0c1bce9c 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1824,7 +1824,9 @@ pub(crate) fn linked_symbols( let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { - if info.level.is_below_threshold(export_threshold) || info.used { + if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) + || info.used + { symbols.push(( symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), info.kind, From b2d7271858fa13374963bb650f4d836426589a49 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Mar 2025 16:08:48 +0100 Subject: [PATCH 194/546] target spec check: better error when llvm-floatabi is missing --- compiler/rustc_target/src/spec/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1887134c5757..263646d8347b 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3342,7 +3342,10 @@ impl Target { ); } "arm" => { - check!(self.llvm_floatabi.is_some(), "ARM targets must specify their float ABI",) + check!( + self.llvm_floatabi.is_some(), + "ARM targets must set `llvm-floatabi` to `hard` or `soft`", + ) } _ => {} } From 0ac2801f25335b017da63f3bff1c2b46a39ee12d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 21 Mar 2025 18:14:27 +0300 Subject: [PATCH 195/546] expand: Do not report `cfg_attr` traces on macros as unused attributes --- compiler/rustc_expand/src/expand.rs | 2 +- tests/ui/lint/inert-attr-macro.rs | 7 +++++++ tests/ui/lint/inert-attr-macro.stderr | 14 +++++++------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 87f01be26c25..e2a557528504 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1941,7 +1941,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let attr_name = attr.ident().unwrap().name; // `#[cfg]` and `#[cfg_attr]` are special - they are // eagerly evaluated. - if attr_name != sym::cfg && attr_name != sym::cfg_attr { + if attr_name != sym::cfg && attr_name != sym::cfg_attr_trace { self.cx.sess.psess.buffer_lint( UNUSED_ATTRIBUTES, attr.span, diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs index 90303a1fc3d1..5d4133d6c774 100644 --- a/tests/ui/lint/inert-attr-macro.rs +++ b/tests/ui/lint/inert-attr-macro.rs @@ -1,5 +1,6 @@ //@ check-pass +#![feature(cfg_boolean_literals)] #![warn(unused)] macro_rules! foo { @@ -17,4 +18,10 @@ fn main() { // This does work, since the attribute is on a parent // of the macro invocation. #[allow(warnings)] { #[inline] foo!(); } + + // Ok, `cfg` and `cfg_attr` are expanded eagerly and do not warn. + #[cfg(true)] foo!(); + #[cfg(false)] foo!(); + #[cfg_attr(true, cfg(true))] foo!(); + #[cfg_attr(false, nonexistent)] foo!(); } diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr index 5ccb4ffe7929..b85b0319e712 100644 --- a/tests/ui/lint/inert-attr-macro.stderr +++ b/tests/ui/lint/inert-attr-macro.stderr @@ -1,41 +1,41 @@ warning: unused attribute `inline` - --> $DIR/inert-attr-macro.rs:10:5 + --> $DIR/inert-attr-macro.rs:11:5 | LL | #[inline] foo!(); | ^^^^^^^^^ | note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:10:15 + --> $DIR/inert-attr-macro.rs:11:15 | LL | #[inline] foo!(); | ^^^ note: the lint level is defined here - --> $DIR/inert-attr-macro.rs:3:9 + --> $DIR/inert-attr-macro.rs:4:9 | LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]` warning: unused attribute `allow` - --> $DIR/inert-attr-macro.rs:14:5 + --> $DIR/inert-attr-macro.rs:15:5 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^^^^^^^^^^^^^^^^ | note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:14:34 + --> $DIR/inert-attr-macro.rs:15:34 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^ warning: unused attribute `inline` - --> $DIR/inert-attr-macro.rs:14:24 + --> $DIR/inert-attr-macro.rs:15:24 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^^^^^^^ | note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:14:34 + --> $DIR/inert-attr-macro.rs:15:34 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^ From 9b7060ad3123eb21e7d93b59e2a21482afe36b6c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 21 Mar 2025 16:51:14 +0100 Subject: [PATCH 196/546] Add todo comment on using a niche type for fmt flags. --- library/core/src/fmt/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e46424700087..54c84b07d06f 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -299,6 +299,8 @@ pub struct FormattingOptions { /// a &str size when stored in (the upper bits of) the same field. /// (fmt::Arguments will make use of this property in the future.) /// ``` + // Note: This could use a special niche type with range 0x8000_0000..=0xfdd0ffff. + // It's unclear if that's useful, though. flags: u32, /// Width if width flag (bit 27) above is set. Otherwise, always 0. width: u16, From d7685f0d0b530f39c318713f90bc4c2ba8832f47 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 21 Mar 2025 17:04:29 +0100 Subject: [PATCH 197/546] Add test for Formatter flags. --- library/coretests/tests/fmt/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs index 025c69c4f623..f08545d8bdcf 100644 --- a/library/coretests/tests/fmt/mod.rs +++ b/library/coretests/tests/fmt/mod.rs @@ -58,6 +58,7 @@ fn formatting_options_ctor() { } #[test] +#[allow(deprecated)] fn formatting_options_flags() { use core::fmt::*; for sign in [None, Some(Sign::Plus), Some(Sign::Minus)] { @@ -75,6 +76,25 @@ fn formatting_options_flags() { assert_eq!(formatting_options.get_alternate(), alternate); assert_eq!(formatting_options.get_sign_aware_zero_pad(), sign_aware_zero_pad); assert_eq!(formatting_options.get_debug_as_hex(), debug_as_hex); + + let mut output = String::new(); + let fmt = Formatter::new(&mut output, formatting_options); + assert_eq!(fmt.options(), formatting_options); + + assert_eq!(fmt.sign_minus(), sign == Some(Sign::Minus)); + assert_eq!(fmt.sign_plus(), sign == Some(Sign::Plus)); + assert_eq!(fmt.alternate(), alternate); + assert_eq!(fmt.sign_aware_zero_pad(), sign_aware_zero_pad); + + // The flags method is deprecated. + // This checks compatibility with older versions of Rust. + assert_eq!(fmt.flags() & 1 != 0, sign == Some(Sign::Plus)); + assert_eq!(fmt.flags() & 2 != 0, sign == Some(Sign::Minus)); + assert_eq!(fmt.flags() & 4 != 0, alternate); + assert_eq!(fmt.flags() & 8 != 0, sign_aware_zero_pad); + assert_eq!(fmt.flags() & 16 != 0, debug_as_hex == Some(DebugAsHex::Lower)); + assert_eq!(fmt.flags() & 32 != 0, debug_as_hex == Some(DebugAsHex::Upper)); + assert_eq!(fmt.flags() & 0xFFFF_FFC0, 0); } } } From b52330136837aadf977b1f188cb5d60a264900d6 Mon Sep 17 00:00:00 2001 From: Redddy <78539407+reddevilmidzy@users.noreply.github.com> Date: Sat, 15 Mar 2025 02:11:38 +0900 Subject: [PATCH 198/546] Add test to ensure no index out of bounds panic (#135474) --- tests/ui/fn/trait-fn-generic-mismatch.rs | 12 ++++++++ tests/ui/fn/trait-fn-generic-mismatch.stderr | 32 ++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/ui/fn/trait-fn-generic-mismatch.rs create mode 100644 tests/ui/fn/trait-fn-generic-mismatch.stderr diff --git a/tests/ui/fn/trait-fn-generic-mismatch.rs b/tests/ui/fn/trait-fn-generic-mismatch.rs new file mode 100644 index 000000000000..dc8222e967e4 --- /dev/null +++ b/tests/ui/fn/trait-fn-generic-mismatch.rs @@ -0,0 +1,12 @@ +fn retry() -> impl Sized {} + +struct Core(T); + +impl Core { //~ ERROR cannot find type `XXX` in this scope + pub fn spawn(self) {} +} + +fn main() { + let core = Core(1); + core.spawn(retry()); //~ ERROR this method takes 0 arguments but 1 argument was supplied +} diff --git a/tests/ui/fn/trait-fn-generic-mismatch.stderr b/tests/ui/fn/trait-fn-generic-mismatch.stderr new file mode 100644 index 000000000000..8384d74e225a --- /dev/null +++ b/tests/ui/fn/trait-fn-generic-mismatch.stderr @@ -0,0 +1,32 @@ +error[E0412]: cannot find type `XXX` in this scope + --> $DIR/trait-fn-generic-mismatch.rs:5:11 + | +LL | impl Core { + | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl Core { + | +++++ + +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/trait-fn-generic-mismatch.rs:11:10 + | +LL | core.spawn(retry()); + | ^^^^^ ------- unexpected argument of type `impl Sized` + | +note: method defined here + --> $DIR/trait-fn-generic-mismatch.rs:6:12 + | +LL | pub fn spawn(self) {} + | ^^^^^ +help: remove the extra argument + | +LL - core.spawn(retry()); +LL + core.spawn(); + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0061, E0412. +For more information about an error, try `rustc --explain E0061`. From 7b9d5b8758589db0cda82be95e43f41be48e9311 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Mar 2025 21:02:06 +0100 Subject: [PATCH 199/546] remove remnants of const_box feature --- library/alloc/src/boxed.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index e77caad65401..4644e37f809c 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1149,9 +1149,8 @@ impl Box { /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { Box(unsafe { Unique::new_unchecked(raw) }, alloc) } @@ -1203,9 +1202,8 @@ impl Box { /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] - #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub const unsafe fn from_non_null_in(raw: NonNull, alloc: A) -> Self { + pub unsafe fn from_non_null_in(raw: NonNull, alloc: A) -> Self { // SAFETY: guaranteed by the caller. unsafe { Box::from_raw_in(raw.as_ptr(), alloc) } } @@ -1550,9 +1548,8 @@ impl Box { /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This /// is so that there is no conflict with a method on the inner type. #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub const fn allocator(b: &Self) -> &A { + pub fn allocator(b: &Self) -> &A { &b.1 } @@ -1639,8 +1636,7 @@ impl Box { /// let bar = Pin::from(foo); /// ``` #[stable(feature = "box_into_pin", since = "1.63.0")] - #[rustc_const_unstable(feature = "const_box", issue = "92521")] - pub const fn into_pin(boxed: Self) -> Pin + pub fn into_pin(boxed: Self) -> Pin where A: 'static, { From eb2a2f86bb7b018afaabb1b42d55086470780bfa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 21 Mar 2025 20:51:06 +0000 Subject: [PATCH 200/546] Allow inlining for `Atomic*::from_ptr` Currently this cannot be inlined, which among other things means it can't be used in `compiler-builtins` [1]. These are trivial functions that should be inlineable, so add `#[inline]`. [1]: https://github.com/rust-lang/compiler-builtins/pull/790#issuecomment-2744371738 --- library/core/src/sync/atomic.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 88bee6220310..9b1b13e7129e 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -469,6 +469,7 @@ impl AtomicBool { /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses + #[inline] #[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool { @@ -1389,6 +1390,7 @@ impl AtomicPtr { /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses + #[inline] #[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr { @@ -2525,6 +2527,7 @@ macro_rules! atomic_int { /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses + #[inline] #[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type { From f0c0862a2b7734a4bc222d8ab88a5a12cce291d7 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 21 Mar 2025 15:05:35 -0500 Subject: [PATCH 201/546] triagebot: add autolabel rules for D-* and L-* fixes #138565 --- triagebot.toml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 293ad259910f..c3ed32ce09e3 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -308,6 +308,23 @@ exclude_labels = [ "T-*", ] +trigger_labels = [ + "D-*", + "A-diagnostics", +] + +[autolabel."A-diagnostics"] + +trigger_labels = [ + "D-*", +] + +[autolabel."A-lints"] + +trigger_labels = [ + "L-*", +] + [autolabel."T-libs"] trigger_files = [ "library/alloc", From 14062b299cd259b0303c995c2b6596f1d1b1f00b Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 21 Mar 2025 19:25:30 -0400 Subject: [PATCH 202/546] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 6cf826701257..307cbfda3119 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 6cf8267012570f63d6b86e85a2ae5627de52df9e +Subproject commit 307cbfda3119f06600e43cd38283f4a746fe1f8b From 8cab8e07bc94fb2fea8e1421d2d2e6de6398b69b Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 21 Mar 2025 17:34:45 -0700 Subject: [PATCH 203/546] Don't produce debug information for compiler-introduced-vars when desugaring assignments. An assignment such as (a, b) = (b, c); desugars to the HIR { let (lhs, lhs) = (b, c); a = lhs; b = lhs; }; The repeated `lhs` leads to multiple Locals assigned to the same DILocalVariable. Rather than attempting to fix that, get rid of the debug info for these bindings that don't even exist in the program to begin with. Fixes #138198 --- .../src/builder/matches/mod.rs | 58 ++++++++++++++----- tests/codegen/assign-desugar-debuginfo.rs | 18 ++++++ 2 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 tests/codegen/assign-desugar-debuginfo.rs diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index ea341b604e0b..cf216ff73ca2 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -13,13 +13,13 @@ use std::sync::Arc; use rustc_abi::VariantIdx; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::{BindingMode, ByRef}; +use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node}; use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; -use rustc_span::{BytePos, Pos, Span, Symbol}; +use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard}; @@ -2796,13 +2796,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { )))), }; let for_arm_body = self.local_decls.push(local); - self.var_debug_info.push(VarDebugInfo { - name, - source_info: debug_source_info, - value: VarDebugInfoContents::Place(for_arm_body.into()), - composite: None, - argument_index: None, - }); + if self.should_emit_debug_info_for_binding(name, var_id) { + self.var_debug_info.push(VarDebugInfo { + name, + source_info: debug_source_info, + value: VarDebugInfoContents::Place(for_arm_body.into()), + composite: None, + argument_index: None, + }); + } let locals = if has_guard.0 { let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> { // This variable isn't mutated but has a name, so has to be @@ -2815,13 +2817,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { BindingForm::RefForGuard, ))), }); - self.var_debug_info.push(VarDebugInfo { - name, - source_info: debug_source_info, - value: VarDebugInfoContents::Place(ref_for_guard.into()), - composite: None, - argument_index: None, - }); + if self.should_emit_debug_info_for_binding(name, var_id) { + self.var_debug_info.push(VarDebugInfo { + name, + source_info: debug_source_info, + value: VarDebugInfoContents::Place(ref_for_guard.into()), + composite: None, + argument_index: None, + }); + } LocalsForNode::ForGuard { ref_for_guard, for_arm_body } } else { LocalsForNode::One(for_arm_body) @@ -2829,4 +2833,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!(?locals); self.var_indices.insert(var_id, locals); } + + /// Some bindings are introduced when producing HIR from the AST and don't + /// actually exist in the source. Skip producing debug info for those when + /// we can recognize them. + fn should_emit_debug_info_for_binding(&self, name: Symbol, var_id: LocalVarId) -> bool { + // For now we only recognize the output of desugaring assigns. + if name != sym::lhs { + return true; + } + + let tcx = self.tcx; + for (_, node) in tcx.hir_parent_iter(var_id.0) { + // FIXME(khuey) at what point is it safe to bail on the iterator? + // Can we stop at the first non-Pat node? + if matches!(node, Node::LetStmt(&LetStmt { source: LocalSource::AssignDesugar(_), .. })) + { + return false; + } + } + + true + } } diff --git a/tests/codegen/assign-desugar-debuginfo.rs b/tests/codegen/assign-desugar-debuginfo.rs new file mode 100644 index 000000000000..77ee8758b3b3 --- /dev/null +++ b/tests/codegen/assign-desugar-debuginfo.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -g -Zmir-opt-level=0 + +#![crate_type = "lib"] + +#[inline(never)] +fn swizzle(a: u32, b: u32, c: u32) -> (u32, (u32, u32)) { + (b, (c, a)) +} + +pub fn work() { + let mut a = 1; + let mut b = 2; + let mut c = 3; + (a, (b, c)) = swizzle(a, b, c); + println!("{a} {b} {c}"); +} + +// CHECK-NOT: !DILocalVariable(name: "lhs", From 83145a674444c15e61f1b4fb7043e8cdc4a62ea3 Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 21 Mar 2025 19:52:53 -0700 Subject: [PATCH 204/546] match lowering cleanup: `non_scalar_compare` is only for `&str` Since array and slice constants are now lowered to array and slice patterns, `non_scalar_compare` was only called for string comparisons. This specializes it to strings, renames it, and removes the unused array-unsizing logic. This also updates some outdated doc comments. --- compiler/rustc_middle/src/thir.rs | 6 +- .../src/builder/matches/mod.rs | 4 +- .../src/builder/matches/test.rs | 108 +++--------------- 3 files changed, 24 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index bbcd509c5586..6783bbf8bf42 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -800,9 +800,9 @@ pub enum PatKind<'tcx> { }, /// One of the following: - /// * `&str`/`&[u8]` (represented as a valtree), which will be handled as a string/slice pattern - /// and thus exhaustiveness checking will detect if you use the same string/slice twice in - /// different patterns. + /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus + /// exhaustiveness checking will detect if you use the same string twice in different + /// patterns. /// * integer, bool, char or float (represented as a valtree), which will be handled by /// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are /// much simpler. diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index ea341b604e0b..710538ef4b86 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1326,8 +1326,8 @@ enum TestKind<'tcx> { Eq { value: Const<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT - // types are converted back into patterns, so this can only be `&str`, - // `&[T]`, `f32` or `f64`. + // types and `&[T]` types are converted back into patterns, so this can + // only be `&str`, `f32` or `f64`. ty: Ty<'tcx>, }, diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index e5d61bc9e556..7ef9e48326f6 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -11,7 +11,6 @@ use std::sync::Arc; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; use rustc_middle::mir::*; -use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -178,21 +177,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => {} } + assert_eq!(expect_ty, ty); if !ty.is_scalar() { // Use `PartialEq::eq` instead of `BinOp::Eq` // (the binop can only handle primitives) - self.non_scalar_compare( + // Make sure that we do *not* call any user-defined code here. + // The only type that can end up here is string literals, which have their + // comparison defined in `core`. + // (Interestingly this means that exhaustiveness analysis relies, for soundness, + // on the `PartialEq` impl for `str` to b correct!) + match *ty.kind() { + ty::Ref(_, deref_ty, _) if deref_ty == self.tcx.types.str_ => {} + _ => { + span_bug!(source_info.span, "invalid type for non-scalar compare: {ty}") + } + }; + self.string_compare( block, success_block, fail_block, source_info, expect, - expect_ty, Operand::Copy(place), - ty, ); } else { - assert_eq!(expect_ty, ty); self.compare( block, success_block, @@ -370,97 +378,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } - /// Compare two values using `::eq`. - /// If the values are already references, just call it directly, otherwise - /// take a reference to the values first and then call it. - fn non_scalar_compare( + /// Compare two values of type `&str` using `::eq`. + fn string_compare( &mut self, block: BasicBlock, success_block: BasicBlock, fail_block: BasicBlock, source_info: SourceInfo, - mut expect: Operand<'tcx>, - expect_ty: Ty<'tcx>, - mut val: Operand<'tcx>, - mut ty: Ty<'tcx>, + expect: Operand<'tcx>, + val: Operand<'tcx>, ) { - // If we're using `b"..."` as a pattern, we need to insert an - // unsizing coercion, as the byte string has the type `&[u8; N]`. - // - // We want to do this even when the scrutinee is a reference to an - // array, so we can call `<[u8]>::eq` rather than having to find an - // `<[u8; N]>::eq`. - let unsize = |ty: Ty<'tcx>| match ty.kind() { - ty::Ref(region, rty, _) => match rty.kind() { - ty::Array(inner_ty, n) => Some((region, inner_ty, n)), - _ => None, - }, - _ => None, - }; - let opt_ref_ty = unsize(ty); - let opt_ref_test_ty = unsize(expect_ty); - match (opt_ref_ty, opt_ref_test_ty) { - // nothing to do, neither is an array - (None, None) => {} - (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => { - let tcx = self.tcx; - // make both a slice - ty = Ty::new_imm_ref(tcx, *region, Ty::new_slice(tcx, *elem_ty)); - if opt_ref_ty.is_some() { - let temp = self.temp(ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - temp, - Rvalue::Cast( - CastKind::PointerCoercion( - PointerCoercion::Unsize, - CoercionSource::Implicit, - ), - val, - ty, - ), - ); - val = Operand::Copy(temp); - } - if opt_ref_test_ty.is_some() { - let slice = self.temp(ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - slice, - Rvalue::Cast( - CastKind::PointerCoercion( - PointerCoercion::Unsize, - CoercionSource::Implicit, - ), - expect, - ty, - ), - ); - expect = Operand::Move(slice); - } - } - } - - // Figure out the type on which we are calling `PartialEq`. This involves an extra wrapping - // reference: we can only compare two `&T`, and then compare_ty will be `T`. - // Make sure that we do *not* call any user-defined code here. - // The only types that can end up here are string and byte literals, - // which have their comparison defined in `core`. - // (Interestingly this means that exhaustiveness analysis relies, for soundness, - // on the `PartialEq` impls for `str` and `[u8]` to b correct!) - let compare_ty = match *ty.kind() { - ty::Ref(_, deref_ty, _) - if deref_ty == self.tcx.types.str_ || deref_ty != self.tcx.types.u8 => - { - deref_ty - } - _ => span_bug!(source_info.span, "invalid type for non-scalar compare: {}", ty), - }; - + let str_ty = self.tcx.types.str_; let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); - let method = trait_method(self.tcx, eq_def_id, sym::eq, [compare_ty, compare_ty]); + let method = trait_method(self.tcx, eq_def_id, sym::eq, [str_ty, str_ty]); let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); From 110f1fe17f370c88548187397b425e1d256cced6 Mon Sep 17 00:00:00 2001 From: moxian Date: Fri, 21 Mar 2025 20:24:31 -0700 Subject: [PATCH 205/546] Revert "Stabilize file_lock" This reverts commit 82af73dd4c58cd6bec5fb44cf02f7ac96b1ed48b. --- library/std/src/fs.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index f9a360585e85..29a46fb2e6c8 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -665,6 +665,7 @@ impl File { /// # Examples /// /// ```no_run + /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -673,7 +674,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[unstable(feature = "file_lock", issue = "130994")] pub fn lock(&self) -> io::Result<()> { self.inner.lock() } @@ -717,6 +718,7 @@ impl File { /// # Examples /// /// ```no_run + /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -725,7 +727,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[unstable(feature = "file_lock", issue = "130994")] pub fn lock_shared(&self) -> io::Result<()> { self.inner.lock_shared() } @@ -774,6 +776,7 @@ impl File { /// # Examples /// /// ```no_run + /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -782,7 +785,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[unstable(feature = "file_lock", issue = "130994")] pub fn try_lock(&self) -> io::Result { self.inner.try_lock() } @@ -830,6 +833,7 @@ impl File { /// # Examples /// /// ```no_run + /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -838,7 +842,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[unstable(feature = "file_lock", issue = "130994")] pub fn try_lock_shared(&self) -> io::Result { self.inner.try_lock_shared() } @@ -866,6 +870,7 @@ impl File { /// # Examples /// /// ```no_run + /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -875,7 +880,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[unstable(feature = "file_lock", issue = "130994")] pub fn unlock(&self) -> io::Result<()> { self.inner.unlock() } From 26cfa6f819e10fa597766d8c5549b86e503ff288 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 21 Mar 2025 22:36:50 +0800 Subject: [PATCH 206/546] Note potential but private items in show_candidates Signed-off-by: xizheyin --- compiler/rustc_resolve/src/diagnostics.rs | 22 ++++++++--------- compiler/rustc_resolve/src/imports.rs | 2 +- tests/ui/imports/glob-resolve1.stderr | 5 ++++ tests/ui/imports/issue-4366-2.stderr | 5 ++++ tests/ui/imports/issue-4366.stderr | 5 ++++ .../show-private-items-issue-138626.rs | 19 +++++++++++++++ .../show-private-items-issue-138626.stderr | 20 ++++++++++++++++ tests/ui/privacy/privacy-ns1.stderr | 24 +++++++++++++++++++ tests/ui/privacy/privacy-ns2.stderr | 24 +++++++++++++++++++ tests/ui/resolve/issue-21221-1.stderr | 11 +++++++++ tests/ui/unresolved/unresolved-import.rs | 2 ++ tests/ui/unresolved/unresolved-import.stderr | 10 ++++++-- 12 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 tests/ui/imports/show-private-items-issue-138626.rs create mode 100644 tests/ui/imports/show-private-items-issue-138626.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5361af98f3c7..b1dcca460553 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1325,11 +1325,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - // If only some candidates are accessible, take just them - if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) { - candidates.retain(|x| x.accessible) - } - candidates } @@ -1794,7 +1789,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import_suggestions, Instead::Yes, FoundUse::Yes, - DiagMode::Import { append: single_nested }, + DiagMode::Import { append: single_nested, unresolved_import: false }, vec![], "", ); @@ -2751,6 +2746,8 @@ pub(crate) enum DiagMode { Pattern, /// The binding is part of a use statement Import { + /// `true` means diagnostics is for unresolved import + unresolved_import: bool, /// `true` mean add the tips afterward for case `use a::{b,c}`, /// rather than replacing within. append: bool, @@ -2801,6 +2798,7 @@ fn show_candidates( return false; } + let mut showed = false; let mut accessible_path_strings: Vec> = Vec::new(); let mut inaccessible_path_strings: Vec> = Vec::new(); @@ -2959,8 +2957,11 @@ fn show_candidates( append_candidates(&mut msg, accessible_path_strings); err.help(msg); } - true - } else if !(inaccessible_path_strings.is_empty() || matches!(mode, DiagMode::Import { .. })) { + showed = true; + } + if !inaccessible_path_strings.is_empty() + && (!matches!(mode, DiagMode::Import { unresolved_import: false, .. })) + { let prefix = if let DiagMode::Pattern = mode { "you might have meant to match on " } else { "" }; if let [(name, descr, source_span, note, _)] = &inaccessible_path_strings[..] { @@ -3023,10 +3024,9 @@ fn show_candidates( err.span_note(multi_span, msg); } - true - } else { - false + showed = true; } + showed } #[derive(Debug)] diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 89b9a0743518..b38503e07b11 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -734,7 +734,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut diag, Some(err.span), candidates, - DiagMode::Import { append: false }, + DiagMode::Import { append: false, unresolved_import: true }, (source != target) .then(|| format!(" as {target}")) .as_deref() diff --git a/tests/ui/imports/glob-resolve1.stderr b/tests/ui/imports/glob-resolve1.stderr index 75e65681c3ab..23b0db0fa465 100644 --- a/tests/ui/imports/glob-resolve1.stderr +++ b/tests/ui/imports/glob-resolve1.stderr @@ -58,6 +58,11 @@ error[E0425]: cannot find function `import` in this scope LL | import(); | ^^^^^^ not found in this scope | +note: function `bar::import` exists but is inaccessible + --> $DIR/glob-resolve1.rs:7:5 + | +LL | fn fpriv() {} + | ^^^^^^^^^^ not accessible help: consider importing this function | LL + use other::import; diff --git a/tests/ui/imports/issue-4366-2.stderr b/tests/ui/imports/issue-4366-2.stderr index 412423f4d595..b1c0092b05d1 100644 --- a/tests/ui/imports/issue-4366-2.stderr +++ b/tests/ui/imports/issue-4366-2.stderr @@ -16,6 +16,11 @@ error[E0423]: expected function, found module `foo` LL | foo(); | ^^^ not a function | +note: function `m1::foo` exists but is inaccessible + --> $DIR/issue-4366-2.rs:21:5 + | +LL | fn foo() {} + | ^^^^^^^^ not accessible help: consider importing this function instead | LL + use foo::foo; diff --git a/tests/ui/imports/issue-4366.stderr b/tests/ui/imports/issue-4366.stderr index e63399d554ee..54b7f31b2313 100644 --- a/tests/ui/imports/issue-4366.stderr +++ b/tests/ui/imports/issue-4366.stderr @@ -4,6 +4,11 @@ error[E0425]: cannot find function `foo` in this scope LL | fn sub() -> isize { foo(); 1 } | ^^^ not found in this scope | +note: function `m1::foo` exists but is inaccessible + --> $DIR/issue-4366.rs:23:5 + | +LL | fn foo() {} + | ^^^^^^^^ not accessible help: consider importing this function | LL + use foo::foo; diff --git a/tests/ui/imports/show-private-items-issue-138626.rs b/tests/ui/imports/show-private-items-issue-138626.rs new file mode 100644 index 000000000000..d9708fc33c21 --- /dev/null +++ b/tests/ui/imports/show-private-items-issue-138626.rs @@ -0,0 +1,19 @@ +pub mod one { + mod foo { + pub struct Foo; + } + + pub use self::foo::Foo; +} + +pub mod two { + mod foo { + mod bar { + pub struct Foo; + } + } + + pub use crate::two::foo::Foo; //~ ERROR unresolved import `crate::two::foo::Foo` [E0432] +} + +fn main() {} diff --git a/tests/ui/imports/show-private-items-issue-138626.stderr b/tests/ui/imports/show-private-items-issue-138626.stderr new file mode 100644 index 000000000000..b664462daed7 --- /dev/null +++ b/tests/ui/imports/show-private-items-issue-138626.stderr @@ -0,0 +1,20 @@ +error[E0432]: unresolved import `crate::two::foo::Foo` + --> $DIR/show-private-items-issue-138626.rs:16:13 + | +LL | pub use crate::two::foo::Foo; + | ^^^^^^^^^^^^^^^^^^^^ no `Foo` in `two::foo` + | +note: struct `two::foo::bar::Foo` exists but is inaccessible + --> $DIR/show-private-items-issue-138626.rs:12:13 + | +LL | pub struct Foo; + | ^^^^^^^^^^^^^^^ not accessible +help: consider importing this struct through its public re-export instead + | +LL - pub use crate::two::foo::Foo; +LL + pub use one::Foo; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/privacy/privacy-ns1.stderr b/tests/ui/privacy/privacy-ns1.stderr index 3396330c993c..c782c67e71c6 100644 --- a/tests/ui/privacy/privacy-ns1.stderr +++ b/tests/ui/privacy/privacy-ns1.stderr @@ -7,6 +7,14 @@ LL | pub struct Baz; LL | Bar(); | ^^^ | +note: these functions exist but are inaccessible + --> $DIR/privacy-ns1.rs:14:5 + | +LL | fn Bar() { } + | ^^^^^^^^ `foo1::Bar`: not accessible +... +LL | fn Bar() { } + | ^^^^^^^^ `foo3::Bar`: not accessible help: a unit struct with a similar name exists | LL - Bar(); @@ -26,6 +34,14 @@ LL | pub struct Baz; LL | Bar(); | ^^^ | +note: these functions exist but are inaccessible + --> $DIR/privacy-ns1.rs:14:5 + | +LL | fn Bar() { } + | ^^^^^^^^ `foo1::Bar`: not accessible +... +LL | fn Bar() { } + | ^^^^^^^^ `foo3::Bar`: not accessible help: a unit struct with a similar name exists | LL - Bar(); @@ -45,6 +61,14 @@ LL | pub struct Baz; LL | let _x: Box; | ^^^ | +note: these traits exist but are inaccessible + --> $DIR/privacy-ns1.rs:25:5 + | +LL | trait Bar { + | ^^^^^^^^^ `foo2::Bar`: not accessible +... +LL | trait Bar { + | ^^^^^^^^^ `foo3::Bar`: not accessible help: a struct with a similar name exists | LL - let _x: Box; diff --git a/tests/ui/privacy/privacy-ns2.stderr b/tests/ui/privacy/privacy-ns2.stderr index ac98682b2b39..fe1f0c9bd48c 100644 --- a/tests/ui/privacy/privacy-ns2.stderr +++ b/tests/ui/privacy/privacy-ns2.stderr @@ -4,6 +4,14 @@ error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar LL | Bar(); | ^^^ not a function, tuple struct or tuple variant | +note: these functions exist but are inaccessible + --> $DIR/privacy-ns2.rs:14:5 + | +LL | fn Bar() { } + | ^^^^^^^^ `foo1::Bar`: not accessible +... +LL | fn Bar() { } + | ^^^^^^^^ `foo3::Bar`: not accessible help: consider importing this function instead | LL + use foo2::Bar; @@ -18,6 +26,14 @@ LL | pub struct Baz; LL | Bar(); | ^^^ | +note: these functions exist but are inaccessible + --> $DIR/privacy-ns2.rs:14:5 + | +LL | fn Bar() { } + | ^^^^^^^^ `foo1::Bar`: not accessible +... +LL | fn Bar() { } + | ^^^^^^^^ `foo3::Bar`: not accessible help: a unit struct with a similar name exists | LL - Bar(); @@ -34,6 +50,14 @@ error[E0573]: expected type, found function `Bar` LL | let _x : Bar(); | ^^^^^ not a type | +note: these traits exist but are inaccessible + --> $DIR/privacy-ns2.rs:31:5 + | +LL | trait Bar { + | ^^^^^^^^^ `foo2::Bar`: not accessible +... +LL | trait Bar { + | ^^^^^^^^^ `foo3::Bar`: not accessible help: use `=` if you meant to assign | LL - let _x : Bar(); diff --git a/tests/ui/resolve/issue-21221-1.stderr b/tests/ui/resolve/issue-21221-1.stderr index ccf03afaa19f..dafa41bf312f 100644 --- a/tests/ui/resolve/issue-21221-1.stderr +++ b/tests/ui/resolve/issue-21221-1.stderr @@ -19,6 +19,17 @@ error[E0412]: cannot find type `Mul` in this scope LL | fn getMul() -> Mul { | ^^^ not found in this scope | +note: these items exist but are inaccessible + --> $DIR/issue-21221-1.rs:10:5 + | +LL | enum Mul { + | ^^^^^^^^ `mul3::Mul`: not accessible +... +LL | type Mul = String; + | ^^^^^^^^^^^^^^^^^^ `mul4::Mul`: not accessible +... +LL | struct Mul{ + | ^^^^^^^^^^ `mul5::Mul`: not accessible help: consider importing one of these traits | LL + use std::ops::Mul; diff --git a/tests/ui/unresolved/unresolved-import.rs b/tests/ui/unresolved/unresolved-import.rs index 763e9496734d..b0fdcf970155 100644 --- a/tests/ui/unresolved/unresolved-import.rs +++ b/tests/ui/unresolved/unresolved-import.rs @@ -31,6 +31,8 @@ mod food { mod zug { pub mod baz { + //~^ NOTE module `food::zug::baz` exists but is inaccessible + //~| NOTE not accessible pub struct Foobar; } } diff --git a/tests/ui/unresolved/unresolved-import.stderr b/tests/ui/unresolved/unresolved-import.stderr index c65fe841001d..4001695459a9 100644 --- a/tests/ui/unresolved/unresolved-import.stderr +++ b/tests/ui/unresolved/unresolved-import.stderr @@ -26,6 +26,12 @@ LL | use food::baz; | | | | | help: a similar name exists in the module: `bag` | no `baz` in `food` + | +note: module `food::zug::baz` exists but is inaccessible + --> $DIR/unresolved-import.rs:33:9 + | +LL | pub mod baz { + | ^^^^^^^^^^^ not accessible error[E0432]: unresolved import `food::beens` --> $DIR/unresolved-import.rs:19:12 @@ -37,13 +43,13 @@ LL | use food::{beens as Foo}; | help: a similar name exists in the module: `beans` error[E0432]: unresolved import `MyEnum` - --> $DIR/unresolved-import.rs:44:9 + --> $DIR/unresolved-import.rs:46:9 | LL | use MyEnum::*; | ^^^^^^ help: a similar path exists: `self::MyEnum` error[E0432]: unresolved import `Enum` - --> $DIR/unresolved-import.rs:55:9 + --> $DIR/unresolved-import.rs:57:9 | LL | use Enum::*; | ^^^^ help: a similar path exists: `self::Enum` From 5e6b4592d2da0df6b4a83695fd30d232bc7eb902 Mon Sep 17 00:00:00 2001 From: Spencer Date: Mon, 17 Mar 2025 21:40:20 -0600 Subject: [PATCH 207/546] cleaned and organized 3 tests in `./tests/ui/issues` --- src/tools/tidy/src/issues.txt | 3 -- src/tools/tidy/src/ui_tests.rs | 2 +- .../ui/coercion/struct-coerce-vec-to-slice.rs | 20 ++++++++++ ...al-field-type-coercion-to-expected-type.rs | 16 ++++++++ tests/ui/issues/issue-28777.rs | 22 ----------- tests/ui/issues/issue-31260.rs | 15 -------- tests/ui/issues/issue-9382.rs | 37 ------------------- .../operator-precedence-braces-exprs.rs | 28 ++++++++++++++ 8 files changed, 65 insertions(+), 78 deletions(-) create mode 100644 tests/ui/coercion/struct-coerce-vec-to-slice.rs create mode 100644 tests/ui/coercion/struct-literal-field-type-coercion-to-expected-type.rs delete mode 100644 tests/ui/issues/issue-28777.rs delete mode 100644 tests/ui/issues/issue-31260.rs delete mode 100644 tests/ui/issues/issue-9382.rs create mode 100644 tests/ui/parser/operator-precedence-braces-exprs.rs diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 2b9ae1954785..4a929a376d78 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2000,7 +2000,6 @@ ui/issues/issue-28586.rs ui/issues/issue-28600.rs ui/issues/issue-28625.rs ui/issues/issue-28776.rs -ui/issues/issue-28777.rs ui/issues/issue-28828.rs ui/issues/issue-28839.rs ui/issues/issue-28936.rs @@ -2063,7 +2062,6 @@ ui/issues/issue-3091.rs ui/issues/issue-31011.rs ui/issues/issue-3109.rs ui/issues/issue-3121.rs -ui/issues/issue-31260.rs ui/issues/issue-31267-additional.rs ui/issues/issue-31267.rs ui/issues/issue-31299.rs @@ -2608,7 +2606,6 @@ ui/issues/issue-9243.rs ui/issues/issue-9249.rs ui/issues/issue-9259.rs ui/issues/issue-92741.rs -ui/issues/issue-9382.rs ui/issues/issue-9446.rs ui/issues/issue-9719.rs ui/issues/issue-9725.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index fe51231c4810..61728d0553fd 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1634; +const ISSUES_ENTRY_LIMIT: u32 = 1631; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/coercion/struct-coerce-vec-to-slice.rs b/tests/ui/coercion/struct-coerce-vec-to-slice.rs new file mode 100644 index 000000000000..9ef20ac4ea63 --- /dev/null +++ b/tests/ui/coercion/struct-coerce-vec-to-slice.rs @@ -0,0 +1,20 @@ +//! Regression test that ensures struct field literals can be coerced into slice and `Box` types + +//@ check-pass + +struct Thing1<'a> { + baz: &'a [Box], + bar: Box, +} + +struct Thing2<'a> { + baz: &'a [Box], + bar: u64, +} + +pub fn main() { + let _a = Thing1 { baz: &[], bar: Box::new(32) }; + let _b = Thing1 { baz: &Vec::new(), bar: Box::new(32) }; + let _c = Thing2 { baz: &[], bar: 32 }; + let _d = Thing2 { baz: &Vec::new(), bar: 32 }; +} diff --git a/tests/ui/coercion/struct-literal-field-type-coercion-to-expected-type.rs b/tests/ui/coercion/struct-literal-field-type-coercion-to-expected-type.rs new file mode 100644 index 000000000000..0b8ec7dc07a7 --- /dev/null +++ b/tests/ui/coercion/struct-literal-field-type-coercion-to-expected-type.rs @@ -0,0 +1,16 @@ +//! Regression test to check that literal expressions in a struct field can be coerced to the +//! expected field type, including block expressions. +//! +//! Issue: + +//@ check-pass + +pub struct Struct { + pub field: K, +} + +static STRUCT: Struct<&'static [u8]> = Struct { field: { &[1] } }; + +static STRUCT2: Struct<&'static [u8]> = Struct { field: &[1] }; + +fn main() {} diff --git a/tests/ui/issues/issue-28777.rs b/tests/ui/issues/issue-28777.rs deleted file mode 100644 index f67e11e36946..000000000000 --- a/tests/ui/issues/issue-28777.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ run-pass -#![allow(unused_braces)] -fn main() { - let v1 = { 1 + {2} * {3} }; - let v2 = 1 + {2} * {3} ; - - assert_eq!(7, v1); - assert_eq!(7, v2); - - let v3; - v3 = { 1 + {2} * {3} }; - let v4; - v4 = 1 + {2} * {3}; - assert_eq!(7, v3); - assert_eq!(7, v4); - - let v5 = { 1 + {2} * 3 }; - assert_eq!(7, v5); - - let v9 = { 1 + if 1 > 2 {1} else {2} * {3} }; - assert_eq!(7, v9); -} diff --git a/tests/ui/issues/issue-31260.rs b/tests/ui/issues/issue-31260.rs deleted file mode 100644 index 5e9fffb195c6..000000000000 --- a/tests/ui/issues/issue-31260.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ check-pass -#![allow(dead_code)] -pub struct Struct { - pub field: K, -} - -static STRUCT: Struct<&'static [u8]> = Struct { - field: {&[1]} -}; - -static STRUCT2: Struct<&'static [u8]> = Struct { - field: &[1] -}; - -fn main() {} diff --git a/tests/ui/issues/issue-9382.rs b/tests/ui/issues/issue-9382.rs deleted file mode 100644 index 27f9ab577437..000000000000 --- a/tests/ui/issues/issue-9382.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -// Tests for a previous bug that occurred due to an interaction -// between struct field initialization and the auto-coercion -// from a vector to a slice. The drop glue was being invoked on -// the temporary slice with a wrong type, triggering an LLVM assert. - - -struct Thing1<'a> { - baz: &'a [Box], - bar: Box, -} - -struct Thing2<'a> { - baz: &'a [Box], - bar: u64, -} - -pub fn main() { - let _t1_fixed = Thing1 { - baz: &[], - bar: Box::new(32), - }; - Thing1 { - baz: &Vec::new(), - bar: Box::new(32), - }; - let _t2_fixed = Thing2 { - baz: &[], - bar: 32, - }; - Thing2 { - baz: &Vec::new(), - bar: 32, - }; -} diff --git a/tests/ui/parser/operator-precedence-braces-exprs.rs b/tests/ui/parser/operator-precedence-braces-exprs.rs new file mode 100644 index 000000000000..d6f44ef879ce --- /dev/null +++ b/tests/ui/parser/operator-precedence-braces-exprs.rs @@ -0,0 +1,28 @@ +//! Regression test for ensuring that operator precedence is correctly handled in the presence of +//! braces +//! +//! Issue: + +//@ run-pass + +#[allow(unused_braces)] +fn main() { + let v1 = { 1 + { 2 } * { 3 } }; + let v2 = 1 + { 2 } * { 3 }; + + assert_eq!(7, v1); + assert_eq!(7, v2); + + let v3; + v3 = { 1 + { 2 } * { 3 } }; + let v4; + v4 = 1 + { 2 } * { 3 }; + assert_eq!(7, v3); + assert_eq!(7, v4); + + let v5 = { 1 + { 2 } * 3 }; + assert_eq!(7, v5); + + let v9 = { 1 + if 1 > 2 { 1 } else { 2 } * { 3 } }; + assert_eq!(7, v9); +} From 5016467a23c93384ffcb58b9c5ff2f8afc349d54 Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 28 Nov 2024 21:57:39 +0800 Subject: [PATCH 208/546] Implement `UniqueArc` --- library/alloc/src/sync.rs | 182 +++++++++++++++++++++++++++++++- library/alloctests/tests/arc.rs | 5 +- library/std/src/sync/mod.rs | 2 + 3 files changed, 187 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index c62f8e5b70f4..3903303bcea6 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -20,7 +20,7 @@ use core::iter; use core::marker::{PhantomData, Unsize}; use core::mem::{self, ManuallyDrop, align_of_val_raw}; use core::num::NonZeroUsize; -use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, LegacyReceiver}; +use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::{Pin, PinCoerceUnsized}; use core::ptr::{self, NonNull}; @@ -4066,3 +4066,183 @@ impl core::error::Error for Arc { core::error::Error::provide(&**self, req); } } + +/// A uniquely owned [`Arc`]. +/// +/// This represents an `Arc` that is known to be uniquely owned -- that is, have exactly one strong +/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong +/// references will fail unless the `UniqueArc` they point to has been converted into a regular `Arc`. +/// +/// Because they are uniquely owned, the contents of a `UniqueArc` can be freely mutated. A common +/// use case is to have an object be mutable during its initialization phase but then have it become +/// immutable and converted to a normal `Arc`. +/// +/// This can be used as a flexible way to create cyclic data structures, as in the example below. +/// +/// ``` +/// #![feature(unique_rc_arc)] +/// use std::sync::{Arc, Weak, UniqueArc}; +/// +/// struct Gadget { +/// #[allow(dead_code)] +/// me: Weak, +/// } +/// +/// fn create_gadget() -> Option> { +/// let mut rc = UniqueArc::new(Gadget { +/// me: Weak::new(), +/// }); +/// rc.me = UniqueArc::downgrade(&rc); +/// Some(UniqueArc::into_arc(rc)) +/// } +/// +/// create_gadget().unwrap(); +/// ``` +/// +/// An advantage of using `UniqueArc` over [`Arc::new_cyclic`] to build cyclic data structures is that +/// [`Arc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the +/// previous example, `UniqueArc` allows for more flexibility in the construction of cyclic data, +/// including fallible or async constructors. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[derive(Debug)] +pub struct UniqueArc< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + ptr: NonNull>, + phantom: PhantomData>, + alloc: A, +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> + for UniqueArc +{ +} + +// Depends on A = Global +impl UniqueArc { + /// Creates a new `UniqueArc`. + /// + /// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueArc` has been converted into an [`Arc`]. + /// After converting the `UniqueArc` into an [`Arc`], any weak references created beforehand will + /// point to the new [`Arc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new(value: T) -> Self { + Self::new_in(value, Global) + } +} + +impl UniqueArc { + /// Creates a new `UniqueArc` in the provided allocator. + /// + /// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueArc` has been converted into an [`Arc`]. + /// After converting the `UniqueArc` into an [`Arc`], any weak references created beforehand will + /// point to the new [`Arc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new_in(data: T, alloc: A) -> Self { + let (ptr, alloc) = Box::into_unique(Box::new_in( + ArcInner { + strong: atomic::AtomicUsize::new(0), + // keep one weak reference so if all the weak pointers that are created are dropped + // the UniqueArc still stays valid. + weak: atomic::AtomicUsize::new(1), + data, + }, + alloc, + )); + Self { ptr: ptr.into(), phantom: PhantomData, alloc } + } +} + +impl UniqueArc { + /// Converts the `UniqueArc` into a regular [`Arc`]. + /// + /// This consumes the `UniqueArc` and returns a regular [`Arc`] that contains the `value` that + /// is passed to `into_arc`. + /// + /// Any weak references created before this method is called can now be upgraded to strong + /// references. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn into_arc(this: Self) -> Arc { + let this = ManuallyDrop::new(this); + + // Move the allocator out. + // SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in + // a `ManuallyDrop`. + let alloc: A = unsafe { ptr::read(&this.alloc) }; + + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { + // Convert our weak reference into a strong reference + (*this.ptr.as_ptr()).strong.store(1, Release); + Arc::from_inner_in(this.ptr, alloc) + } + } +} + +impl UniqueArc { + /// Creates a new weak reference to the `UniqueArc`. + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueArc` has been converted + /// to a [`Arc`] using [`UniqueArc::into_arc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak { + // Using a relaxed ordering is alright here, as knowledge of the + // original reference prevents other threads from erroneously deleting + // the object or converting the object to a normal `Arc`. + // + // Note that we don't need to test if the weak counter is locked because there + // are no such operations like `Arc::get_mut` or `Arc::make_mut` that will lock + // the weak counter. + // + // SAFETY: This pointer was allocated at creation time so we know it is valid. + let old_size = unsafe { (*this.ptr.as_ptr()).weak.fetch_add(1, Relaxed) }; + + // See comments in Arc::clone() for why we do this (for mem::forget). + if old_size > MAX_REFCOUNT { + abort(); + } + + Weak { ptr: this.ptr, alloc: this.alloc.clone() } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Deref for UniqueArc { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { &self.ptr.as_ref().data } + } +} + +// #[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for UniqueArc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl DerefMut for UniqueArc { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we + // have unique ownership and therefore it's safe to make a mutable reference because + // `UniqueArc` owns the only strong reference to itself. + unsafe { &mut (*self.ptr.as_ptr()).data } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueArc { + fn drop(&mut self) { + // See `Arc::drop_slow` which drops an `Arc` with a strong count of 0. + // SAFETY: This pointer was allocated at creation time so we know it is valid. + let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; + + unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) }; + } +} diff --git a/library/alloctests/tests/arc.rs b/library/alloctests/tests/arc.rs index 0baa50f439b3..45a145c6271a 100644 --- a/library/alloctests/tests/arc.rs +++ b/library/alloctests/tests/arc.rs @@ -265,7 +265,7 @@ fn make_mut_unsized() { #[allow(unused)] mod pin_coerce_unsized { - use alloc::sync::Arc; + use alloc::sync::{Arc, UniqueArc}; use core::pin::Pin; pub trait MyTrait {} @@ -275,4 +275,7 @@ mod pin_coerce_unsized { pub fn pin_arc(arg: Pin>) -> Pin> { arg } + pub fn pin_unique_arc(arg: Pin>) -> Pin> { + arg + } } diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 5b50a3c6ccf9..e67b4f6f22f5 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -176,6 +176,8 @@ pub use core::sync::Exclusive; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; +#[unstable(feature = "unique_rc_arc", issue = "112566")] +pub use alloc_crate::sync::UniqueArc; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::sync::{Arc, Weak}; From 9e5cca504988932581fa6c83c8626101013d64cd Mon Sep 17 00:00:00 2001 From: Frank King Date: Mon, 3 Mar 2025 10:53:25 +0800 Subject: [PATCH 209/546] Make UniqueArc invariant for soundness --- library/alloc/src/sync.rs | 8 ++++-- tests/ui/variance/variance-uniquearc.rs | 27 +++++++++++++++++++++ tests/ui/variance/variance-uniquearc.stderr | 15 ++++++++++++ tests/ui/variance/variance-uniquerc.rs | 2 +- 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/ui/variance/variance-uniquearc.rs create mode 100644 tests/ui/variance/variance-uniquearc.stderr diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 3903303bcea6..5f0133c6c56d 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4110,7 +4110,11 @@ pub struct UniqueArc< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { ptr: NonNull>, - phantom: PhantomData>, + // Define the ownership of `ArcInner` for drop-check + _marker: PhantomData>, + // Invariance is necessary for soundness: once other `Weak` + // references exist, we already have a form of shared mutability! + _marker2: PhantomData<*mut T>, alloc: A, } @@ -4155,7 +4159,7 @@ impl UniqueArc { }, alloc, )); - Self { ptr: ptr.into(), phantom: PhantomData, alloc } + Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } } } diff --git a/tests/ui/variance/variance-uniquearc.rs b/tests/ui/variance/variance-uniquearc.rs new file mode 100644 index 000000000000..035895123886 --- /dev/null +++ b/tests/ui/variance/variance-uniquearc.rs @@ -0,0 +1,27 @@ +// regression test of https://github.com/rust-lang/rust/pull/133572#issuecomment-2543007164 +// see also the test for UniqueRc` in variance-uniquerc.rs +// +// inline comments explain how this code *would* compile if UniqueArc was still covariant + +#![feature(unique_rc_arc)] + +use std::sync::UniqueArc; + +fn extend_lifetime<'a, 'b>(x: &'a str) -> &'b str { + let r = UniqueArc::new(""); // UniqueArc<&'static str> + let w = UniqueArc::downgrade(&r); // Weak<&'static str> + let mut r = r; // [IF COVARIANT]: ==>> UniqueArc<&'a str> + *r = x; // assign the &'a str + let _r = UniqueArc::into_arc(r); // Arc<&'a str>, but we only care to activate the weak + let r = w.upgrade().unwrap(); // Arc<&'static str> + *r // &'static str, coerces to &'b str + //~^ ERROR lifetime may not live long enough +} + +fn main() { + let s = String::from("Hello World!"); + let r = extend_lifetime(&s); + println!("{r}"); + drop(s); + println!("{r}"); +} diff --git a/tests/ui/variance/variance-uniquearc.stderr b/tests/ui/variance/variance-uniquearc.stderr new file mode 100644 index 000000000000..55076dae7324 --- /dev/null +++ b/tests/ui/variance/variance-uniquearc.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/variance-uniquearc.rs:17:5 + | +LL | fn extend_lifetime<'a, 'b>(x: &'a str) -> &'b str { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | *r // &'static str, coerces to &'b str + | ^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 1 previous error + diff --git a/tests/ui/variance/variance-uniquerc.rs b/tests/ui/variance/variance-uniquerc.rs index 0c395ab06eaa..2e9738f66dcb 100644 --- a/tests/ui/variance/variance-uniquerc.rs +++ b/tests/ui/variance/variance-uniquerc.rs @@ -1,5 +1,5 @@ // regression test of https://github.com/rust-lang/rust/pull/133572#issuecomment-2543007164 -// we should also test UniqueArc once implemented +// see also the test for UniqueArc in variance-uniquearc.rs // // inline comments explain how this code *would* compile if UniqueRc was still covariant From b542a2bd4bbef0221a78ecbd31d4a4ea9fb22f64 Mon Sep 17 00:00:00 2001 From: Frank King Date: Mon, 3 Mar 2025 15:51:05 +0800 Subject: [PATCH 210/546] Add more APIs for UniqueArc --- library/alloc/src/sync.rs | 255 +++++++++++++++++++++++++++++++++++++- 1 file changed, 250 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5f0133c6c56d..b883f84d68ee 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4073,7 +4073,7 @@ impl core::error::Error for Arc { /// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong /// references will fail unless the `UniqueArc` they point to has been converted into a regular `Arc`. /// -/// Because they are uniquely owned, the contents of a `UniqueArc` can be freely mutated. A common +/// Because it is uniquely owned, the contents of a `UniqueArc` can be freely mutated. A common /// use case is to have an object be mutable during its initialization phase but then have it become /// immutable and converted to a normal `Arc`. /// @@ -4084,7 +4084,6 @@ impl core::error::Error for Arc { /// use std::sync::{Arc, Weak, UniqueArc}; /// /// struct Gadget { -/// #[allow(dead_code)] /// me: Weak, /// } /// @@ -4104,7 +4103,6 @@ impl core::error::Error for Arc { /// previous example, `UniqueArc` allows for more flexibility in the construction of cyclic data, /// including fallible or async constructors. #[unstable(feature = "unique_rc_arc", issue = "112566")] -#[derive(Debug)] pub struct UniqueArc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -4119,13 +4117,248 @@ pub struct UniqueArc< } #[unstable(feature = "unique_rc_arc", issue = "112566")] +unsafe impl Send for UniqueArc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +unsafe impl Sync for UniqueArc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +// #[unstable(feature = "coerce_unsized", issue = "18598")] impl, U: ?Sized, A: Allocator> CoerceUnsized> for UniqueArc { } -// Depends on A = Global -impl UniqueArc { +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl, U: ?Sized> DispatchFromDyn> for UniqueArc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Display for UniqueArc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Debug for UniqueArc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Pointer for UniqueArc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(&raw const **self), f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl borrow::Borrow for UniqueArc { + fn borrow(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl borrow::BorrowMut for UniqueArc { + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsRef for UniqueArc { + fn as_ref(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsMut for UniqueArc { + fn as_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Unpin for UniqueArc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl PartialEq for UniqueArc { + /// Equality for two `UniqueArc`s. + /// + /// Two `UniqueArc`s are equal if their inner values are equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::sync::UniqueArc; + /// + /// let five = UniqueArc::new(5); + /// + /// assert!(five == UniqueArc::new(5)); + /// ``` + #[inline] + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(&**self, &**other) + } + + /// Inequality for two `UniqueArc`s. + /// + /// Two `UniqueArc`s are not equal if their inner values are not equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::sync::UniqueArc; + /// + /// let five = UniqueArc::new(5); + /// + /// assert!(five != UniqueArc::new(6)); + /// ``` + #[inline] + fn ne(&self, other: &Self) -> bool { + PartialEq::ne(&**self, &**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl PartialOrd for UniqueArc { + /// Partial comparison for two `UniqueArc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::sync::UniqueArc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueArc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&UniqueArc::new(6))); + /// ``` + #[inline(always)] + fn partial_cmp(&self, other: &UniqueArc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `UniqueArc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::sync::UniqueArc; + /// + /// let five = UniqueArc::new(5); + /// + /// assert!(five < UniqueArc::new(6)); + /// ``` + #[inline(always)] + fn lt(&self, other: &UniqueArc) -> bool { + **self < **other + } + + /// 'Less than or equal to' comparison for two `UniqueArc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::sync::UniqueArc; + /// + /// let five = UniqueArc::new(5); + /// + /// assert!(five <= UniqueArc::new(5)); + /// ``` + #[inline(always)] + fn le(&self, other: &UniqueArc) -> bool { + **self <= **other + } + + /// Greater-than comparison for two `UniqueArc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::sync::UniqueArc; + /// + /// let five = UniqueArc::new(5); + /// + /// assert!(five > UniqueArc::new(4)); + /// ``` + #[inline(always)] + fn gt(&self, other: &UniqueArc) -> bool { + **self > **other + } + + /// 'Greater than or equal to' comparison for two `UniqueArc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::sync::UniqueArc; + /// + /// let five = UniqueArc::new(5); + /// + /// assert!(five >= UniqueArc::new(5)); + /// ``` + #[inline(always)] + fn ge(&self, other: &UniqueArc) -> bool { + **self >= **other + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Ord for UniqueArc { + /// Comparison for two `UniqueArc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::sync::UniqueArc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueArc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&UniqueArc::new(6))); + /// ``` + #[inline] + fn cmp(&self, other: &UniqueArc) -> Ordering { + (**self).cmp(&**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Eq for UniqueArc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Hash for UniqueArc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + +impl UniqueArc { /// Creates a new `UniqueArc`. /// /// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading @@ -4134,6 +4367,7 @@ impl UniqueArc { /// point to the new [`Arc`]. #[cfg(not(no_global_oom_handling))] #[unstable(feature = "unique_rc_arc", issue = "112566")] + #[must_use] pub fn new(value: T) -> Self { Self::new_in(value, Global) } @@ -4148,6 +4382,8 @@ impl UniqueArc { /// point to the new [`Arc`]. #[cfg(not(no_global_oom_handling))] #[unstable(feature = "unique_rc_arc", issue = "112566")] + #[must_use] + // #[unstable(feature = "allocator_api", issue = "32838")] pub fn new_in(data: T, alloc: A) -> Self { let (ptr, alloc) = Box::into_unique(Box::new_in( ArcInner { @@ -4172,6 +4408,7 @@ impl UniqueArc { /// Any weak references created before this method is called can now be upgraded to strong /// references. #[unstable(feature = "unique_rc_arc", issue = "112566")] + #[must_use] pub fn into_arc(this: Self) -> Arc { let this = ManuallyDrop::new(this); @@ -4195,6 +4432,7 @@ impl UniqueArc { /// Attempting to upgrade this weak reference will fail before the `UniqueArc` has been converted /// to a [`Arc`] using [`UniqueArc::into_arc`]. #[unstable(feature = "unique_rc_arc", issue = "112566")] + #[must_use] pub fn downgrade(this: &Self) -> Weak { // Using a relaxed ordering is alright here, as knowledge of the // original reference prevents other threads from erroneously deleting @@ -4236,10 +4474,17 @@ impl DerefMut for UniqueArc { // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we // have unique ownership and therefore it's safe to make a mutable reference because // `UniqueArc` owns the only strong reference to itself. + // We also need to be careful to only create a mutable reference to the `data` field, + // as a mutable reference to the entire `ArcInner` would assert uniqueness over the + // ref count fields too, invalidating any attempt by `Weak`s to access the ref count. unsafe { &mut (*self.ptr.as_ptr()).data } } } +#[unstable(feature = "unique_rc_arc", issue = "112566")] +// #[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for UniqueArc {} + #[unstable(feature = "unique_rc_arc", issue = "112566")] unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueArc { fn drop(&mut self) { From eb094ed7b4c600de21d1ace851349c9c38298fa8 Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 6 Mar 2025 22:15:58 +0800 Subject: [PATCH 211/546] Remove `PartialEq::ne` for `UniqueArc` --- library/alloc/src/sync.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index b883f84d68ee..be581661f4ce 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4205,25 +4205,6 @@ impl PartialEq for UniqueArc { fn eq(&self, other: &Self) -> bool { PartialEq::eq(&**self, &**other) } - - /// Inequality for two `UniqueArc`s. - /// - /// Two `UniqueArc`s are not equal if their inner values are not equal. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::sync::UniqueArc; - /// - /// let five = UniqueArc::new(5); - /// - /// assert!(five != UniqueArc::new(6)); - /// ``` - #[inline] - fn ne(&self, other: &Self) -> bool { - PartialEq::ne(&**self, &**other) - } } #[unstable(feature = "unique_rc_arc", issue = "112566")] From bd49a4beb703325a0356d64aef0b65e239033d61 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Fri, 7 Feb 2025 13:59:00 -0800 Subject: [PATCH 212/546] Implement optional methods for unsupported stdio Match what `std::io::Empty` does, since it is very similar. However, still evaluate the `fmt::Arguments` in `write_fmt` to be consistent with other platforms. --- library/std/src/sys/stdio/unsupported.rs | 65 +++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/stdio/unsupported.rs b/library/std/src/sys/stdio/unsupported.rs index 67f7c1b7efb9..177264f5c104 100644 --- a/library/std/src/sys/stdio/unsupported.rs +++ b/library/std/src/sys/stdio/unsupported.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; pub struct Stdin; pub struct Stdout; @@ -11,9 +11,47 @@ impl Stdin { } impl io::Read for Stdin { + #[inline] fn read(&mut self, _buf: &mut [u8]) -> io::Result { Ok(0) } + + #[inline] + fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn read_vectored(&mut self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + Ok(0) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + // Do not force `Chain` or `Chain` to use vectored + // reads, unless the other reader is vectored. + false + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } + } + + #[inline] + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + if cursor.capacity() != 0 { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } + } + + #[inline] + fn read_to_end(&mut self, _buf: &mut Vec) -> io::Result { + Ok(0) + } + + #[inline] + fn read_to_string(&mut self, _buf: &mut String) -> io::Result { + Ok(0) + } } impl Stdout { @@ -23,10 +61,35 @@ impl Stdout { } impl io::Write for Stdout { + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + // Keep the default write_fmt so the `fmt::Arguments` are still evaluated. + + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } From ec4beda5d2403ff13ea138c12f98857701ef5c70 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sun, 9 Feb 2025 02:02:42 -0800 Subject: [PATCH 213/546] Implement exact reads for StdinRaw --- library/std/src/io/stdio.rs | 63 ++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index ce46241f8e84..8fc163313397 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -97,15 +97,15 @@ const fn stderr_raw() -> StderrRaw { impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result { - handle_ebadf(self.0.read(buf), 0) + handle_ebadf(self.0.read(buf), || Ok(0)) } fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - handle_ebadf(self.0.read_buf(buf), ()) + handle_ebadf(self.0.read_buf(buf), || Ok(())) } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - handle_ebadf(self.0.read_vectored(bufs), 0) + handle_ebadf(self.0.read_vectored(bufs), || Ok(0)) } #[inline] @@ -113,23 +113,37 @@ impl Read for StdinRaw { self.0.is_read_vectored() } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + if buf.is_empty() { + return Ok(()); + } + handle_ebadf(self.0.read_exact(buf), || Err(io::Error::READ_EXACT_EOF)) + } + + fn read_buf_exact(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + if buf.capacity() == 0 { + return Ok(()); + } + handle_ebadf(self.0.read_buf_exact(buf), || Err(io::Error::READ_EXACT_EOF)) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - handle_ebadf(self.0.read_to_end(buf), 0) + handle_ebadf(self.0.read_to_end(buf), || Ok(0)) } fn read_to_string(&mut self, buf: &mut String) -> io::Result { - handle_ebadf(self.0.read_to_string(buf), 0) + handle_ebadf(self.0.read_to_string(buf), || Ok(0)) } } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result { - handle_ebadf(self.0.write(buf), buf.len()) + handle_ebadf(self.0.write(buf), || Ok(buf.len())) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = || bufs.iter().map(|b| b.len()).sum(); - handle_ebadf_lazy(self.0.write_vectored(bufs), total) + let total = || Ok(bufs.iter().map(|b| b.len()).sum()); + handle_ebadf(self.0.write_vectored(bufs), total) } #[inline] @@ -138,30 +152,30 @@ impl Write for StdoutRaw { } fn flush(&mut self) -> io::Result<()> { - handle_ebadf(self.0.flush(), ()) + handle_ebadf(self.0.flush(), || Ok(())) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - handle_ebadf(self.0.write_all(buf), ()) + handle_ebadf(self.0.write_all(buf), || Ok(())) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - handle_ebadf(self.0.write_all_vectored(bufs), ()) + handle_ebadf(self.0.write_all_vectored(bufs), || Ok(())) } fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - handle_ebadf(self.0.write_fmt(fmt), ()) + handle_ebadf(self.0.write_fmt(fmt), || Ok(())) } } impl Write for StderrRaw { fn write(&mut self, buf: &[u8]) -> io::Result { - handle_ebadf(self.0.write(buf), buf.len()) + handle_ebadf(self.0.write(buf), || Ok(buf.len())) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = || bufs.iter().map(|b| b.len()).sum(); - handle_ebadf_lazy(self.0.write_vectored(bufs), total) + let total = || Ok(bufs.iter().map(|b| b.len()).sum()); + handle_ebadf(self.0.write_vectored(bufs), total) } #[inline] @@ -170,32 +184,25 @@ impl Write for StderrRaw { } fn flush(&mut self) -> io::Result<()> { - handle_ebadf(self.0.flush(), ()) + handle_ebadf(self.0.flush(), || Ok(())) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - handle_ebadf(self.0.write_all(buf), ()) + handle_ebadf(self.0.write_all(buf), || Ok(())) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - handle_ebadf(self.0.write_all_vectored(bufs), ()) + handle_ebadf(self.0.write_all_vectored(bufs), || Ok(())) } fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - handle_ebadf(self.0.write_fmt(fmt), ()) + handle_ebadf(self.0.write_fmt(fmt), || Ok(())) } } -fn handle_ebadf(r: io::Result, default: T) -> io::Result { +fn handle_ebadf(r: io::Result, default: impl FnOnce() -> io::Result) -> io::Result { match r { - Err(ref e) if stdio::is_ebadf(e) => Ok(default), - r => r, - } -} - -fn handle_ebadf_lazy(r: io::Result, default: impl FnOnce() -> T) -> io::Result { - match r { - Err(ref e) if stdio::is_ebadf(e) => Ok(default()), + Err(ref e) if stdio::is_ebadf(e) => default(), r => r, } } From f6e90d804a82cce1606596f6116402843794deb3 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Tue, 18 Feb 2025 14:29:24 -0800 Subject: [PATCH 214/546] Use unit structs for stateless stdio This seems to be the pattern for newer pal stdio types. --- library/std/src/sys/stdio/sgx.rs | 12 ++++++------ library/std/src/sys/stdio/unix.rs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/std/src/sys/stdio/sgx.rs b/library/std/src/sys/stdio/sgx.rs index 03d754cb2173..e45ece5ea3bc 100644 --- a/library/std/src/sys/stdio/sgx.rs +++ b/library/std/src/sys/stdio/sgx.rs @@ -3,9 +3,9 @@ use fortanix_sgx_abi as abi; use crate::io; use crate::sys::fd::FileDesc; -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; fn with_std_fd R, R>(fd: abi::Fd, f: F) -> R { let fd = FileDesc::new(fd); @@ -16,7 +16,7 @@ fn with_std_fd R, R>(fd: abi::Fd, f: F) -> R { impl Stdin { pub const fn new() -> Stdin { - Stdin(()) + Stdin } } @@ -28,7 +28,7 @@ impl io::Read for Stdin { impl Stdout { pub const fn new() -> Stdout { - Stdout(()) + Stdout } } @@ -44,7 +44,7 @@ impl io::Write for Stdout { impl Stderr { pub const fn new() -> Stderr { - Stderr(()) + Stderr } } diff --git a/library/std/src/sys/stdio/unix.rs b/library/std/src/sys/stdio/unix.rs index 8d133857c596..b511b8effceb 100644 --- a/library/std/src/sys/stdio/unix.rs +++ b/library/std/src/sys/stdio/unix.rs @@ -13,13 +13,13 @@ use crate::os::hermit::io::FromRawFd; use crate::os::unix::io::FromRawFd; use crate::sys::fd::FileDesc; -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; impl Stdin { pub const fn new() -> Stdin { - Stdin(()) + Stdin } } @@ -45,7 +45,7 @@ impl io::Read for Stdin { impl Stdout { pub const fn new() -> Stdout { - Stdout(()) + Stdout } } @@ -71,7 +71,7 @@ impl io::Write for Stdout { impl Stderr { pub const fn new() -> Stderr { - Stderr(()) + Stderr } } From 89f85cbfa7e508e55f2f05c00356b6d430c55c4e Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 12 Feb 2025 16:26:34 +0100 Subject: [PATCH 215/546] std: move process implementations to `sys` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per #117276, this moves the implementations of `Process` and friends out of the `pal` module and into the `sys` module, removing quite a lot of error-prone `#[path]` imports in the process (hah, get it ;-)). I've also made the `zircon` module a dedicated submodule of `pal::unix`, hopefully we can move some other definitions there as well (they are currently quite a lot of duplications in `sys`). Also, the `ensure_no_nuls` function on Windows now lives in `sys::pal::windows` – it's not specific to processes and shared by the argument implementation. --- library/std/src/sys/mod.rs | 1 + library/std/src/sys/pal/hermit/mod.rs | 2 -- library/std/src/sys/pal/sgx/mod.rs | 2 -- library/std/src/sys/pal/solid/mod.rs | 2 -- library/std/src/sys/pal/teeos/mod.rs | 2 -- library/std/src/sys/pal/uefi/mod.rs | 1 - .../unix/{process/zircon.rs => fuchsia.rs} | 0 library/std/src/sys/pal/unix/mod.rs | 5 ++-- library/std/src/sys/pal/unix/process/mod.rs | 27 ------------------- library/std/src/sys/pal/unsupported/mod.rs | 1 - library/std/src/sys/pal/wasi/mod.rs | 2 -- library/std/src/sys/pal/wasip2/mod.rs | 2 -- library/std/src/sys/pal/wasm/mod.rs | 2 -- library/std/src/sys/pal/windows/args.rs | 2 +- library/std/src/sys/pal/windows/mod.rs | 9 ++++++- library/std/src/sys/pal/xous/mod.rs | 2 -- library/std/src/sys/pal/zkvm/mod.rs | 2 -- library/std/src/sys/process/mod.rs | 19 +++++++++++++ .../{pal/uefi/process.rs => process/uefi.rs} | 10 +++---- .../unix/common.rs} | 2 +- .../unix/common}/tests.rs | 0 .../unix/fuchsia.rs} | 14 +++------- library/std/src/sys/process/unix/mod.rs | 23 ++++++++++++++++ .../process_unix.rs => process/unix/unix.rs} | 18 ++++++------- .../unix/unix}/tests.rs | 0 .../unix/unsupported.rs} | 4 +-- .../unix/unsupported}/wait_status.rs | 7 ++--- .../unix/unsupported}/wait_status/tests.rs | 2 +- .../unix/vxworks.rs} | 6 ++--- .../process.rs => process/unsupported.rs} | 0 .../windows/process.rs => process/windows.rs} | 25 ++++++----------- .../process => process/windows}/tests.rs | 0 32 files changed, 90 insertions(+), 104 deletions(-) rename library/std/src/sys/pal/unix/{process/zircon.rs => fuchsia.rs} (100%) delete mode 100644 library/std/src/sys/pal/unix/process/mod.rs create mode 100644 library/std/src/sys/process/mod.rs rename library/std/src/sys/{pal/uefi/process.rs => process/uefi.rs} (99%) rename library/std/src/sys/{pal/unix/process/process_common.rs => process/unix/common.rs} (99%) rename library/std/src/sys/{pal/unix/process/process_common => process/unix/common}/tests.rs (100%) rename library/std/src/sys/{pal/unix/process/process_fuchsia.rs => process/unix/fuchsia.rs} (96%) create mode 100644 library/std/src/sys/process/unix/mod.rs rename library/std/src/sys/{pal/unix/process/process_unix.rs => process/unix/unix.rs} (99%) rename library/std/src/sys/{pal/unix/process/process_unix => process/unix/unix}/tests.rs (100%) rename library/std/src/sys/{pal/unix/process/process_unsupported.rs => process/unix/unsupported.rs} (94%) rename library/std/src/sys/{pal/unix/process/process_unsupported => process/unix/unsupported}/wait_status.rs (91%) rename library/std/src/sys/{pal/unix/process/process_unsupported => process/unix/unsupported}/wait_status/tests.rs (96%) rename library/std/src/sys/{pal/unix/process/process_vxworks.rs => process/unix/vxworks.rs} (98%) rename library/std/src/sys/{pal/unsupported/process.rs => process/unsupported.rs} (100%) rename library/std/src/sys/{pal/windows/process.rs => process/windows.rs} (98%) rename library/std/src/sys/{pal/windows/process => process/windows}/tests.rs (100%) diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 09677b9d6428..f0cfb9b27736 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -17,6 +17,7 @@ pub mod io; pub mod net; pub mod os_str; pub mod path; +pub mod process; pub mod random; pub mod stdio; pub mod sync; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 608245bd430b..67eab96fa403 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -25,8 +25,6 @@ pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index bb419c2530ec..fe43cfd2caf7 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -16,8 +16,6 @@ mod libunwind_integration; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; pub mod thread; pub mod thread_parking; pub mod time; diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index e4a61fdcfe3e..22052a168fd1 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -25,8 +25,6 @@ pub(crate) mod error; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; pub use self::itron::{thread, thread_parking}; pub mod time; diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 41b251215928..c1921a2f40df 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -14,8 +14,6 @@ pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; pub mod thread; #[allow(non_upper_case_globals)] #[path = "../unix/time.rs"] diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 714dc392688f..fc12ec63b5c9 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -19,7 +19,6 @@ pub mod helpers; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub mod process; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/unix/process/zircon.rs b/library/std/src/sys/pal/unix/fuchsia.rs similarity index 100% rename from library/std/src/sys/pal/unix/process/zircon.rs rename to library/std/src/sys/pal/unix/fuchsia.rs diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index e2e537b7bd36..413fda1d8d8e 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -9,6 +9,8 @@ pub mod weak; pub mod args; pub mod env; pub mod fd; +#[cfg(target_os = "fuchsia")] +pub mod fuchsia; pub mod futex; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod kernel_copy; @@ -16,7 +18,6 @@ pub mod kernel_copy; pub mod linux; pub mod os; pub mod pipe; -pub mod process; pub mod stack_overflow; pub mod sync; pub mod thread; @@ -419,7 +420,7 @@ cfg_if::cfg_if! { } #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] -mod unsupported { +pub mod unsupported { use crate::io; pub fn unsupported() -> io::Result { diff --git a/library/std/src/sys/pal/unix/process/mod.rs b/library/std/src/sys/pal/unix/process/mod.rs deleted file mode 100644 index 2751d51c44d2..000000000000 --- a/library/std/src/sys/pal/unix/process/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; -pub use self::process_inner::{ExitStatus, ExitStatusError, Process}; -pub use crate::ffi::OsString as EnvKey; - -#[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))] -mod process_common; - -#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] -mod process_unsupported; - -cfg_if::cfg_if! { - if #[cfg(target_os = "fuchsia")] { - #[path = "process_fuchsia.rs"] - mod process_inner; - mod zircon; - } else if #[cfg(target_os = "vxworks")] { - #[path = "process_vxworks.rs"] - mod process_inner; - } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] { - mod process_inner { - pub use super::process_unsupported::*; - } - } else { - #[path = "process_unix.rs"] - mod process_inner; - } -} diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index bcea699f3b2a..38838b915b5c 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -4,7 +4,6 @@ pub mod args; pub mod env; pub mod os; pub mod pipe; -pub mod process; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index c89832857dd7..cdd613f76b63 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -23,8 +23,6 @@ pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 3008ba887535..6ac28f1bf4fc 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -20,8 +20,6 @@ pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; #[path = "../wasi/thread.rs"] pub mod thread; #[path = "../wasi/time.rs"] diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 175fe75357fb..8d39b70d0397 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -23,8 +23,6 @@ pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; #[path = "../unsupported/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs index 3447a0157e4c..d973743639ab 100644 --- a/library/std/src/sys/pal/windows/args.rs +++ b/library/std/src/sys/pal/windows/args.rs @@ -6,13 +6,13 @@ #[cfg(test)] mod tests; +use super::ensure_no_nuls; use super::os::current_exe; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; use crate::sys::path::get_long_path; -use crate::sys::process::ensure_no_nuls; use crate::sys::{c, to_u16s}; use crate::sys_common::AsInner; use crate::sys_common::wstr::WStrUnits; diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 6eb68f3a3bc4..bdf0cc2c59cf 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -22,7 +22,6 @@ pub mod futex; pub mod handle; pub mod os; pub mod pipe; -pub mod process; pub mod thread; pub mod time; cfg_if::cfg_if! { @@ -287,6 +286,14 @@ pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { } } +pub fn ensure_no_nuls>(s: T) -> crate::io::Result { + if s.as_ref().encode_wide().any(|b| b == 0) { + Err(crate::io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data")) + } else { + Ok(s) + } +} + pub trait IsZero { fn is_zero(&self) -> bool; } diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 7d823012ad14..58926e2beb1d 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -6,8 +6,6 @@ pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 499e27872015..4659dad16e85 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -17,8 +17,6 @@ pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; #[path = "../unsupported/thread.rs"] pub mod thread; #[path = "../unsupported/time.rs"] diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs new file mode 100644 index 000000000000..92cfac7f47cf --- /dev/null +++ b/library/std/src/sys/process/mod.rs @@ -0,0 +1,19 @@ +cfg_if::cfg_if! { + if #[cfg(target_family = "unix")] { + mod unix; + use unix as imp; + } else if #[cfg(target_os = "windows")] { + mod windows; + use windows as imp; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + use uefi as imp; + } else { + mod unsupported; + use unsupported as imp; + } +} + +pub use imp::{ + Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes, +}; diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/process/uefi.rs similarity index 99% rename from library/std/src/sys/pal/uefi/process.rs rename to library/std/src/sys/process/uefi.rs index 1203d51e5312..b46418ae9bb6 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/process/uefi.rs @@ -1,12 +1,13 @@ use r_efi::protocols::simple_text_output; -use super::helpers; use crate::collections::BTreeMap; pub use crate::ffi::OsString as EnvKey; use crate::ffi::{OsStr, OsString}; use crate::num::{NonZero, NonZeroI32}; use crate::path::Path; use crate::sys::fs::File; +use crate::sys::pal::helpers; +use crate::sys::pal::os::error_string; use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; use crate::sys_common::process::{CommandEnv, CommandEnvs}; @@ -225,7 +226,7 @@ impl ExitStatus { impl fmt::Display for ExitStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let err_str = super::os::error_string(self.0.as_usize()); + let err_str = error_string(self.0.as_usize()); write!(f, "{}", err_str) } } @@ -241,7 +242,7 @@ pub struct ExitStatusError(r_efi::efi::Status); impl fmt::Debug for ExitStatusError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let err_str = super::os::error_string(self.0.as_usize()); + let err_str = error_string(self.0.as_usize()); write!(f, "{}", err_str) } } @@ -335,7 +336,6 @@ impl<'a> fmt::Debug for CommandArgs<'a> { mod uefi_command_internal { use r_efi::protocols::{loaded_image, simple_text_output}; - use super::super::helpers; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; use crate::mem::MaybeUninit; @@ -343,7 +343,7 @@ mod uefi_command_internal { use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::ptr::NonNull; use crate::slice; - use crate::sys::pal::uefi::helpers::OwnedTable; + use crate::sys::pal::helpers::{self, OwnedTable}; use crate::sys_common::wstr::WStrUnits; pub struct Image { diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/process/unix/common.rs similarity index 99% rename from library/std/src/sys/pal/unix/process/process_common.rs rename to library/std/src/sys/process/unix/common.rs index a1c747c8df47..8bc17f314911 100644 --- a/library/std/src/sys/pal/unix/process/process_common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -54,7 +54,7 @@ cfg_if::cfg_if! { let bit = (signum - 1) as usize; if set.is_null() || bit >= (8 * size_of::()) { - crate::sys::pal::unix::os::set_errno(libc::EINVAL); + crate::sys::pal::os::set_errno(libc::EINVAL); return -1; } let raw = slice::from_raw_parts_mut( diff --git a/library/std/src/sys/pal/unix/process/process_common/tests.rs b/library/std/src/sys/process/unix/common/tests.rs similarity index 100% rename from library/std/src/sys/pal/unix/process/process_common/tests.rs rename to library/std/src/sys/process/unix/common/tests.rs diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs similarity index 96% rename from library/std/src/sys/pal/unix/process/process_fuchsia.rs rename to library/std/src/sys/process/unix/fuchsia.rs index 05c9ace470e3..0de32ecffd4b 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/process/unix/fuchsia.rs @@ -1,8 +1,8 @@ use libc::{c_int, size_t}; +use super::common::*; use crate::num::NonZero; -use crate::sys::process::process_common::*; -use crate::sys::process::zircon::{Handle, zx_handle_t}; +use crate::sys::pal::fuchsia::*; use crate::{fmt, io, mem, ptr}; //////////////////////////////////////////////////////////////////////////////// @@ -58,8 +58,6 @@ impl Command { stdio: ChildPipes, maybe_envp: Option<&CStringArray>, ) -> io::Result { - use crate::sys::process::zircon::*; - let envp = match maybe_envp { // None means to clone the current environment, which is done in the // flags below. @@ -152,8 +150,6 @@ impl Process { } pub fn kill(&mut self) -> io::Result<()> { - use crate::sys::process::zircon::*; - unsafe { zx_cvt(zx_task_kill(self.handle.raw()))?; } @@ -162,8 +158,6 @@ impl Process { } pub fn wait(&mut self) -> io::Result { - use crate::sys::process::zircon::*; - let mut proc_info: zx_info_process_t = Default::default(); let mut actual: size_t = 0; let mut avail: size_t = 0; @@ -194,8 +188,6 @@ impl Process { } pub fn try_wait(&mut self) -> io::Result> { - use crate::sys::process::zircon::*; - let mut proc_info: zx_info_process_t = Default::default(); let mut actual: size_t = 0; let mut avail: size_t = 0; @@ -251,7 +243,7 @@ impl ExitStatus { None } - // FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al. + // FIXME: The actually-Unix implementation in unix.rs uses WSTOPSIG, WCOREDUMP et al. // I infer from the implementation of `success`, `code` and `signal` above that these are not // available on Fuchsia. // diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs new file mode 100644 index 000000000000..2e8b38f7de1b --- /dev/null +++ b/library/std/src/sys/process/unix/mod.rs @@ -0,0 +1,23 @@ +#[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))] +mod common; + +cfg_if::cfg_if! { + if #[cfg(target_os = "fuchsia")] { + mod fuchsia; + use fuchsia as imp; + } else if #[cfg(target_os = "vxworks")] { + mod vxworks; + use vxworks as imp; + } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] { + mod unsupported; + use unsupported as imp; + } else { + mod unix; + use unix as imp; + } +} + +pub use imp::{ExitStatus, ExitStatusError, Process}; + +pub use self::common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; +pub use crate::ffi::OsString as EnvKey; diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/process/unix/unix.rs similarity index 99% rename from library/std/src/sys/pal/unix/process/process_unix.rs rename to library/std/src/sys/process/unix/unix.rs index f19512233d8d..42542f81b654 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -10,12 +10,12 @@ use libc::{c_int, pid_t}; )))] use libc::{gid_t, uid_t}; +use super::common::*; use crate::io::{self, Error, ErrorKind}; use crate::num::NonZero; use crate::sys::cvt; #[cfg(target_os = "linux")] -use crate::sys::pal::unix::linux::pidfd::PidFd; -use crate::sys::process::process_common::*; +use crate::sys::pal::linux::pidfd::PidFd; use crate::{fmt, mem, sys}; cfg_if::cfg_if! { @@ -1051,7 +1051,7 @@ impl ExitStatus { // true on all actual versions of Unix, is widely assumed, and is specified in SuS // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not // true for a platform pretending to be Unix, the tests (our doctests, and also - // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. + // unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. match NonZero::try_from(self.0) { /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), /* was zero, couldn't convert */ Err(_) => Ok(()), @@ -1232,10 +1232,9 @@ impl ExitStatusError { #[cfg(target_os = "linux")] mod linux_child_ext { - + use crate::io::ErrorKind; use crate::os::linux::process as os; - use crate::sys::pal::unix::ErrorKind; - use crate::sys::pal::unix::linux::pidfd as imp; + use crate::sys::pal::linux::pidfd as imp; use crate::sys_common::FromInner; use crate::{io, mem}; @@ -1261,10 +1260,9 @@ mod linux_child_ext { } #[cfg(test)] -#[path = "process_unix/tests.rs"] mod tests; -// See [`process_unsupported_wait_status::compare_with_linux`]; +// See [`unsupported_wait_status::compare_with_linux`]; #[cfg(all(test, target_os = "linux"))] -#[path = "process_unsupported/wait_status.rs"] -mod process_unsupported_wait_status; +#[path = "unsupported/wait_status.rs"] +mod unsupported_wait_status; diff --git a/library/std/src/sys/pal/unix/process/process_unix/tests.rs b/library/std/src/sys/process/unix/unix/tests.rs similarity index 100% rename from library/std/src/sys/pal/unix/process/process_unix/tests.rs rename to library/std/src/sys/process/unix/unix/tests.rs diff --git a/library/std/src/sys/pal/unix/process/process_unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs similarity index 94% rename from library/std/src/sys/pal/unix/process/process_unsupported.rs rename to library/std/src/sys/process/unix/unsupported.rs index c58548835ff3..78d270923cfa 100644 --- a/library/std/src/sys/pal/unix/process/process_unsupported.rs +++ b/library/std/src/sys/process/unix/unsupported.rs @@ -1,9 +1,9 @@ use libc::{c_int, pid_t}; +use super::common::*; use crate::io; use crate::num::NonZero; -use crate::sys::pal::unix::unsupported::*; -use crate::sys::process::process_common::*; +use crate::sys::pal::unsupported::*; //////////////////////////////////////////////////////////////////////////////// // Command diff --git a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs b/library/std/src/sys/process/unix/unsupported/wait_status.rs similarity index 91% rename from library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs rename to library/std/src/sys/process/unix/unsupported/wait_status.rs index f04036bde492..f348d557e4b7 100644 --- a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs +++ b/library/std/src/sys/process/unix/unsupported/wait_status.rs @@ -7,7 +7,7 @@ use crate::ffi::c_int; use crate::fmt; use crate::num::NonZero; -/// Emulated wait status for use by `process_unsupported.rs` +/// Emulated wait status for use by `unsupported.rs` /// /// Uses the "traditional unix" encoding. For use on platfors which are `#[cfg(unix)]` /// but do not actually support subprocesses at all. @@ -48,7 +48,7 @@ impl ExitStatus { // true on all actual versions of Unix, is widely assumed, and is specified in SuS // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not // true for a platform pretending to be Unix, the tests (our doctests, and also - // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. + // unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. match NonZero::try_from(self.wait_status) { /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), /* was zero, couldn't convert */ Err(_) => Ok(()), @@ -79,5 +79,6 @@ impl ExitStatus { } #[cfg(test)] -#[path = "wait_status/tests.rs"] // needed because of strange layout of process_unsupported +#[path = "wait_status/tests.rs"] +// needed because this module is also imported through #[path] for testing purposes mod tests; diff --git a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status/tests.rs b/library/std/src/sys/process/unix/unsupported/wait_status/tests.rs similarity index 96% rename from library/std/src/sys/pal/unix/process/process_unsupported/wait_status/tests.rs rename to library/std/src/sys/process/unix/unsupported/wait_status/tests.rs index 5132eab10a11..0d9232fac5e4 100644 --- a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status/tests.rs +++ b/library/std/src/sys/process/unix/unsupported/wait_status/tests.rs @@ -1,4 +1,4 @@ -// Note that tests in this file are run on Linux as well as on platforms using process_unsupported +// Note that tests in this file are run on Linux as well as on platforms using unsupported // Test that our emulation exactly matches Linux // diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs similarity index 98% rename from library/std/src/sys/pal/unix/process/process_vxworks.rs rename to library/std/src/sys/process/unix/vxworks.rs index e2c1b6a03262..5f1727789a1b 100644 --- a/library/std/src/sys/pal/unix/process/process_vxworks.rs +++ b/library/std/src/sys/process/unix/vxworks.rs @@ -1,11 +1,11 @@ #![forbid(unsafe_op_in_unsafe_fn)] use libc::{self, RTP_ID, c_char, c_int}; +use super::common::*; use crate::io::{self, ErrorKind}; use crate::num::NonZero; use crate::sys::cvt; -use crate::sys::pal::unix::thread; -use crate::sys::process::process_common::*; +use crate::sys::pal::thread; use crate::{fmt, sys}; //////////////////////////////////////////////////////////////////////////////// @@ -200,7 +200,7 @@ impl ExitStatus { // true on all actual versions of Unix, is widely assumed, and is specified in SuS // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not // true for a platform pretending to be Unix, the tests (our doctests, and also - // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. + // unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. match NonZero::try_from(self.0) { Ok(failure) => Err(ExitStatusError(failure)), Err(_) => Ok(()), diff --git a/library/std/src/sys/pal/unsupported/process.rs b/library/std/src/sys/process/unsupported.rs similarity index 100% rename from library/std/src/sys/pal/unsupported/process.rs rename to library/std/src/sys/process/unsupported.rs diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/process/windows.rs similarity index 98% rename from library/std/src/sys/pal/windows/process.rs rename to library/std/src/sys/process/windows.rs index 50e4baba6072..06c15e08f3fb 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/process/windows.rs @@ -5,11 +5,10 @@ mod tests; use core::ffi::c_void; -use super::api::{self, WinError}; use crate::collections::BTreeMap; use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX}; use crate::ffi::{OsStr, OsString}; -use crate::io::{self, Error, ErrorKind}; +use crate::io::{self, Error}; use crate::num::NonZero; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle}; @@ -20,6 +19,8 @@ use crate::sys::args::{self, Arg}; use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS}; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; +use crate::sys::pal::api::{self, WinError}; +use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; use crate::sys_common::IntoInner; @@ -142,14 +143,6 @@ impl AsRef for EnvKey { } } -pub(crate) fn ensure_no_nuls>(s: T) -> io::Result { - if s.as_ref().encode_wide().any(|b| b == 0) { - Err(io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data")) - } else { - Ok(s) - } -} - pub struct Command { program: OsString, args: Vec, @@ -279,7 +272,7 @@ impl Command { let is_batch_file = if path::is_verbatim(&program) { has_bat_extension(&program[..program.len() - 1]) } else { - super::fill_utf16_buf( + fill_utf16_buf( |buffer, size| unsafe { // resolve the path so we can test the final file name. c::GetFullPathNameW(program.as_ptr(), size, buffer, ptr::null_mut()) @@ -521,7 +514,7 @@ where // 3 & 4. System paths // SAFETY: This uses `fill_utf16_buf` to safely call the OS functions. unsafe { - if let Ok(Some(path)) = super::fill_utf16_buf( + if let Ok(Some(path)) = fill_utf16_buf( |buf, size| c::GetSystemDirectoryW(buf, size), |buf| exists(PathBuf::from(OsString::from_wide(buf))), ) { @@ -529,7 +522,7 @@ where } #[cfg(not(target_vendor = "uwp"))] { - if let Ok(Some(path)) = super::fill_utf16_buf( + if let Ok(Some(path)) = fill_utf16_buf( |buf, size| c::GetWindowsDirectoryW(buf, size), |buf| exists(PathBuf::from(OsString::from_wide(buf))), ) { @@ -851,10 +844,8 @@ fn make_command_line(argv0: &OsStr, args: &[Arg], force_quotes: bool) -> io::Res // Get `cmd.exe` for use with bat scripts, encoded as a UTF-16 string. fn command_prompt() -> io::Result> { - let mut system: Vec = super::fill_utf16_buf( - |buf, size| unsafe { c::GetSystemDirectoryW(buf, size) }, - |buf| buf.into(), - )?; + let mut system: Vec = + fill_utf16_buf(|buf, size| unsafe { c::GetSystemDirectoryW(buf, size) }, |buf| buf.into())?; system.extend("\\cmd.exe".encode_utf16().chain([0])); Ok(system) } diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/process/windows/tests.rs similarity index 100% rename from library/std/src/sys/pal/windows/process/tests.rs rename to library/std/src/sys/process/windows/tests.rs From 51d51c866601524ec36b019762053371d309de6c Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 22 Mar 2025 13:35:46 +0100 Subject: [PATCH 216/546] core: optimize `RepeatN` ...by adding an optimized implementation of `try_fold` and `fold` as well as replacing some unnecessary `mem::replace` calls with `MaybeUninit` helper methods. --- library/core/src/iter/sources/repeat_n.rs | 59 +++++++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index cc089c617c0e..ada37b9af4c8 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -1,7 +1,8 @@ use crate::fmt; use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator}; -use crate::mem::{self, MaybeUninit}; +use crate::mem::MaybeUninit; use crate::num::NonZero; +use crate::ops::{NeverShortCircuit, Try}; /// Creates a new iterator that repeats a single element a given number of times. /// @@ -95,10 +96,10 @@ impl RepeatN { fn take_element(&mut self) -> Option { if self.count > 0 { self.count = 0; - let element = mem::replace(&mut self.element, MaybeUninit::uninit()); // SAFETY: We just set count to zero so it won't be dropped again, // and it used to be non-zero so it hasn't already been dropped. - unsafe { Some(element.assume_init()) } + let element = unsafe { self.element.assume_init_read() }; + Some(element) } else { None } @@ -169,6 +170,39 @@ impl Iterator for RepeatN { } } + fn try_fold(&mut self, mut acc: B, mut f: F) -> R + where + F: FnMut(B, A) -> R, + R: Try, + { + if self.count > 0 { + while self.count > 1 { + self.count -= 1; + // SAFETY: the count was larger than 1, so the element is + // initialized and hasn't been dropped. + acc = f(acc, unsafe { self.element.assume_init_ref().clone() })?; + } + + // We could just set the count to zero directly, but doing it this + // way should make it easier for the optimizer to fold this tail + // into the loop when `clone()` is equivalent to copying. + self.count -= 1; + // SAFETY: we just set the count to zero from one, so the element + // is still initialized, has not been dropped yet and will not be + // accessed by future calls. + f(acc, unsafe { self.element.assume_init_read() }) + } else { + try { acc } + } + } + + fn fold(mut self, init: B, f: F) -> B + where + F: FnMut(B, A) -> B, + { + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + #[inline] fn last(mut self) -> Option { self.take_element() @@ -203,6 +237,23 @@ impl DoubleEndedIterator for RepeatN { fn nth_back(&mut self, n: usize) -> Option { self.nth(n) } + + #[inline] + fn try_rfold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, A) -> R, + R: Try, + { + self.try_fold(init, f) + } + + #[inline] + fn rfold(self, init: B, f: F) -> B + where + F: FnMut(B, A) -> B, + { + self.fold(init, f) + } } #[stable(feature = "iter_repeat_n", since = "1.82.0")] @@ -220,7 +271,7 @@ impl UncheckedIterator for RepeatN { // SAFETY: the check above ensured that the count used to be non-zero, // so element hasn't been dropped yet, and we just lowered the count to // zero so it won't be dropped later, and thus it's okay to take it here. - unsafe { mem::replace(&mut self.element, MaybeUninit::uninit()).assume_init() } + unsafe { self.element.assume_init_read() } } else { // SAFETY: the count is non-zero, so it must have not been dropped yet. let element = unsafe { self.element.assume_init_ref() }; From e9ddf54d16ea4563714185cf744fd753c734261a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 22 Mar 2025 13:57:27 +0100 Subject: [PATCH 217/546] Group test diffs by stage in post-merge analysis --- src/ci/citool/src/analysis.rs | 43 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 2088ce296209..98e9be0f35af 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -210,6 +210,7 @@ struct TestSuiteData { #[derive(Hash, PartialEq, Eq, Debug, Clone)] struct Test { name: String, + stage: u8, is_doctest: bool, } @@ -218,27 +219,24 @@ fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { let mut tests = HashMap::new(); let test_suites = get_test_suites(&metrics); for suite in test_suites { + let stage = match suite.metadata { + TestSuiteMetadata::CargoPackage { stage, .. } => stage, + TestSuiteMetadata::Compiletest { stage, .. } => stage, + } as u8; for test in &suite.tests { // Poor man's detection of doctests based on the "(line XYZ)" suffix let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. }) && test.name.contains("(line"); - let test_entry = Test { name: generate_test_name(&test.name, &suite), is_doctest }; + let test_entry = Test { name: generate_test_name(&test.name), stage, is_doctest }; tests.insert(test_entry, test.outcome.clone()); } } TestSuiteData { tests } } -/// Normalizes Windows-style path delimiters to Unix-style paths -/// and adds suite metadata to the test name. -fn generate_test_name(name: &str, suite: &TestSuite) -> String { - let name = name.replace('\\', "/"); - let stage = match suite.metadata { - TestSuiteMetadata::CargoPackage { stage, .. } => stage, - TestSuiteMetadata::Compiletest { stage, .. } => stage, - }; - - format!("{name} (stage {stage})") +/// Normalizes Windows-style path delimiters to Unix-style paths. +fn generate_test_name(name: &str) -> String { + name.replace('\\', "/") } /// Prints test changes in Markdown format to stdout. @@ -321,16 +319,25 @@ fn report_test_diffs(diff: AggregatedTestDiffs) { // Sort diffs by job group and test name grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name))); + // Now group the tests by stage + let mut grouped_by_stage: BTreeMap> = Default::default(); + for (diff, group) in grouped_diffs { + grouped_by_stage.entry(diff.test.stage).or_default().push((diff, group)) + } + output_details( &format!("Show {} test {}\n", original_diff_count, pluralize("diff", original_diff_count)), || { - for (diff, job_group) in grouped_diffs { - println!( - "- `{}`: {} ({})", - diff.test.name, - format_diff(&diff.diff), - format_job_group(job_group) - ); + for (stage, diffs) in grouped_by_stage { + println!("## Stage {stage}"); + for (diff, job_group) in diffs { + println!( + "- `{}`: {} ({})", + diff.test.name, + format_diff(&diff.diff), + format_job_group(job_group) + ); + } } let extra_diffs = diffs.len().saturating_sub(max_diff_count); From f39478f8a538eba5c56229b4f2c4f686d504e71d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 22 Mar 2025 09:50:07 -0700 Subject: [PATCH 218/546] Clarify "Windows 1607" --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 58df0b00d50a..755e73a34c6b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -5,7 +5,7 @@ Version 1.85.1 (2025-03-18) - [Fix the doctest-merging feature of the 2024 Edition.](https://github.com/rust-lang/rust/pull/137899/) - [Relax some `target_feature` checks when generating docs.](https://github.com/rust-lang/rust/pull/137632/) -- [Fix errors in `std::fs::rename` on Windows 1607.](https://github.com/rust-lang/rust/pull/137528/) +- [Fix errors in `std::fs::rename` on Windows 10, version 1607.](https://github.com/rust-lang/rust/pull/137528/) - [Downgrade bootstrap `cc` to fix custom targets.](https://github.com/rust-lang/rust/pull/137460/) - [Skip submodule updates when building Rust from a source tarball.](https://github.com/rust-lang/rust/pull/137338/) From c25e4bfe68ff3d313398cdbf0a459f82c37d1bb7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 22 Mar 2025 18:09:01 +0300 Subject: [PATCH 219/546] resolve: Avoid some unstable iteration 3 --- compiler/rustc_resolve/src/late.rs | 13 ++++++------- compiler/rustc_resolve/src/late/diagnostics.rs | 5 ----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6056a69ee71f..1eff824aa624 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -272,7 +272,7 @@ impl RibKind<'_> { /// resolving, the name is looked up from inside out. #[derive(Debug)] pub(crate) struct Rib<'ra, R = Res> { - pub bindings: FxHashMap, + pub bindings: FxIndexMap, pub patterns_with_skipped_bindings: UnordMap)>>, pub kind: RibKind<'ra>, } @@ -1642,8 +1642,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Allow all following defaults to refer to this type parameter. let i = &Ident::with_dummy_span(param.ident.name); - forward_ty_ban_rib.bindings.remove(i); - forward_ty_ban_rib_const_param_ty.bindings.remove(i); + forward_ty_ban_rib.bindings.swap_remove(i); + forward_ty_ban_rib_const_param_ty.bindings.swap_remove(i); } GenericParamKind::Const { ref ty, kw_span: _, ref default } => { // Const parameters can't have param bounds. @@ -1678,8 +1678,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Allow all following defaults to refer to this const parameter. let i = &Ident::with_dummy_span(param.ident.name); - forward_const_ban_rib.bindings.remove(i); - forward_const_ban_rib_const_param_ty.bindings.remove(i); + forward_const_ban_rib.bindings.swap_remove(i); + forward_const_ban_rib_const_param_ty.bindings.swap_remove(i); } } } @@ -2888,7 +2888,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { break; } - #[allow(rustc::potential_query_instability)] // FIXME seen_bindings .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); } @@ -4003,7 +4002,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } - fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxHashMap { + fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxIndexMap { &mut self.ribs[ns].last_mut().unwrap().bindings } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3d666055a94f..6d95c02c55fc 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -830,7 +830,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(rib) = &self.last_block_rib && let RibKind::Normal = rib.kind { - #[allow(rustc::potential_query_instability)] // FIXME for (ident, &res) in &rib.bindings { if let Res::Local(_) = res && path.len() == 1 @@ -1019,7 +1018,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(err_code) = err.code { if err_code == E0425 { for label_rib in &self.label_ribs { - #[allow(rustc::potential_query_instability)] // FIXME for (label_ident, node_id) in &label_rib.bindings { let ident = path.last().unwrap().ident; if format!("'{ident}") == label_ident.to_string() { @@ -2265,7 +2263,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }; // Locals and type parameters - #[allow(rustc::potential_query_instability)] // FIXME for (ident, &res) in &rib.bindings { if filter_fn(res) && ident.span.ctxt() == rib_ctxt { names.push(TypoSuggestion::typo_from_ident(*ident, res)); @@ -2793,7 +2790,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let within_scope = self.is_label_valid_from_rib(rib_index); let rib = &self.label_ribs[rib_index]; - #[allow(rustc::potential_query_instability)] // FIXME let names = rib .bindings .iter() @@ -2805,7 +2801,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Upon finding a similar name, get the ident that it was from - the span // contained within helps make a useful diagnostic. In addition, determine // whether this candidate is within scope. - #[allow(rustc::potential_query_instability)] // FIXME let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap(); (*ident, within_scope) }) From b46412f6d7fde0c24780b0808aa7aefbc18d9e1e Mon Sep 17 00:00:00 2001 From: binarycat Date: Sun, 16 Mar 2025 15:42:04 -0500 Subject: [PATCH 220/546] rustdoc: be more strict about "Methods from Deref" hack: is_doc_subtype_of always returns true for TyAlias it's worth noting that this function is only used in the handling of "Methods from Deref", and we were previously assuming all generic parameters were meaningless, so this is still an improvment from the status quo. this change means that we will have strictly less false positives without adding any new false negitives. Co-authored-by: Guillaume Gomez --- src/librustdoc/clean/types.rs | 14 ++++++++++ src/librustdoc/html/render/mod.rs | 16 +++++++++-- src/librustdoc/html/render/sidebar.rs | 5 +++- .../deref/deref-methods-24686-target.rs | 27 +++++++++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 tests/rustdoc/deref/deref-methods-24686-target.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3f9023659dba..257687ae0a38 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1533,6 +1533,10 @@ impl Type { matches!(self, Type::BorrowedRef { .. }) } + fn is_type_alias(&self) -> bool { + matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } }) + } + /// Check if two types are "the same" for documentation purposes. /// /// This is different from `Eq`, because it knows that things like @@ -1561,6 +1565,16 @@ impl Type { } else { (self, other) }; + + // FIXME: `Cache` does not have the data required to unwrap type aliases, + // so we just assume they are equal. + // This is only remotely acceptable because we were previously + // assuming all types were equal when used + // as a generic parameter of a type in `Deref::Target`. + if self_cleared.is_type_alias() || other_cleared.is_type_alias() { + return true; + } + match (self_cleared, other_cleared) { // Recursive cases. (Type::Tuple(a), Type::Tuple(b)) => { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index b2ad2fa773ae..900de90c7366 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -89,7 +89,7 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display { /// Specifies whether rendering directly implemented trait items or ones from a certain Deref /// impl. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) enum AssocItemRender<'a> { All, DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, @@ -1296,7 +1296,8 @@ fn render_assoc_items_inner( info!("Documenting associated items of {:?}", containing_item.name); let cache = &cx.shared.cache; let Some(v) = cache.impls.get(&it) else { return }; - let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); + let (mut non_trait, traits): (Vec<_>, _) = + v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { let mut close_tags = >::with_capacity(1); let mut tmp_buf = String::new(); @@ -1314,6 +1315,16 @@ fn render_assoc_items_inner( AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { let id = cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); + // the `impls.get` above only looks at the outermost type, + // and the Deref impl may only be implemented for certain + // values of generic parameters. + // for example, if an item impls `Deref<[u8]>`, + // we should not show methods from `[MaybeUninit]`. + // this `retain` filters out any instances where + // the types do not line up perfectly. + non_trait.retain(|impl_| { + type_.is_doc_subtype_of(&impl_.inner_impl().for_, &cx.shared.cache) + }); let derived_id = cx.derive_id(&id); close_tags.push(""); write_str( @@ -1392,6 +1403,7 @@ fn render_assoc_items_inner( } } +/// `derefs` is the set of all deref targets that have already been handled. fn render_deref_methods( mut w: impl Write, cx: &Context<'_>, diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 3130815af0bd..9c78dcdc571d 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -533,7 +533,10 @@ fn sidebar_deref_methods<'a>( debug!("found inner_impl: {impls:?}"); let mut ret = impls .iter() - .filter(|i| i.inner_impl().trait_.is_none()) + .filter(|i| { + i.inner_impl().trait_.is_none() + && real_target.is_doc_subtype_of(&i.inner_impl().for_, &c) + }) .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx())) .collect::>(); if !ret.is_empty() { diff --git a/tests/rustdoc/deref/deref-methods-24686-target.rs b/tests/rustdoc/deref/deref-methods-24686-target.rs new file mode 100644 index 000000000000..e019488ca802 --- /dev/null +++ b/tests/rustdoc/deref/deref-methods-24686-target.rs @@ -0,0 +1,27 @@ +#![crate_name = "foo"] + +// test for https://github.com/rust-lang/rust/issues/24686 +use std::ops::Deref; + +pub struct Foo(T); +impl Foo { + pub fn get_i32(&self) -> i32 { self.0 } +} +impl Foo { + pub fn get_u32(&self) -> u32 { self.0 } +} + +// Note that the same href is used both on the method itself, +// and on the sidebar items. +//@ has foo/struct.Bar.html +//@ has - '//a[@href="#method.get_i32"]' 'get_i32' +//@ !has - '//a[@href="#method.get_u32"]' 'get_u32' +//@ count - '//ul[@class="block deref-methods"]//a' 1 +//@ count - '//a[@href="#method.get_i32"]' 2 +pub struct Bar(Foo); +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { + &self.0 + } +} From bafdbcadd5e70e4a1a35647002c30efd315621b4 Mon Sep 17 00:00:00 2001 From: Predrag Gruevski Date: Tue, 4 Mar 2025 22:02:06 +0000 Subject: [PATCH 221/546] rustdoc: Use own logic to print `#[repr(..)]` attributes in JSON output. --- src/librustdoc/clean/types.rs | 25 +++++++++++----- src/rustdoc-json-types/lib.rs | 22 +++++++++++--- tests/rustdoc-json/attrs/repr_align.rs | 2 +- tests/rustdoc-json/attrs/repr_c.rs | 6 ++-- tests/rustdoc-json/attrs/repr_combination.rs | 23 ++++++++------- tests/rustdoc-json/attrs/repr_int_enum.rs | 6 ++-- tests/rustdoc-json/attrs/repr_packed.rs | 8 ++--- tests/rustdoc-json/attrs/repr_transparent.rs | 29 ++++++++++++++----- .../rustdoc-json/enums/discriminant/struct.rs | 2 +- .../rustdoc-json/enums/discriminant/tuple.rs | 2 +- 10 files changed, 82 insertions(+), 43 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3b2dcb3db81d..1207f2f0360f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -768,12 +768,22 @@ impl Item { .iter() .filter_map(|attr| { if is_json { - if matches!(attr, hir::Attribute::Parsed(AttributeKind::Deprecation { .. })) { - // rustdoc-json stores this in `Item::deprecation`, so we - // don't want it it `Item::attrs`. - None - } else { - Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)) + match attr { + hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => { + // rustdoc-json stores this in `Item::deprecation`, so we + // don't want it it `Item::attrs`. + None + } + rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr( + .., + )) => { + // We have separate pretty-printing logic for `#[repr(..)]` attributes. + // For example, there are circumstances where `#[repr(transparent)]` + // is applied but should not be publicly shown in rustdoc + // because it isn't public API. + None + } + _ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)), } } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { Some( @@ -789,8 +799,7 @@ impl Item { .collect(); // Add #[repr(...)] - if !is_json - && let Some(def_id) = self.def_id() + if let Some(def_id) = self.def_id() && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_() { let adt = tcx.adt_def(def_id); diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 44e82c7d8b19..137fe4c4c354 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 42; +pub const FORMAT_VERSION: u32 = 43; /// The root of the emitted JSON blob. /// @@ -120,9 +120,23 @@ pub struct Item { pub docs: Option, /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs pub links: HashMap, - /// Stringified versions of parsed attributes on this item. - /// Essentially debug printed (e.g. `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`). - /// Equivalent to the hir pretty-printing of attributes. + /// Attributes on this item. + /// + /// Does not include `#[deprecated]` attributes: see the [`Self::deprecation`] field instead. + /// + /// Some attributes appear in pretty-printed Rust form, regardless of their formatting + /// in the original source code. For example: + /// - `#[non_exhaustive]` and `#[must_use]` are represented as themselves. + /// - `#[no_mangle]` and `#[export_name]` are also represented as themselves. + /// - `#[repr(C)]` and other reprs also appear as themselves, + /// though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`. + /// Multiple repr attributes on the same item may be combined into an equivalent single attr. + /// + /// Other attributes may appear debug-printed. For example: + /// - `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`. + /// + /// As an internal implementation detail subject to change, this debug-printing format + /// is currently equivalent to the HIR pretty-printing of parsed attributes. pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs index 83506737b211..c6debda7f1c9 100644 --- a/tests/rustdoc-json/attrs/repr_align.rs +++ b/tests/rustdoc-json/attrs/repr_align.rs @@ -1,6 +1,6 @@ #![no_std] -//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]' +//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]' #[repr(align(4))] pub struct Aligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs index 018086b3c1ff..e6219413f308 100644 --- a/tests/rustdoc-json/attrs/repr_c.rs +++ b/tests/rustdoc-json/attrs/repr_c.rs @@ -1,16 +1,16 @@ #![no_std] -//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]' #[repr(C)] pub struct ReprCStruct(pub i64); -//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]' #[repr(C)] pub enum ReprCEnum { First, } -//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]' #[repr(C)] pub union ReprCUnion { pub left: i64, diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs index c3ef8becb779..0e8e2ef0d83e 100644 --- a/tests/rustdoc-json/attrs/repr_combination.rs +++ b/tests/rustdoc-json/attrs/repr_combination.rs @@ -1,34 +1,35 @@ #![no_std] // Combinations of `#[repr(..)]` attributes. +// Rustdoc JSON emits normalized output, regardless of the original source. -//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]' +//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[repr(C, i8)]"]' #[repr(C, i8)] pub enum ReprCI8 { First, } -//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[repr(C, i16)]"]' #[repr(C)] #[repr(i16)] pub enum SeparateReprCI16 { First, } -//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[repr(C, usize)]"]' #[repr(usize, C)] pub enum ReversedReprCUsize { First, } -//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[repr(C, packed(1))]"]' #[repr(C, packed)] pub struct ReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' #[repr(C)] #[repr(packed(2))] pub struct SeparateReprCPacked { @@ -36,21 +37,21 @@ pub struct SeparateReprCPacked { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' #[repr(packed(2), C)] pub struct ReversedReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[repr(C, align(16))]"]' #[repr(C, align(16))] pub struct ReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[repr(C, align(2))]"]' #[repr(C)] #[repr(align(2))] pub struct SeparateReprCAlign { @@ -58,20 +59,20 @@ pub struct SeparateReprCAlign { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[repr(C, align(2))]"]' #[repr(align(2), C)] pub struct ReversedReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]' +//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' #[repr(C, align(16), isize)] pub enum AlignedExplicitRepr { First, } -//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' #[repr(isize, C, align(16))] pub enum ReorderedAlignedExplicitRepr { First, diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs index 206cb7835f52..9b09f341d4fe 100644 --- a/tests/rustdoc-json/attrs/repr_int_enum.rs +++ b/tests/rustdoc-json/attrs/repr_int_enum.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]' +//@ is "$.index[?(@.name=='I8')].attrs" '["#[repr(i8)]"]' #[repr(i8)] pub enum I8 { First, } -//@ is "$.index[?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' +//@ is "$.index[?(@.name=='I32')].attrs" '["#[repr(i32)]"]' #[repr(i32)] pub enum I32 { First, } -//@ is "$.index[?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]' +//@ is "$.index[?(@.name=='Usize')].attrs" '["#[repr(usize)]"]' #[repr(usize)] pub enum Usize { First, diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs index d4c400f72f81..9f3fd86c4b03 100644 --- a/tests/rustdoc-json/attrs/repr_packed.rs +++ b/tests/rustdoc-json/attrs/repr_packed.rs @@ -1,16 +1,16 @@ #![no_std] // Note the normalization: -// `#[repr(packed)]` in has the implict "1" in rustdoc JSON. - -//@ is "$.index[?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]' +// `#[repr(packed)]` in source becomes `#[repr(packed(1))]` in rustdoc JSON. +// +//@ is "$.index[?(@.name=='Packed')].attrs" '["#[repr(packed(1))]"]' #[repr(packed)] pub struct Packed { a: i8, b: i64, } -//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]' +//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[repr(packed(4))]"]' #[repr(packed(4))] pub struct PackedAligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_transparent.rs b/tests/rustdoc-json/attrs/repr_transparent.rs index 3f57b21dcc52..1e634ca901dc 100644 --- a/tests/rustdoc-json/attrs/repr_transparent.rs +++ b/tests/rustdoc-json/attrs/repr_transparent.rs @@ -1,22 +1,37 @@ #![no_std] -// Rustdoc JSON currently includes `#[repr(transparent)]` -// even if the transparency is not part of the public API +// Rustdoc JSON *only* includes `#[repr(transparent)]` +// if the transparency is public API: +// - if a non-1-ZST field exists, it has to be public +// - otherwise, all fields are 1-ZST and at least one of them is public // -// https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent +// More info: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent -//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +// Here, the non-1-ZST field is public. +// We expect `#[repr(transparent)]` in the attributes. +// +//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]' #[repr(transparent)] pub struct Transparent(pub i64); -//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +// Here the non-1-ZST field isn't public, so the attribute isn't included. +// +//@ has "$.index[?(@.name=='TransparentNonPub')]" +//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '[]' #[repr(transparent)] pub struct TransparentNonPub(i64); -//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +// Only 1-ZST fields here, and one of them is public. +// We expect `#[repr(transparent)]` in the attributes. +// +//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[repr(transparent)]"]' #[repr(transparent)] pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ()); -//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +// Only 1-ZST fields here but none of them are public. +// The attribute isn't included. +// +//@ has "$.index[?(@.name=='AllZstNotPublic')]" +//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '[]' #[repr(transparent)] pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ()); diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index 08fb80540fa9..ea669e6a0b30 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,5 +1,5 @@ #[repr(i32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' +//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' pub enum Foo { //@ is "$.index[?(@.name=='Struct')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index c74e9a2c58dd..1b8e791eb230 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,5 +1,5 @@ #[repr(u32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(U32))])]\n"]' +//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' pub enum Foo { //@ is "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 From fa0c951a2795a0e1e5caa94317309a8bdb9b94a5 Mon Sep 17 00:00:00 2001 From: Chiichen Date: Sun, 23 Mar 2025 12:41:23 +0800 Subject: [PATCH 222/546] doc: rename reference #create-a-configtoml to #create-a-bootstraptoml --- bootstrap.example.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 294d9780716e..caffe1a93712 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -1,7 +1,7 @@ # Sample TOML configuration file for building Rust. # # To configure bootstrap, run `./configure` or `./x.py setup`. -# See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-configtoml for more information. +# See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-bootstraptoml for more information. # # All options are commented out by default in this file, and they're commented # out with their default values. The build system by default looks for @@ -446,7 +446,7 @@ # a specific version. #ccache = false -# List of paths to exclude from the build and test processes. +# List of paths to exclude from the build and test processes. # For example, exclude = ["tests/ui", "src/tools/tidy"]. #exclude = [] From 5950c862bd3c2c410197d17d173cade26d38f041 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 17 Mar 2025 13:06:34 +0100 Subject: [PATCH 223/546] Slim `rustc_parse_format` dependencies down `rustc_index` is only used for its size assertion macro, so demote it to a dev-dependency gated under testing instead --- compiler/rustc_parse_format/Cargo.toml | 4 +++- compiler/rustc_parse_format/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index d6c3bd9877c9..289e062fb5e2 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -8,5 +8,7 @@ edition = "2024" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end -[target.'cfg(target_pointer_width = "64")'.dependencies] +[target.'cfg(target_pointer_width = "64")'.dev-dependencies] +# tidy-alphabetical-start rustc_index = { path = "../rustc_index", default-features = false } +# tidy-alphabetical-end diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 5b8a2fe52d3f..97931742985e 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -1105,7 +1105,7 @@ fn unescape_string(string: &str) -> Option { } // Assert a reasonable size for `Piece` -#[cfg(target_pointer_width = "64")] +#[cfg(all(test, target_pointer_width = "64"))] rustc_index::static_assert_size!(Piece<'_>, 16); #[cfg(test)] From 20f4a0d586fcb27936f07f001bf128b2f407b018 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 23 Mar 2025 17:02:42 +0900 Subject: [PATCH 224/546] fix ICE #138415 --- compiler/rustc_ast_lowering/src/item.rs | 4 ++-- .../invalid-extern-fn-body.rs | 11 ++++++++++ .../invalid-extern-fn-body.stderr | 20 +++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/define_opaques_attr/invalid-extern-fn-body.rs create mode 100644 tests/ui/type-alias-impl-trait/define_opaques_attr/invalid-extern-fn-body.stderr diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index bd011d59aaa7..518349343b3a 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1724,8 +1724,8 @@ impl<'hir> LoweringContext<'_, 'hir> { return; }; let define_opaque = define_opaque.iter().filter_map(|(id, path)| { - let res = self.resolver.get_partial_res(*id).unwrap(); - let Some(did) = res.expect_full_res().opt_def_id() else { + let res = self.resolver.get_partial_res(*id); + let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) else { self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); return None; }; diff --git a/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid-extern-fn-body.rs b/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid-extern-fn-body.rs new file mode 100644 index 000000000000..d873af44adf9 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid-extern-fn-body.rs @@ -0,0 +1,11 @@ +#![feature(type_alias_impl_trait)] + +extern "C" { + fn a() { + //~^ ERROR incorrect function inside `extern` block + #[define_opaque(String)] + fn c() {} + } +} + +pub fn main() {} diff --git a/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid-extern-fn-body.stderr b/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid-extern-fn-body.stderr new file mode 100644 index 000000000000..2e944257d8f6 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid-extern-fn-body.stderr @@ -0,0 +1,20 @@ +error: incorrect function inside `extern` block + --> $DIR/invalid-extern-fn-body.rs:4:8 + | +LL | extern "C" { + | ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | fn a() { + | ________^___- + | | | + | | cannot have a body +LL | | +LL | | #[define_opaque(String)] +LL | | fn c() {} +LL | | } + | |_____- help: remove the invalid body: `;` + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 1 previous error + From 34b7d51b95663071729b83a2127bdd6a98b9ca08 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 23 Mar 2025 17:47:10 +0900 Subject: [PATCH 225/546] fix typo --- library/core/src/macros/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index fa0d882181a5..5f200b31d1ae 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1744,7 +1744,7 @@ pub(crate) mod builtin { } /// Provide a list of type aliases and other opaque-type-containing type definitions. - /// This list will be used in the body of the item it is applied to to define opaque + /// This list will be used in the body of the item it is applied to define opaque /// types' hidden types. /// Can only be applied to things that have bodies. #[unstable( From 0e7dbab1fc4a2cfc63bac4f5c4d283d2504f1547 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 18 Mar 2025 13:16:01 +0800 Subject: [PATCH 226/546] Implement `supported-crate-types` print request As an unstable print request. --- compiler/rustc_driver_impl/src/lib.rs | 14 +++++++++++-- compiler/rustc_session/src/config.rs | 7 ++++++- tests/ui/print-request/stability.rs | 4 ++++ .../supported-crate-types.linux.stdout | 7 +++++++ .../supported-crate-types.musl.stdout | 5 +++++ .../ui/print-request/supported-crate-types.rs | 20 +++++++++++++++++++ .../supported-crate-types.wasm.stdout | 5 +++++ 7 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 tests/ui/print-request/supported-crate-types.linux.stdout create mode 100644 tests/ui/print-request/supported-crate-types.musl.stdout create mode 100644 tests/ui/print-request/supported-crate-types.rs create mode 100644 tests/ui/print-request/supported-crate-types.wasm.stdout diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 4ba076c64e10..37755e7d61db 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -20,7 +20,7 @@ // tidy-alphabetical-end use std::cmp::max; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsString; use std::fmt::Write as _; use std::fs::{self, File}; @@ -61,7 +61,7 @@ use rustc_session::config::{ }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; -use rustc_session::output::collect_crate_types; +use rustc_session::output::{CRATE_TYPES, collect_crate_types, invalid_output_for_target}; use rustc_session::{EarlyDiagCtxt, Session, config, filesearch}; use rustc_span::FileName; use rustc_target::json::ToJson; @@ -790,6 +790,16 @@ fn print_crate_info( sess.dcx().fatal("only Apple targets currently support deployment version info") } } + SupportedCrateTypes => { + let supported_crate_types = CRATE_TYPES + .iter() + .filter(|(_, crate_type)| !invalid_output_for_target(&sess, *crate_type)) + .map(|(crate_type_sym, _)| *crate_type_sym) + .collect::>(); + for supported_crate_type in supported_crate_types { + println_info!("{}", supported_crate_type.as_str()); + } + } } req.out.overwrite(&crate_info, sess); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 43b78423c727..ed336cc55961 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -58,6 +58,7 @@ pub const PRINT_KINDS: &[(&str, PrintKind)] = &[ ("relocation-models", PrintKind::RelocationModels), ("split-debuginfo", PrintKind::SplitDebuginfo), ("stack-protector-strategies", PrintKind::StackProtectorStrategies), + ("supported-crate-types", PrintKind::SupportedCrateTypes), ("sysroot", PrintKind::Sysroot), ("target-cpus", PrintKind::TargetCPUs), ("target-features", PrintKind::TargetFeatures), @@ -888,6 +889,7 @@ pub enum PrintKind { RelocationModels, SplitDebuginfo, StackProtectorStrategies, + SupportedCrateTypes, Sysroot, TargetCPUs, TargetFeatures, @@ -2063,7 +2065,10 @@ fn check_print_request_stability( (print_name, print_kind): (&str, PrintKind), ) { match print_kind { - PrintKind::AllTargetSpecsJson | PrintKind::CheckCfg | PrintKind::TargetSpecJson + PrintKind::AllTargetSpecsJson + | PrintKind::CheckCfg + | PrintKind::SupportedCrateTypes + | PrintKind::TargetSpecJson if !unstable_opts.unstable_options => { early_dcx.early_fatal(format!( diff --git a/tests/ui/print-request/stability.rs b/tests/ui/print-request/stability.rs index b205b0555691..c3421224d720 100644 --- a/tests/ui/print-request/stability.rs +++ b/tests/ui/print-request/stability.rs @@ -22,6 +22,10 @@ //@[check_cfg] compile-flags: --print=check-cfg //@[check_cfg] error-pattern: the `-Z unstable-options` flag must also be passed +//@ revisions: supported_crate_types +//@[supported_crate_types] compile-flags: --print=supported-crate-types +//@[supported_crate_types] error-pattern: the `-Z unstable-options` flag must also be passed + //@ revisions: target_spec_json //@[target_spec_json] compile-flags: --print=target-spec-json //@[target_spec_json] error-pattern: the `-Z unstable-options` flag must also be passed diff --git a/tests/ui/print-request/supported-crate-types.linux.stdout b/tests/ui/print-request/supported-crate-types.linux.stdout new file mode 100644 index 000000000000..721adb432e7a --- /dev/null +++ b/tests/ui/print-request/supported-crate-types.linux.stdout @@ -0,0 +1,7 @@ +bin +cdylib +dylib +lib +proc-macro +rlib +staticlib diff --git a/tests/ui/print-request/supported-crate-types.musl.stdout b/tests/ui/print-request/supported-crate-types.musl.stdout new file mode 100644 index 000000000000..1f4b991e49fd --- /dev/null +++ b/tests/ui/print-request/supported-crate-types.musl.stdout @@ -0,0 +1,5 @@ +bin +lib +proc-macro +rlib +staticlib diff --git a/tests/ui/print-request/supported-crate-types.rs b/tests/ui/print-request/supported-crate-types.rs new file mode 100644 index 000000000000..c8b4c0c1a416 --- /dev/null +++ b/tests/ui/print-request/supported-crate-types.rs @@ -0,0 +1,20 @@ +//! Basic smoke test for `--print=supported-crate-types`, which should print a newline delimited +//! list of crate types supported by the given target. This test cherry-picks a few well-known +//! targets as examples. +//! +//! Tracking issue: + +// ignore-tidy-linelength + +//@ check-pass + +//@ revisions: wasm musl linux + +//@[wasm] compile-flags: --target=wasm32-unknown-unknown --print=supported-crate-types -Zunstable-options +//@[wasm] needs-llvm-components: webassembly + +//@[musl] compile-flags: --target=x86_64-unknown-linux-musl --print=supported-crate-types -Zunstable-options +//@[musl] needs-llvm-components: x86 + +//@[linux] compile-flags: --target=x86_64-unknown-linux-gnu --print=supported-crate-types -Zunstable-options +//@[linux] needs-llvm-components: x86 diff --git a/tests/ui/print-request/supported-crate-types.wasm.stdout b/tests/ui/print-request/supported-crate-types.wasm.stdout new file mode 100644 index 000000000000..ca1de519598a --- /dev/null +++ b/tests/ui/print-request/supported-crate-types.wasm.stdout @@ -0,0 +1,5 @@ +bin +cdylib +lib +rlib +staticlib From 13530afc08909a44874dc1e8667747fddb48e3c7 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 18 Mar 2025 13:37:36 +0800 Subject: [PATCH 227/546] Document `supported-crate-types` print request in unstable book --- .../print-supported-crate-types.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/print-supported-crate-types.md diff --git a/src/doc/unstable-book/src/compiler-flags/print-supported-crate-types.md b/src/doc/unstable-book/src/compiler-flags/print-supported-crate-types.md new file mode 100644 index 000000000000..f285d6e71751 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/print-supported-crate-types.md @@ -0,0 +1,27 @@ +# `print=supported-crate-types` + +The tracking issue for this feature is: [#138640](https://github.com/rust-lang/rust/issues/138640). + +------------------------ + +This option of the `--print` flag produces a list of crate types (delimited by newlines) supported for the given target. + +The crate type strings correspond to the values accepted by the `--crate-type` flag. + +Intended to be used like this: + +```bash +rustc --print=supported-crate-types -Zunstable-options --target=x86_64-unknown-linux-gnu +``` + +Example output for `x86_64-unknown-linux-gnu`: + +```text +bin +cdylib +dylib +lib +proc-macro +rlib +staticlib +``` From f1b8d896597534af16e3c1e540c336b9b444af0a Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 18 Mar 2025 14:39:46 +0800 Subject: [PATCH 228/546] Rebless tests with changed help due to new print request option --- tests/run-make/rustc-help/help-v.stdout | 2 +- tests/run-make/rustc-help/help.stdout | 2 +- tests/ui/invalid-compile-flags/print-without-arg.stderr | 2 +- tests/ui/invalid-compile-flags/print.stderr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index c8ea09ee2c8a..98e56735082d 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -29,7 +29,7 @@ Options: --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] Comma separated list of types of output for the compiler to emit - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] + --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] Compiler information to print on stdout -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index 434e71e901e4..040555f1d04f 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -29,7 +29,7 @@ Options: --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] Comma separated list of types of output for the compiler to emit - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] + --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] Compiler information to print on stdout -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr index 05d42247d419..aa8a2ae42db2 100644 --- a/tests/ui/invalid-compile-flags/print-without-arg.stderr +++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr @@ -1,5 +1,5 @@ error: Argument to option 'print' missing Usage: - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] + --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] Compiler information to print on stdout diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr index 4ea06a06539a..f9cfb1616ce5 100644 --- a/tests/ui/invalid-compile-flags/print.stderr +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -1,5 +1,5 @@ error: unknown print request: `yyyy` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information From f2cde8eeb4378b99cb722a9ef4a2f6cc83b805e1 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 21 Mar 2025 14:52:26 +0800 Subject: [PATCH 229/546] Adjust `rustc-print-info-issue-138612.rs` - Document test intent to check for `-Whelp` suggestion if `--print=lints` was specified. - Move this test under `tests/ui/print-request/` and rename it to `print-lints-help.rs` to better reflect what it is checking. --- tests/ui/print-request/print-lints-help.rs | 7 +++++++ .../print-lints-help.stderr} | 2 +- tests/ui/rustc-print-info-issue-138612.rs | 2 -- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 tests/ui/print-request/print-lints-help.rs rename tests/ui/{rustc-print-info-issue-138612.stderr => print-request/print-lints-help.stderr} (74%) delete mode 100644 tests/ui/rustc-print-info-issue-138612.rs diff --git a/tests/ui/print-request/print-lints-help.rs b/tests/ui/print-request/print-lints-help.rs new file mode 100644 index 000000000000..420eae27ed43 --- /dev/null +++ b/tests/ui/print-request/print-lints-help.rs @@ -0,0 +1,7 @@ +//! Check that we point to `-Whelp` to guide the user to find the list of lints if the user requests +//! `--print=lints` (which is not a valid print request). + +//@ compile-flags: --print lints +//@ error-pattern: error: unknown print request: `lints` +//@ error-pattern: help: use `-Whelp` to print a list of lints +//@ error-pattern: help: for more information, see the rustc book diff --git a/tests/ui/rustc-print-info-issue-138612.stderr b/tests/ui/print-request/print-lints-help.stderr similarity index 74% rename from tests/ui/rustc-print-info-issue-138612.stderr rename to tests/ui/print-request/print-lints-help.stderr index 4f7ed8219521..0530d11f2e80 100644 --- a/tests/ui/rustc-print-info-issue-138612.stderr +++ b/tests/ui/print-request/print-lints-help.stderr @@ -1,6 +1,6 @@ error: unknown print request: `lints` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` = help: use `-Whelp` to print a list of lints = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/ui/rustc-print-info-issue-138612.rs b/tests/ui/rustc-print-info-issue-138612.rs deleted file mode 100644 index 65b595635b15..000000000000 --- a/tests/ui/rustc-print-info-issue-138612.rs +++ /dev/null @@ -1,2 +0,0 @@ -//@ check-fail -//@ compile-flags: /dev/null --print lints From f10b58714e864ac7c1f6d6ac1666f26d4a1ca955 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 23 Mar 2025 19:28:10 +0800 Subject: [PATCH 230/546] Say which test failed the `COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS` assertion --- src/tools/compiletest/src/header.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 7675e13990d6..d7a5f304d238 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1385,7 +1385,7 @@ pub fn make_test_description( decision!(cfg::handle_ignore(config, ln)); decision!(cfg::handle_only(config, ln)); decision!(needs::handle_needs(&cache.needs, config, ln)); - decision!(ignore_llvm(config, ln)); + decision!(ignore_llvm(config, path, ln)); decision!(ignore_cdb(config, ln)); decision!(ignore_gdb(config, ln)); decision!(ignore_lldb(config, ln)); @@ -1525,7 +1525,7 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { +fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision { if let Some(needed_components) = config.parse_name_value_directive(line, "needs-llvm-components") { @@ -1536,8 +1536,9 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { { if env::var_os("COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS").is_some() { panic!( - "missing LLVM component {}, and COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS is set", - missing_component + "missing LLVM component {}, and COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS is set: {}", + missing_component, + path.display() ); } return IgnoreDecision::Ignore { From eb3707e4b49e7d19d048cf2187d6e3643be9dba2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Mar 2025 20:50:51 +0000 Subject: [PATCH 231/546] Stabilize precise_capturing_in_traits --- compiler/rustc_ast_lowering/messages.ftl | 3 --- compiler/rustc_ast_lowering/src/errors.rs | 8 ------- compiler/rustc_ast_lowering/src/lib.rs | 22 ------------------- compiler/rustc_feature/src/accepted.rs | 2 ++ compiler/rustc_feature/src/unstable.rs | 2 -- ...eature-gate-precise_capturing_in_traits.rs | 6 ----- ...re-gate-precise_capturing_in_traits.stderr | 13 ----------- tests/ui/impl-trait/in-trait/dump.rs | 2 +- .../ui/impl-trait/in-trait/refine-captures.rs | 2 -- .../in-trait/refine-captures.stderr | 8 +++---- tests/ui/impl-trait/in-trait/variance.rs | 2 +- .../forgot-to-capture-type.rs | 2 -- .../forgot-to-capture-type.stderr | 4 ++-- .../impl-trait/precise-capturing/redundant.rs | 1 - .../precise-capturing/redundant.stderr | 10 ++++----- .../rpitit-captures-more-method-lifetimes.rs | 2 -- ...itit-captures-more-method-lifetimes.stderr | 4 ++-- .../rpitit-impl-captures-too-much.rs | 2 -- .../rpitit-impl-captures-too-much.stderr | 4 ++-- .../precise-capturing/rpitit-outlives-2.rs | 2 -- .../precise-capturing/rpitit-outlives.rs | 2 -- .../ui/impl-trait/precise-capturing/rpitit.rs | 2 -- .../precise-capturing/rpitit.stderr | 6 ++--- .../precise-capturing/self-capture.rs | 2 -- 24 files changed, 22 insertions(+), 91 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs delete mode 100644 tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 65e5b530bbe3..5ef76fb64aaf 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -141,9 +141,6 @@ ast_lowering_never_pattern_with_guard = ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` -ast_lowering_no_precise_captures_on_rpitit = `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - .note = currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - ast_lowering_previously_used_here = previously used here ast_lowering_register1 = register `{$reg1_name}` diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index ceeb5dffbea0..576fa9731e90 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -444,14 +444,6 @@ pub(crate) struct NoPreciseCapturesOnApit { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_lowering_no_precise_captures_on_rpitit)] -#[note] -pub(crate) struct NoPreciseCapturesOnRpitit { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_lowering_yield_in_closure)] pub(crate) struct YieldInClosure { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e08850da4a7a..787706597368 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1438,28 +1438,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - // Feature gate for RPITIT + use<..> - match origin { - rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { - if !self.tcx.features().precise_capturing_in_traits() - && let Some(span) = bounds.iter().find_map(|bound| match *bound { - ast::GenericBound::Use(_, span) => Some(span), - _ => None, - }) - { - let mut diag = - self.tcx.dcx().create_err(errors::NoPreciseCapturesOnRpitit { span }); - add_feature_diagnostics( - &mut diag, - self.tcx.sess, - sym::precise_capturing_in_traits, - ); - diag.emit(); - } - } - _ => {} - } - self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| { this.lower_param_bounds(bounds, itctx) }) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 980f39460354..88e6593572bc 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -331,6 +331,8 @@ declare_features! ( (accepted, pattern_parentheses, "1.31.0", Some(51087)), /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. (accepted, precise_capturing, "1.82.0", Some(123432)), + /// Allows `use<..>` precise capturign on impl Trait in traits. + (accepted, precise_capturing_in_traits, "CURRENT_RUSTC_VERSION", Some(130044)), /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356)), /// Allows multi-segment paths in attributes and derives. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4707daea0891..72468dd4714d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -600,8 +600,6 @@ declare_features! ( (incomplete, pin_ergonomics, "1.83.0", Some(130494)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), - /// Allows `use<..>` precise capturign on impl Trait in traits. - (unstable, precise_capturing_in_traits, "1.83.0", Some(130044)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows the use of raw-dylibs on ELF platforms diff --git a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs deleted file mode 100644 index 308b41dfc68a..000000000000 --- a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs +++ /dev/null @@ -1,6 +0,0 @@ -trait Foo { - fn test() -> impl Sized + use; - //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr deleted file mode 100644 index b2c6bf61124d..000000000000 --- a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/feature-gate-precise_capturing_in_traits.rs:2:31 - | -LL | fn test() -> impl Sized + use; - | ^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - = note: see issue #130044 for more information - = help: add `#![feature(precise_capturing_in_traits)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - diff --git a/tests/ui/impl-trait/in-trait/dump.rs b/tests/ui/impl-trait/in-trait/dump.rs index 47198d511505..20b0e60702fa 100644 --- a/tests/ui/impl-trait/in-trait/dump.rs +++ b/tests/ui/impl-trait/in-trait/dump.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Zverbose-internals -#![feature(precise_capturing_in_traits, rustc_attrs)] +#![feature(rustc_attrs)] #![rustc_hidden_type_of_opaques] trait Foo { diff --git a/tests/ui/impl-trait/in-trait/refine-captures.rs b/tests/ui/impl-trait/in-trait/refine-captures.rs index e7dffcb52aae..199cc464c4e5 100644 --- a/tests/ui/impl-trait/in-trait/refine-captures.rs +++ b/tests/ui/impl-trait/in-trait/refine-captures.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing_in_traits)] - trait LifetimeParam<'a> { fn test() -> impl Sized; } diff --git a/tests/ui/impl-trait/in-trait/refine-captures.stderr b/tests/ui/impl-trait/in-trait/refine-captures.stderr index 166991894d16..6f213f161449 100644 --- a/tests/ui/impl-trait/in-trait/refine-captures.stderr +++ b/tests/ui/impl-trait/in-trait/refine-captures.stderr @@ -1,5 +1,5 @@ warning: impl trait in impl method captures fewer lifetimes than in trait - --> $DIR/refine-captures.rs:8:31 + --> $DIR/refine-captures.rs:6:31 | LL | fn test() -> impl Sized + use<> {} | ^^^^^ @@ -13,7 +13,7 @@ LL | fn test() -> impl Sized + use<'a> {} | ++ warning: impl trait in impl method captures fewer lifetimes than in trait - --> $DIR/refine-captures.rs:22:31 + --> $DIR/refine-captures.rs:20:31 | LL | fn test() -> impl Sized + use<> {} | ^^^^^ @@ -26,7 +26,7 @@ LL | fn test() -> impl Sized + use<'a> {} | ++ warning: impl trait in impl method captures fewer lifetimes than in trait - --> $DIR/refine-captures.rs:27:31 + --> $DIR/refine-captures.rs:25:31 | LL | fn test() -> impl Sized + use<'b> {} | ^^^^^^^ @@ -39,7 +39,7 @@ LL | fn test() -> impl Sized + use<'a, 'b> {} | ++++ error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/refine-captures.rs:32:18 + --> $DIR/refine-captures.rs:30:18 | LL | impl TypeParam for u64 { | - type parameter is implicitly captured by this `impl Trait` diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index cd2f43fca9a6..c0f569c690ab 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, precise_capturing_in_traits)] +#![feature(rustc_attrs)] #![allow(internal_features)] #![rustc_variance_of_opaques] diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index 6c2477c9744a..1b52b1702019 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing_in_traits)] - fn type_param() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all type parameters in scope diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index 93b44a0c18c2..93c35203f1dc 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,5 +1,5 @@ error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-type.rs:3:23 + --> $DIR/forgot-to-capture-type.rs:1:23 | LL | fn type_param() -> impl Sized + use<> {} | - ^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | fn type_param() -> impl Sized + use<> {} = note: currently, all type parameters are required to be mentioned in the precise captures list error: `impl Trait` must mention the `Self` type of the trait in `use<...>` - --> $DIR/forgot-to-capture-type.rs:7:17 + --> $DIR/forgot-to-capture-type.rs:5:17 | LL | trait Foo { | --------- `Self` type parameter is implicitly captured by this `impl Trait` diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index 32dc09273175..2385827db228 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -1,6 +1,5 @@ //@ edition: 2024 -#![feature(precise_capturing_in_traits)] #![deny(impl_trait_redundant_captures)] fn hello<'a>() -> impl Sized + use<'a> {} diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr index 5c8b35c22858..c9f84d360e3c 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.stderr +++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr @@ -1,5 +1,5 @@ error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:6:19 + --> $DIR/redundant.rs:5:19 | LL | fn hello<'a>() -> impl Sized + use<'a> {} | ^^^^^^^^^^^^^------- @@ -7,13 +7,13 @@ LL | fn hello<'a>() -> impl Sized + use<'a> {} | help: remove the `use<...>` syntax | note: the lint level is defined here - --> $DIR/redundant.rs:4:9 + --> $DIR/redundant.rs:3:9 | LL | #![deny(impl_trait_redundant_captures)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:11:27 + --> $DIR/redundant.rs:10:27 | LL | fn inherent(&self) -> impl Sized + use<'_> {} | ^^^^^^^^^^^^^------- @@ -21,7 +21,7 @@ LL | fn inherent(&self) -> impl Sized + use<'_> {} | help: remove the `use<...>` syntax error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:16:22 + --> $DIR/redundant.rs:15:22 | LL | fn in_trait() -> impl Sized + use<'a, Self>; | ^^^^^^^^^^^^^------------- @@ -29,7 +29,7 @@ LL | fn in_trait() -> impl Sized + use<'a, Self>; | help: remove the `use<...>` syntax error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:20:22 + --> $DIR/redundant.rs:19:22 | LL | fn in_trait() -> impl Sized + use<'a> {} | ^^^^^^^^^^^^^------- diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs index b39c1408c050..f6126c033391 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs @@ -2,8 +2,6 @@ // trait definition, which is not allowed. Due to the default lifetime capture // rules of RPITITs, this is only doable if we use precise capturing. -#![feature(precise_capturing_in_traits)] - pub trait Foo { fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; } diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr index 45f755d3cc1b..d90660188806 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr @@ -1,5 +1,5 @@ error: return type captures more lifetimes than trait definition - --> $DIR/rpitit-captures-more-method-lifetimes.rs:12:40 + --> $DIR/rpitit-captures-more-method-lifetimes.rs:10:40 | LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + use<'im> {} | --- ^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + use<'im> {} | this lifetime was captured | note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/rpitit-captures-more-method-lifetimes.rs:8:40 + --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:40 | LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs index b16b0522d6e1..115cab1cb992 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing_in_traits)] - struct Invariant<'a>(&'a mut &'a mut ()); trait Trait { diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr index 360f0d7e7f37..123e0acf171c 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr @@ -1,5 +1,5 @@ error: return type captures more lifetimes than trait definition - --> $DIR/rpitit-impl-captures-too-much.rs:10:39 + --> $DIR/rpitit-impl-captures-too-much.rs:8:39 | LL | fn hello(self_: Invariant<'_>) -> impl Sized + use; | -- this lifetime was captured @@ -8,7 +8,7 @@ LL | fn hello(self_: Invariant<'_>) -> impl Sized + use<'_> {} | ^^^^^^^^^^^^^^^^^^^^ | note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/rpitit-impl-captures-too-much.rs:6:39 + --> $DIR/rpitit-impl-captures-too-much.rs:4:39 | LL | fn hello(self_: Invariant<'_>) -> impl Sized + use; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs b/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs index 6f7e1a0eaefa..6fc129a6480c 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs @@ -2,8 +2,6 @@ // Ensure that we skip uncaptured args from RPITITs when comptuing outlives. -#![feature(precise_capturing_in_traits)] - struct Invariant(*mut T); trait Foo { diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs b/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs index 94d81d766f72..616368d25cf4 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs @@ -3,8 +3,6 @@ // Ensure that we skip uncaptured args from RPITITs when collecting the regions // to enforce member constraints in opaque type inference. -#![feature(precise_capturing_in_traits)] - struct Invariant(*mut T); trait Foo { diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.rs b/tests/ui/impl-trait/precise-capturing/rpitit.rs index 3f887e8e47f1..91c52817d857 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit.rs @@ -3,8 +3,6 @@ // To fix this soundly, we need to make sure that all the trait header args // remain captured, since they affect trait selection. -#![feature(precise_capturing_in_traits)] - fn eq_types(_: T, _: T) {} trait TraitLt<'a: 'a> { diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.stderr b/tests/ui/impl-trait/precise-capturing/rpitit.stderr index 498eae54a1c6..ff461e81079b 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit.stderr @@ -1,5 +1,5 @@ error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/rpitit.rs:11:19 + --> $DIR/rpitit.rs:9:19 | LL | trait TraitLt<'a: 'a> { | -- all lifetime parameters originating from a trait are captured implicitly @@ -7,7 +7,7 @@ LL | fn hello() -> impl Sized + use; | ^^^^^^^^^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/rpitit.rs:15:5 + --> $DIR/rpitit.rs:13:5 | LL | fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { | -- -- lifetime `'b` defined here @@ -24,7 +24,7 @@ LL | | ); = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/rpitit.rs:15:5 + --> $DIR/rpitit.rs:13:5 | LL | fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { | -- -- lifetime `'b` defined here diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index 15985da50b55..66fbfc780438 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(precise_capturing_in_traits)] - trait Foo { fn bar<'a>() -> impl Sized + use; } From 264e1addfd72181741188ab318f2542e86ad4d53 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 23 Mar 2025 16:26:03 +0000 Subject: [PATCH 232/546] Rustup to rustc 1.87.0-nightly (b48576b4d 2025-03-22) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index cbed84253fbe..a6b0bf5fba1a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-21" +channel = "nightly-2025-03-23" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 542dbbdcfed457beb70b2133e57c312537711564 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 23 Mar 2025 17:36:31 +0000 Subject: [PATCH 233/546] Fix rustc testsuite --- scripts/setup_rust_fork.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index c2c8e625f60b..ca6426f2ba9d 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -46,6 +46,28 @@ llvm-tools = false std-features = ["panic-unwind", "compiler-builtins-no-f16-f128"] EOF + +cat < Date: Sun, 23 Mar 2025 16:24:39 +0000 Subject: [PATCH 234/546] Visit coroutine kind ty in FlagComputation --- compiler/rustc_middle/src/ty/flags.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 0b8f0e8cd41d..abfc5463c8ff 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -113,6 +113,7 @@ impl FlagComputation { self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; } + self.add_ty(args.kind_ty()); self.add_ty(args.resume_ty()); self.add_ty(args.return_ty()); self.add_ty(args.witness()); From e4f13e3ccd143b866044f7875d3caf866cfa66fd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 23 Mar 2025 16:37:27 +0000 Subject: [PATCH 235/546] Remove HAS_TY_COROUTINE --- compiler/rustc_middle/src/ty/flags.rs | 1 - compiler/rustc_type_ir/src/flags.rs | 5 +---- compiler/rustc_type_ir/src/visit.rs | 4 ---- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index abfc5463c8ff..8d5a213b7460 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -128,7 +128,6 @@ impl FlagComputation { if should_remove_further_specializable { self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; } - self.add_flags(TypeFlags::HAS_TY_COROUTINE); } &ty::Closure(_, args) => { diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 81aa4a1f19ee..fe401b11f396 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -119,10 +119,7 @@ bitflags::bitflags! { /// Does this value have `InferConst::Fresh`? const HAS_CT_FRESH = 1 << 23; - /// Does this have `Coroutine` or `CoroutineWitness`? - const HAS_TY_COROUTINE = 1 << 24; - /// Does this have any binders with bound vars (e.g. that need to be anonymized)? - const HAS_BINDER_VARS = 1 << 25; + const HAS_BINDER_VARS = 1 << 24; } } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 119b658a2bf3..2285e0e75de0 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -269,10 +269,6 @@ pub trait TypeVisitableExt: TypeVisitable { self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) } - fn has_coroutines(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_COROUTINE) - } - fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_ERROR) } From 77a106e61fe8331e646212382cd2ee5d2bbcd149 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 23 Mar 2025 16:44:30 +0000 Subject: [PATCH 236/546] Remove STILL_FURTHER_SPECIALIZABLE special casing --- compiler/rustc_middle/src/ty/flags.rs | 91 +++++---------------------- compiler/rustc_type_ir/src/flags.rs | 13 ++-- 2 files changed, 25 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 8d5a213b7460..b0c442d28f0a 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -101,63 +101,13 @@ impl FlagComputation { &ty::Param(_) => { self.add_flags(TypeFlags::HAS_TY_PARAM); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } - ty::Coroutine(_, args) => { - let args = args.as_coroutine(); - let should_remove_further_specializable = - !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); - self.add_args(args.parent_args()); - if should_remove_further_specializable { - self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; - } - - self.add_ty(args.kind_ty()); - self.add_ty(args.resume_ty()); - self.add_ty(args.return_ty()); - self.add_ty(args.witness()); - self.add_ty(args.yield_ty()); - self.add_ty(args.tupled_upvars_ty()); - } - - ty::CoroutineWitness(_, args) => { - let should_remove_further_specializable = - !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + &ty::Closure(_, args) + | &ty::Coroutine(_, args) + | &ty::CoroutineClosure(_, args) + | &ty::CoroutineWitness(_, args) => { self.add_args(args); - if should_remove_further_specializable { - self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; - } - } - - &ty::Closure(_, args) => { - let args = args.as_closure(); - let should_remove_further_specializable = - !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); - self.add_args(args.parent_args()); - if should_remove_further_specializable { - self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; - } - - self.add_ty(args.sig_as_fn_ptr_ty()); - self.add_ty(args.kind_ty()); - self.add_ty(args.tupled_upvars_ty()); - } - - &ty::CoroutineClosure(_, args) => { - let args = args.as_coroutine_closure(); - let should_remove_further_specializable = - !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); - self.add_args(args.parent_args()); - if should_remove_further_specializable { - self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; - } - - self.add_ty(args.kind_ty()); - self.add_ty(args.signature_parts_ty()); - self.add_ty(args.tupled_upvars_ty()); - self.add_ty(args.coroutine_captures_by_ref_ty()); - self.add_ty(args.coroutine_witness_ty()); } &ty::Bound(debruijn, _) => { @@ -167,21 +117,17 @@ impl FlagComputation { &ty::Placeholder(..) => { self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } - &ty::Infer(infer) => { - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); - match infer { - ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { - self.add_flags(TypeFlags::HAS_TY_FRESH) - } - - ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { - self.add_flags(TypeFlags::HAS_TY_INFER) - } + &ty::Infer(infer) => match infer { + ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { + self.add_flags(TypeFlags::HAS_TY_FRESH) } - } + + ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { + self.add_flags(TypeFlags::HAS_TY_INFER) + } + }, &ty::Adt(_, args) => { self.add_args(args); @@ -358,24 +304,19 @@ impl FlagComputation { self.add_args(uv.args); self.add_flags(TypeFlags::HAS_CT_PROJECTION); } - ty::ConstKind::Infer(infer) => { - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); - match infer { - InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), - InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), - } - } + ty::ConstKind::Infer(infer) => match infer { + InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), + InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), + }, ty::ConstKind::Bound(debruijn, _) => { self.add_bound_var(debruijn); self.add_flags(TypeFlags::HAS_CT_BOUND); } ty::ConstKind::Param(_) => { self.add_flags(TypeFlags::HAS_CT_PARAM); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Placeholder(_) => { self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Value(cv) => self.add_ty(cv.ty), ty::ConstKind::Expr(e) => self.add_args(e.args()), diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index fe401b11f396..6a2498242fee 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -111,15 +111,20 @@ bitflags::bitflags! { /// Does this value have parameters/placeholders/inference variables which could be /// replaced later, in a way that would change the results of `impl` specialization? - const STILL_FURTHER_SPECIALIZABLE = 1 << 21; + const STILL_FURTHER_SPECIALIZABLE = TypeFlags::HAS_TY_PARAM.bits() + | TypeFlags::HAS_TY_PLACEHOLDER.bits() + | TypeFlags::HAS_TY_INFER.bits() + | TypeFlags::HAS_CT_PARAM.bits() + | TypeFlags::HAS_CT_PLACEHOLDER.bits() + | TypeFlags::HAS_CT_INFER.bits(); /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`? - const HAS_TY_FRESH = 1 << 22; + const HAS_TY_FRESH = 1 << 21; /// Does this value have `InferConst::Fresh`? - const HAS_CT_FRESH = 1 << 23; + const HAS_CT_FRESH = 1 << 22; /// Does this have any binders with bound vars (e.g. that need to be anonymized)? - const HAS_BINDER_VARS = 1 << 24; + const HAS_BINDER_VARS = 1 << 23; } } From 575f129faa5126869f11ef945276072b097a2b2a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Mar 2025 22:09:16 +0000 Subject: [PATCH 237/546] Obligation::as_goal --- .../src/fn_ctxt/inspect_obligations.rs | 4 ++-- compiler/rustc_infer/src/infer/opaque_types/mod.rs | 3 +-- compiler/rustc_infer/src/traits/mod.rs | 12 ++++++------ compiler/rustc_trait_selection/src/solve/delegate.rs | 2 +- compiler/rustc_trait_selection/src/solve/fulfill.rs | 4 ++-- .../src/solve/fulfill/derive_errors.rs | 8 ++++---- .../rustc_trait_selection/src/traits/coherence.rs | 2 +- 7 files changed, 17 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 95b9cb3be627..e068e6079027 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -1,7 +1,7 @@ //! A utility module to inspect currently ambiguous obligations in the current context. use rustc_infer::traits::{self, ObligationCause, PredicateObligations}; -use rustc_middle::traits::solve::{Goal, GoalSource}; +use rustc_middle::traits::solve::GoalSource; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::solve::inspect::{ @@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { root_cause: &obligation.cause, }; - let goal = Goal::new(self.tcx, obligation.param_env, obligation.predicate); + let goal = obligation.as_goal(); self.visit_proof_tree(goal, &mut visitor); } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 3fa1923121a2..215b13337266 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -246,8 +246,7 @@ impl<'tcx> InferCtxt<'tcx> { .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)? .obligations .into_iter() - // FIXME: Shuttling between obligations and goals is awkward. - .map(Goal::from), + .map(|obligation| obligation.as_goal()), ); } } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index ac641ef56522..b537750f1b51 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -54,6 +54,12 @@ pub struct Obligation<'tcx, T> { pub recursion_depth: usize, } +impl<'tcx, T: Copy> Obligation<'tcx, T> { + pub fn as_goal(&self) -> solve::Goal<'tcx, T> { + solve::Goal { param_env: self.param_env, predicate: self.predicate } + } +} + impl<'tcx, T: PartialEq> PartialEq> for Obligation<'tcx, T> { #[inline] fn eq(&self, other: &Obligation<'tcx, T>) -> bool { @@ -75,12 +81,6 @@ impl Hash for Obligation<'_, T> { } } -impl<'tcx, P> From> for solve::Goal<'tcx, P> { - fn from(value: Obligation<'tcx, P>) -> Self { - solve::Goal { param_env: value.param_env, predicate: value.predicate } - } -} - pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::TraitPredicate<'tcx>>; pub type PolyTraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index af5a60027ba4..3d9a90eb74e7 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -96,7 +96,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ) -> Option>>> { crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg, DUMMY_SP, CRATE_DEF_ID) .map(|obligations| { - obligations.into_iter().map(|obligation| obligation.into()).collect() + obligations.into_iter().map(|obligation| obligation.as_goal()).collect() }) } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 704ba6e501d8..192e632a2d5b 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -80,7 +80,7 @@ impl<'tcx> ObligationStorage<'tcx> { // change. // FIXME: is merged, this can be removed. self.overflowed.extend(ExtractIf::new(&mut self.pending, |o| { - let goal = o.clone().into(); + let goal = o.as_goal(); let result = <&SolverDelegate<'tcx>>::from(infcx) .evaluate_root_goal(goal, GenerateProofTree::No, o.cause.span) .0; @@ -161,7 +161,7 @@ where let mut has_changed = false; for obligation in self.obligations.unstalled_for_select() { - let goal = obligation.clone().into(); + let goal = obligation.as_goal(); let result = <&SolverDelegate<'tcx>>::from(infcx) .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span) .0; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 352ac7c1a4e6..3a939df25e07 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; -use rustc_type_ir::solve::{Goal, NoSolution}; +use rustc_type_ir::solve::NoSolution; use tracing::{instrument, trace}; use crate::solve::Certainty; @@ -89,7 +89,7 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( let (code, refine_obligation) = infcx.probe(|_| { match <&SolverDelegate<'tcx>>::from(infcx) .evaluate_root_goal( - root_obligation.clone().into(), + root_obligation.as_goal(), GenerateProofTree::No, root_obligation.cause.span, ) @@ -155,7 +155,7 @@ fn find_best_leaf_obligation<'tcx>( .fudge_inference_if_ok(|| { infcx .visit_proof_tree( - obligation.clone().into(), + obligation.as_goal(), &mut BestObligation { obligation: obligation.clone(), consider_ambiguities }, ) .break_value() @@ -245,7 +245,7 @@ impl<'tcx> BestObligation<'tcx> { { let nested_goal = candidate.instantiate_proof_tree_for_nested_goal( GoalSource::Misc, - Goal::new(infcx.tcx, obligation.param_env, obligation.predicate), + obligation.as_goal(), self.span(), ); // Skip nested goals that aren't the *reason* for our goal's failure. diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 4c7172c32781..bcc247ba53c2 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -625,7 +625,7 @@ fn compute_intercrate_ambiguity_causes<'tcx>( let mut causes: FxIndexSet> = Default::default(); for obligation in obligations { - search_ambiguity_causes(infcx, obligation.clone().into(), &mut causes); + search_ambiguity_causes(infcx, obligation.as_goal(), &mut causes); } causes From d588bc2a2b49cb9f18fe051774a3f4a41ab5068e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Mar 2025 21:01:11 +0000 Subject: [PATCH 238/546] Don't super fold const in Resolver --- compiler/rustc_hir_typeck/src/writeback.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6a3417ae5d6f..748cb11290d9 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -864,10 +864,7 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - self.handle_term(ct, ty::Const::outer_exclusive_binder, |tcx, guar| { - ty::Const::new_error(tcx, guar) - }) - .super_fold_with(self) + self.handle_term(ct, ty::Const::outer_exclusive_binder, ty::Const::new_error) } fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { From fad34c603cd6c7e432f297e682bb68a2cf55df0b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 23 Mar 2025 18:34:33 +0000 Subject: [PATCH 239/546] Explicitly don't fold coroutine obligations in writeback --- compiler/rustc_hir_typeck/src/writeback.rs | 45 +++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 748cb11290d9..b63c0b6ab7e0 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -548,7 +548,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); for (predicate, cause) in &fcx_typeck_results.coroutine_stalled_predicates { - let (predicate, cause) = self.resolve((*predicate, cause.clone()), &cause.span); + let (predicate, cause) = + self.resolve_coroutine_predicate((*predicate, cause.clone()), &cause.span); self.typeck_results.coroutine_stalled_predicates.insert((predicate, cause)); } } @@ -730,7 +731,25 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { T: TypeFoldable>, { let value = self.fcx.resolve_vars_if_possible(value); - let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body)); + let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true)); + assert!(!value.has_infer()); + + // We may have introduced e.g. `ty::Error`, if inference failed, make sure + // to mark the `TypeckResults` as tainted in that case, so that downstream + // users of the typeck results don't produce extra errors, or worse, ICEs. + if let Err(guar) = value.error_reported() { + self.typeck_results.tainted_by_errors = Some(guar); + } + + value + } + + fn resolve_coroutine_predicate(&mut self, value: T, span: &dyn Locatable) -> T + where + T: TypeFoldable>, + { + let value = self.fcx.resolve_vars_if_possible(value); + let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false)); assert!(!value.has_infer()); // We may have introduced e.g. `ty::Error`, if inference failed, make sure @@ -774,8 +793,9 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fcx: &'cx FnCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, + should_normalize: bool, ) -> Resolver<'cx, 'tcx> { - Resolver { fcx, span, body, should_normalize: fcx.next_trait_solver() } + Resolver { fcx, span, body, should_normalize } } fn report_error(&self, p: impl Into>) -> ErrorGuaranteed { @@ -805,10 +825,9 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { T: Into> + TypeSuperFoldable> + Copy, { let tcx = self.fcx.tcx; - // We must deeply normalize in the new solver, since later lints - // expect that types that show up in the typeck are fully - // normalized. - let mut value = if self.should_normalize { + // We must deeply normalize in the new solver, since later lints expect + // that types that show up in the typeck are fully normalized. + let mut value = if self.should_normalize && self.fcx.next_trait_solver() { let body_id = tcx.hir_body_owner_def_id(self.body.id()); let cause = ObligationCause::misc(self.span.to_span(tcx), body_id); let at = self.fcx.at(&cause, self.fcx.param_env); @@ -868,13 +887,11 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { } fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - // Do not normalize predicates in the new solver. The new solver is - // supposed to handle unnormalized predicates and incorrectly normalizing - // them can be unsound, e.g. for `WellFormed` predicates. - let prev = mem::replace(&mut self.should_normalize, false); - let predicate = predicate.super_fold_with(self); - self.should_normalize = prev; - predicate + assert!( + !self.should_normalize, + "normalizing predicates in writeback is not generally sound" + ); + predicate.super_fold_with(self) } } From 6948343b9fd4855377fd68c93b9c027d525df590 Mon Sep 17 00:00:00 2001 From: Hadrien Eyraud Date: Thu, 9 Jan 2025 18:39:40 +0100 Subject: [PATCH 240/546] fix: Check empty SIMD vector in inline asm --- .../rustc_hir_analysis/src/check/intrinsicck.rs | 8 ++++++++ tests/crashes/134334.rs | 9 --------- tests/ui/simd/empty-simd-vector-in-operand.rs | 14 ++++++++++++++ tests/ui/simd/empty-simd-vector-in-operand.stderr | 15 +++++++++++++++ 4 files changed, 37 insertions(+), 9 deletions(-) delete mode 100644 tests/crashes/134334.rs create mode 100644 tests/ui/simd/empty-simd-vector-in-operand.rs create mode 100644 tests/ui/simd/empty-simd-vector-in-operand.stderr diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index d63165f0f169..32a582aadc1c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -29,6 +29,7 @@ enum NonAsmTypeReason<'tcx> { Invalid(Ty<'tcx>), InvalidElement(DefId, Ty<'tcx>), NotSizedPtr(Ty<'tcx>), + EmptySIMDArray(Ty<'tcx>), } impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { @@ -102,6 +103,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } ty::Adt(adt, args) if adt.repr().simd() => { let fields = &adt.non_enum_variant().fields; + if fields.is_empty() { + return Err(NonAsmTypeReason::EmptySIMDArray(ty)); + } let field = &fields[FieldIdx::ZERO]; let elem_ty = field.ty(self.tcx(), args); @@ -226,6 +230,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { can be used as arguments for inline assembly", ).emit(); } + NonAsmTypeReason::EmptySIMDArray(ty) => { + let msg = format!("use of empty SIMD vector `{ty}`"); + self.infcx.dcx().struct_span_err(expr.span, msg).emit(); + } } return None; } diff --git a/tests/crashes/134334.rs b/tests/crashes/134334.rs deleted file mode 100644 index d99df7bdc1ed..000000000000 --- a/tests/crashes/134334.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #134334 -//@ only-x86_64 - -#[repr(simd)] -struct A(); - -fn main() { - std::arch::asm!("{}", in(xmm_reg) A()); -} diff --git a/tests/ui/simd/empty-simd-vector-in-operand.rs b/tests/ui/simd/empty-simd-vector-in-operand.rs new file mode 100644 index 000000000000..ae21461eb95b --- /dev/null +++ b/tests/ui/simd/empty-simd-vector-in-operand.rs @@ -0,0 +1,14 @@ +// Regression test for issue #134224. + +#![feature(repr_simd)] + +#[repr(simd)] +struct A(); +//~^ ERROR SIMD vector cannot be empty + +fn main() { + unsafe { + std::arch::asm!("{}", in(xmm_reg) A()); + //~^ use of empty SIMD vector `A` + } +} diff --git a/tests/ui/simd/empty-simd-vector-in-operand.stderr b/tests/ui/simd/empty-simd-vector-in-operand.stderr new file mode 100644 index 000000000000..a0faf5f06d20 --- /dev/null +++ b/tests/ui/simd/empty-simd-vector-in-operand.stderr @@ -0,0 +1,15 @@ +error[E0075]: SIMD vector cannot be empty + --> $DIR/empty-simd-vector-in-operand.rs:6:1 + | +LL | struct A(); + | ^^^^^^^^ + +error: use of empty SIMD vector `A` + --> $DIR/empty-simd-vector-in-operand.rs:11:43 + | +LL | std::arch::asm!("{}", in(xmm_reg) A()); + | ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0075`. From ff699ce9f55e974e9181a800203fae9d73b90e37 Mon Sep 17 00:00:00 2001 From: Hadrien Eyraud Date: Mon, 3 Feb 2025 14:16:27 +0100 Subject: [PATCH 241/546] fix: running the test only on x86_64. The test was failing on aarch64-apple-darwin. --- tests/ui/simd/empty-simd-vector-in-operand.rs | 1 + tests/ui/simd/empty-simd-vector-in-operand.stderr | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ui/simd/empty-simd-vector-in-operand.rs b/tests/ui/simd/empty-simd-vector-in-operand.rs index ae21461eb95b..2a2a6c0737db 100644 --- a/tests/ui/simd/empty-simd-vector-in-operand.rs +++ b/tests/ui/simd/empty-simd-vector-in-operand.rs @@ -1,4 +1,5 @@ // Regression test for issue #134224. +//@ only-x86_64 #![feature(repr_simd)] diff --git a/tests/ui/simd/empty-simd-vector-in-operand.stderr b/tests/ui/simd/empty-simd-vector-in-operand.stderr index a0faf5f06d20..7210dddd461f 100644 --- a/tests/ui/simd/empty-simd-vector-in-operand.stderr +++ b/tests/ui/simd/empty-simd-vector-in-operand.stderr @@ -1,11 +1,11 @@ error[E0075]: SIMD vector cannot be empty - --> $DIR/empty-simd-vector-in-operand.rs:6:1 + --> $DIR/empty-simd-vector-in-operand.rs:7:1 | LL | struct A(); | ^^^^^^^^ error: use of empty SIMD vector `A` - --> $DIR/empty-simd-vector-in-operand.rs:11:43 + --> $DIR/empty-simd-vector-in-operand.rs:12:43 | LL | std::arch::asm!("{}", in(xmm_reg) A()); | ^^^ From 7210df1a9ac3cec2e925012bcc9190c13b5a2402 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 23 Mar 2025 18:45:34 +0100 Subject: [PATCH 242/546] Rework `--print` options documentation --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/command-line-arguments.md | 53 +---- .../command-line-arguments/print-options.md | 212 ++++++++++++++++++ 3 files changed, 214 insertions(+), 52 deletions(-) create mode 100644 src/doc/rustc/src/command-line-arguments/print-options.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 542ee9fffce3..e258b0a76ffd 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -2,6 +2,7 @@ - [What is rustc?](what-is-rustc.md) - [Command-line Arguments](command-line-arguments.md) + - [Print Options](command-line-arguments/print-options.md) - [Codegen Options](codegen-options/index.md) - [Jobserver](jobserver.md) - [Lints](lints/index.md) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 9dd2e7de1b33..b704cee705b0 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -247,58 +247,7 @@ types to stdout at the same time will result in an error. ## `--print`: print compiler information -This flag prints out various information about the compiler. This flag may be -specified multiple times, and the information is printed in the order the -flags are specified. Specifying a `--print` flag will usually disable the -[`--emit`](#option-emit) step and will only print the requested information. -The valid types of print values are: - -- `crate-name` — The name of the crate. -- `file-names` — The names of the files created by the `link` emit kind. -- `sysroot` — Path to the sysroot. -- `target-libdir` — Path to the target libdir. -- `host-tuple` — The target-tuple string of the host compiler (e.g. `x86_64-unknown-linux-gnu`) -- `cfg` — List of cfg values. See [conditional compilation] for more - information about cfg values. -- `target-list` — List of known targets. The target may be selected with the - `--target` flag. -- `target-cpus` — List of available CPU values for the current target. The - target CPU may be selected with the [`-C target-cpu=val` - flag](codegen-options/index.md#target-cpu). -- `target-features` — List of available target features for the current - target. Target features may be enabled with the [`-C target-feature=val` - flag](codegen-options/index.md#target-feature). This flag is unsafe. See - [known issues](targets/known-issues.md) for more details. -- `relocation-models` — List of relocation models. Relocation models may be - selected with the [`-C relocation-model=val` - flag](codegen-options/index.md#relocation-model). -- `code-models` — List of code models. Code models may be selected with the - [`-C code-model=val` flag](codegen-options/index.md#code-model). -- `tls-models` — List of Thread Local Storage models supported. The model may - be selected with the `-Z tls-model=val` flag. -- `native-static-libs` — This may be used when creating a `staticlib` crate - type. If this is the only flag, it will perform a full compilation and - include a diagnostic note that indicates the linker flags to use when - linking the resulting static library. The note starts with the text - `native-static-libs:` to make it easier to fetch the output. -- `link-args` — This flag does not disable the `--emit` step. When linking, - this flag causes `rustc` to print the full linker invocation in a - human-readable form. This can be useful when debugging linker options. The - exact format of this debugging output is not a stable guarantee, other than - that it will include the linker executable and the text of each command-line - argument passed to the linker. -- `deployment-target` — The currently selected [deployment target] (or minimum OS version) - for the selected Apple platform target. This value can be used or passed along to other - components alongside a Rust build that need this information, such as C compilers. - This returns rustc's minimum supported deployment target if no `*_DEPLOYMENT_TARGET` variable - is present in the environment, or otherwise returns the variable's parsed value. - -A filepath may optionally be specified for each requested information kind, in -the format `--print KIND=PATH`, just like for `--emit`. When a path is -specified, information will be written there instead of to stdout. - -[conditional compilation]: ../reference/conditional-compilation.html -[deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html +This flag will allow you to set [print options](command-line-arguments/print-options.md). ## `-g`: include debug information diff --git a/src/doc/rustc/src/command-line-arguments/print-options.md b/src/doc/rustc/src/command-line-arguments/print-options.md new file mode 100644 index 000000000000..1f33e91e5d1b --- /dev/null +++ b/src/doc/rustc/src/command-line-arguments/print-options.md @@ -0,0 +1,212 @@ +# Print Options + +All of these options are passed to `rustc` via the `--print` flag. + +Those options prints out various information about the compiler. Multiple options can be +specified, and the information is printed in the order the options are specified. + +Specifying an option will usually disable the [`--emit`](../command-line-arguments.md#option-emit) +step and will only print the requested information. + +A filepath may optionally be specified for each requested information kind, in the format +`--print KIND=PATH`, just like for `--emit`. When a path is specified, information will be +written there instead of to stdout. + +## `crate-name` + +The name of the crate. + +Generally coming from either from the `#![crate_name = "..."]` attribute, +[`--crate-name` flag](../command-line-arguments.md#option-crate-name) or the filename. + +Example: + +```bash +$ rustc --print crate-name --crate-name my_crate a.rs +my_crate +``` + +## `file-names` + +The names of the files created by the `link` emit kind. + +## `sysroot` + +Abosulte path to the sysroot. + +Example (with rustup and the stable toolchain): + +```bash +$ rustc --print sysroot a.rs +/home/[REDACTED]/.rustup/toolchains/stable-x86_64-unknown-linux-gnu +``` + +## `target-libdir` + +Path to the target libdir. + +Example (with rustup and the stable toolchain): + +```bash +$ rustc --print target-libdir a.rs +/home/[REDACTED]/.rustup/toolchains/beta-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib +``` + +## `host-tuple` + +The target-tuple string of the host compiler. + +Example: + +```bash +$ rustc --print host-tuple a.rs +x86_64-unknown-linux-gnu +``` + +Example with the `--target` flag: + +```bash +$ rustc --print host-tuple --target "armv7-unknown-linux-gnueabihf" a.rs +x86_64-unknown-linux-gnu +``` + +## `cfg` + +List of cfg values. See [conditional compilation] for more information about cfg values. + +Example (for `x86_64-unknown-linux-gnu`): + +```bash +$ rustc --print cfg a.rs +debug_assertions +panic="unwind" +target_abi="" +target_arch="x86_64" +target_endian="little" +target_env="gnu" +target_family="unix" +target_feature="fxsr" +target_feature="sse" +target_feature="sse2" +target_has_atomic="16" +target_has_atomic="32" +target_has_atomic="64" +target_has_atomic="8" +target_has_atomic="ptr" +target_os="linux" +target_pointer_width="64" +target_vendor="unknown" +unix +``` + +## `target-list` + +List of known targets. The target may be selected with the `--target` flag. + +## `target-cpus` + +List of available CPU values for the current target. The target CPU may be selected with +the [`-C target-cpu=val` flag](../codegen-options/index.md#target-cpu). + +## `target-features` + +List of available target features for the *current target*. + +Target features may be enabled with the **unsafe** +[`-C target-feature=val` flag](../codegen-options/index.md#target-feature). + +See [known issues](../targets/known-issues.md) for more details. + +## `relocation-models` + +List of relocation models. Relocation models may be selected with the +[`-C relocation-model=val` flag](../codegen-options/index.md#relocation-model). + +Example: + +```bash +$ rustc --print relocation-models a.rs +Available relocation models: + static + pic + pie + dynamic-no-pic + ropi + rwpi + ropi-rwpi + default +``` + +## `code-models` + +List of code models. Code models may be selected with the +[`-C code-model=val` flag](../codegen-options/index.md#code-model). + +Example: + +```bash +$ rustc --print code-models a.rs +Available code models: + tiny + small + kernel + medium + large +``` + +## `tls-models` + +List of Thread Local Storage models supported. The model may be selected with the +`-Z tls-model=val` flag. + +Example: + +```bash +$ rustc --print tls-models a.rs +Available TLS models: + global-dynamic + local-dynamic + initial-exec + local-exec + emulated +``` + +## `native-static-libs` + +This may be used when creating a `staticlib` crate type. + +If this is the only flag, it will perform a full compilation and include a diagnostic note +that indicates the linker flags to use when linking the resulting static library. + +The note starts with the text `native-static-libs:` to make it easier to fetch the output. + +Example: + +```bash +$ rustc --print native-static-libs --crate-type staticlib a.rs +note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. + +note: native-static-libs: -lgcc_s -lutil [REDACTED] -lpthread -lm -ldl -lc +``` + +## `link-args` + +This flag does not disable the `--emit` step. This can be useful when debugging linker options. + +When linking, this flag causes `rustc` to print the full linker invocation in a human-readable +form. The exact format of this debugging output is not a stable guarantee, other than that it +will include the linker executable and the text of each command-line argument passed to the +linker. + +## `deployment-target` + +The currently selected [deployment target] (or minimum OS version) for the selected Apple +platform target. + +This value can be used or passed along to other components alongside a Rust build that need +this information, such as C compilers. This returns rustc's minimum supported deployment target +if no `*_DEPLOYMENT_TARGET` variable is present in the environment, or otherwise returns the +variable's parsed value. + +[conditional compilation]: ../../reference/conditional-compilation.html +[deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html From 7781346243c1e1a038e0bc6fa11e5e1aefea7d4a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 23 Mar 2025 15:27:31 -0700 Subject: [PATCH 243/546] Stop using specialization for this Uses `__`-named `doc(hidden)` methods instead. --- library/core/src/cmp.rs | 162 ++++++++++-------- library/core/src/tuple.rs | 13 +- ...e_ord.demo_ge_partial.PreCodegen.after.mir | 2 +- ...ple_ord.demo_le_total.PreCodegen.after.mir | 2 +- 4 files changed, 95 insertions(+), 84 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index af14c4b50725..0b0dbf723b65 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -29,7 +29,7 @@ mod bytewise; pub(crate) use bytewise::BytewiseEq; use self::Ordering::*; -use crate::ops::ControlFlow::{self, Break, Continue}; +use crate::ops::ControlFlow; /// Trait for comparisons using the equality operator. /// @@ -1436,6 +1436,67 @@ pub trait PartialOrd: PartialEq { fn ge(&self, other: &Rhs) -> bool { self.partial_cmp(other).is_some_and(Ordering::is_ge) } + + /// If `self == other`, returns `ControlFlow::Continue(())`. + /// Otherwise, returns `ControlFlow::Break(self < other)`. + /// + /// This is useful for chaining together calls when implementing a lexical + /// `PartialOrd::lt`, as it allows types (like primitives) which can cheaply + /// check `==` and `<` separately to do rather than needing to calculate + /// (then optimize out) the three-way `Ordering` result. + #[inline] + #[must_use] + // Added to improve the behaviour of tuples; not necessarily stabilization-track. + #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] + #[doc(hidden)] + fn __chaining_lt(&self, other: &Rhs) -> ControlFlow { + default_chaining_impl(self, other, Ordering::is_lt) + } + + /// Same as `__chaining_lt`, but for `<=` instead of `<`. + #[inline] + #[must_use] + #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] + #[doc(hidden)] + fn __chaining_le(&self, other: &Rhs) -> ControlFlow { + default_chaining_impl(self, other, Ordering::is_le) + } + + /// Same as `__chaining_lt`, but for `>` instead of `<`. + #[inline] + #[must_use] + #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] + #[doc(hidden)] + fn __chaining_gt(&self, other: &Rhs) -> ControlFlow { + default_chaining_impl(self, other, Ordering::is_gt) + } + + /// Same as `__chaining_lt`, but for `>=` instead of `<`. + #[inline] + #[must_use] + #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] + #[doc(hidden)] + fn __chaining_ge(&self, other: &Rhs) -> ControlFlow { + default_chaining_impl(self, other, Ordering::is_ge) + } +} + +fn default_chaining_impl( + lhs: &T, + rhs: &U, + p: impl FnOnce(Ordering) -> bool, +) -> ControlFlow +where + T: PartialOrd, +{ + // It's important that this only call `partial_cmp` once, not call `eq` then + // one of the relational operators. We don't want to `bcmp`-then-`memcp` a + // `String`, for example, or similarly for other data structures (#108157). + match >::partial_cmp(lhs, rhs) { + Some(Equal) => ControlFlow::Continue(()), + Some(c) => ControlFlow::Break(p(c)), + None => ControlFlow::Break(false), + } } /// Derive macro generating an impl of the trait [`PartialOrd`]. @@ -1447,54 +1508,6 @@ pub macro PartialOrd($item:item) { /* compiler built-in */ } -/// Helpers for chaining together field PartialOrds into the full type's ordering. -/// -/// If the two values are equal, returns `ControlFlow::Continue`. -/// If the two values are not equal, returns `ControlFlow::Break(self OP other)`. -/// -/// This allows simple types like `i32` and `f64` to just emit two comparisons -/// directly, instead of needing to optimize the 3-way comparison. -/// -/// Currently this is done using specialization, but it doesn't need that: -/// it could be provided methods on `PartialOrd` instead and work fine. -pub(crate) trait SpecChainingPartialOrd: PartialOrd { - fn spec_chain_lt(&self, other: &Rhs) -> ControlFlow; - fn spec_chain_le(&self, other: &Rhs) -> ControlFlow; - fn spec_chain_gt(&self, other: &Rhs) -> ControlFlow; - fn spec_chain_ge(&self, other: &Rhs) -> ControlFlow; -} - -impl, U> SpecChainingPartialOrd for T { - #[inline] - default fn spec_chain_lt(&self, other: &U) -> ControlFlow { - match PartialOrd::partial_cmp(self, other) { - Some(Equal) => Continue(()), - c => Break(c.is_some_and(Ordering::is_lt)), - } - } - #[inline] - default fn spec_chain_le(&self, other: &U) -> ControlFlow { - match PartialOrd::partial_cmp(self, other) { - Some(Equal) => Continue(()), - c => Break(c.is_some_and(Ordering::is_le)), - } - } - #[inline] - default fn spec_chain_gt(&self, other: &U) -> ControlFlow { - match PartialOrd::partial_cmp(self, other) { - Some(Equal) => Continue(()), - c => Break(c.is_some_and(Ordering::is_gt)), - } - } - #[inline] - default fn spec_chain_ge(&self, other: &U) -> ControlFlow { - match PartialOrd::partial_cmp(self, other) { - Some(Equal) => Continue(()), - c => Break(c.is_some_and(Ordering::is_ge)), - } - } -} - /// Compares and returns the minimum of two values. /// /// Returns the first argument if the comparison determines them to be equal. @@ -1829,32 +1842,31 @@ mod impls { eq_impl! { () bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - macro_rules! chaining_impl { + macro_rules! chaining_methods_impl { ($t:ty) => { // These implementations are the same for `Ord` or `PartialOrd` types // because if either is NAN the `==` test will fail so we end up in // the `Break` case and the comparison will correctly return `false`. - impl super::SpecChainingPartialOrd<$t> for $t { - #[inline] - fn spec_chain_lt(&self, other: &Self) -> ControlFlow { - let (lhs, rhs) = (*self, *other); - if lhs == rhs { Continue(()) } else { Break(lhs < rhs) } - } - #[inline] - fn spec_chain_le(&self, other: &Self) -> ControlFlow { - let (lhs, rhs) = (*self, *other); - if lhs == rhs { Continue(()) } else { Break(lhs <= rhs) } - } - #[inline] - fn spec_chain_gt(&self, other: &Self) -> ControlFlow { - let (lhs, rhs) = (*self, *other); - if lhs == rhs { Continue(()) } else { Break(lhs > rhs) } - } - #[inline] - fn spec_chain_ge(&self, other: &Self) -> ControlFlow { - let (lhs, rhs) = (*self, *other); - if lhs == rhs { Continue(()) } else { Break(lhs >= rhs) } - } + + #[inline] + fn __chaining_lt(&self, other: &Self) -> ControlFlow { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs < rhs) } + } + #[inline] + fn __chaining_le(&self, other: &Self) -> ControlFlow { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs <= rhs) } + } + #[inline] + fn __chaining_gt(&self, other: &Self) -> ControlFlow { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs > rhs) } + } + #[inline] + fn __chaining_ge(&self, other: &Self) -> ControlFlow { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs >= rhs) } } }; } @@ -1880,9 +1892,9 @@ mod impls { fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } #[inline(always)] fn gt(&self, other: &$t) -> bool { (*self) > (*other) } - } - chaining_impl!($t); + chaining_methods_impl!($t); + } )*) } @@ -1920,9 +1932,9 @@ mod impls { fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } #[inline(always)] fn gt(&self, other: &$t) -> bool { (*self) > (*other) } - } - chaining_impl!($t); + chaining_methods_impl!($t); + } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for $t { diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 75faaa06ee7f..d754bb903430 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,7 +1,6 @@ // See core/src/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; -use crate::cmp::SpecChainingPartialOrd; use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; use crate::ops::ControlFlow::{Break, Continue}; @@ -82,19 +81,19 @@ macro_rules! tuple_impls { } #[inline] fn lt(&self, other: &($($T,)+)) -> bool { - lexical_ord!(lt, spec_chain_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(lt, __chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn le(&self, other: &($($T,)+)) -> bool { - lexical_ord!(le, spec_chain_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(le, __chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn ge(&self, other: &($($T,)+)) -> bool { - lexical_ord!(ge, spec_chain_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(ge, __chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn gt(&self, other: &($($T,)+)) -> bool { - lexical_ord!(gt, spec_chain_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(gt, __chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } } } @@ -173,11 +172,11 @@ macro_rules! maybe_tuple_doc { // `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1, // a2, b2, a3, b3)` (and similarly for `lexical_cmp`) // -// `$chain_rel` is the method from `SpecChainingPartialOrd` to use for all but the +// `$chain_rel` is the chaining method from `PartialOrd` to use for all but the // final value, to produce better results for simple primitives. macro_rules! lexical_ord { ($rel: ident, $chain_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{ - match SpecChainingPartialOrd::$chain_rel(&$a, &$b) { + match PartialOrd::$chain_rel(&$a, &$b) { Break(val) => val, Continue(()) => lexical_ord!($rel, $chain_rel, $($rest_a, $rest_b),+), } diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir index 6531683b6445..dd2eebc8f4a1 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir @@ -10,7 +10,7 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool { let _8: bool; scope 3 { } - scope 4 (inlined std::cmp::impls:: for f32>::spec_chain_ge) { + scope 4 (inlined std::cmp::impls::::__chaining_ge) { let mut _3: f32; let mut _4: f32; let mut _5: bool; diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir index d252052f0aef..ea1d164cefaf 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir @@ -10,7 +10,7 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool { let _8: bool; scope 3 { } - scope 4 (inlined std::cmp::impls:: for u16>::spec_chain_le) { + scope 4 (inlined std::cmp::impls::::__chaining_le) { let mut _3: u16; let mut _4: u16; let mut _5: bool; From f390dd7911561f4d377a51c7ef2f423d0e484ea0 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Mon, 24 Mar 2025 01:02:07 +0100 Subject: [PATCH 244/546] Add do_not_recommend typo help --- compiler/rustc_resolve/src/macros.rs | 14 +++++++------- tests/ui/diagnostic_namespace/suggest_typos.rs | 5 +++++ tests/ui/diagnostic_namespace/suggest_typos.stderr | 14 +++++++++++++- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c4304a7a6df6..34441d313f59 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -28,7 +28,7 @@ use rustc_session::lint::builtin::{ UNUSED_MACRO_RULES, UNUSED_MACROS, }; use rustc_session::parse::feature_err; -use rustc_span::edit_distance::edit_distance; +use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::{self, AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -652,13 +652,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) && let [namespace, attribute, ..] = &*path.segments && namespace.ident.name == sym::diagnostic - && !(attribute.ident.name == sym::on_unimplemented - || attribute.ident.name == sym::do_not_recommend) + && ![sym::on_unimplemented, sym::do_not_recommend].contains(&attribute.ident.name) { - let distance = - edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5); - - let typo_name = distance.map(|_| sym::on_unimplemented); + let typo_name = find_best_match_for_name( + &[sym::on_unimplemented, sym::do_not_recommend], + attribute.ident.name, + Some(5), + ); self.tcx.sess.psess.buffer_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, diff --git a/tests/ui/diagnostic_namespace/suggest_typos.rs b/tests/ui/diagnostic_namespace/suggest_typos.rs index 6fa4f800462f..8d1dc6f59da9 100644 --- a/tests/ui/diagnostic_namespace/suggest_typos.rs +++ b/tests/ui/diagnostic_namespace/suggest_typos.rs @@ -16,4 +16,9 @@ trait Y{} //~^^HELP an attribute with a similar name exists trait Z{} +#[diagnostic::dont_recommend] +//~^ERROR unknown diagnostic attribute +//~^^HELP an attribute with a similar name exists +impl X for u8 {} + fn main(){} diff --git a/tests/ui/diagnostic_namespace/suggest_typos.stderr b/tests/ui/diagnostic_namespace/suggest_typos.stderr index 86d778c6ec05..1f19fd4bbcf5 100644 --- a/tests/ui/diagnostic_namespace/suggest_typos.stderr +++ b/tests/ui/diagnostic_namespace/suggest_typos.stderr @@ -37,5 +37,17 @@ help: an attribute with a similar name exists LL | #[diagnostic::on_unimplemented] | ++ -error: aborting due to 3 previous errors +error: unknown diagnostic attribute + --> $DIR/suggest_typos.rs:19:15 + | +LL | #[diagnostic::dont_recommend] + | ^^^^^^^^^^^^^^ + | +help: an attribute with a similar name exists + | +LL - #[diagnostic::dont_recommend] +LL + #[diagnostic::do_not_recommend] + | + +error: aborting due to 4 previous errors From 95181ae170e6961bf541c01dee8320f026e85d0a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 20 Mar 2025 02:12:40 +0000 Subject: [PATCH 245/546] Update `compiler-builtins` to 0.1.152 Includes the following changes related to unordered atomics: * Remove element_unordered_atomic intrinsics [1] * Remove use of `atomic_load_unordered` and undefined behaviour [2] There are a handful of other small changes, but nothing else user-visible. [1]: https://github.com/rust-lang/compiler-builtins/pull/789 [2]: https://github.com/rust-lang/compiler-builtins/pull/790 --- ...029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 4 ++-- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index 754025ff49db..34249ea48345 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644 [dependencies] core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } +-compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std', 'no-f16-f128'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/Cargo.lock b/library/Cargo.lock index 104e0a3d0107..6b1a0a080551 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.151" +version = "0.1.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abc30f1766d387c35f2405e586d3e7a88230dc728ff78cd1d0bc59ae0b63154b" +checksum = "2153cf213eb259361567720ce55f6446f17acd0ccca87fb6dc05360578228a58" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 8d0253bd29aa..b729d5e116d2 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 9d9601b79a7e..176da603d58d 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.151" } +compiler_builtins = { version = "=0.1.152" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From 0b2acddf01b58ef4825b5ca68f39d9f2ac86072b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 20 Mar 2025 02:12:40 +0000 Subject: [PATCH 246/546] Update `compiler-builtins` to 0.1.152 Includes the following changes related to unordered atomics: * Remove element_unordered_atomic intrinsics [1] * Remove use of `atomic_load_unordered` and undefined behaviour [2] There are a handful of other small changes, but nothing else user-visible. [1]: https://github.com/rust-lang/compiler-builtins/pull/789 [2]: https://github.com/rust-lang/compiler-builtins/pull/790 --- ...029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index 754025ff49db..34249ea48345 100644 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644 [dependencies] core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } +-compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std', 'no-f16-f128'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] From fbcf7657055a5a562fa7cc176e4bafec9e99c661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 24 Mar 2025 02:02:10 +0100 Subject: [PATCH 247/546] Revert "resume one waiter at a call" This reverts commit cc1e4ede9388d87750c3751f41e8c6c4f6cae995. --- compiler/rustc_query_system/src/query/job.rs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 37b305d0a8b5..a8c2aa98cd08 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -477,8 +477,8 @@ fn remove_cycle( /// Detects query cycles by using depth first search over all active query jobs. /// If a query cycle is found it will break the cycle by finding an edge which /// uses a query latch and then resuming that waiter. -/// There may be multiple cycles involved in a deadlock, but we only search -/// one cycle at a call and resume one waiter at once. See `FIXME` below. +/// There may be multiple cycles involved in a deadlock, so this searches +/// all active queries for cycles before finally resuming all the waiters at once. pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) { let mut wakelist = Vec::new(); let mut jobs: Vec = query_map.keys().cloned().collect(); @@ -488,19 +488,6 @@ pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) while jobs.len() > 0 { if remove_cycle(&query_map, &mut jobs, &mut wakelist) { found_cycle = true; - - // FIXME(#137731): Resume all the waiters at once may cause deadlocks, - // so we resume one waiter at a call for now. It's still unclear whether - // it's due to possible issues in rustc-rayon or instead in the handling - // of query cycles. - // This seem to only appear when multiple query cycles errors - // are involved, so this reduction in parallelism, while suboptimal, is not - // universal and only the deadlock handler will encounter these cases. - // The workaround shows loss of potential gains, but there still are big - // improvements in the common case, and no regressions compared to the - // single-threaded case. More investigation is still needed, and once fixed, - // we can wake up all the waiters up. - break; } } From 14786ce645ef96c732f8b30154bc939ee4ba9faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 24 Mar 2025 02:09:14 +0100 Subject: [PATCH 248/546] Batch mark waiters as unblocked when resuming in the deadlock handler --- compiler/rustc_query_system/src/query/job.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index a8c2aa98cd08..e6ab7c4ef574 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -506,9 +506,15 @@ pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) ); } - // FIXME: Ensure this won't cause a deadlock before we return + // Mark all the thread we're about to wake up as unblocked. This needs to be done before + // we wake the threads up as otherwise Rayon could detect a deadlock if a thread we + // resumed fell asleep and this thread had yet to mark the remaining threads as unblocked. + for _ in 0..wakelist.len() { + rayon_core::mark_unblocked(registry); + } + for waiter in wakelist.into_iter() { - waiter.notify(registry); + waiter.condvar.notify_one(); } } From b672659472e792198390d94f926be61f894547b6 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sun, 23 Mar 2025 19:32:20 -0700 Subject: [PATCH 249/546] Trusty: Fix build for anonymous pipes and std::sys::process PRs #136842 (Add libstd support for Trusty targets), #137793 (Stablize anonymous pipe), and #136929 (std: move process implementations to `sys`) merged around the same time, so update Trusty to take them into account. --- library/std/src/os/fd/owned.rs | 9 +++++++-- library/std/src/os/fd/raw.rs | 9 +++++++-- library/std/src/sys/pal/trusty/mod.rs | 2 -- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 2dcbfc966189..be73e7dee9c7 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -15,9 +15,8 @@ use crate::mem::ManuallyDrop; target_os = "trusty" )))] use crate::sys::cvt; -use crate::sys_common::FromInner; #[cfg(not(target_os = "trusty"))] -use crate::sys_common::{AsInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, io}; type ValidRawFd = core::num::niche_types::NotAllOnes; @@ -507,6 +506,7 @@ impl<'a> AsFd for io::StderrLock<'a> { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeReader { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() @@ -514,6 +514,7 @@ impl AsFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl From for OwnedFd { fn from(pipe: io::PipeReader) -> Self { pipe.0.into_inner() @@ -521,6 +522,7 @@ impl From for OwnedFd { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeWriter { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() @@ -528,6 +530,7 @@ impl AsFd for io::PipeWriter { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl From for OwnedFd { fn from(pipe: io::PipeWriter) -> Self { pipe.0.into_inner() @@ -535,6 +538,7 @@ impl From for OwnedFd { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl From for io::PipeReader { fn from(owned_fd: OwnedFd) -> Self { Self(FromInner::from_inner(owned_fd)) @@ -542,6 +546,7 @@ impl From for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl From for io::PipeWriter { fn from(owned_fd: OwnedFd) -> Self { Self(FromInner::from_inner(owned_fd)) diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 596b21a52044..c800c1489ad2 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -18,9 +18,8 @@ use crate::os::unix::io::AsFd; use crate::os::unix::io::OwnedFd; #[cfg(target_os = "wasi")] use crate::os::wasi::io::OwnedFd; -use crate::sys_common::FromInner; #[cfg(not(target_os = "trusty"))] -use crate::sys_common::{AsInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -287,6 +286,7 @@ impl AsRawFd for Box { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeReader { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() @@ -294,6 +294,7 @@ impl AsRawFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeReader { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) }) @@ -301,6 +302,7 @@ impl FromRawFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeReader { fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() @@ -308,6 +310,7 @@ impl IntoRawFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeWriter { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() @@ -315,6 +318,7 @@ impl AsRawFd for io::PipeWriter { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeWriter { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) }) @@ -322,6 +326,7 @@ impl FromRawFd for io::PipeWriter { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeWriter { fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index 7034b643d8e8..5295d3fdc914 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -11,8 +11,6 @@ pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; #[path = "../unsupported/thread.rs"] pub mod thread; #[path = "../unsupported/time.rs"] From 38c39ffc6c6e19867f450c7204f341aeb0c495ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 24 Mar 2025 03:53:19 +0100 Subject: [PATCH 250/546] Remove `QueryWaiter::notify` --- compiler/rustc_query_system/src/query/job.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index e6ab7c4ef574..5ed8fb5393fe 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -163,13 +163,6 @@ struct QueryWaiter { cycle: Mutex>, } -impl QueryWaiter { - fn notify(&self, registry: &rayon_core::Registry) { - rayon_core::mark_unblocked(registry); - self.condvar.notify_one(); - } -} - #[derive(Debug)] struct QueryLatchInfo { complete: bool, @@ -232,7 +225,8 @@ impl QueryLatch { info.complete = true; let registry = rayon_core::Registry::current(); for waiter in info.waiters.drain(..) { - waiter.notify(®istry); + rayon_core::mark_unblocked(®istry); + waiter.condvar.notify_one(); } } From 0cd1d516aee85608a695d0376cdef059cc50e00a Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 18 Mar 2025 18:09:22 +0530 Subject: [PATCH 251/546] std: fs: uefi: Implement canonicalize - Should be same as absolute in UEFI since there are no symlinks. - Also each absolute path representation should be unique according to the UEFI specification. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 54acd4c27b33..f7c33b7c40f0 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -315,8 +315,8 @@ pub fn lstat(_p: &Path) -> io::Result { unsupported() } -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() +pub fn canonicalize(p: &Path) -> io::Result { + crate::path::absolute(p) } pub fn copy(_from: &Path, _to: &Path) -> io::Result { From fc0cf52e28cdbc5de45b650797365c91d0c8de76 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 18 Mar 2025 18:11:18 +0530 Subject: [PATCH 252/546] std: fs: uefi: Make lstat call stat - UEFI does not have symlinks. So lstat and stat should behave the same. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index f7c33b7c40f0..e1d61aaa309e 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -311,8 +311,8 @@ pub fn stat(_p: &Path) -> io::Result { unsupported() } -pub fn lstat(_p: &Path) -> io::Result { - unsupported() +pub fn lstat(p: &Path) -> io::Result { + stat(p) } pub fn canonicalize(p: &Path) -> io::Result { From 021d23b64ee58b6d4d7f8803729182ad02a567c2 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 18 Mar 2025 18:26:00 +0530 Subject: [PATCH 253/546] std: fs: uefi: Implement OpenOptions UEFI does not have specific modes for create_new, truncate and append. So those need to to be simulated after opening the file. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 66 +++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index e1d61aaa309e..d6ae86bd3d26 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -1,3 +1,5 @@ +use r_efi::protocols::file; + use crate::ffi::OsString; use crate::fmt; use crate::hash::Hash; @@ -22,7 +24,12 @@ pub struct ReadDir(!); pub struct DirEntry(!); #[derive(Clone, Debug)] -pub struct OpenOptions {} +pub struct OpenOptions { + mode: u64, + append: bool, + truncate: bool, + create_new: bool, +} #[derive(Copy, Clone, Debug, Default)] pub struct FileTimes {} @@ -141,15 +148,58 @@ impl DirEntry { impl OpenOptions { pub fn new() -> OpenOptions { - OpenOptions {} + OpenOptions { mode: 0, append: false, create_new: false, truncate: false } } - pub fn read(&mut self, _read: bool) {} - pub fn write(&mut self, _write: bool) {} - pub fn append(&mut self, _append: bool) {} - pub fn truncate(&mut self, _truncate: bool) {} - pub fn create(&mut self, _create: bool) {} - pub fn create_new(&mut self, _create_new: bool) {} + pub fn read(&mut self, read: bool) { + if read { + self.mode |= file::MODE_READ; + } else { + self.mode &= !file::MODE_READ; + } + } + + pub fn write(&mut self, write: bool) { + if write { + // Valid Combinations: Read, Read/Write, Read/Write/Create + self.read(true); + self.mode |= file::MODE_WRITE; + } else { + self.mode &= !file::MODE_WRITE; + } + } + + pub fn append(&mut self, append: bool) { + // Docs state that `.write(true).append(true)` has the same effect as `.append(true)` + if append { + self.write(true); + } + self.append = append; + } + + pub fn truncate(&mut self, truncate: bool) { + self.truncate = truncate; + } + + pub fn create(&mut self, create: bool) { + if create { + self.mode |= file::MODE_CREATE; + } else { + self.mode &= !file::MODE_CREATE; + } + } + + pub fn create_new(&mut self, create_new: bool) { + self.create_new = create_new; + } + + #[expect(dead_code)] + const fn is_mode_valid(&self) -> bool { + // Valid Combinations: Read, Read/Write, Read/Write/Create + self.mode == file::MODE_READ + || self.mode == (file::MODE_READ | file::MODE_WRITE) + || self.mode == (file::MODE_READ | file::MODE_WRITE | file::MODE_CREATE) + } } impl File { From c71569a765fdd9364ea215ae01442a026e127ab9 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 24 Mar 2025 14:09:06 +0800 Subject: [PATCH 254/546] Revert "Rollup merge of #137593 - RalfJung:subtree-sync-download-llvm, r=Mark-Simulacrum" Looks like unfortunately the `--diff-merges` flag is a `git show`-only command, not `git rev-list`. This reverts commit 95994f94ff5c9335426af4dec19afb5024f82fab, reversing changes made to 7290b04b0a46de2118968aa556bfc0970aac6661. --- src/build_helper/src/git.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index f47d5663fc94..693e0fc8f46d 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -140,7 +140,6 @@ pub fn get_closest_merge_commit( // cd \"/checkout\" && \"git\" \"merge-base\" \"origin/master\" \"HEAD\"\nexpected success, got: exit status: 1\n" // ``` // Investigate and resolve this issue instead of skipping it like this. - // NOTE (2025-03): this is probably caused by CI using a sparse checkout. (channel == "nightly" || !CiEnv::is_rust_lang_managed_ci_job()) { git_upstream_merge_base(config, git_dir).unwrap() @@ -151,18 +150,11 @@ pub fn get_closest_merge_commit( } }; - // Now that rust-lang/rust is the only repo using bors, we can search the entire - // history for a bors commit, not just "first parents". This is crucial to make - // this logic work when the user has currently checked out a subtree sync branch. - // At the same time, we use this logic in CI where only a tiny part of the history - // is even checked out, making this kind of history search very fragile. It turns - // out that by adding `--diff-merges=first-parent`, we get a usable reply - // even for sparse checkouts: it will just return the most recent bors commit. git.args([ "rev-list", &format!("--author={}", config.git_merge_commit_email), "-n1", - "--diff-merges=first-parent", + "--first-parent", &merge_base, ]); From 9dd5340d3cbbd3acbe6cc9dfcbcea07e7eb4355e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:14:32 +1100 Subject: [PATCH 255/546] Remove `is_any_keyword` methods. They're dodgy, covering all the keywords, including weak ones, and edition-specific ones without considering the edition. They have a single use in rustfmt. This commit changes that use to `is_reserved_ident`, which is a much more widely used alternative and is good enough, judging by the lack of effect on the test suite. --- compiler/rustc_ast/src/token.rs | 5 ----- compiler/rustc_span/src/symbol.rs | 24 +++++++---------------- src/tools/rustfmt/src/parse/macros/mod.rs | 2 +- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index f7cd63aaaf82..6e6f0f1b2660 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -928,11 +928,6 @@ impl Token { self.is_non_raw_ident_where(Ident::is_path_segment_keyword) } - /// Don't use this unless you're doing something very loose and heuristic-y. - pub fn is_any_keyword(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_any_keyword) - } - /// Returns true for reserved identifiers used internally for elided lifetimes, /// unnamed method parameters, crate root module, error recovery etc. pub fn is_special_ident(&self) -> bool { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 210966bed627..5f81d36a74e7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -32,7 +32,7 @@ symbols! { Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. - // Matching predicates: `is_any_keyword`, `is_special`/`is_reserved` + // Matching predicates: `is_special`/`is_reserved` // // Notes about `kw::Empty`: // - Its use can blur the lines between "empty symbol" and "no symbol". @@ -48,7 +48,7 @@ symbols! { Underscore: "_", // Keywords that are used in stable Rust. - // Matching predicates: `is_any_keyword`, `is_used_keyword_always`/`is_reserved` + // Matching predicates: `is_used_keyword_always`/`is_reserved` As: "as", Break: "break", Const: "const", @@ -86,7 +86,7 @@ symbols! { While: "while", // Keywords that are used in unstable Rust or reserved for future use. - // Matching predicates: `is_any_keyword`, `is_unused_keyword_always`/`is_reserved` + // Matching predicates: `is_unused_keyword_always`/`is_reserved` Abstract: "abstract", Become: "become", Box: "box", @@ -101,14 +101,14 @@ symbols! { Yield: "yield", // Edition-specific keywords that are used in stable Rust. - // Matching predicates: `is_any_keyword`, `is_used_keyword_conditional`/`is_reserved` (if + // Matching predicates: `is_used_keyword_conditional`/`is_reserved` (if // the edition suffices) Async: "async", // >= 2018 Edition only Await: "await", // >= 2018 Edition only Dyn: "dyn", // >= 2018 Edition only // Edition-specific keywords that are used in unstable Rust or reserved for future use. - // Matching predicates: `is_any_keyword`, `is_unused_keyword_conditional`/`is_reserved` (if + // Matching predicates: `is_unused_keyword_conditional`/`is_reserved` (if // the edition suffices) Gen: "gen", // >= 2024 Edition only Try: "try", // >= 2018 Edition only @@ -116,12 +116,12 @@ symbols! { // NOTE: When adding new keywords, consider adding them to the ui/parser/raw/raw-idents.rs test. // "Lifetime keywords": regular keywords with a leading `'`. - // Matching predicates: `is_any_keyword` + // Matching predicates: none UnderscoreLifetime: "'_", StaticLifetime: "'static", // Weak keywords, have special meaning only in specific contexts. - // Matching predicates: `is_any_keyword` + // Matching predicates: none Auto: "auto", Builtin: "builtin", Catch: "catch", @@ -2677,11 +2677,6 @@ pub mod sym { } impl Symbol { - /// Don't use this unless you're doing something very loose and heuristic-y. - pub fn is_any_keyword(self) -> bool { - self >= kw::As && self <= kw::Yeet - } - fn is_special(self) -> bool { self <= kw::Underscore } @@ -2738,11 +2733,6 @@ impl Symbol { } impl Ident { - /// Don't use this unless you're doing something very loose and heuristic-y. - pub fn is_any_keyword(self) -> bool { - self.name.is_any_keyword() - } - /// Returns `true` for reserved identifiers used internally for elided lifetimes, /// unnamed method parameters, crate root module, error recovery etc. pub fn is_special(self) -> bool { diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 680a35f7e03a..d7964484b261 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -81,7 +81,7 @@ pub(crate) struct ParsedMacroArgs { } fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { - if parser.token.is_any_keyword() + if parser.token.is_reserved_ident() && parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma) { let keyword = parser.token.ident().unwrap().0.name; From a28d5092e9da9973fd56a4de5e85a632400c85f0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:18:20 +1100 Subject: [PATCH 256/546] Improve keyword comments a little. --- compiler/rustc_span/src/symbol.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5f81d36a74e7..11f271af0b73 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -26,9 +26,10 @@ symbols! { // documents (such as the Rust Reference) about whether it is a keyword // (e.g. `_`). // - // If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` predicates and - // `used_keywords`. - // But this should rarely be necessary if the keywords are kept in alphabetic order. + // If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` + // predicates and `used_keywords`. (This should rarely be necessary if + // the keywords are kept in alphabetic order.) Also consider adding new + // keywords to the `ui/parser/raw/raw-idents.rs` test. Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. @@ -113,8 +114,6 @@ symbols! { Gen: "gen", // >= 2024 Edition only Try: "try", // >= 2018 Edition only - // NOTE: When adding new keywords, consider adding them to the ui/parser/raw/raw-idents.rs test. - // "Lifetime keywords": regular keywords with a leading `'`. // Matching predicates: none UnderscoreLifetime: "'_", From 3aaa12f622f294fd0d5f86a31415eb1fb4669bdd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:18:40 +1100 Subject: [PATCH 257/546] Fix some formatting. --- compiler/rustc_span/src/symbol.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 11f271af0b73..394774b57646 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -128,8 +128,8 @@ symbols! { MacroRules: "macro_rules", Raw: "raw", Reuse: "reuse", - ContractEnsures: "contract_ensures", - ContractRequires: "contract_requires", + ContractEnsures: "contract_ensures", + ContractRequires: "contract_requires", Safe: "safe", Union: "union", Yeet: "yeet", From 10236fbe7bea988dd94509e437c63b855fd1ec00 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:26:24 +1100 Subject: [PATCH 258/546] Alphabetize the keywords list. --- compiler/rustc_span/src/symbol.rs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 394774b57646..33ffa00a3691 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -27,9 +27,8 @@ symbols! { // (e.g. `_`). // // If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` - // predicates and `used_keywords`. (This should rarely be necessary if - // the keywords are kept in alphabetic order.) Also consider adding new - // keywords to the `ui/parser/raw/raw-idents.rs` test. + // predicates and `used_keywords`. Also consider adding new keywords to the + // `ui/parser/raw/raw-idents.rs` test. Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. @@ -43,13 +42,16 @@ symbols! { // present, it's better to use `sym::dummy` than `kw::Empty`, because // it's clearer that it's intended as a dummy value, and more likely // to be detected if it accidentally does get used. + // tidy-alphabetical-start + DollarCrate: "$crate", Empty: "", PathRoot: "{{root}}", - DollarCrate: "$crate", Underscore: "_", + // tidy-alphabetical-end // Keywords that are used in stable Rust. // Matching predicates: `is_used_keyword_always`/`is_reserved` + // tidy-alphabetical-start As: "as", Break: "break", Const: "const", @@ -85,9 +87,11 @@ symbols! { Use: "use", Where: "where", While: "while", + // tidy-alphabetical-end // Keywords that are used in unstable Rust or reserved for future use. // Matching predicates: `is_unused_keyword_always`/`is_reserved` + // tidy-alphabetical-start Abstract: "abstract", Become: "become", Box: "box", @@ -100,39 +104,48 @@ symbols! { Unsized: "unsized", Virtual: "virtual", Yield: "yield", + // tidy-alphabetical-end // Edition-specific keywords that are used in stable Rust. // Matching predicates: `is_used_keyword_conditional`/`is_reserved` (if // the edition suffices) + // tidy-alphabetical-start Async: "async", // >= 2018 Edition only Await: "await", // >= 2018 Edition only Dyn: "dyn", // >= 2018 Edition only + // tidy-alphabetical-end // Edition-specific keywords that are used in unstable Rust or reserved for future use. // Matching predicates: `is_unused_keyword_conditional`/`is_reserved` (if // the edition suffices) + // tidy-alphabetical-start Gen: "gen", // >= 2024 Edition only Try: "try", // >= 2018 Edition only + // tidy-alphabetical-end // "Lifetime keywords": regular keywords with a leading `'`. // Matching predicates: none - UnderscoreLifetime: "'_", + // tidy-alphabetical-start StaticLifetime: "'static", + UnderscoreLifetime: "'_", + // tidy-alphabetical-end // Weak keywords, have special meaning only in specific contexts. // Matching predicates: none + // tidy-alphabetical-start Auto: "auto", Builtin: "builtin", Catch: "catch", + ContractEnsures: "contract_ensures", + ContractRequires: "contract_requires", Default: "default", MacroRules: "macro_rules", Raw: "raw", Reuse: "reuse", - ContractEnsures: "contract_ensures", - ContractRequires: "contract_requires", Safe: "safe", Union: "union", Yeet: "yeet", + // tidy-alphabetical-end } // Pre-interned symbols that can be referred to with `rustc_span::sym::*`. @@ -2781,7 +2794,7 @@ impl Ident { /// *Note:* Please update this if a new keyword is added beyond the current /// range. pub fn used_keywords(edition: impl Copy + FnOnce() -> Edition) -> Vec { - (kw::Empty.as_u32()..kw::Yeet.as_u32()) + (kw::DollarCrate.as_u32()..kw::Yeet.as_u32()) .filter_map(|kw| { let kw = Symbol::new(kw); if kw.is_used_keyword_always() || kw.is_used_keyword_conditional(edition) { From a29e875b63542b1809ae6beb6fabbdacbb16971f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:28:15 +1100 Subject: [PATCH 259/546] Move `is_used_keyword_conditional`. So the order of the `Symbol::is_*` predicates match the order of the keywords list. --- compiler/rustc_span/src/symbol.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 33ffa00a3691..3e4742439655 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2697,14 +2697,14 @@ impl Symbol { self >= kw::As && self <= kw::While } - fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { - (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018 - } - fn is_unused_keyword_always(self) -> bool { self >= kw::Abstract && self <= kw::Yield } + fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { + (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018 + } + fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool { self == kw::Gen && edition().at_least_rust_2024() || self == kw::Try && edition().at_least_rust_2018() From 2d3115f61f40b43855bbf252cfb1f4d480c1ccc9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 24 Mar 2025 09:39:02 +0000 Subject: [PATCH 260/546] `with_scope` is only ever used for ast modules --- compiler/rustc_resolve/src/late.rs | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6056a69ee71f..e04d0083548b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1544,20 +1544,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ret } - fn with_scope(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) { - // Move down in the graph. - let orig_module = replace(&mut self.parent_scope.module, module); - self.with_rib(ValueNS, RibKind::Module(module), |this| { - this.with_rib(TypeNS, RibKind::Module(module), |this| { - let ret = f(this); - this.parent_scope.module = orig_module; - ret - }) + fn with_mod_rib(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + let module = self.r.expect_module(self.r.local_def_id(id).to_def_id()); + // Move down in the graph. + let orig_module = replace(&mut self.parent_scope.module, module); + self.with_rib(ValueNS, RibKind::Module(module), |this| { + this.with_rib(TypeNS, RibKind::Module(module), |this| { + let ret = f(this); + this.parent_scope.module = orig_module; + ret }) - } else { - f(self) - } + }) } fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) { @@ -2738,7 +2735,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ItemKind::Mod(..) => { - self.with_scope(item.id, |this| { + self.with_mod_rib(item.id, |this| { if mod_inner_docs { this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); } From d9f250af21dbadcde2113a961132a263392bf091 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 20 Mar 2025 18:23:07 +0100 Subject: [PATCH 261/546] Remove duplicated loop when computing doc cfgs --- src/librustdoc/clean/types.rs | 59 +++++++++++++---------------------- 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5f80aded9d0b..27eb56a9858b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1013,7 +1013,6 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet, ) -> Option> { - let sess = tcx.sess; let doc_cfg_active = tcx.features().doc_cfg(); let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); @@ -1034,9 +1033,27 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator .filter(|attr| attr.has_name(sym::cfg)) .peekable(); if doc_cfg.peek().is_some() && doc_cfg_active { - doc_cfg - .filter_map(|attr| Cfg::parse(&attr).ok()) - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + let sess = tcx.sess; + doc_cfg.fold(Cfg::True, |mut cfg, item| { + if let Some(cfg_mi) = + item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess)) + { + // The result is unused here but we can gate unstable predicates + rustc_attr_parsing::cfg_matches( + cfg_mi, + tcx.sess, + rustc_ast::CRATE_NODE_ID, + Some(tcx.features()), + ); + match Cfg::parse(cfg_mi) { + Ok(new_cfg) => cfg &= new_cfg, + Err(e) => { + sess.dcx().span_err(e.span, e.msg); + } + } + } + cfg + }) } else if doc_auto_cfg_active { // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because // `doc(cfg())` overrides `cfg()`). @@ -1053,40 +1070,6 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator Cfg::True }; - for attr in attrs.clone() { - // #[doc] - if attr.doc_str().is_none() && attr.has_name(sym::doc) { - // #[doc(...)] - if let Some(list) = attr.meta_item_list() { - for item in list { - // #[doc(hidden)] - if !item.has_name(sym::cfg) { - continue; - } - // #[doc(cfg(...))] - if let Some(cfg_mi) = item - .meta_item() - .and_then(|item| rustc_expand::config::parse_cfg(item, sess)) - { - // The result is unused here but we can gate unstable predicates - rustc_attr_parsing::cfg_matches( - cfg_mi, - tcx.sess, - rustc_ast::CRATE_NODE_ID, - Some(tcx.features()), - ); - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg &= new_cfg, - Err(e) => { - sess.dcx().span_err(e.span, e.msg); - } - } - } - } - } - } - } - // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well for attr in hir_attr_lists(attrs, sym::target_feature) { From f5659f28f8a426d16c2c6f7b0ab7461958b4f0a6 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 24 Mar 2025 11:33:56 +0100 Subject: [PATCH 262/546] ignore tests broken while cross compiling --- tests/run-make/doctests-keep-binaries/rmake.rs | 2 ++ tests/run-make/target-cpu-native/rmake.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/run-make/doctests-keep-binaries/rmake.rs b/tests/run-make/doctests-keep-binaries/rmake.rs index 246539bcf823..a05223994df4 100644 --- a/tests/run-make/doctests-keep-binaries/rmake.rs +++ b/tests/run-make/doctests-keep-binaries/rmake.rs @@ -1,3 +1,5 @@ +//@ ignore-cross-compile attempts to run the doctests + // Check that valid binaries are persisted by running them, regardless of whether the // --run or --no-run option is used. diff --git a/tests/run-make/target-cpu-native/rmake.rs b/tests/run-make/target-cpu-native/rmake.rs index fd5fb6193fe0..7b7974f30978 100644 --- a/tests/run-make/target-cpu-native/rmake.rs +++ b/tests/run-make/target-cpu-native/rmake.rs @@ -3,6 +3,8 @@ // warnings when used, and that binaries produced by it can also be successfully executed. // See https://github.com/rust-lang/rust/pull/23238 +//@ ignore-cross-compile target-cpu=native doesn't work well when cross compiling + use run_make_support::{run, rustc}; fn main() { From 02e1f118cd5adb995c3801cc7703faaba8910ccc Mon Sep 17 00:00:00 2001 From: Eduard Stefes Date: Mon, 24 Mar 2025 11:54:44 +0100 Subject: [PATCH 263/546] Fix ui pattern_types test for big-endian platforms The newly added pattern types validity tests fail on s390x and presumably other big-endian systems, due to print of raw values with padding bytes. To fix the tests remove the raw output values in the error note by `normalize-stderr`. --- tests/ui/type/pattern_types/validity.rs | 2 ++ tests/ui/type/pattern_types/validity.stderr | 26 ++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs index 5a6a688e1b30..c61bb71ac252 100644 --- a/tests/ui/type/pattern_types/validity.rs +++ b/tests/ui/type/pattern_types/validity.rs @@ -1,4 +1,6 @@ //! Check that pattern types have their validity checked +// Strip out raw byte dumps to make tests platform-independent: +//@ normalize-stderr: "([[:xdigit:]]{2}\s){4,8}\s+│\s.{4,8}" -> "HEX_DUMP" #![feature(pattern_types, const_trait_impl, pattern_type_range_trait)] #![feature(pattern_type_macro)] diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index 5bc18cfba3f7..b990ec2d3682 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -1,22 +1,22 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:8:1 + --> $DIR/validity.rs:10:1 | LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - 00 00 00 00 │ .... + HEX_DUMP } error[E0080]: evaluation of constant value failed - --> $DIR/validity.rs:11:1 + --> $DIR/validity.rs:13:1 | LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory error[E0080]: evaluation of constant value failed - --> $DIR/validity.rs:15:1 + --> $DIR/validity.rs:17:1 | LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer @@ -25,53 +25,53 @@ LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(& = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:18:1 + --> $DIR/validity.rs:20:1 | LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ + HEX_DUMP } error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:24:1 + --> $DIR/validity.rs:26:1 | LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); | ^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - 00 00 00 00 │ .... + HEX_DUMP } error[E0080]: evaluation of constant value failed - --> $DIR/validity.rs:27:1 + --> $DIR/validity.rs:29:1 | LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:31:1 + --> $DIR/validity.rs:33:1 | LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 97, but expected something in the range 65..=89 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - 61 00 00 00 │ a... + HEX_DUMP } error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:34:1 + --> $DIR/validity.rs:36:1 | LL | const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ff ff ff ff │ .... + HEX_DUMP } error: aborting due to 8 previous errors From 856a181570371e1622bcb42ef94fc23090f93a12 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 24 Mar 2025 11:53:09 +0100 Subject: [PATCH 264/546] =?UTF-8?q?Fix=20autofix=20for=20`self`=20and=20`s?= =?UTF-8?q?elf=20as=20=E2=80=A6`=20in=20`unused=5Fimports`=20lint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes two problems with the autofixes for the `unused_imports` lint: - `use std::collections::{HashMap, self as coll};` would suggest, when `HashMap` is unused, the incorrect `use std::collections::self as coll;` which does not compile. - `use std::borrow::{self, Cow};` would suggest, when `self` is unused, `use std::borrow::{Cow};`, which contains unnecessary brackets. --- compiler/rustc_resolve/src/check_unused.rs | 3 +- .../lint-unused-imports-self-single.fixed | 29 ++++++++++++ .../unused/lint-unused-imports-self-single.rs | 30 +++++++++++++ .../lint-unused-imports-self-single.stderr | 44 +++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/unused/lint-unused-imports-self-single.fixed create mode 100644 tests/ui/lint/unused/lint-unused-imports-self-single.rs create mode 100644 tests/ui/lint/unused/lint-unused-imports-self-single.stderr diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 1c1e8494ffc7..51ff4aa834ba 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -337,7 +337,8 @@ fn calc_unused_spans( } } contains_self |= use_tree.prefix == kw::SelfLower - && matches!(use_tree.kind, ast::UseTreeKind::Simple(None)); + && matches!(use_tree.kind, ast::UseTreeKind::Simple(_)) + && !unused_import.unused.contains(&use_tree_id); previous_unused = remove.is_some(); } if unused_spans.is_empty() { diff --git a/tests/ui/lint/unused/lint-unused-imports-self-single.fixed b/tests/ui/lint/unused/lint-unused-imports-self-single.fixed new file mode 100644 index 000000000000..361548bfdc12 --- /dev/null +++ b/tests/ui/lint/unused/lint-unused-imports-self-single.fixed @@ -0,0 +1,29 @@ +//@ run-rustfix + +#![deny(unused_imports)] +#![allow(unreachable_code)] + +use std::collections::{self as coll}; +//~^ ERROR unused import: `HashMap` + +//~^ ERROR unused import: `self as std_io` + +use std::sync::Mutex; +//~^ ERROR unused import: `self as std_sync` + +use std::sync::mpsc::Sender; +//~^ ERROR unused import: `self as std_sync_mpsc` + +use std::collections::hash_map::{self as std_coll_hm}; +//~^ ERROR unused import: `Keys` + +use std::borrow::Cow; +//~^ ERROR unused import: `self` + +fn main() { + let _ = coll::BTreeSet::::default(); + let _ = Mutex::new(String::new()); + let _: Cow<'static, str> = "foo".into(); + let _: Sender = todo!(); + let _: std_coll_hm::Entry<'static, u32, u32> = todo!(); +} diff --git a/tests/ui/lint/unused/lint-unused-imports-self-single.rs b/tests/ui/lint/unused/lint-unused-imports-self-single.rs new file mode 100644 index 000000000000..d03d3822e04e --- /dev/null +++ b/tests/ui/lint/unused/lint-unused-imports-self-single.rs @@ -0,0 +1,30 @@ +//@ run-rustfix + +#![deny(unused_imports)] +#![allow(unreachable_code)] + +use std::collections::{HashMap, self as coll}; +//~^ ERROR unused import: `HashMap` + +use std::io::{self as std_io}; +//~^ ERROR unused import: `self as std_io` + +use std::sync::{Mutex, self as std_sync}; +//~^ ERROR unused import: `self as std_sync` + +use std::sync::{mpsc::{self as std_sync_mpsc, Sender}}; +//~^ ERROR unused import: `self as std_sync_mpsc` + +use std::collections::{hash_map::{self as std_coll_hm, Keys}}; +//~^ ERROR unused import: `Keys` + +use std::borrow::{self, Cow}; +//~^ ERROR unused import: `self` + +fn main() { + let _ = coll::BTreeSet::::default(); + let _ = Mutex::new(String::new()); + let _: Cow<'static, str> = "foo".into(); + let _: Sender = todo!(); + let _: std_coll_hm::Entry<'static, u32, u32> = todo!(); +} diff --git a/tests/ui/lint/unused/lint-unused-imports-self-single.stderr b/tests/ui/lint/unused/lint-unused-imports-self-single.stderr new file mode 100644 index 000000000000..70a9b78a6640 --- /dev/null +++ b/tests/ui/lint/unused/lint-unused-imports-self-single.stderr @@ -0,0 +1,44 @@ +error: unused import: `HashMap` + --> $DIR/lint-unused-imports-self-single.rs:6:24 + | +LL | use std::collections::{HashMap, self as coll}; + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-unused-imports-self-single.rs:3:9 + | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: unused import: `self as std_io` + --> $DIR/lint-unused-imports-self-single.rs:9:15 + | +LL | use std::io::{self as std_io}; + | ^^^^^^^^^^^^^^ + +error: unused import: `self as std_sync` + --> $DIR/lint-unused-imports-self-single.rs:12:24 + | +LL | use std::sync::{Mutex, self as std_sync}; + | ^^^^^^^^^^^^^^^^ + +error: unused import: `self as std_sync_mpsc` + --> $DIR/lint-unused-imports-self-single.rs:15:24 + | +LL | use std::sync::{mpsc::{self as std_sync_mpsc, Sender}}; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unused import: `Keys` + --> $DIR/lint-unused-imports-self-single.rs:18:56 + | +LL | use std::collections::{hash_map::{self as std_coll_hm, Keys}}; + | ^^^^ + +error: unused import: `self` + --> $DIR/lint-unused-imports-self-single.rs:21:19 + | +LL | use std::borrow::{self, Cow}; + | ^^^^ + +error: aborting due to 6 previous errors + From 67e0b899f0db3f20ad29481b16703d81a896e749 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 24 Mar 2025 15:23:25 +0000 Subject: [PATCH 265/546] Add a helper for building an owner id in ast lowering --- compiler/rustc_ast_lowering/src/item.rs | 17 +++++++---------- compiler/rustc_ast_lowering/src/lib.rs | 16 ++++++++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index bd011d59aaa7..83b2001d5c5b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -132,8 +132,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> { - let mut node_ids = - smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }]; + let mut node_ids = smallvec![hir::ItemId { owner_id: self.owner_id(i.id) }]; if let ItemKind::Use(use_tree) = &i.kind { self.lower_item_id_use_tree(use_tree, &mut node_ids); } @@ -144,9 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match &tree.kind { UseTreeKind::Nested { items, .. } => { for &(ref nested, id) in items { - vec.push(hir::ItemId { - owner_id: hir::OwnerId { def_id: self.local_def_id(id) }, - }); + vec.push(hir::ItemId { owner_id: self.owner_id(id) }); self.lower_item_id_use_tree(nested, vec); } } @@ -585,7 +582,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Add all the nested `PathListItem`s to the HIR. for &(ref use_tree, id) in trees { - let new_hir_id = self.local_def_id(id); + let owner_id = self.owner_id(id); // Each `use` import is an item and thus are owners of the // names in the path. Up to this point the nested import is @@ -602,7 +599,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let item = hir::Item { - owner_id: hir::OwnerId { def_id: new_hir_id }, + owner_id, kind, vis_span, span: this.lower_span(use_tree.span), @@ -710,7 +707,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef { hir::ForeignItemRef { - id: hir::ForeignItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, + id: hir::ForeignItemId { owner_id: self.owner_id(i.id) }, ident: self.lower_ident(i.ident), span: self.lower_span(i.span), } @@ -931,7 +928,7 @@ impl<'hir> LoweringContext<'_, 'hir> { panic!("macros should have been expanded by now") } }; - let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }; + let id = hir::TraitItemId { owner_id: self.owner_id(i.id) }; hir::TraitItemRef { id, ident: self.lower_ident(i.ident), @@ -1046,7 +1043,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef { hir::ImplItemRef { - id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, + id: hir::ImplItemId { owner_id: self.owner_id(i.id) }, ident: self.lower_ident(i.ident), span: self.lower_span(i.span), kind: match &i.kind { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e24b45c5b194..32eb5e225ab7 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -536,6 +536,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } + /// Given the id of an owner node in the AST, returns the corresponding `OwnerId`. + fn owner_id(&self, node: NodeId) -> hir::OwnerId { + hir::OwnerId { def_id: self.local_def_id(node) } + } + /// Freshen the `LoweringContext` and ready it to lower a nested item. /// The lowered item is registered into `self.children`. /// @@ -547,7 +552,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>, ) { - let def_id = self.local_def_id(owner); + let owner_id = self.owner_id(owner); let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); @@ -558,8 +563,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[cfg(debug_assertions)] let current_node_id_to_local_id = std::mem::take(&mut self.node_id_to_local_id); let current_trait_map = std::mem::take(&mut self.trait_map); - let current_owner = - std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); + let current_owner = std::mem::replace(&mut self.current_hir_id_owner, owner_id); let current_local_counter = std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs); @@ -577,7 +581,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let item = f(self); - debug_assert_eq!(def_id, item.def_id().def_id); + debug_assert_eq!(owner_id, item.def_id()); // `f` should have consumed all the elements in these vectors when constructing `item`. debug_assert!(self.impl_trait_defs.is_empty()); debug_assert!(self.impl_trait_bounds.is_empty()); @@ -598,8 +602,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.impl_trait_defs = current_impl_trait_defs; self.impl_trait_bounds = current_impl_trait_bounds; - debug_assert!(!self.children.iter().any(|(id, _)| id == &def_id)); - self.children.push((def_id, hir::MaybeOwner::Owner(info))); + debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id)); + self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info))); } fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { From 724a5a430bf14de79d2fe64543a1103fe250a57e Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 24 Mar 2025 19:38:16 +0300 Subject: [PATCH 266/546] bump thorin to drop duped deps --- Cargo.lock | 54 ++++++-------------------- compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- 3 files changed, 13 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 651895714320..01d7e0beea61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,18 +34,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.7.35", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -1425,17 +1413,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "gimli" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" -dependencies = [ - "fallible-iterator", - "indexmap", - "stable_deref_trait", -] - [[package]] name = "gimli" version = "0.31.1" @@ -1475,16 +1452,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - [[package]] name = "hashbrown" version = "0.15.2" @@ -1492,6 +1459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", + "equivalent", "foldhash", "serde", ] @@ -1815,7 +1783,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown", "serde", ] @@ -2470,7 +2438,7 @@ checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.15.2", + "hashbrown", "indexmap", "memchr", "ruzstd", @@ -3413,7 +3381,7 @@ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ "bitflags", - "gimli 0.30.0", + "gimli 0.31.1", "itertools", "libc", "measureme 12.0.1", @@ -3527,7 +3495,7 @@ dependencies = [ "either", "elsa", "ena", - "hashbrown 0.15.2", + "hashbrown", "indexmap", "jobserver", "libc", @@ -4306,7 +4274,7 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ - "hashbrown 0.15.2", + "hashbrown", "parking_lot", "rustc-rayon-core", "rustc_abi", @@ -5241,12 +5209,12 @@ dependencies = [ [[package]] name = "thorin-dwp" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "813ba76597db32dc4f6992fd8bf8f394715b88d352fd97401da67dab6283b4c6" +checksum = "9e9c1e705f82a260173f3eec93f2ff6d7807f23ad5a8cc2e7316a891733ea7a1" dependencies = [ - "gimli 0.30.0", - "hashbrown 0.14.5", + "gimli 0.31.1", + "hashbrown", "object 0.36.7", "tracing", ] @@ -5972,7 +5940,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5a99faceb1a5a84dd6084ec4bfa4b2ab153b5793b43fd8f58b89232634afc35" dependencies = [ "bitflags", - "hashbrown 0.15.2", + "hashbrown", "indexmap", "semver", "serde", diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index ec1fd4b641a2..3185993c2076 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -11,7 +11,7 @@ test = false bitflags = "2.4.1" # To avoid duplicate dependencies, this should match the version of gimli used # by `rustc_codegen_ssa` via its `thorin-dwp` dependency. -gimli = "0.30" +gimli = "0.31" itertools = "0.12" libc = "0.2" measureme = "12.0.1" diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 0a2f1d5bb678..97eebffd1fe8 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -42,7 +42,7 @@ serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tempfile = "3.2" thin-vec = "0.2.12" -thorin-dwp = "0.8" +thorin-dwp = "0.9" tracing = "0.1" wasm-encoder = "0.219" # tidy-alphabetical-end From e06d50cf327aed841de4394b7183aa815bb3ed9e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Mar 2025 16:21:31 +0000 Subject: [PATCH 267/546] Revert "Rollup merge of #136127 - WaffleLapkin:dyn_ptr_unwrap_cast, r=compiler-errors" This reverts commit 84c2050bf63f734246572345aedca9edb2abe96e, reversing changes made to a96fa317d78c78a9de996afd317603c6970efc0d. --- compiler/rustc_hir_typeck/src/coercion.rs | 68 +-------- .../ui/cast/ptr-to-trait-obj-wrap-add-auto.rs | 36 ----- .../ptr-to-trait-obj-wrap-add-auto.stderr | 48 ------ .../ptr-to-trait-obj-wrap-different-args.rs | 36 ----- ...tr-to-trait-obj-wrap-different-args.stderr | 43 ------ ...ptr-to-trait-obj-wrap-different-regions.rs | 41 ----- ...to-trait-obj-wrap-different-regions.stderr | 140 ------------------ tests/ui/cast/ptr-to-trait-obj-wrap.rs | 32 ---- 8 files changed, 8 insertions(+), 436 deletions(-) delete mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs delete mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr delete mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs delete mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr delete mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs delete mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr delete mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap.rs diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 4cbc42b99ea3..f42ca3af2b35 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -41,8 +41,8 @@ use rustc_abi::ExternAbi; use rustc_attr_parsing::InlineAttr; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; +use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, LangItem}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer::relate::RelateResult; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; @@ -55,7 +55,7 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, AliasTy, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -592,63 +592,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Create an obligation for `Source: CoerceUnsized`. let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target }); - let root_obligation = Obligation::new( - self.tcx, - cause.clone(), - self.fcx.param_env, - ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]), - ); - - // If the root `Source: CoerceUnsized` obligation can't possibly hold, - // we don't have to assume that this is unsizing coercion (it will always lead to an error) - // - // However, we don't want to bail early all the time, since the unholdable obligations - // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id`), - // so we only bail if there (likely) is another way to convert the types. - if !self.infcx.predicate_may_hold(&root_obligation) { - if let Some(dyn_metadata_adt_def_id) = self.tcx.lang_items().get(LangItem::DynMetadata) - && let Some(metadata_type_def_id) = self.tcx.lang_items().get(LangItem::Metadata) - { - self.probe(|_| { - let ocx = ObligationCtxt::new(&self.infcx); - - // returns `true` if `::Metadata` is `DynMetadata<_>` - let has_dyn_trait_metadata = |ty| { - let metadata_ty: Result<_, _> = ocx.structurally_normalize_ty( - &ObligationCause::dummy(), - self.fcx.param_env, - Ty::new_alias( - self.tcx, - ty::AliasTyKind::Projection, - AliasTy::new(self.tcx, metadata_type_def_id, [ty]), - ), - ); - - metadata_ty.is_ok_and(|metadata_ty| { - metadata_ty - .ty_adt_def() - .is_some_and(|d| d.did() == dyn_metadata_adt_def_id) - }) - }; - - // If both types are raw pointers to a (wrapper over a) trait object, - // this might be a cast like `*const W -> *const dyn Trait`. - // So it's better to bail and try that. (even if the cast is not possible, for - // example due to vtables not matching, cast diagnostic will likely still be better) - // - // N.B. use `target`, not `coerce_target` (the latter is a var) - if let &ty::RawPtr(source_pointee, _) = coerce_source.kind() - && let &ty::RawPtr(target_pointee, _) = target.kind() - && has_dyn_trait_metadata(source_pointee) - && has_dyn_trait_metadata(target_pointee) - { - return Err(TypeError::Mismatch); - } - - Ok(()) - })?; - } - } // Use a FIFO queue for this custom fulfillment procedure. // @@ -657,7 +600,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // and almost never more than 3. By using a SmallVec we avoid an // allocation, at the (very small) cost of (occasionally) having to // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![root_obligation]; + let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new( + self.tcx, + cause, + self.fcx.param_env, + ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]) + )]; // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs deleted file mode 100644 index cfc0a97989dc..000000000000 --- a/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Combination of `ptr-to-trait-obj-wrap.rs` and `ptr-to-trait-obj-add-auto.rs`. -// -// Checks that you *can't* add auto traits to trait object in pointer casts involving wrapping said -// traits structures. - -trait A {} - -struct W(T); -struct X(T); - -fn unwrap(a: *const W) -> *const (dyn A + Send) { - a as _ - //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast -} - -fn unwrap_nested(a: *const W>) -> *const W { - a as _ - //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast -} - -fn rewrap(a: *const W) -> *const X { - a as _ - //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast -} - -fn rewrap_nested(a: *const W>) -> *const W> { - a as _ - //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast -} - -fn wrap(a: *const dyn A) -> *const W { - a as _ - //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast -} - -fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr deleted file mode 100644 index 42cdbc34ee82..000000000000 --- a/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast - --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:12:5 - | -LL | a as _ - | ^^^^^^ unsupported cast - | - = note: this could allow UB elsewhere - = help: use `transmute` if you're sure this is sound - -error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast - --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:17:5 - | -LL | a as _ - | ^^^^^^ unsupported cast - | - = note: this could allow UB elsewhere - = help: use `transmute` if you're sure this is sound - -error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast - --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:22:5 - | -LL | a as _ - | ^^^^^^ unsupported cast - | - = note: this could allow UB elsewhere - = help: use `transmute` if you're sure this is sound - -error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast - --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:27:5 - | -LL | a as _ - | ^^^^^^ unsupported cast - | - = note: this could allow UB elsewhere - = help: use `transmute` if you're sure this is sound - -error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast - --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:32:5 - | -LL | a as _ - | ^^^^^^ unsupported cast - | - = note: this could allow UB elsewhere - = help: use `transmute` if you're sure this is sound - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0804`. diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs deleted file mode 100644 index ebe7a06a7a15..000000000000 --- a/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Combination of `ptr-to-trait-obj-different-args.rs` and `ptr-to-trait-obj-wrap.rs`. -// -// Checks that you *can't* change type arguments of trait objects in pointer casts involving -// wrapping said traits structures. - -trait A {} - -struct W(T); -struct X(T); - -fn unwrap(a: *const W>) -> *const dyn A { - a as _ - //~^ error casting `*const W<(dyn A + 'static)>` as `*const dyn A` is invalid -} - -fn unwrap_nested(a: *const W>>) -> *const W> { - a as _ - //~^ error casting `*const W + 'static)>>` as `*const W>` is invalid -} - -fn rewrap(a: *const W>) -> *const X> { - a as _ - //~^ error: casting `*const W<(dyn A + 'static)>` as `*const X>` is invalid -} - -fn rewrap_nested(a: *const W>>) -> *const W>> { - a as _ - //~^ error: casting `*const W + 'static)>>` as `*const W>>` is invalid -} - -fn wrap(a: *const dyn A) -> *const W> { - a as _ - //~^ error: casting `*const (dyn A + 'static)` as `*const W>` is invalid -} - -fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr deleted file mode 100644 index 4f85b208d05a..000000000000 --- a/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0606]: casting `*const W<(dyn A + 'static)>` as `*const dyn A` is invalid - --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:12:5 - | -LL | a as _ - | ^^^^^^ - | - = note: the trait objects may have different vtables - -error[E0606]: casting `*const W + 'static)>>` as `*const W>` is invalid - --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:17:5 - | -LL | a as _ - | ^^^^^^ - | - = note: the trait objects may have different vtables - -error[E0606]: casting `*const W<(dyn A + 'static)>` as `*const X>` is invalid - --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:22:5 - | -LL | a as _ - | ^^^^^^ - | - = note: the trait objects may have different vtables - -error[E0606]: casting `*const W + 'static)>>` as `*const W>>` is invalid - --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:27:5 - | -LL | a as _ - | ^^^^^^ - | - = note: the trait objects may have different vtables - -error[E0606]: casting `*const (dyn A + 'static)` as `*const W>` is invalid - --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:32:5 - | -LL | a as _ - | ^^^^^^ - | - = note: the trait objects may have different vtables - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs deleted file mode 100644 index b0941277d01d..000000000000 --- a/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Combination of `ptr-to-trait-obj-different-regions-misc.rs` and `ptr-to-trait-obj-wrap.rs`. -// -// Checks that you *can't* change lifetime arguments of trait objects in pointer casts involving -// wrapping said traits structures. - -trait A<'a> {} - -struct W(T); -struct X(T); - -fn unwrap<'a, 'b>(a: *const W>) -> *const dyn A<'b> { - a as _ - //~^ error - //~| error -} - -fn unwrap_nested<'a, 'b>(a: *const W>>) -> *const W> { - a as _ - //~^ error - //~| error -} - -fn rewrap<'a, 'b>(a: *const W>) -> *const X> { - a as _ - //~^ error: lifetime may not live long enough - //~| error: lifetime may not live long enough -} - -fn rewrap_nested<'a, 'b>(a: *const W>>) -> *const W>> { - a as _ - //~^ error: lifetime may not live long enough - //~| error: lifetime may not live long enough -} - -fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W> { - a as _ - //~^ error: lifetime may not live long enough - //~| error: lifetime may not live long enough -} - -fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr deleted file mode 100644 index 17a0ca3c34fc..000000000000 --- a/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr +++ /dev/null @@ -1,140 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:12:5 - | -LL | fn unwrap<'a, 'b>(a: *const W>) -> *const dyn A<'b> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` - | - = help: consider adding the following bound: `'b: 'a` - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:12:5 - | -LL | fn unwrap<'a, 'b>(a: *const W>) -> *const dyn A<'b> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` - | - = help: consider adding the following bound: `'a: 'b` - -help: `'b` and `'a` must be the same: replace one with the other - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:18:5 - | -LL | fn unwrap_nested<'a, 'b>(a: *const W>>) -> *const W> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` - | - = help: consider adding the following bound: `'b: 'a` - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:18:5 - | -LL | fn unwrap_nested<'a, 'b>(a: *const W>>) -> *const W> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` - | - = help: consider adding the following bound: `'a: 'b` - -help: `'b` and `'a` must be the same: replace one with the other - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:24:5 - | -LL | fn rewrap<'a, 'b>(a: *const W>) -> *const X> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` - | - = help: consider adding the following bound: `'b: 'a` - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:24:5 - | -LL | fn rewrap<'a, 'b>(a: *const W>) -> *const X> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` - | - = help: consider adding the following bound: `'a: 'b` - -help: `'b` and `'a` must be the same: replace one with the other - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:30:5 - | -LL | fn rewrap_nested<'a, 'b>(a: *const W>>) -> *const W>> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` - | - = help: consider adding the following bound: `'b: 'a` - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:30:5 - | -LL | fn rewrap_nested<'a, 'b>(a: *const W>>) -> *const W>> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` - | - = help: consider adding the following bound: `'a: 'b` - -help: `'b` and `'a` must be the same: replace one with the other - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:36:5 - | -LL | fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` - | - = help: consider adding the following bound: `'b: 'a` - -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:36:5 - | -LL | fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W> { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | a as _ - | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` - | - = help: consider adding the following bound: `'a: 'b` - -help: `'b` and `'a` must be the same: replace one with the other - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 10 previous errors - diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap.rs b/tests/ui/cast/ptr-to-trait-obj-wrap.rs deleted file mode 100644 index 9809ea80f95c..000000000000 --- a/tests/ui/cast/ptr-to-trait-obj-wrap.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Checks that various casts of pointers to trait objects wrapped in structures -// work. Note that the metadata doesn't change when a DST is wrapped in a -// structure, so these casts *are* fine. -// -//@ check-pass - -trait A {} - -struct W(T); -struct X(T); - -fn unwrap(a: *const W) -> *const dyn A { - a as _ -} - -fn unwrap_nested(a: *const W>) -> *const W { - a as _ -} - -fn rewrap(a: *const W) -> *const X { - a as _ -} - -fn rewrap_nested(a: *const W>) -> *const W> { - a as _ -} - -fn wrap(a: *const dyn A) -> *const W { - a as _ -} - -fn main() {} From 75f283e40b02b63ecebeac53138fb94c76cb27df Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 24 Mar 2025 19:40:52 +0300 Subject: [PATCH 268/546] happy tidy --- src/tools/tidy/src/deps.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 81c55ecaa7a2..1a6550691ee3 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -240,7 +240,6 @@ const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!()); const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start "adler2", - "ahash", "aho-corasick", "allocator-api2", // FIXME: only appears in Cargo.lock due to https://github.com/rust-lang/cargo/issues/10801 "annotate-snippets", From 251455bcc5b3652d2af2eed29a317d0afd907e48 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 23 Mar 2025 18:56:34 +0000 Subject: [PATCH 269/546] Allow WellFormed goals to be returned from relating in new solver --- .../src/solve/eval_ctxt/mod.rs | 16 ++++++----- .../next-solver/well-formed-in-relate.rs | 21 +++++++++++++++ .../next-solver/well-formed-in-relate.stderr | 27 +++++++++++++++++++ 3 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 tests/ui/traits/next-solver/well-formed-in-relate.rs create mode 100644 tests/ui/traits/next-solver/well-formed-in-relate.stderr diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 0322c9e4ab01..7ef36d0e9ae3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -971,15 +971,17 @@ where rhs: T, ) -> Result<(), NoSolution> { let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?; - if cfg!(debug_assertions) { - for g in goals.iter() { - match g.predicate.kind().skip_binder() { - ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {} - p => unreachable!("unexpected nested goal in `relate`: {p:?}"), + for &goal in goals.iter() { + let source = match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => { + GoalSource::TypeRelating } - } + // FIXME(-Znext-solver=coinductive): should these WF goals also be unproductive? + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc, + p => unreachable!("unexpected nested goal in `relate`: {p:?}"), + }; + self.add_goal(source, goal); } - self.add_goals(GoalSource::TypeRelating, goals); Ok(()) } diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.rs b/tests/ui/traits/next-solver/well-formed-in-relate.rs new file mode 100644 index 000000000000..eec1ddef228c --- /dev/null +++ b/tests/ui/traits/next-solver/well-formed-in-relate.rs @@ -0,0 +1,21 @@ +fn main() { + let x; + //~^ ERROR type annotations needed for `Map<_, _>` + higher_ranked(); + x = unconstrained_map(); +} + +fn higher_ranked() where for<'a> &'a (): Sized {} + +struct Map where T: Fn() -> U { + t: T, +} + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +fn unconstrained_map U, U>() -> as Mirror>::Assoc { todo!() } diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.stderr b/tests/ui/traits/next-solver/well-formed-in-relate.stderr new file mode 100644 index 000000000000..5294a072d312 --- /dev/null +++ b/tests/ui/traits/next-solver/well-formed-in-relate.stderr @@ -0,0 +1,27 @@ +error[E0283]: type annotations needed for `Map<_, _>` + --> $DIR/well-formed-in-relate.rs:2:9 + | +LL | let x; + | ^ +... +LL | x = unconstrained_map(); + | ------------------- type must be known at this point + | + = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: + - impl Fn for &F + where A: Tuple, F: Fn, F: ?Sized; + - impl Fn for Box + where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; +note: required by a bound in `unconstrained_map` + --> $DIR/well-formed-in-relate.rs:21:25 + | +LL | fn unconstrained_map U, U>() -> as Mirror>::Assoc { todo!() } + | ^^^^^^^^^ required by this bound in `unconstrained_map` +help: consider giving `x` an explicit type, where the type for type parameter `T` is specified + | +LL | let x: Map; + | +++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. From aba23fd5003cf75aa524847d88d9d1337edd5f8e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 21 Mar 2025 19:28:35 +0000 Subject: [PATCH 270/546] Don't mark privacy test as needing GCE --- .../where-pub-type-impls-priv-trait.rs | 1 - .../where-pub-type-impls-priv-trait.stderr | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/tests/ui/privacy/where-pub-type-impls-priv-trait.rs b/tests/ui/privacy/where-pub-type-impls-priv-trait.rs index 1ebc396cdf5b..57548f75d5e4 100644 --- a/tests/ui/privacy/where-pub-type-impls-priv-trait.rs +++ b/tests/ui/privacy/where-pub-type-impls-priv-trait.rs @@ -3,7 +3,6 @@ // priv-in-pub lint tests where the private trait bounds a public type #![crate_type = "lib"] -#![feature(generic_const_exprs)] #![allow(incomplete_features)] struct PrivTy; diff --git a/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr b/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr index ee79ce3f5d75..33f82a3a4fec 100644 --- a/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr +++ b/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr @@ -1,30 +1,30 @@ warning: trait `PrivTr` is more private than the item `S` - --> $DIR/where-pub-type-impls-priv-trait.rs:20:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:19:1 | LL | pub struct S | ^^^^^^^^^^^^ struct `S` is reachable at visibility `pub` | note: but trait `PrivTr` is only usable at visibility `pub(crate)` - --> $DIR/where-pub-type-impls-priv-trait.rs:10:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:9:1 | LL | trait PrivTr {} | ^^^^^^^^^^^^ = note: `#[warn(private_bounds)]` on by default warning: trait `PrivTr` is more private than the item `E` - --> $DIR/where-pub-type-impls-priv-trait.rs:27:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:26:1 | LL | pub enum E | ^^^^^^^^^^ enum `E` is reachable at visibility `pub` | note: but trait `PrivTr` is only usable at visibility `pub(crate)` - --> $DIR/where-pub-type-impls-priv-trait.rs:10:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:9:1 | LL | trait PrivTr {} | ^^^^^^^^^^^^ warning: trait `PrivTr` is more private than the item `f` - --> $DIR/where-pub-type-impls-priv-trait.rs:34:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:33:1 | LL | / pub fn f() LL | | @@ -33,13 +33,13 @@ LL | | PubTy: PrivTr | |_________________^ function `f` is reachable at visibility `pub` | note: but trait `PrivTr` is only usable at visibility `pub(crate)` - --> $DIR/where-pub-type-impls-priv-trait.rs:10:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:9:1 | LL | trait PrivTr {} | ^^^^^^^^^^^^ warning: trait `PrivTr` is more private than the item `S` - --> $DIR/where-pub-type-impls-priv-trait.rs:41:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:40:1 | LL | / impl S LL | | @@ -48,13 +48,13 @@ LL | | PubTy: PrivTr | |_________________^ implementation `S` is reachable at visibility `pub` | note: but trait `PrivTr` is only usable at visibility `pub(crate)` - --> $DIR/where-pub-type-impls-priv-trait.rs:10:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:9:1 | LL | trait PrivTr {} | ^^^^^^^^^^^^ warning: trait `PrivTr` is more private than the item `S::f` - --> $DIR/where-pub-type-impls-priv-trait.rs:46:5 + --> $DIR/where-pub-type-impls-priv-trait.rs:45:5 | LL | / pub fn f() LL | | @@ -63,7 +63,7 @@ LL | | PubTy: PrivTr | |_____________________^ associated function `S::f` is reachable at visibility `pub` | note: but trait `PrivTr` is only usable at visibility `pub(crate)` - --> $DIR/where-pub-type-impls-priv-trait.rs:10:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:9:1 | LL | trait PrivTr {} | ^^^^^^^^^^^^ From c80d9b8d67a78ed19be86f9d129a57922c7dc86e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Mar 2025 18:51:33 +0000 Subject: [PATCH 271/546] Don't ICE when encountering placeholders in layout computation --- compiler/rustc_ty_utils/src/layout.rs | 8 ++------ ...e.stderr => too_generic_eval_ice.current.stderr} | 8 ++++---- tests/ui/consts/too_generic_eval_ice.next.stderr | 9 +++++++++ tests/ui/consts/too_generic_eval_ice.rs | 13 +++++++++---- 4 files changed, 24 insertions(+), 14 deletions(-) rename tests/ui/consts/{too_generic_eval_ice.stderr => too_generic_eval_ice.current.stderr} (90%) create mode 100644 tests/ui/consts/too_generic_eval_ice.next.stderr diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 7334beb52c9d..0017186c1b08 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -611,7 +611,7 @@ fn layout_of_uncached<'tcx>( } // Types with no meaningful known layout. - ty::Param(_) => { + ty::Param(_) | ty::Placeholder(..) => { return Err(error(cx, LayoutError::TooGeneric(ty))); } @@ -628,11 +628,7 @@ fn layout_of_uncached<'tcx>( return Err(error(cx, err)); } - ty::Placeholder(..) - | ty::Bound(..) - | ty::CoroutineWitness(..) - | ty::Infer(_) - | ty::Error(_) => { + ty::Bound(..) | ty::CoroutineWitness(..) | ty::Infer(_) | ty::Error(_) => { // `ty::Error` is handled at the top of this function. bug!("layout_of: unexpected type `{ty}`") } diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.current.stderr similarity index 90% rename from tests/ui/consts/too_generic_eval_ice.stderr rename to tests/ui/consts/too_generic_eval_ice.current.stderr index 3cc4377514a2..02bcaee80154 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.current.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/too_generic_eval_ice.rs:7:13 + --> $DIR/too_generic_eval_ice.rs:11:13 | LL | [5; Self::HOST_SIZE] == [6; 0] | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | [5; Self::HOST_SIZE] == [6; 0] = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/too_generic_eval_ice.rs:7:9 + --> $DIR/too_generic_eval_ice.rs:11:9 | LL | [5; Self::HOST_SIZE] == [6; 0] | ^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | [5; Self::HOST_SIZE] == [6; 0] = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/too_generic_eval_ice.rs:7:30 + --> $DIR/too_generic_eval_ice.rs:11:30 | LL | [5; Self::HOST_SIZE] == [6; 0] | ^^ @@ -23,7 +23,7 @@ LL | [5; Self::HOST_SIZE] == [6; 0] = note: this may fail depending on what value the parameter takes error[E0277]: can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]` - --> $DIR/too_generic_eval_ice.rs:7:30 + --> $DIR/too_generic_eval_ice.rs:11:30 | LL | [5; Self::HOST_SIZE] == [6; 0] | ^^ no implementation for `[{integer}; Self::HOST_SIZE] == [{integer}; 0]` diff --git a/tests/ui/consts/too_generic_eval_ice.next.stderr b/tests/ui/consts/too_generic_eval_ice.next.stderr new file mode 100644 index 000000000000..01da33241c81 --- /dev/null +++ b/tests/ui/consts/too_generic_eval_ice.next.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `the constant `Self::HOST_SIZE` can be evaluated` + --> $DIR/too_generic_eval_ice.rs:11:13 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^^^^^^^ cannot satisfy `the constant `Self::HOST_SIZE` can be evaluated` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/consts/too_generic_eval_ice.rs b/tests/ui/consts/too_generic_eval_ice.rs index 0d46a4c8276d..ff741cdcf20b 100644 --- a/tests/ui/consts/too_generic_eval_ice.rs +++ b/tests/ui/consts/too_generic_eval_ice.rs @@ -1,3 +1,7 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + pub struct Foo(A, B); impl Foo { @@ -5,10 +9,11 @@ impl Foo { pub fn crash() -> bool { [5; Self::HOST_SIZE] == [6; 0] - //~^ ERROR constant expression depends on a generic parameter - //~| ERROR constant expression depends on a generic parameter - //~| ERROR constant expression depends on a generic parameter - //~| ERROR can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]` + //[current]~^ ERROR constant expression depends on a generic parameter + //[current]~| ERROR constant expression depends on a generic parameter + //[current]~| ERROR constant expression depends on a generic parameter + //[current]~| ERROR can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]` + //[next]~^^^^^ ERROR type annotations needed } } From 484362e3f809ec77eae394603e587ec49a9348e7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 21 Mar 2025 18:04:34 +0000 Subject: [PATCH 272/546] Mark a fixed test --- ...err => dedup-normalized-2-higher-ranked.current.stderr} | 4 ++-- .../dedup-normalized-2-higher-ranked.rs | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) rename tests/ui/associated-type-bounds/{dedup-normalized-2-higher-ranked.stderr => dedup-normalized-2-higher-ranked.current.stderr} (86%) diff --git a/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.stderr b/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.current.stderr similarity index 86% rename from tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.stderr rename to tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.current.stderr index 372d379de5a4..64304be9d6b1 100644 --- a/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.stderr +++ b/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.current.stderr @@ -1,12 +1,12 @@ error[E0283]: type annotations needed - --> $DIR/dedup-normalized-2-higher-ranked.rs:23:5 + --> $DIR/dedup-normalized-2-higher-ranked.rs:28:5 | LL | impls(rigid); | ^^^^^ cannot infer type of the type parameter `U` declared on the function `impls` | = note: cannot satisfy `for<'b>

::Rigid: Bound<'b, _>` note: required by a bound in `impls` - --> $DIR/dedup-normalized-2-higher-ranked.rs:20:13 + --> $DIR/dedup-normalized-2-higher-ranked.rs:25:13 | LL | fn impls Bound<'b, U>, U>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls` diff --git a/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.rs b/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.rs index 9224d47d30fd..32b8c689248f 100644 --- a/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.rs +++ b/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.rs @@ -1,3 +1,8 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + // We try to prove `for<'b> T::Rigid: Bound<'b, ?0>` and have 2 candidates from where-clauses: // // - `for<'a> Bound<'a, String>` @@ -21,7 +26,7 @@ fn impls Bound<'b, U>, U>(_: T) {} fn test(rigid: P::Rigid) { impls(rigid); - //~^ ERROR type annotations needed + //[current]~^ ERROR type annotations needed } fn main() {} From 41d68e098c29d59714165fef30f705fac9baf8a0 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:00:58 +0100 Subject: [PATCH 273/546] Update books --- src/doc/book | 2 +- src/doc/reference | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book b/src/doc/book index 81a976a237f8..45f05367360f 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 81a976a237f84b8392c4ce1bd5fd076eb757a2eb +Subproject commit 45f05367360f033f89235eacbbb54e8d73ce6b70 diff --git a/src/doc/reference b/src/doc/reference index dda31c85f2ef..e95ebdfee025 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit dda31c85f2ef2e5d2f0f2f643c9231690a30a626 +Subproject commit e95ebdfee02514d93f79ec92ae310a804e87f01f From 60e4a1b8f37c48cfc4c8c78aaafc5ff2f8d02ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 19 Mar 2025 02:31:12 +0100 Subject: [PATCH 274/546] Remove `prev_index_to_index` field from `CurrentDepGraph` --- .../rustc_query_system/src/dep_graph/graph.rs | 291 +++++++----------- .../src/dep_graph/serialized.rs | 38 ++- 2 files changed, 144 insertions(+), 185 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index de5bbacf2740..495f34733f70 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -66,7 +66,7 @@ pub struct MarkFrame<'a> { parent: Option<&'a MarkFrame<'a>>, } -enum DepNodeColor { +pub(super) enum DepNodeColor { Red, Green(DepNodeIndex), } @@ -140,7 +140,7 @@ impl DepGraph { let colors = DepNodeColorMap::new(prev_graph_node_count); // Instantiate a dependy-less node only once for anonymous queries. - let _green_node_index = current.alloc_new_node( + let _green_node_index = current.alloc_node( DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() }, EdgesVec::new(), Fingerprint::ZERO, @@ -148,26 +148,17 @@ impl DepGraph { assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE); // Instantiate a dependy-less red node only once for anonymous queries. - let (red_node_index, red_node_prev_index_and_color) = current.intern_node( - &prev_graph, + let red_node_index = current.alloc_node( DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() }, EdgesVec::new(), - None, + Fingerprint::ZERO, ); assert_eq!(red_node_index, DepNodeIndex::FOREVER_RED_NODE); - match red_node_prev_index_and_color { - None => { - // This is expected when we have no previous compilation session. - assert!(prev_graph_node_count == 0); - } - Some((prev_red_node_index, DepNodeColor::Red)) => { - assert_eq!(prev_red_node_index.as_usize(), red_node_index.as_usize()); - colors.insert(prev_red_node_index, DepNodeColor::Red); - } - Some((_, DepNodeColor::Green(_))) => { - // There must be a logic error somewhere if we hit this branch. - panic!("DepNodeIndex::FOREVER_RED_NODE evaluated to DepNodeColor::Green") - } + if prev_graph_node_count > 0 { + colors.insert( + SerializedDepNodeIndex::from_u32(DepNodeIndex::FOREVER_RED_NODE.as_u32()), + DepNodeColor::Red, + ); } DepGraph { @@ -376,8 +367,7 @@ impl DepGraphData { }; let dcx = cx.dep_context(); - let dep_node_index = - self.hash_result_and_intern_node(dcx, key, edges, &result, hash_result); + let dep_node_index = self.hash_result_and_alloc_node(dcx, key, edges, &result, hash_result); (result, dep_node_index) } @@ -447,7 +437,7 @@ impl DepGraphData { // memory impact of this `anon_node_to_index` map remains tolerable, and helps // us avoid useless growth of the graph with almost-equivalent nodes. self.current.anon_node_to_index.get_or_insert_with(target_dep_node, || { - self.current.alloc_new_node(target_dep_node, task_deps, Fingerprint::ZERO) + self.current.alloc_node(target_dep_node, task_deps, Fingerprint::ZERO) }) } }; @@ -456,7 +446,7 @@ impl DepGraphData { } /// Intern the new `DepNode` with the dependencies up-to-now. - fn hash_result_and_intern_node, R>( + fn hash_result_and_alloc_node, R>( &self, cx: &Ctxt, node: DepNode, @@ -468,22 +458,8 @@ impl DepGraphData { let current_fingerprint = hash_result.map(|hash_result| { cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result)) }); - - // Intern the new `DepNode` with the dependencies up-to-now. - let (dep_node_index, prev_and_color) = - self.current.intern_node(&self.previous, node, edges, current_fingerprint); - + let dep_node_index = self.alloc_and_color_node(node, edges, current_fingerprint); hashing_timer.finish_with_query_invocation_id(dep_node_index.into()); - - if let Some((prev_index, color)) = prev_and_color { - debug_assert!( - self.colors.get(prev_index).is_none(), - "DepGraph::with_task() - Duplicate DepNodeColor insertion for {node:?}", - ); - - self.colors.insert(prev_index, color); - } - dep_node_index } } @@ -601,7 +577,7 @@ impl DepGraph { // // For sanity, we still check that the loaded stable hash and the new one match. if let Some(prev_index) = data.previous.node_to_index_opt(&node) { - let dep_node_index = data.current.prev_index_to_index.lock()[prev_index]; + let dep_node_index = data.colors.current(prev_index); if let Some(dep_node_index) = dep_node_index { crate::query::incremental_verify_ich( cx, @@ -637,7 +613,7 @@ impl DepGraph { } }); - data.hash_result_and_intern_node(&cx, node, edges, result, hash_result) + data.hash_result_and_alloc_node(&cx, node, edges, result, hash_result) } else { // Incremental compilation is turned off. We just execute the task // without tracking. We still provide a dep-node index that uniquely @@ -655,13 +631,11 @@ impl DepGraphData { msg: impl FnOnce() -> S, ) { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { - let current = self.current.prev_index_to_index.lock()[prev_index]; + let current = self.colors.get(prev_index); assert!(current.is_none(), "{}", msg()) - } else if let Some(nodes_newly_allocated_in_current_session) = - &self.current.nodes_newly_allocated_in_current_session - { + } else if let Some(nodes_in_current_session) = &self.current.nodes_in_current_session { outline(|| { - let seen = nodes_newly_allocated_in_current_session.lock().contains_key(dep_node); + let seen = nodes_in_current_session.lock().contains_key(dep_node); assert!(!seen, "{}", msg()); }); } @@ -738,15 +712,77 @@ impl DepGraphData { } } - // Promote the previous diagnostics to the current session. - let index = self.current.promote_node_and_deps_to_current(&self.previous, prev_index); - // FIXME: Can this race with a parallel compiler? - qcx.store_side_effect(index, side_effect); + // Manually recreate the node as `promote_node_and_deps_to_current` expects all + // green dependencies. + let dep_node_index = self.current.encoder.send( + DepNode { + kind: D::DEP_KIND_SIDE_EFFECT, + hash: PackedFingerprint::from(Fingerprint::ZERO), + }, + Fingerprint::ZERO, + std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), + ); + qcx.store_side_effect(dep_node_index, side_effect); // Mark the node as green. - self.colors.insert(prev_index, DepNodeColor::Green(index)); + self.colors.insert(prev_index, DepNodeColor::Green(dep_node_index)); }) } + + fn alloc_and_color_node( + &self, + key: DepNode, + edges: EdgesVec, + fingerprint: Option, + ) -> DepNodeIndex { + let dep_node_index = + self.current.alloc_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO)); + + if let Some(prev_index) = self.previous.node_to_index_opt(&key) { + // Determine the color and index of the new `DepNode`. + let color = if let Some(fingerprint) = fingerprint { + if fingerprint == self.previous.fingerprint_by_index(prev_index) { + // This is a green node: it existed in the previous compilation, + // its query was re-executed, and it has the same result as before. + DepNodeColor::Green(dep_node_index) + } else { + // This is a red node: it existed in the previous compilation, its query + // was re-executed, but it has a different result from before. + DepNodeColor::Red + } + } else { + // This is a red node, effectively: it existed in the previous compilation + // session, its query was re-executed, but it doesn't compute a result hash + // (i.e. it represents a `no_hash` query), so we have no way of determining + // whether or not the result was the same as before. + DepNodeColor::Red + }; + + debug_assert!( + self.colors.get(prev_index).is_none(), + "DepGraph::with_task() - Duplicate DepNodeColor insertion for {key:?}", + ); + + self.colors.insert(prev_index, color); + } + + dep_node_index + } + + fn promote_node_and_deps_to_current(&self, prev_index: SerializedDepNodeIndex) -> DepNodeIndex { + self.current.debug_assert_not_in_new_nodes(&self.previous, prev_index); + + let dep_node_index = self.current.encoder.send_promoted(prev_index, &self.colors); + + #[cfg(debug_assertions)] + self.current.record_edge( + dep_node_index, + self.previous.index_to_node(prev_index), + self.previous.fingerprint_by_index(prev_index), + ); + + dep_node_index + } } impl DepGraph { @@ -948,14 +984,10 @@ impl DepGraphData { // We allocating an entry for the node in the current dependency graph and // adding all the appropriate edges imported from the previous graph - let dep_node_index = - self.current.promote_node_and_deps_to_current(&self.previous, prev_dep_node_index); - - // ... emitting any stored diagnostic ... + let dep_node_index = self.promote_node_and_deps_to_current(prev_dep_node_index); // ... and finally storing a "Green" entry in the color map. // Multiple threads can all write the same color here - self.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); debug!("successfully marked {dep_node:?} as green"); Some(dep_node_index) @@ -1106,7 +1138,6 @@ rustc_index::newtype_index! { /// first, and `data` second. pub(super) struct CurrentDepGraph { encoder: GraphEncoder, - prev_index_to_index: Lock>>, anon_node_to_index: ShardedHashMap, /// This is used to verify that fingerprints do not change between the creation of a node @@ -1123,9 +1154,8 @@ pub(super) struct CurrentDepGraph { /// This field is only `Some` if the `-Z incremental_verify_ich` option is present /// or if `debug_assertions` are enabled. /// - /// The map contains all DepNodes that have been allocated in the current session so far and - /// for which there is no equivalent in the previous session. - nodes_newly_allocated_in_current_session: Option>>, + /// The map contains all DepNodes that have been allocated in the current session so far. + nodes_in_current_session: Option>>, /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of /// their edges. This has the beneficial side-effect that multiple anonymous @@ -1190,13 +1220,12 @@ impl CurrentDepGraph { // FIXME: The count estimate is off as anon nodes are only a portion of the nodes. new_node_count_estimate / sharded::shards(), ), - prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)), anon_id_seed, #[cfg(debug_assertions)] forbidden_edge, #[cfg(debug_assertions)] fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)), - nodes_newly_allocated_in_current_session: new_node_dbg.then(|| { + nodes_in_current_session: new_node_dbg.then(|| { Lock::new(FxHashMap::with_capacity_and_hasher( new_node_count_estimate, Default::default(), @@ -1219,7 +1248,7 @@ impl CurrentDepGraph { /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it. /// Assumes that this is a node that has no equivalent in the previous dep-graph. #[inline(always)] - fn alloc_new_node( + fn alloc_node( &self, key: DepNode, edges: EdgesVec, @@ -1230,15 +1259,9 @@ impl CurrentDepGraph { #[cfg(debug_assertions)] self.record_edge(dep_node_index, key, current_fingerprint); - if let Some(ref nodes_newly_allocated_in_current_session) = - self.nodes_newly_allocated_in_current_session - { + if let Some(ref nodes_in_current_session) = self.nodes_in_current_session { outline(|| { - if nodes_newly_allocated_in_current_session - .lock() - .insert(key, dep_node_index) - .is_some() - { + if nodes_in_current_session.lock().insert(key, dep_node_index).is_some() { panic!("Found duplicate dep-node {key:?}"); } }); @@ -1247,102 +1270,20 @@ impl CurrentDepGraph { dep_node_index } - fn intern_node( - &self, - prev_graph: &SerializedDepGraph, - key: DepNode, - edges: EdgesVec, - fingerprint: Option, - ) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) { - if let Some(prev_index) = prev_graph.node_to_index_opt(&key) { - let get_dep_node_index = |fingerprint| { - let mut prev_index_to_index = self.prev_index_to_index.lock(); - - let dep_node_index = match prev_index_to_index[prev_index] { - Some(dep_node_index) => dep_node_index, - None => { - let dep_node_index = self.encoder.send(key, fingerprint, edges); - prev_index_to_index[prev_index] = Some(dep_node_index); - dep_node_index - } - }; - - #[cfg(debug_assertions)] - self.record_edge(dep_node_index, key, fingerprint); - - dep_node_index - }; - - // Determine the color and index of the new `DepNode`. - if let Some(fingerprint) = fingerprint { - if fingerprint == prev_graph.fingerprint_by_index(prev_index) { - // This is a green node: it existed in the previous compilation, - // its query was re-executed, and it has the same result as before. - let dep_node_index = get_dep_node_index(fingerprint); - (dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index)))) - } else { - // This is a red node: it existed in the previous compilation, its query - // was re-executed, but it has a different result from before. - let dep_node_index = get_dep_node_index(fingerprint); - (dep_node_index, Some((prev_index, DepNodeColor::Red))) - } - } else { - // This is a red node, effectively: it existed in the previous compilation - // session, its query was re-executed, but it doesn't compute a result hash - // (i.e. it represents a `no_hash` query), so we have no way of determining - // whether or not the result was the same as before. - let dep_node_index = get_dep_node_index(Fingerprint::ZERO); - (dep_node_index, Some((prev_index, DepNodeColor::Red))) - } - } else { - let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO); - - // This is a new node: it didn't exist in the previous compilation session. - let dep_node_index = self.alloc_new_node(key, edges, fingerprint); - - (dep_node_index, None) - } - } - - fn promote_node_and_deps_to_current( - &self, - prev_graph: &SerializedDepGraph, - prev_index: SerializedDepNodeIndex, - ) -> DepNodeIndex { - self.debug_assert_not_in_new_nodes(prev_graph, prev_index); - - let mut prev_index_to_index = self.prev_index_to_index.lock(); - - match prev_index_to_index[prev_index] { - Some(dep_node_index) => dep_node_index, - None => { - let dep_node_index = self.encoder.send_promoted(prev_index, &*prev_index_to_index); - prev_index_to_index[prev_index] = Some(dep_node_index); - #[cfg(debug_assertions)] - self.record_edge( - dep_node_index, - prev_graph.index_to_node(prev_index), - prev_graph.fingerprint_by_index(prev_index), - ); - dep_node_index - } - } - } - #[inline] fn debug_assert_not_in_new_nodes( &self, prev_graph: &SerializedDepGraph, prev_index: SerializedDepNodeIndex, ) { - let node = &prev_graph.index_to_node(prev_index); - debug_assert!( - !self - .nodes_newly_allocated_in_current_session - .as_ref() - .map_or(false, |set| set.lock().contains_key(node)), - "node from previous graph present in new node collection" - ); + if let Some(ref nodes_in_current_session) = self.nodes_in_current_session { + debug_assert!( + !nodes_in_current_session + .lock() + .contains_key(&prev_graph.index_to_node(prev_index)), + "node from previous graph present in new node collection" + ); + } } } @@ -1389,36 +1330,40 @@ impl Default for TaskDeps { } // A data structure that stores Option values as a contiguous // array, using one u32 per entry. -struct DepNodeColorMap { +pub(super) struct DepNodeColorMap { values: IndexVec, } -const COMPRESSED_NONE: u32 = 0; -const COMPRESSED_RED: u32 = 1; -const COMPRESSED_FIRST_GREEN: u32 = 2; +const COMPRESSED_NONE: u32 = u32::MAX; +const COMPRESSED_RED: u32 = u32::MAX - 1; impl DepNodeColorMap { fn new(size: usize) -> DepNodeColorMap { + debug_assert!(COMPRESSED_RED > DepNodeIndex::MAX_AS_U32); DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() } } #[inline] - fn get(&self, index: SerializedDepNodeIndex) -> Option { + pub(super) fn current(&self, index: SerializedDepNodeIndex) -> Option { + let value = self.values[index].load(Ordering::Relaxed); + if value <= DepNodeIndex::MAX_AS_U32 { Some(DepNodeIndex::from_u32(value)) } else { None } + } + + #[inline] + pub(super) fn get(&self, index: SerializedDepNodeIndex) -> Option { match self.values[index].load(Ordering::Acquire) { COMPRESSED_NONE => None, COMPRESSED_RED => Some(DepNodeColor::Red), - value => { - Some(DepNodeColor::Green(DepNodeIndex::from_u32(value - COMPRESSED_FIRST_GREEN))) - } + value => Some(DepNodeColor::Green(DepNodeIndex::from_u32(value))), } } #[inline] - fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) { + pub(super) fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) { self.values[index].store( match color { DepNodeColor::Red => COMPRESSED_RED, - DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN, + DepNodeColor::Green(index) => index.as_u32(), }, Ordering::Release, ) @@ -1454,16 +1399,16 @@ fn panic_on_forbidden_read(data: &DepGraphData, dep_node_index: DepN let mut dep_node = None; // First try to find the dep node among those that already existed in the - // previous session - for (prev_index, index) in data.current.prev_index_to_index.lock().iter_enumerated() { - if index == &Some(dep_node_index) { + // previous session and has been marked green + for prev_index in data.colors.values.indices() { + if data.colors.current(prev_index) == Some(dep_node_index) { dep_node = Some(data.previous.index_to_node(prev_index)); break; } } if dep_node.is_none() - && let Some(nodes) = &data.current.nodes_newly_allocated_in_current_session + && let Some(nodes) = &data.current.nodes_in_current_session { // Try to find it among the nodes allocated so far in this session if let Some((node, _)) = nodes.lock().iter().find(|&(_, index)| *index == dep_node_index) { diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index f4b2cf631ed7..7750d6d1fef4 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -50,6 +50,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixed use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use tracing::{debug, instrument}; +use super::graph::{DepNodeColor, DepNodeColorMap}; use super::query::DepGraphQuery; use super::{DepKind, DepNode, DepNodeIndex, Deps}; use crate::dep_graph::edges::EdgesVec; @@ -441,7 +442,7 @@ impl NodeInfo { node: DepNode, fingerprint: Fingerprint, prev_index: SerializedDepNodeIndex, - prev_index_to_index: &IndexVec>, + colors: &DepNodeColorMap, previous: &SerializedDepGraph, ) -> usize { let edges = previous.edge_targets_from(prev_index); @@ -449,7 +450,7 @@ impl NodeInfo { // Find the highest edge in the new dep node indices let edge_max = - edges.clone().map(|i| prev_index_to_index[i].unwrap().as_u32()).max().unwrap_or(0); + edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0); let header = SerializedNodeHeader::::new(node, fingerprint, edge_max, edge_count); e.write_array(header.bytes); @@ -460,7 +461,7 @@ impl NodeInfo { let bytes_per_index = header.bytes_per_index(); for node_index in edges { - let node_index = prev_index_to_index[node_index].unwrap(); + let node_index = colors.current(node_index).unwrap(); e.write_with(|dest| { *dest = node_index.as_u32().to_le_bytes(); bytes_per_index @@ -565,7 +566,7 @@ impl EncoderState { &mut self, prev_index: SerializedDepNodeIndex, record_graph: &Option>, - prev_index_to_index: &IndexVec>, + colors: &DepNodeColorMap, ) -> DepNodeIndex { let node = self.previous.index_to_node(prev_index); @@ -575,7 +576,7 @@ impl EncoderState { node, fingerprint, prev_index, - prev_index_to_index, + colors, &self.previous, ); @@ -585,7 +586,7 @@ impl EncoderState { |this| { this.previous .edge_targets_from(prev_index) - .map(|i| prev_index_to_index[i].unwrap()) + .map(|i| colors.current(i).unwrap()) .collect() }, record_graph, @@ -719,18 +720,31 @@ impl GraphEncoder { /// Encodes a node that was promoted from the previous graph. It reads the information directly from /// the previous dep graph and expects all edges to already have a new dep node index assigned. + /// + /// This will also ensure the dep node is marked green. #[inline] pub(crate) fn send_promoted( &self, prev_index: SerializedDepNodeIndex, - prev_index_to_index: &IndexVec>, + colors: &DepNodeColorMap, ) -> DepNodeIndex { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); - self.status.lock().as_mut().unwrap().encode_promoted_node( - prev_index, - &self.record_graph, - prev_index_to_index, - ) + + let mut status = self.status.lock(); + let status = status.as_mut().unwrap(); + + // Check colors inside the lock to avoid racing when `send_promoted` is called concurrently + // on the same index. + match colors.get(prev_index) { + None => { + let dep_node_index = + status.encode_promoted_node(prev_index, &self.record_graph, colors); + colors.insert(prev_index, DepNodeColor::Green(dep_node_index)); + dep_node_index + } + Some(DepNodeColor::Green(dep_node_index)) => dep_node_index, + Some(DepNodeColor::Red) => panic!(), + } } pub(crate) fn finish(&self) -> FileEncodeResult { From 848b0da34fa20d0ff5d12d1d4f506affc765534b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 23 Mar 2025 22:00:39 +0100 Subject: [PATCH 275/546] Remove fields that are dead since the removal of type ascription syntax Since `{ ident: ident }` is a parse error, these fields are dead. --- compiler/rustc_ast/src/ast.rs | 8 ------ compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_builtin_macros/src/autodiff.rs | 1 - .../rustc_builtin_macros/src/deriving/mod.rs | 1 - compiler/rustc_expand/src/build.rs | 1 - .../rustc_parse/src/parser/diagnostics.rs | 25 ++++++++----------- compiler/rustc_parse/src/parser/stmt.rs | 9 +------ compiler/rustc_resolve/src/late.rs | 13 ---------- .../rustc_resolve/src/late/diagnostics.rs | 14 ----------- src/tools/rustfmt/src/closures.rs | 1 - src/tools/rustfmt/src/macros.rs | 1 - tests/ui-fulldeps/pprust-expr-roundtrip.rs | 1 - 13 files changed, 13 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5b7545b33966..cc2fa8810d69 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -545,14 +545,6 @@ pub struct Block { pub rules: BlockCheckMode, pub span: Span, pub tokens: Option, - /// The following *isn't* a parse error, but will cause multiple errors in following stages. - /// ```compile_fail - /// let x = { - /// foo: var - /// }; - /// ``` - /// #34255 - pub could_be_bare_literal: bool, } /// A match pattern. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 4edd08643000..c898a60fbe69 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1225,7 +1225,7 @@ fn walk_mt(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) { } pub fn walk_block(vis: &mut T, block: &mut P) { - let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut(); + let Block { id, stmts, rules: _, span, tokens } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); visit_lazy_tts(vis, tokens); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ce8d6df75afb..50d8aa293c5c 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1035,7 +1035,7 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) } pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result { - let Block { stmts, id: _, rules: _, span: _, tokens: _, could_be_bare_literal: _ } = block; + let Block { stmts, id: _, rules: _, span: _, tokens: _ } = block; walk_list!(visitor, visit_stmt, stmts); V::Result::output() } diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 6591ed151cf6..f3a40b8c6829 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -395,7 +395,6 @@ mod llvm_enzyme { tokens: None, rules: unsf, span, - could_be_bare_literal: false, }; let unsf_expr = ecx.expr_block(P(unsf_block)); let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path)); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index c112589b1319..50e7b989ed8a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -110,7 +110,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P { rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), span, tokens: None, - could_be_bare_literal: false, })) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index ee7f68cc2f01..99b336969e47 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -286,7 +286,6 @@ impl<'a> ExtCtxt<'a> { rules: BlockCheckMode::Default, span, tokens: None, - could_be_bare_literal: false, }) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c1cca1186af4..daa27b146690 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -971,18 +971,8 @@ impl<'a> Parser<'a> { // fn foo() -> Foo { // field: value, // } - // Suggest: - // fn foo() -> Foo { Path { - // field: value, - // } } let guar = err.delay_as_bug(); self.restore_snapshot(snapshot); - let mut tail = self.mk_block( - thin_vec![self.mk_stmt_err(expr.span, guar)], - s, - lo.to(self.prev_token.span), - ); - tail.could_be_bare_literal = true; if maybe_struct_name.is_ident() && can_be_struct_literal { // Account for `if Example { a: one(), }.is_pos() {}`. // expand `before` so that we take care of module path such as: @@ -1004,6 +994,10 @@ impl<'a> Parser<'a> { return None; } } else { + // Suggest: + // fn foo() -> Foo { Path { + // field: value, + // } } self.dcx().emit_err(StructLiteralBodyWithoutPath { span: expr.span, sugg: StructLiteralBodyWithoutPathSugg { @@ -1011,7 +1005,11 @@ impl<'a> Parser<'a> { after: expr.span.shrink_to_hi(), }, }); - Ok(tail) + Ok(self.mk_block( + thin_vec![self.mk_stmt_err(expr.span, guar)], + s, + lo.to(self.prev_token.span), + )) } } (Err(err), Ok(tail)) => { @@ -1025,10 +1023,7 @@ impl<'a> Parser<'a> { self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes); Err(err) } - (Ok(_), Ok(mut tail)) => { - tail.could_be_bare_literal = true; - Ok(tail) - } + (Ok(_), Ok(tail)) => Ok(tail), }); } None diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 0fe247078d51..368366c60d65 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -1043,14 +1043,7 @@ impl<'a> Parser<'a> { rules: BlockCheckMode, span: Span, ) -> P { - P(Block { - stmts, - id: DUMMY_NODE_ID, - rules, - span, - tokens: None, - could_be_bare_literal: false, - }) + P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None }) } pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6056a69ee71f..b4d9d5a8a0ec 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -674,11 +674,6 @@ struct DiagMetadata<'ast> { /// they are used (in a `break` or `continue` statement) unused_labels: FxHashMap, - /// Only used for better errors on `let x = { foo: bar };`. - /// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only - /// needed for cases where this parses as a correct type ascription. - current_block_could_be_bare_struct_literal: Option, - /// Only used for better errors on `let : ;`. current_let_binding: Option<(Span, Option, Option)>, @@ -4650,13 +4645,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.ribs[ValueNS].push(Rib::new(RibKind::Normal)); } - let prev = self.diag_metadata.current_block_could_be_bare_struct_literal.take(); - if let (true, [Stmt { kind: StmtKind::Expr(expr), .. }]) = - (block.could_be_bare_literal, &block.stmts[..]) - && let ExprKind::Type(..) = expr.kind - { - self.diag_metadata.current_block_could_be_bare_struct_literal = Some(block.span); - } // Descend into the block. for stmt in &block.stmts { if let StmtKind::Item(ref item) = stmt.kind @@ -4670,7 +4658,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.visit_stmt(stmt); } - self.diag_metadata.current_block_could_be_bare_struct_literal = prev; // Move back up. self.parent_scope.module = orig_module; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3d666055a94f..dff9b4786985 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -450,7 +450,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect); } - self.suggest_bare_struct_literal(&mut err); self.suggest_changing_type_to_const_param(&mut err, res, source, span); self.explain_functions_in_pattern(&mut err, res, source); @@ -1281,19 +1280,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - fn suggest_bare_struct_literal(&mut self, err: &mut Diag<'_>) { - if let Some(span) = self.diag_metadata.current_block_could_be_bare_struct_literal { - err.multipart_suggestion( - "you might have meant to write a `struct` literal", - vec![ - (span.shrink_to_lo(), "{ SomeStruct ".to_string()), - (span.shrink_to_hi(), "}".to_string()), - ], - Applicability::HasPlaceholders, - ); - } - } - fn explain_functions_in_pattern( &mut self, err: &mut Diag<'_>, diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index a37b47e3bc95..61e148cdf188 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -176,7 +176,6 @@ fn rewrite_closure_with_block( .first() .map(|attr| attr.span.to(body.span)) .unwrap_or(body.span), - could_be_bare_literal: false, }; let block = crate::expr::rewrite_block_with_visitor( context, diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index 664c90b991a9..e239ff47c043 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -423,7 +423,6 @@ fn rewrite_empty_macro_def_body( rules: ast::BlockCheckMode::Default, span, tokens: None, - could_be_bare_literal: false, }; block.rewrite_result(context, shape) } diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 37e328a315f1..4a866560e798 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -114,7 +114,6 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { rules: BlockCheckMode::Default, span: DUMMY_SP, tokens: None, - could_be_bare_literal: false, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); } From 1aed58ceb6fc2bdbd4d323fb18fd6d7c9ee21630 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 22 Mar 2025 22:29:23 +0100 Subject: [PATCH 276/546] Emit `unused_attributes` for `#[inline]` on exported functions I saw someone post a code sample that contained these two attributes, which immediately made me suspicious. My suspicions were confirmed when I did a small test and checked the compiler source code to confirm that in these cases, `#[inline]` is indeed ignored (because you can't exactly `LocalCopy`an unmangled symbol since that would lead to duplicate symbols, and doing a mix of an unmangled `GloballyShared` and mangled `LocalCopy` instantiation is too complicated for our current instatiation mode logic, which I don't want to change right now). So instead, emit the usual unused attribute lint with a message saying that the attribute is ignored in this position. I think this is not 100% true, since I expect LLVM `inlinehint` to still be applied to such a function, but that's not why people use this attribute, they use it for the `LocalCopy` instantiation mode, where it doesn't work. --- .../src/middle/codegen_fn_attrs.rs | 2 ++ compiler/rustc_middle/src/mir/mono.rs | 1 + compiler/rustc_passes/messages.ftl | 4 +++ compiler/rustc_passes/src/check_attr.rs | 17 ++++++++++ compiler/rustc_passes/src/errors.rs | 5 +++ tests/ui/lint/inline-exported.rs | 30 ++++++++++++++++++ tests/ui/lint/inline-exported.stderr | 31 +++++++++++++++++++ .../target-feature/invalid-attribute.stderr | 12 +++---- 8 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 tests/ui/lint/inline-exported.rs create mode 100644 tests/ui/lint/inline-exported.stderr diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 311bc60c3cd3..a33b1fe283b8 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -172,6 +172,8 @@ impl CodegenFnAttrs { /// * `#[no_mangle]` is present /// * `#[export_name(...)]` is present /// * `#[linkage]` is present + /// + /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint. pub fn contains_extern_indicator(&self) -> bool { self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || self.export_name.is_some() diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 58d5c94d0332..2aa31761178f 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -117,6 +117,7 @@ impl<'tcx> MonoItem<'tcx> { // If the function is #[naked] or contains any other attribute that requires exactly-once // instantiation: + // We emit an unused_attributes lint for this case, which should be kept in sync if possible. let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); if codegen_fn_attrs.contains_extern_indicator() || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index b65430c34802..22631cc96d28 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -383,6 +383,10 @@ passes_inline_ignored_constants = .warn = {-passes_previously_accepted} .note = {-passes_see_issue(issue: "65833")} +passes_inline_ignored_for_exported = + `#[inline]` is ignored on externally exported functions + .help = externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]` + passes_inline_ignored_function_prototype = `#[inline]` is ignored on function prototypes diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5ada289cc209..5a76f7c586d4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -445,6 +445,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }); } } + + // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported. + if let Some(did) = hir_id.as_owner() + && self.tcx.def_kind(did).has_codegen_attrs() + && !matches!(attr.meta_item_list().as_deref(), Some([item]) if item.has_name(sym::never)) + { + let attrs = self.tcx.codegen_fn_attrs(did); + // Not checking naked as `#[inline]` is forbidden for naked functions anyways. + if attrs.contains_extern_indicator() { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span(), + errors::InlineIgnoredForExported {}, + ); + } + } } /// Checks that `#[coverage(..)]` is applied to a function/closure/method, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 9bb9b2353dc8..b282828a8ae9 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1435,6 +1435,11 @@ pub(crate) struct OnlyHasEffectOn { pub target_name: String, } +#[derive(LintDiagnostic)] +#[diag(passes_inline_ignored_for_exported)] +#[help] +pub(crate) struct InlineIgnoredForExported {} + #[derive(Diagnostic)] #[diag(passes_object_lifetime_err)] pub(crate) struct ObjectLifetimeErr { diff --git a/tests/ui/lint/inline-exported.rs b/tests/ui/lint/inline-exported.rs new file mode 100644 index 000000000000..69e322ef513a --- /dev/null +++ b/tests/ui/lint/inline-exported.rs @@ -0,0 +1,30 @@ +//! Ensure the unused_attributes lint fires for externally exported functions with `#[inline]`, +//! because `#[inline]` is ignored for such functions. + +#![crate_type = "lib"] + +#![feature(linkage)] +#![feature(naked_functions)] +#![deny(unused_attributes)] + +#[inline] +//~^ ERROR: `#[inline]` is ignored on externally exported functions +#[no_mangle] +fn no_mangle() {} + +#[inline] +//~^ ERROR: `#[inline]` is ignored on externally exported functions +#[export_name = "export_name"] +fn export_name() {} + +#[inline] +//~^ ERROR: `#[inline]` is ignored on externally exported functions +#[linkage = "external"] +fn external_linkage() {} + +#[inline] +fn normal() {} + +#[inline] +#[linkage = "internal"] // not exported +fn internal_linkage() {} diff --git a/tests/ui/lint/inline-exported.stderr b/tests/ui/lint/inline-exported.stderr new file mode 100644 index 000000000000..dcf63cc4090e --- /dev/null +++ b/tests/ui/lint/inline-exported.stderr @@ -0,0 +1,31 @@ +error: `#[inline]` is ignored on externally exported functions + --> $DIR/inline-exported.rs:10:1 + | +LL | #[inline] + | ^^^^^^^^^ + | + = help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]` +note: the lint level is defined here + --> $DIR/inline-exported.rs:8:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: `#[inline]` is ignored on externally exported functions + --> $DIR/inline-exported.rs:15:1 + | +LL | #[inline] + | ^^^^^^^^^ + | + = help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]` + +error: `#[inline]` is ignored on externally exported functions + --> $DIR/inline-exported.rs:20:1 + | +LL | #[inline] + | ^^^^^^^^^ + | + = help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index dc8a53041640..05ae49d6b0dd 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -98,6 +98,12 @@ LL | LL | trait Baz {} | ------------ not a function definition +error: cannot use `#[inline(always)]` with `#[target_feature]` + --> $DIR/invalid-attribute.rs:69:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:74:1 | @@ -163,12 +169,6 @@ error: malformed `target_feature` attribute input LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."` -error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:69:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - error[E0046]: not all trait items implemented, missing: `foo` --> $DIR/invalid-attribute.rs:81:1 | From ba4190cf7e919d7cc31c366906ded41874ef0439 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 17 Mar 2025 01:34:46 +0300 Subject: [PATCH 277/546] resolve: Avoid some unstable iteration 2 --- compiler/rustc_resolve/src/build_reduced_graph.rs | 1 - compiler/rustc_resolve/src/diagnostics.rs | 1 - compiler/rustc_resolve/src/ident.rs | 1 - compiler/rustc_resolve/src/imports.rs | 8 ++++---- compiler/rustc_resolve/src/late.rs | 5 ++--- compiler/rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_resolve/src/macros.rs | 3 +-- 8 files changed, 9 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 763e9207a126..42fe01b1c84c 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1115,7 +1115,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } }); } else { - #[allow(rustc::potential_query_instability)] // FIXME for ident in single_imports.iter().cloned() { let result = self.r.maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5361af98f3c7..7decc2a09721 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1468,7 +1468,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - #[allow(rustc::potential_query_instability)] // FIXME let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| { if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None } }); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 27d63198836a..5f0a2a597e9b 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -946,7 +946,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. - #[allow(rustc::potential_query_instability)] // FIXME for single_import in &resolution.single_imports { if ignore_import == Some(*single_import) { // This branch handles a cycle in single imports. diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 89b9a0743518..454460e10dc9 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -4,7 +4,7 @@ use std::cell::Cell; use std::mem; use rustc_ast::NodeId; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_errors::codes::*; use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; @@ -233,7 +233,7 @@ impl<'ra> ImportData<'ra> { pub(crate) struct NameResolution<'ra> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. - pub single_imports: FxHashSet>, + pub single_imports: FxIndexSet>, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option>, pub shadowed_glob: Option>, @@ -494,7 +494,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let key = BindingKey::new(target, ns); let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false); this.update_resolution(import.parent_scope.module, key, false, |_, resolution| { - resolution.single_imports.remove(&import); + resolution.single_imports.swap_remove(&import); }) }); self.record_use(target, dummy_binding, Used::Other); @@ -862,7 +862,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let key = BindingKey::new(target, ns); this.update_resolution(parent, key, false, |_, resolution| { - resolution.single_imports.remove(&import); + resolution.single_imports.swap_remove(&import); }); } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6056a69ee71f..dd663ce057e2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -672,7 +672,7 @@ struct DiagMetadata<'ast> { /// A list of labels as of yet unused. Labels will be removed from this map when /// they are used (in a `break` or `continue` statement) - unused_labels: FxHashMap, + unused_labels: FxIndexMap, /// Only used for better errors on `let x = { foo: bar };`. /// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only @@ -4779,7 +4779,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { Ok((node_id, _)) => { // Since this res is a label, it is never read. self.r.label_res_map.insert(expr.id, node_id); - self.diag_metadata.unused_labels.remove(&node_id); + self.diag_metadata.unused_labels.swap_remove(&node_id); } Err(error) => { self.report_error(label.ident.span, error); @@ -5201,7 +5201,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut late_resolution_visitor = LateResolutionVisitor::new(self); late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); visit::walk_crate(&mut late_resolution_visitor, krate); - #[allow(rustc::potential_query_instability)] // FIXME for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() { self.lint_buffer.buffer_lint( lint::builtin::UNUSED_LABELS, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3d666055a94f..69a7c81956aa 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1036,7 +1036,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { Applicability::MaybeIncorrect, ); // Do not lint against unused label when we suggest them. - self.diag_metadata.unused_labels.remove(node_id); + self.diag_metadata.unused_labels.swap_remove(node_id); } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ff31af0025b5..78153fd41740 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1137,7 +1137,7 @@ pub struct Resolver<'ra, 'tcx> { non_macro_attr: MacroData, local_macro_def_scopes: FxHashMap>, ast_transform_scopes: FxHashMap>, - unused_macros: FxHashMap, + unused_macros: FxIndexMap, /// A map from the macro to all its potentially unused arms. unused_macro_rules: FxIndexMap>, proc_macro_stubs: FxHashSet, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c4304a7a6df6..d577d7e80792 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -323,7 +323,6 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn check_unused_macros(&mut self) { - #[allow(rustc::potential_query_instability)] // FIXME for (_, &(node_id, ident)) in self.unused_macros.iter() { self.lint_buffer.buffer_lint( UNUSED_MACROS, @@ -576,7 +575,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match res { Res::Def(DefKind::Macro(_), def_id) => { if let Some(def_id) = def_id.as_local() { - self.unused_macros.remove(&def_id); + self.unused_macros.swap_remove(&def_id); if self.proc_macro_stubs.contains(&def_id) { self.dcx().emit_err(errors::ProcMacroSameCrate { span: path.span, From 7f2cb4c206510943fe87cae19e2f4e1b43f605e9 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 22 Mar 2025 18:22:45 +0800 Subject: [PATCH 278/546] Slightly reword triagebot ping message for `relnotes-interest-group` Now that there's also a meta relnotes tracking issue. --- triagebot.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 53cdd8b585b4..89986dffb4ab 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -174,8 +174,8 @@ label = "O-emscripten" [ping.relnotes-interest-group] message = """\ -Hi relnotes-interest-group, this PR adds release notes. Could you review this PR -if you have time? Thanks <3 +Hi relnotes-interest-group, this issue/PR could use some help in reviewing / +adjusting release notes. Could you take a look if available? Thanks <3 """ [prioritize] From c123adf860b008f703b325d013e7c7c0cc707d56 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 15:57:07 -0500 Subject: [PATCH 279/546] rustdoc js: add nonundef and use it to remove a ts-expect-error --- src/librustdoc/html/static/js/rustdoc.d.ts | 4 +++- src/librustdoc/html/static/js/search.js | 7 +++---- src/librustdoc/html/static/js/storage.js | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index e94c6beabea3..e2ebb1391837 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -6,8 +6,10 @@ declare global { /** Map from crate name to directory structure, for source view */ declare var srcIndex: Map; - /** Defined and documented in `main.js` */ + /** Defined and documented in `storage.js` */ declare function nonnull(x: T|null, msg: string|undefined); + /** Defined and documented in `storage.js` */ + declare function nonundef(x: T|undefined, msg: string|undefined); interface Window { /** Make the current theme easy to find */ currentTheme: HTMLLinkElement|null; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index c275127997ab..decb4807e884 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1,5 +1,5 @@ // ignore-tidy-filelength -/* global addClass, getNakedUrl, getSettingValue, getVar */ +/* global addClass, getNakedUrl, getSettingValue, getVar, nonnull, nonundef */ /* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */ "use strict"; @@ -338,9 +338,8 @@ function getFilteredNextElem(query, parserState, elems, isInGenerics) { // The type filter doesn't count as an element since it's a modifier. const typeFilterElem = elems.pop(); checkExtraTypeFilterCharacters(start, parserState); - // typeFilterElem is not null. If it was, the elems.length check would have fired. - // @ts-expect-error - parserState.typeFilter = typeFilterElem.normalizedPathLast; + // typeFilterElem is not undefined. If it was, the elems.length check would have fired. + parserState.typeFilter = nonundef(typeFilterElem).normalizedPathLast; parserState.pos += 1; parserState.totalElems -= 1; query.literalSearch = false; diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 748d2ef33c32..761137268947 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -43,6 +43,28 @@ function nonnull(x, msg) { } } +/** + * Assert that the passed value is not undefined, then return it. + * + * Takes an optional error message argument. + * + * Must be defined in this file, as it is loaded before all others. + * + * @template T + * @param {T|undefined} x + * @param {string=} msg + * @returns T + */ +// used in other files, not yet used in this one. +// eslint-disable-next-line no-unused-vars +function nonundef(x, msg) { + if (x === undefined) { + throw (msg || "unexpected null value!"); + } else { + return x; + } +} + /** * Get a configuration value. If it's not set, get the default. * From 43653c1835d59de69c6a5977b52df4708e6fddca Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 23 Mar 2025 22:13:52 +0300 Subject: [PATCH 280/546] linker: Fix staticlib naming for UEFI It uses `libname.a` instead of the standard MSVC naming `name.lib`. Naming for import libraries isn't touched. --- compiler/rustc_codegen_ssa/src/back/link.rs | 7 ++++++- compiler/rustc_codegen_ssa/src/back/linker.rs | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 74597f6263d4..99b4591051af 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1494,7 +1494,12 @@ fn print_native_static_libs( | NativeLibKind::Unspecified => { let verbatim = lib.verbatim; if sess.target.is_like_msvc { - Some(format!("{}{}", name, if verbatim { "" } else { ".lib" })) + let (prefix, suffix) = if verbatim { + ("", "") + } else { + (&*sess.target.staticlib_prefix, &*sess.target.staticlib_suffix) + }; + Some(format!("{prefix}{name}{suffix}")) } else if sess.target.linker_flavor.is_gnu() { Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name)) } else { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3f5e0c1bce9c..7f24d79b83b2 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -958,9 +958,13 @@ impl<'a> Linker for MsvcLinker<'a> { if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) { self.link_staticlib_by_path(&path, whole_archive); } else { - let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; - let suffix = if verbatim { "" } else { ".lib" }; - self.link_arg(format!("{prefix}{name}{suffix}")); + let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; + let (prefix, suffix) = if verbatim { + ("", "") + } else { + (&*self.sess.target.staticlib_prefix, &*self.sess.target.staticlib_suffix) + }; + self.link_arg(format!("{opts}{prefix}{name}{suffix}")); } } From 27e95f95e6dfcc1effa1f106c90fe53ab2236b76 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 23 Mar 2025 22:18:21 +0300 Subject: [PATCH 281/546] linker: Avoid calling `linker_and_flavor` twice --- compiler/rustc_codegen_ssa/src/back/link.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 99b4591051af..360f6d82dbc3 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -670,7 +670,7 @@ fn link_natively( ) { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); - let self_contained_components = self_contained_components(sess, crate_type); + let self_contained_components = self_contained_components(sess, crate_type, &linker_path); // On AIX, we ship all libraries as .a big_af archive // the expected format is lib.a(libname.so) for the actual @@ -1788,8 +1788,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { } // Returns true if linker is located within sysroot -fn detect_self_contained_mingw(sess: &Session) -> bool { - let (linker, _) = linker_and_flavor(sess); +fn detect_self_contained_mingw(sess: &Session, linker: &Path) -> bool { // Assume `-C linker=rust-lld` as self-contained mode if linker == Path::new("rust-lld") { return true; @@ -1797,7 +1796,7 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { let linker_with_extension = if cfg!(windows) && linker.extension().is_none() { linker.with_extension("exe") } else { - linker + linker.to_path_buf() }; for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let full_path = dir.join(&linker_with_extension); @@ -1812,7 +1811,11 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { /// Various toolchain components used during linking are used from rustc distribution /// instead of being found somewhere on the host system. /// We only provide such support for a very limited number of targets. -fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfContainedComponents { +fn self_contained_components( + sess: &Session, + crate_type: CrateType, + linker: &Path, +) -> LinkSelfContainedComponents { // Turn the backwards compatible bool values for `self_contained` into fully inferred // `LinkSelfContainedComponents`. let self_contained = @@ -1841,7 +1844,7 @@ fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfC LinkSelfContainedDefault::InferredForMingw => { sess.host == sess.target && sess.target.vendor != "uwp" - && detect_self_contained_mingw(sess) + && detect_self_contained_mingw(sess, linker) } } }; From 7c55782e0c1d01dfd7ceab3b4e682c12e24308d8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 25 Mar 2025 00:00:10 +0300 Subject: [PATCH 282/546] rustc_session: Add a helper function for obtaining staticlib prefix and suffix --- compiler/rustc_codegen_ssa/src/back/link.rs | 6 +----- compiler/rustc_codegen_ssa/src/back/linker.rs | 11 ++++------ compiler/rustc_metadata/src/native_libs.rs | 21 +++++++++---------- compiler/rustc_session/src/output.rs | 2 +- compiler/rustc_session/src/session.rs | 8 +++++++ 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 360f6d82dbc3..a564e0e391fe 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1494,11 +1494,7 @@ fn print_native_static_libs( | NativeLibKind::Unspecified => { let verbatim = lib.verbatim; if sess.target.is_like_msvc { - let (prefix, suffix) = if verbatim { - ("", "") - } else { - (&*sess.target.staticlib_prefix, &*sess.target.staticlib_suffix) - }; + let (prefix, suffix) = sess.staticlib_components(verbatim); Some(format!("{prefix}{name}{suffix}")) } else if sess.target.linker_flavor.is_gnu() { Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name)) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 7f24d79b83b2..bcf18cf57be2 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -450,9 +450,10 @@ impl<'a> GccLinker<'a> { // The output filename already contains `dll_suffix` so // the resulting import library will have a name in the // form of libfoo.dll.a - let mut implib_name = OsString::from(&*self.sess.target.staticlib_prefix); + let (prefix, suffix) = self.sess.staticlib_components(false); + let mut implib_name = OsString::from(prefix); implib_name.push(name); - implib_name.push(&*self.sess.target.staticlib_suffix); + implib_name.push(suffix); let mut out_implib = OsString::from("--out-implib="); out_implib.push(out_filename.with_file_name(implib_name)); self.link_arg(out_implib); @@ -959,11 +960,7 @@ impl<'a> Linker for MsvcLinker<'a> { self.link_staticlib_by_path(&path, whole_archive); } else { let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; - let (prefix, suffix) = if verbatim { - ("", "") - } else { - (&*self.sess.target.staticlib_prefix, &*self.sess.target.staticlib_suffix) - }; + let (prefix, suffix) = self.sess.staticlib_components(verbatim); self.link_arg(format!("{opts}{prefix}{name}{suffix}")); } } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 1671b7e06b0a..f63ae8079dcd 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -95,14 +95,14 @@ pub fn try_find_native_static_library( name: &str, verbatim: bool, ) -> Option { + let default = sess.staticlib_components(verbatim); let formats = if verbatim { - vec![("".into(), "".into())] + vec![default] } else { - let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone()); // On Windows, static libraries sometimes show up as libfoo.a and other // times show up as foo.lib - let unix = ("lib".into(), ".a".into()); - if os == unix { vec![os] } else { vec![os, unix] } + let unix = ("lib", ".a"); + if default == unix { vec![default] } else { vec![default, unix] } }; walk_native_lib_search_dirs(sess, None, |dir, is_framework| { @@ -124,18 +124,17 @@ pub fn try_find_native_dynamic_library( name: &str, verbatim: bool, ) -> Option { + let default = sess.staticlib_components(verbatim); let formats = if verbatim { - vec![("".into(), "".into())] + vec![default] } else { // While the official naming convention for MSVC import libraries - // is foo.lib... - let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone()); - // ... Meson follows the libfoo.dll.a convention to + // is foo.lib, Meson follows the libfoo.dll.a convention to // disambiguate .a for static libraries - let meson = ("lib".into(), ".dll.a".into()); + let meson = ("lib", ".dll.a"); // and MinGW uses .a altogether - let mingw = ("lib".into(), ".a".into()); - vec![os, meson, mingw] + let mingw = ("lib", ".a"); + vec![default, meson, mingw] }; walk_native_lib_search_dirs(sess, None, |dir, is_framework| { diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index b37a80274c0c..a24919e434cc 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -103,7 +103,7 @@ pub fn filename_for_input( OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))) } CrateType::Staticlib => { - let (prefix, suffix) = (&sess.target.staticlib_prefix, &sess.target.staticlib_suffix); + let (prefix, suffix) = sess.staticlib_components(false); OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))) } CrateType::Executable => { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1c9adea281dc..a87b1961a995 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -586,6 +586,14 @@ impl Session { .or(self.target.options.default_visibility) .unwrap_or(SymbolVisibility::Interposable) } + + pub fn staticlib_components(&self, verbatim: bool) -> (&str, &str) { + if verbatim { + ("", "") + } else { + (&*self.target.staticlib_prefix, &*self.target.staticlib_suffix) + } + } } // JUSTIFICATION: defn of the suggested wrapper fns From ccd95ac7fde43d6a0380895086efca3a75e1ac35 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 16:19:05 -0500 Subject: [PATCH 283/546] search.js: improve typechecking by avoiding Map.has --- src/librustdoc/html/static/js/search.js | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index decb4807e884..a8c6193a4c13 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1310,10 +1310,9 @@ class NameTrie { let sste; if (substart >= 2) { const tail = name.substring(substart - 2, substart + 1); - if (tailTable.has(tail)) { - // it's not undefined - // @ts-expect-error - sste = tailTable.get(tail); + const entry = tailTable.get(tail); + if (entry !== undefined) { + sste = entry; } else { sste = []; tailTable.set(tail, sste); @@ -1337,10 +1336,9 @@ class NameTrie { new Lev1TParametricDescription(name.length); this.searchLev(name, 0, levParams, results); const tail = name.substring(0, 3); - if (tailTable.has(tail)) { - // it's not undefined - // @ts-expect-error - for (const entry of tailTable.get(tail)) { + const list = tailTable.get(tail); + if (list !== undefined) { + for (const entry of list) { entry.searchSubstringPrefix(name, 3, results); } } @@ -1599,10 +1597,8 @@ class DocSearch { return null; } - if (this.typeNameIdMap.has(name)) { - /** @type {{id: number, assocOnly: boolean}} */ - // @ts-expect-error - const obj = this.typeNameIdMap.get(name); + const obj = this.typeNameIdMap.get(name); + if (obj !== undefined) { obj.assocOnly = !!(isAssocType && obj.assocOnly); return obj.id; } else { @@ -2145,7 +2141,6 @@ class DocSearch { const name = elem[1]; let path = null; if (elem.length > 2 && elem[2] !== null) { - // @ts-expect-error path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath; lastPath = path; } From e9a5470aabcf9dbfd8c463b3156332d75a3881ea Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 16:56:55 -0500 Subject: [PATCH 284/546] search.js: refactor handling of rawPaths in buildIndex --- src/librustdoc/html/static/js/search.js | 42 +++++++++++++------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index a8c6193a4c13..bac174869f57 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2077,7 +2077,8 @@ class DocSearch { descIndex += 1; } - // a String of one character item type codes + // see `RawSearchIndexCrate` in `rustdoc.d.ts` for a more + // up to date description of these fields const itemTypes = crateCorpus.t; // an array of (String) item names const itemNames = crateCorpus.n; @@ -2094,8 +2095,6 @@ class DocSearch { const itemParentIdxDecoder = new VlqHexDecoder(crateCorpus.i, noop => noop); // a map Number, string for impl disambiguators const implDisambiguator = new Map(crateCorpus.b); - // an array of [(Number) item type, - // (String) name] const rawPaths = crateCorpus.p; const aliases = crateCorpus.a; // an array of [(Number) item index, @@ -2134,29 +2133,32 @@ class DocSearch { // convert `rawPaths` entries into object form // generate normalizedPaths for function search mode let len = rawPaths.length; - let lastPath = itemPaths.get(0); + const lastPathU = itemPaths.get(0); + let lastPath = lastPathU === undefined ? null : lastPathU; for (let i = 0; i < len; ++i) { const elem = rawPaths[i]; const ty = elem[0]; const name = elem[1]; - let path = null; - if (elem.length > 2 && elem[2] !== null) { - path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath; - lastPath = path; - } - let exactPath = elem.length > 3 && elem[3] !== null ? - // @ts-expect-error - itemPaths.get(elem[3]) : - path; + /** + * @param {2|3} idx + * @param {string|null} if_null + * @param {string|null} if_not_found + * @returns {string|null} + */ + const elemPath = (idx, if_null, if_not_found) => { + if (elem.length > idx && elem[idx] !== undefined) { + const p = itemPaths.get(elem[idx]); + if (p !== undefined) { + return p; + } + return if_not_found; + } + return if_null; + }; + const path = elemPath(2, lastPath, null); + const exactPath = elemPath(3, path, path); const unboxFlag = elem.length > 4 && !!elem[4]; - if (path === undefined) { - path = null; - } - if (exactPath === undefined) { - exactPath = null; - } - lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath, unboxFlag }); paths[i] = { ty, name, path, exactPath, unboxFlag }; } From 49bf6ca79eb7379e367578cba910d1e1cbacc7d1 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 17:05:35 -0500 Subject: [PATCH 285/546] search.js: add undef2null and eliminate more @ts-expect-error --- src/librustdoc/html/static/js/search.js | 31 +++++++++++++++++-------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index bac174869f57..1817d91af79a 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -33,6 +33,20 @@ function onEachBtwn(arr, func, funcBtwn) { } } +/** + * Convert any `undefined` to `null`. + * + * @template T + * @param {T|undefined} x + * @returns {T|null} + */ +function undef2null(x) { + if (x !== undefined) { + return x; + } + return null; +} + // ==================== Core search logic begin ==================== // This mapping table should match the discriminants of // `rustdoc::formats::item_type::ItemType` type in Rust. @@ -2133,8 +2147,7 @@ class DocSearch { // convert `rawPaths` entries into object form // generate normalizedPaths for function search mode let len = rawPaths.length; - const lastPathU = itemPaths.get(0); - let lastPath = lastPathU === undefined ? null : lastPathU; + let lastPath = undef2null(itemPaths.get(0)); for (let i = 0; i < len; ++i) { const elem = rawPaths[i]; const ty = elem[0]; @@ -2192,12 +2205,11 @@ class DocSearch { } const name = itemNames[i] === "" ? lastName : itemNames[i]; const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase(); - /** @type {string} */ - // @ts-expect-error - const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath; - const paramNames = itemParamNames.has(i) ? - // @ts-expect-error - itemParamNames.get(i).split(",") : + const pathU = itemPaths.get(i); + const path = pathU !== undefined ? pathU : lastPath; + const paramNameString = itemParamNames.get(i); + const paramNames = paramNameString !== undefined ? + paramNameString.split(",") : lastParamNames; const type = itemFunctionDecoder.next(); if (type !== null) { @@ -2239,8 +2251,7 @@ class DocSearch { word, normalizedName, bitIndex, - implDisambiguator: implDisambiguator.has(i) ? - implDisambiguator.get(i) : null, + implDisambiguator: undef2null(implDisambiguator.get(i)), }; this.nameTrie.insert(normalizedName, id, this.tailTable); id += 1; From 1a8ddee65c2a36941d8fe3806beff727a3834d1e Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Mon, 24 Mar 2025 23:01:11 +0100 Subject: [PATCH 286/546] Add target maintainer information for powerpc64-unknown-linux-musl We intend to fix the outstanding issues on the target and eventually promote it to tier 2. We have the capacity to maintain this target in the future and already perform regular builds of rustc for this target. Currently, all host tools except miri build fine, but I have a patch for libffi-sys to make miri also compile fine for this target that is pending review [1]. While at it, add an option for the musl root for this target. [1]: https://github.com/tov/libffi-rs/pull/100 Signed-off-by: Jens Reidel --- src/bootstrap/configure.py | 5 ++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 +- .../powerpc64-unknown-linux-musl.md | 52 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index f6afe0967240..0d4d6e0ff54c 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -249,6 +249,11 @@ v( "target.mips64el-unknown-linux-muslabi64.musl-root", "mips64el-unknown-linux-muslabi64 install directory", ) +v( + "musl-root-powerpc64", + "target.powerpc64-unknown-linux-musl.musl-root", + "powerpc64-unknown-linux-musl install directory", +) v( "musl-root-powerpc64le", "target.powerpc64le-unknown-linux-musl.musl-root", diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 542ee9fffce3..fee61933f5cf 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -72,6 +72,7 @@ - [powerpc-unknown-linux-gnuspe](platform-support/powerpc-unknown-linux-gnuspe.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [powerpc64-unknown-linux-musl](platform-support/powerpc64-unknown-linux-musl.md) - [powerpc64le-unknown-linux-gnu](platform-support/powerpc64le-unknown-linux-gnu.md) - [powerpc64le-unknown-linux-musl](platform-support/powerpc64le-unknown-linux-musl.md) - [riscv32e\*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e8f8684740ac..3a8f84069ccc 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -356,7 +356,7 @@ target | std | host | notes [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) [`powerpc64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64 FreeBSD (ELFv2) -`powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3 +[`powerpc64-unknown-linux-musl`](platform-support/powerpc64-unknown-linux-musl.md) | ✓ | ✓ | PPC64 Linux (kernel 4.19, musl 1.2.3) [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`powerpc64le-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64LE FreeBSD diff --git a/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md new file mode 100644 index 000000000000..0f78dcc089cc --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md @@ -0,0 +1,52 @@ +# powerpc64-unknown-linux-musl + +**Tier: 3** + +Target for 64-bit big endian PowerPC Linux programs using musl libc. +This target uses the ELF v2 ABI. + +## Target maintainers + +- [@Gelbpunkt](https://github.com/Gelbpunkt) +- [@famfo](https://github.com/famfo) +- [@neuschaefer](https://github.com/neuschaefer) + +## Requirements + +Building the target itself requires a 64-bit big endian PowerPC compiler that +is supported by `cc-rs`. + +## Building the target + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["powerpc64-unknown-linux-musl"] +``` + +Make sure your C compiler is included in `$PATH`, then add it to the +`bootstrap.toml`: + +```toml +[target.powerpc64-unknown-linux-musl] +cc = "powerpc64-linux-musl-gcc" +cxx = "powerpc64-linux-musl-g++" +ar = "powerpc64-linux-musl-ar" +linker = "powerpc64-linux-musl-gcc" +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will first need to build Rust with the target enabled (see +"Building the target" above). + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +This target can be tested as normal with `x.py` on a 64-bit big endian PowerPC +host or via QEMU emulation. From 1af16cd135dd4e62f8e68abfb0587b57eb16ce6e Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 17:31:39 -0500 Subject: [PATCH 287/546] search.js(query parser): rethrow error if it isn't a string array only errors that are string arrays are intended to be shown to the user, other errors are bugs, and will be shown in the console as usual. --- src/librustdoc/html/static/js/search.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 1817d91af79a..15bb3816f0b5 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2489,9 +2489,13 @@ class DocSearch { } } catch (err) { query = newParsedQuery(userQuery); - // is string list - // @ts-expect-error - query.error = err; + if (Array.isArray(err) && err.every((elem) => typeof elem == 'string')) { + query.error = err; + } else { + // rethrow the error if it isn't a string array + throw err; + } + return query; } if (!query.literalSearch) { From 8af647c04dbd300518f85619c9e9ce7a94d558c4 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 17:36:16 -0500 Subject: [PATCH 288/546] search.js: remove another Map.has() and @ts-expect-error --- src/librustdoc/html/static/js/search.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 15bb3816f0b5..2317f157bb93 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2583,9 +2583,9 @@ class DocSearch { if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1 && elem.generics.length === 0 && elem.bindings.size === 0) || elem.typeFilter === TY_GENERIC) { - if (genericSymbols.has(elem.normalizedPathLast)) { - // @ts-expect-error - elem.id = genericSymbols.get(elem.normalizedPathLast); + const id = genericSymbols.get(elem.normalizedPathLast); + if (id !== undefined) { + elem.id = id; } else { elem.id = -(genericSymbols.size + 1); genericSymbols.set(elem.normalizedPathLast, elem.id); From 714be45b974ae16a010503587e4628bc72fd107b Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 18:11:43 -0500 Subject: [PATCH 289/546] search.js: refactor transformResults --- src/librustdoc/html/static/js/rustdoc.d.ts | 12 +++++++-- src/librustdoc/html/static/js/search.js | 29 +++++++++++++--------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index e2ebb1391837..91a58fab86ef 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -257,12 +257,20 @@ declare namespace rustdoc { ty: number, type?: FunctionSearchType, paramNames?: string[], - displayType: Promise>>|null, - displayTypeMappedNames: Promise]>>|null, + displayTypeSignature: Promise | null, item: Row, dontValidate?: boolean, } + /** + * output of `formatDisplayTypeSignature` + */ + interface DisplayTypeSignature { + type: Array, + mappedNames: Map, + whereClause: Map>, + } + /** * A pair of [inputs, outputs], or 0 for null. This is stored in the search index. * The JavaScript deserializes this into FunctionSearchType. diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 2317f157bb93..bd09631d487b 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2777,15 +2777,28 @@ class DocSearch { for (const result of results) { if (result.id !== -1) { const res = buildHrefAndPath(this.searchIndex[result.id]); + // many of these properties don't strictly need to be + // copied over, but copying them over satisfies tsc, + // and hopefully plays nice with the shape optimization + // of the browser engine. + /** @type {rustdoc.ResultObject} */ const obj = Object.assign({ + parent: result.parent, + type: result.type, dist: result.dist, + path_dist: result.path_dist, + index: result.index, + desc: result.desc, + item: result.item, displayPath: pathSplitter(res[0]), + fullPath: "", + href: "", + displayTypeSignature: null, }, this.searchIndex[result.id]); // To be sure than it some items aren't considered as duplicate. - // @ts-expect-error - obj.fullPath = res[2] + "|" + obj.ty; - // @ts-expect-error + obj.fullPath = res[2] + "|" + obj.ty + if (duplicates.has(obj.fullPath)) { continue; } @@ -2798,18 +2811,15 @@ class DocSearch { if (duplicates.has(res[2] + "|" + TY_IMPORT)) { continue; } - // @ts-expect-error duplicates.add(obj.fullPath); duplicates.add(res[2]); if (typeInfo !== null) { - // @ts-expect-error obj.displayTypeSignature = // @ts-expect-error this.formatDisplayTypeSignature(obj, typeInfo); } - // @ts-expect-error obj.href = res[1]; out.push(obj); if (out.length >= MAX_RESULTS) { @@ -2817,7 +2827,6 @@ class DocSearch { } } } - // @ts-expect-error return out; }; @@ -2830,11 +2839,7 @@ class DocSearch { * * @param {rustdoc.ResultObject} obj * @param {"sig"|"elems"|"returned"|null} typeInfo - * @returns {Promise<{ - * "type": Array, - * "mappedNames": Map, - * "whereClause": Map>, - * }>} + * @returns {Promise} */ this.formatDisplayTypeSignature = async(obj, typeInfo) => { const objType = obj.type; From ca514c1a13b419606fe051ec897a25a07dc7aa26 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 18:20:51 -0500 Subject: [PATCH 290/546] search.js: fix signature of pushText --- src/librustdoc/html/static/js/search.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index bd09631d487b..f714f361d4b9 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2901,7 +2901,7 @@ class DocSearch { const whereClause = new Map(); const fnParamNames = obj.paramNames || []; - // @ts-expect-error + /** @type {string[]} */ const queryParamNames = []; /** * Recursively writes a map of IDs to query generic names, @@ -2934,7 +2934,7 @@ class DocSearch { * index 2 is not highlighted, etc. * * @param {{name?: string, highlighted?: boolean}} fnType - input - * @param {[string]} result + * @param {string[]} result */ const pushText = (fnType, result) => { // If !!(result.length % 2) == false, then pushing a new slot starts an even @@ -2946,7 +2946,6 @@ class DocSearch { // needs coerced to a boolean. if (!!(result.length % 2) === !!fnType.highlighted) { result.push(""); - // @ts-expect-error } else if (result.length === 0 && !!fnType.highlighted) { result.push(""); result.push(""); @@ -2960,7 +2959,7 @@ class DocSearch { * or a trait bound on Fn, FnMut, or FnOnce. * * @param {rustdoc.HighlightedFunctionType} fnType - input - * @param {[string]} result + * @param {string[]} result */ const writeHof = (fnType, result) => { const hofOutput = fnType.bindings.get(this.typeNameIdOfOutput) || []; @@ -3000,7 +2999,7 @@ class DocSearch { * Returns `false` if the supplied type isn't special. * * @param {rustdoc.HighlightedFunctionType} fnType - * @param {[string]} result + * @param {string[]} result */ const writeSpecialPrimitive = (fnType, result) => { if (fnType.id === this.typeNameIdOfArray || fnType.id === this.typeNameIdOfSlice || @@ -3047,7 +3046,7 @@ class DocSearch { * updating the where clause and generic type param map. * * @param {rustdoc.HighlightedFunctionType} fnType - * @param {[string]} result + * @param {string[]} result */ const writeFn = (fnType, result) => { if (fnType.id !== null && fnType.id < 0) { @@ -3065,7 +3064,6 @@ class DocSearch { for (const [queryId, fnId] of mgens) { if (fnId === fnType.id) { mappedNames.set( - // @ts-expect-error queryParamNames[-1 - queryId], fnParamNames[-1 - fnType.id], ); @@ -3080,7 +3078,6 @@ class DocSearch { const where = []; onEachBtwn( fnType.generics, - // @ts-expect-error nested => writeFn(nested, where), // @ts-expect-error () => pushText({ name: " + ", highlighted: false }, where), @@ -3115,7 +3112,6 @@ class DocSearch { // shown in the where clause and name mapping output, but is // redundant in this spot for (const value of values) { - // @ts-expect-error writeFn(value, []); } return true; From 7f141985ff337926639db092b2ecb5b05a763cd7 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 18:24:07 -0500 Subject: [PATCH 291/546] search.js: use @type instead of @ts-expect-error --- src/librustdoc/html/static/js/search.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index f714f361d4b9..5dda3d34e104 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3153,26 +3153,22 @@ class DocSearch { } } }; - // @ts-expect-error + /** @type {string[]} */ const type = []; onEachBtwn( fnInputs, - // @ts-expect-error fnType => writeFn(fnType, type), // @ts-expect-error () => pushText({ name: ", ", highlighted: false }, type), ); - // @ts-expect-error pushText({ name: " -> ", highlighted: false }, type); onEachBtwn( fnOutput, - // @ts-expect-error fnType => writeFn(fnType, type), // @ts-expect-error () => pushText({ name: ", ", highlighted: false }, type), ); - // @ts-expect-error return {type, mappedNames, whereClause}; }; From 3245e7b069b52d16e82065f05c7c968fab7b3f2b Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 18:27:42 -0500 Subject: [PATCH 292/546] search.js: fix return type of unifyFunctionTypes --- src/librustdoc/html/static/js/search.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 5dda3d34e104..ba672ffb7a41 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3483,8 +3483,7 @@ class DocSearch { } } } - // @ts-expect-error - return false; + return null; } // Multiple element recursive case From 4a00a8449e3603823f5d0c5d01afc4425ed4b448 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 18:29:21 -0500 Subject: [PATCH 293/546] search.js: give type to unifiedGenericsMgens --- src/librustdoc/html/static/js/search.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index ba672ffb7a41..1ba34027a0af 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3539,7 +3539,7 @@ class DocSearch { } /** @type {rustdoc.HighlightedFunctionType[]|null} */ let unifiedGenerics = []; - // @ts-expect-error + /** @type {null|Map} */ let unifiedGenericsMgens = null; /** @type {rustdoc.HighlightedFunctionType[]|null} */ const passesUnification = unifyFunctionTypes( @@ -3593,7 +3593,6 @@ class DocSearch { // @ts-expect-error queryElem.bindings.get(k), whereClause, - // @ts-expect-error unifiedGenericsMgens, solutionCb, unboxingDepth, From 523f413a738822d0312ea82ea69b21b6900af68a Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 18:40:06 -0500 Subject: [PATCH 294/546] search.js: give type annotation to newSolutions --- src/librustdoc/html/static/js/search.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 1ba34027a0af..a54104c3809e 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3990,7 +3990,7 @@ class DocSearch { } const fnTypeBindings = fnType.bindings.get(name); mgensSolutionSet = mgensSolutionSet.flatMap(mgens => { - // @ts-expect-error + /** @type{Array | null>} */ const newSolutions = []; unifyFunctionTypes( // @ts-expect-error @@ -4006,7 +4006,6 @@ class DocSearch { }, unboxingDepth, ); - // @ts-expect-error return newSolutions; }); } @@ -4254,6 +4253,7 @@ class DocSearch { return false; } + // this does not yet have a type in `rustdoc.d.ts`. // @ts-expect-error function createAliasFromItem(item) { return { From 93b3be33001d15e85b38d99560eaa337812ee90a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Mar 2025 17:09:48 +0000 Subject: [PATCH 295/546] Instantiate binder before registering nested obligations for auto/built-in traits --- .../src/traits/select/confirmation.rs | 37 +++++++------------ .../src/traits/select/mod.rs | 11 ++---- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4404324d5cd7..a66c958c1097 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -266,9 +266,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else { bug!("unexpected builtin trait {:?}", trait_def) }; - let BuiltinImplConditions::Where(nested) = conditions else { + let BuiltinImplConditions::Where(types) = conditions else { bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation); }; + let types = self.infcx.enter_forall_and_leak_universe(types); let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); self.collect_predicates_for_types( @@ -276,7 +277,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause, obligation.recursion_depth + 1, trait_def, - nested, + types, ) } else { PredicateObligations::new() @@ -444,37 +445,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { - debug!(?obligation, "confirm_auto_impl_candidate"); - - let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); - let types = self.constituent_types_for_ty(self_ty)?; - Ok(self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types)) - } - - /// See `confirm_auto_impl_candidate`. - fn vtable_auto_impl( - &mut self, - obligation: &PolyTraitObligation<'tcx>, - trait_def_id: DefId, - nested: ty::Binder<'tcx, Vec>>, - ) -> PredicateObligations<'tcx> { - debug!(?nested, "vtable_auto_impl"); ensure_sufficient_stack(|| { - let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive); + let self_ty = + obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); + + let types = self.constituent_types_for_ty(self_ty)?; + let types = self.infcx.enter_forall_and_leak_universe(types); + + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); let obligations = self.collect_predicates_for_types( obligation.param_env, cause, obligation.recursion_depth + 1, - trait_def_id, - nested, + obligation.predicate.def_id(), + types, ); - debug!(?obligations, "vtable_auto_impl"); - - obligations + Ok(obligations) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e1adabbeaa66..e439df76cd4b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2370,7 +2370,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { cause: ObligationCause<'tcx>, recursion_depth: usize, trait_def_id: DefId, - types: ty::Binder<'tcx, Vec>>, + types: Vec>, ) -> PredicateObligations<'tcx> { // Because the types were potentially derived from // higher-ranked obligations they may reference late-bound @@ -2387,13 +2387,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy` types - .as_ref() - .skip_binder() // binder moved -\ - .iter() - .flat_map(|ty| { - let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ - - let placeholder_ty = self.infcx.enter_forall_and_leak_universe(ty); + .into_iter() + .flat_map(|placeholder_ty| { let Normalized { value: normalized_ty, mut obligations } = ensure_sufficient_stack(|| { normalize_with_depth( From 1b8b09a01d6b0acf24b070cd997bff6cb739dfec Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 24 Mar 2025 19:11:55 -0500 Subject: [PATCH 296/546] search.js: fix whitespace --- src/librustdoc/html/static/js/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index a54104c3809e..651d12bb2e90 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2798,7 +2798,7 @@ class DocSearch { // To be sure than it some items aren't considered as duplicate. obj.fullPath = res[2] + "|" + obj.ty - + if (duplicates.has(obj.fullPath)) { continue; } From 817e2c598d01c1c4abc7ae67731432df2cf1047c Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 1 Feb 2025 17:46:40 -0500 Subject: [PATCH 297/546] Remove InstanceKind::generates_cgu_internal_copy --- .../src/back/symbol_export.rs | 13 +--- compiler/rustc_middle/src/mir/mono.rs | 75 ++++++++++++++++--- compiler/rustc_middle/src/ty/instance.rs | 44 ----------- 3 files changed, 68 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index f8f7bb2dbc69..76b0a566f8e7 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -93,16 +93,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap { GlobalAsm(ItemId), } +fn opt_incr_drop_glue_mode<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InstantiationMode { + // Non-ADTs can't have a Drop impl. This case is mostly hit by closures whose captures require + // dropping. + let ty::Adt(adt_def, _) = ty.kind() else { + return InstantiationMode::LocalCopy; + }; + + // Types that don't have a direct Drop impl, but have fields that require dropping. + let Some(dtor) = adt_def.destructor(tcx) else { + // We use LocalCopy for drops of enums only; this code is inherited from + // https://github.com/rust-lang/rust/pull/67332 and the theory is that we get to optimize + // out code like drop_in_place(Option::None) before crate-local ThinLTO, which improves + // compile time. At the time of writing, simply removing this entire check does seem to + // regress incr-opt compile times. But it sure seems like a more sophisticated check could + // do better here. + if adt_def.is_enum() { + return InstantiationMode::LocalCopy; + } else { + return InstantiationMode::GloballyShared { may_conflict: true }; + } + }; + + // We've gotten to a drop_in_place for a type that directly implements Drop. + // The drop glue is a wrapper for the Drop::drop impl, and we are an optimized build, so in an + // effort to coordinate with the mode that the actual impl will get, we make the glue also + // LocalCopy. + if tcx.cross_crate_inlinable(dtor.did) { + InstantiationMode::LocalCopy + } else { + InstantiationMode::GloballyShared { may_conflict: true } + } +} + impl<'tcx> MonoItem<'tcx> { /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims). pub fn is_user_defined(&self) -> bool { @@ -123,16 +156,36 @@ impl<'tcx> MonoItem<'tcx> { return InstantiationMode::GloballyShared { may_conflict: false }; } - // FIXME: The logic for which functions are permitted to get LocalCopy is actually spread - // across 4 functions: - // * cross_crate_inlinable(def_id) - // * InstanceKind::requires_inline - // * InstanceKind::generate_cgu_internal_copy - // * MonoItem::instantiation_mode - // Since reachable_non_generics calls InstanceKind::generates_cgu_internal_copy to decide - // which symbols this crate exports, we are obligated to only generate LocalCopy when - // generates_cgu_internal_copy returns true. - if !instance.def.generates_cgu_internal_copy(tcx) { + // This is technically a heuristic even though it's in the "not a heuristic" part of + // instantiation mode selection. + // It is surely possible to untangle this; the root problem is that the way we instantiate + // InstanceKind other than Item is very complicated. + // + // The fallback case is to give everything else GloballyShared at OptLevel::No and + // LocalCopy at all other opt levels. This is a good default, except for one specific build + // configuration: Optimized incremental builds. + // In the current compiler architecture there is a fundamental tension between + // optimizations (which want big CGUs with as many things LocalCopy as possible) and + // incrementality (which wants small CGUs with as many things GloballyShared as possible). + // The heuristics implemented here do better than a completely naive approach in the + // compiler benchmark suite, but there is no reason to believe they are optimal. + if let InstanceKind::DropGlue(_, Some(ty)) = instance.def { + if tcx.sess.opts.optimize == OptLevel::No { + return InstantiationMode::GloballyShared { may_conflict: false }; + } + if tcx.sess.opts.incremental.is_none() { + return InstantiationMode::LocalCopy; + } + return opt_incr_drop_glue_mode(tcx, ty); + } + + // We need to ensure that we do not decide the InstantiationMode of an exported symbol is + // LocalCopy. Since exported symbols are computed based on the output of + // cross_crate_inlinable, we are beholden to our previous decisions. + // + // Note that just like above, this check for requires_inline is technically a heuristic + // even though it's in the "not a heuristic" part of instantiation mode selection. + if !tcx.cross_crate_inlinable(instance.def_id()) && !instance.def.requires_inline(tcx) { return InstantiationMode::GloballyShared { may_conflict: false }; } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index b7a648aae3f1..c557178096ef 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -301,50 +301,6 @@ impl<'tcx> InstanceKind<'tcx> { ) } - /// Returns `true` if the machine code for this instance is instantiated in - /// each codegen unit that references it. - /// Note that this is only a hint! The compiler can globally decide to *not* - /// do this in order to speed up compilation. CGU-internal copies are - /// only exist to enable inlining. If inlining is not performed (e.g. at - /// `-Copt-level=0`) then the time for generating them is wasted and it's - /// better to create a single copy with external linkage. - pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool { - if self.requires_inline(tcx) { - return true; - } - if let ty::InstanceKind::DropGlue(.., Some(ty)) - | ty::InstanceKind::AsyncDropGlueCtorShim(.., Some(ty)) = *self - { - // Drop glue generally wants to be instantiated at every codegen - // unit, but without an #[inline] hint. We should make this - // available to normal end-users. - if tcx.sess.opts.incremental.is_none() { - return true; - } - // When compiling with incremental, we can generate a *lot* of - // codegen units. Including drop glue into all of them has a - // considerable compile time cost. - // - // We include enums without destructors to allow, say, optimizing - // drops of `Option::None` before LTO. We also respect the intent of - // `#[inline]` on `Drop::drop` implementations. - return ty.ty_adt_def().is_none_or(|adt_def| { - match *self { - ty::InstanceKind::DropGlue(..) => adt_def.destructor(tcx).map(|dtor| dtor.did), - ty::InstanceKind::AsyncDropGlueCtorShim(..) => { - adt_def.async_destructor(tcx).map(|dtor| dtor.ctor) - } - _ => unreachable!(), - } - .map_or_else(|| adt_def.is_enum(), |did| tcx.cross_crate_inlinable(did)) - }); - } - if let ty::InstanceKind::ThreadLocalShim(..) = *self { - return false; - } - tcx.cross_crate_inlinable(self.def_id()) - } - pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { match *self { InstanceKind::Item(def_id) | InstanceKind::Virtual(def_id, _) => { From 1a6266340e53e3f663b49f71a14461dafa47de47 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 10:51:42 +1100 Subject: [PATCH 298/546] Add a test with an empty crate name. This error was untested. --- tests/ui/attributes/crate-name-empty.rs | 5 +++++ tests/ui/attributes/crate-name-empty.stderr | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/ui/attributes/crate-name-empty.rs create mode 100644 tests/ui/attributes/crate-name-empty.stderr diff --git a/tests/ui/attributes/crate-name-empty.rs b/tests/ui/attributes/crate-name-empty.rs new file mode 100644 index 000000000000..dfba77a52def --- /dev/null +++ b/tests/ui/attributes/crate-name-empty.rs @@ -0,0 +1,5 @@ +// Ensure we reject `#![crate_name = ""]`. + +#![crate_name = ""] //~ ERROR crate name must not be empty + +fn main() {} diff --git a/tests/ui/attributes/crate-name-empty.stderr b/tests/ui/attributes/crate-name-empty.stderr new file mode 100644 index 000000000000..509a42d05f71 --- /dev/null +++ b/tests/ui/attributes/crate-name-empty.stderr @@ -0,0 +1,8 @@ +error: crate name must not be empty + --> $DIR/crate-name-empty.rs:3:1 + | +LL | #![crate_name = ""] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From bd61e0129f4ff393ad350f05442a9f1ac3ddbd44 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 24 Mar 2025 18:58:18 +1100 Subject: [PATCH 299/546] Use `Ident::dummy()` in `dummy_annotatable`. This is exactly the kind of case `Ident::dummy()` is for. --- compiler/rustc_builtin_macros/src/derive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 2653a9f48b9b..e259f5b3955b 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -103,7 +103,7 @@ impl MultiItemModifier for Expander { fn dummy_annotatable() -> Annotatable { Annotatable::GenericParam(ast::GenericParam { id: ast::DUMMY_NODE_ID, - ident: Ident::empty(), + ident: Ident::dummy(), attrs: Default::default(), bounds: Default::default(), is_placeholder: false, From 2469ab195a558b3a09b5ef4319ea8a3f989b621f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 24 Mar 2025 18:59:44 +1100 Subject: [PATCH 300/546] Use `Option` in `panic_call`. Instead of `kw::Empty`. It makes it clearer that this is a name that is searched for and might not be found. --- compiler/rustc_lint/src/non_fmt_panic.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index ac9f8d92dacb..16c061008085 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -7,7 +7,7 @@ use rustc_parse_format::{ParseMode, Parser, Piece}; use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; -use rustc_span::{InnerSpan, Span, Symbol, hygiene, kw, sym}; +use rustc_span::{InnerSpan, Span, Symbol, hygiene, sym}; use rustc_trait_selection::infer::InferCtxtExt; use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused}; @@ -167,7 +167,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc .get_diagnostic_item(sym::Debug) .is_some_and(|t| infcx.type_implements_trait(t, [ty], param_env).may_apply()); - let suggest_panic_any = !is_str && panic == sym::std_panic_macro; + let suggest_panic_any = !is_str && panic == Some(sym::std_panic_macro); let fmt_applicability = if suggest_panic_any { // If we can use panic_any, use that as the MachineApplicable suggestion. @@ -297,10 +297,13 @@ fn find_delimiters(cx: &LateContext<'_>, span: Span) -> Option<(Span, Span, char )) } -fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol, Symbol) { +fn panic_call<'tcx>( + cx: &LateContext<'tcx>, + f: &'tcx hir::Expr<'tcx>, +) -> (Span, Option, Symbol) { let mut expn = f.span.ctxt().outer_expn_data(); - let mut panic_macro = kw::Empty; + let mut panic_macro = None; // Unwrap more levels of macro expansion, as panic_2015!() // was likely expanded from panic!() and possibly from @@ -320,7 +323,7 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, break; } expn = parent; - panic_macro = name; + panic_macro = Some(name); } let macro_symbol = From 3f32a321bc0962cd3c700a5625dca4e4967918e4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 09:09:01 +1100 Subject: [PATCH 301/546] Use `Option` in `ModuleKind::Def`. This way, `None` represents "crate root without a name" instead of `kw::Empty`. This changes makes it impossible to forget to handle the exceptional case. --- compiler/rustc_resolve/src/build_reduced_graph.rs | 10 +++++----- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 15 ++++++++------- compiler/rustc_resolve/src/macros.rs | 11 ++++++----- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 763e9207a126..08648a164ab7 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -131,7 +131,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess); return Some(self.new_module( parent, - ModuleKind::Def(def_kind, def_id, self.tcx.item_name(def_id)), + ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))), expn_id, self.def_span(def_id), // FIXME: Account for `#[no_implicit_prelude]` attributes. @@ -594,7 +594,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // HACK(eddyb) unclear how good this is, but keeping `$crate` // in `source` breaks `tests/ui/imports/import-crate-var.rs`, // while the current crate doesn't have a valid `crate_name`. - if crate_name != kw::Empty { + if let Some(crate_name) = crate_name { // `crate_name` should not be interpreted as relative. module_path.push(Segment::from_ident_and_id( Ident { name: kw::PathRoot, span: source.ident.span }, @@ -603,7 +603,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { source.ident.name = crate_name; } if rename.is_none() { - ident.name = crate_name; + ident.name = sym::dummy; } self.r.dcx().emit_err(errors::CrateImported { span: item.span }); @@ -775,7 +775,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Mod(.., ref mod_kind) => { let module = self.r.new_module( Some(parent), - ModuleKind::Def(def_kind, def_id, ident.name), + ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), item.span, parent.no_implicit_prelude @@ -811,7 +811,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Enum(_, _) | ItemKind::Trait(..) => { let module = self.r.new_module( Some(parent), - ModuleKind::Def(def_kind, def_id, ident.name), + ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), item.span, parent.no_implicit_prelude, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5361af98f3c7..d683fd98bd21 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2439,7 +2439,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { return None; }; - let module_name = crate_module.kind.name().unwrap(); + let module_name = crate_module.kind.name().unwrap_or(kw::Empty); let import_snippet = match import.kind { ImportKind::Single { source, target, .. } if source != target => { format!("{source} as {target}") diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ff31af0025b5..d5fd03e5f412 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -503,18 +503,18 @@ enum ModuleKind { /// /// * A normal module – either `mod from_file;` or `mod from_block { }` – /// or the crate root (which is conceptually a top-level module). - /// Note that the crate root's [name][Self::name] will be [`kw::Empty`]. + /// The crate root will have `None` for the symbol. /// * A trait or an enum (it implicitly contains associated types, methods and variant /// constructors). - Def(DefKind, DefId, Symbol), + Def(DefKind, DefId, Option), } impl ModuleKind { /// Get name of the module. fn name(&self) -> Option { - match self { + match *self { ModuleKind::Block => None, - ModuleKind::Def(.., name) => Some(*name), + ModuleKind::Def(.., name) => name, } } } @@ -1402,7 +1402,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut module_self_bindings = FxHashMap::default(); let graph_root = arenas.new_module( None, - ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), + ModuleKind::Def(DefKind::Mod, root_def_id, None), ExpnId::root(), crate_span, attr::contains_name(attrs, sym::no_implicit_prelude), @@ -1411,7 +1411,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); let empty_module = arenas.new_module( None, - ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), + ModuleKind::Def(DefKind::Mod, root_def_id, None), ExpnId::root(), DUMMY_SP, true, @@ -2286,7 +2286,8 @@ fn module_to_string(mut module: Module<'_>) -> Option { loop { if let ModuleKind::Def(.., name) = module.kind { if let Some(parent) = module.parent { - names.push(name); + // `unwrap` is safe: the presence of a parent means it's not the crate root. + names.push(name.unwrap()); module = parent } else { break; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c4304a7a6df6..967cb5a0ec62 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -168,7 +168,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); match self.resolve_crate_root(ident).kind { - ModuleKind::Def(.., name) if name != kw::Empty => name, + ModuleKind::Def(.., name) if let Some(name) = name => name, _ => kw::Crate, } }); @@ -1068,11 +1068,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) { let location = match parent_scope.module.kind { - ModuleKind::Def(_, _, name) if name == kw::Empty => { - "the crate root".to_string() - } ModuleKind::Def(kind, def_id, name) => { - format!("{} `{name}`", kind.descr(def_id)) + if let Some(name) = name { + format!("{} `{name}`", kind.descr(def_id)) + } else { + "the crate root".to_string() + } } ModuleKind::Block => "this scope".to_string(), }; From e576d8850de702f6c712eaca77f758f72ef13419 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 11:10:45 +1100 Subject: [PATCH 302/546] Use `Option` in `DuplicateLangItem`. For the the symbols that might not be present, instead of `kw::Empty`. --- compiler/rustc_passes/src/errors.rs | 20 +++++++++++++------- compiler/rustc_passes/src/lang_items.rs | 14 +++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a72f40cd843a..0ee17430aab8 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1348,12 +1348,12 @@ pub(crate) struct DuplicateLangItem { pub local_span: Option, pub lang_item_name: Symbol, pub crate_name: Symbol, - pub dependency_of: Symbol, + pub dependency_of: Option, pub is_local: bool, pub path: String, pub first_defined_span: Option, - pub orig_crate_name: Symbol, - pub orig_dependency_of: Symbol, + pub orig_crate_name: Option, + pub orig_dependency_of: Option, pub orig_is_local: bool, pub orig_path: String, pub(crate) duplicate: Duplicate, @@ -1374,10 +1374,16 @@ impl Diagnostic<'_, G> for DuplicateLangItem { diag.code(E0152); diag.arg("lang_item_name", self.lang_item_name); diag.arg("crate_name", self.crate_name); - diag.arg("dependency_of", self.dependency_of); + if let Some(dependency_of) = self.dependency_of { + diag.arg("dependency_of", dependency_of); + } diag.arg("path", self.path); - diag.arg("orig_crate_name", self.orig_crate_name); - diag.arg("orig_dependency_of", self.orig_dependency_of); + if let Some(orig_crate_name) = self.orig_crate_name { + diag.arg("orig_crate_name", orig_crate_name); + } + if let Some(orig_dependency_of) = self.orig_dependency_of { + diag.arg("orig_dependency_of", orig_dependency_of); + } diag.arg("orig_path", self.orig_path); if let Some(span) = self.local_span { diag.span(span); @@ -1385,7 +1391,7 @@ impl Diagnostic<'_, G> for DuplicateLangItem { if let Some(span) = self.first_defined_span { diag.span_note(span, fluent::passes_first_defined_span); } else { - if self.orig_dependency_of.is_empty() { + if self.orig_dependency_of.is_none() { diag.note(fluent::passes_first_defined_crate); } else { diag.note(fluent::passes_first_defined_crate_depends); diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index fe1140d893e3..9d4b46cd3066 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -16,7 +16,7 @@ use rustc_hir::{LangItem, LanguageItems, MethodKind, Target}; use rustc_middle::query::Providers; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::cstore::ExternCrate; -use rustc_span::{Span, kw}; +use rustc_span::Span; use crate::errors::{ DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem, @@ -98,7 +98,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { { let lang_item_name = lang_item.name(); let crate_name = self.tcx.crate_name(item_def_id.krate); - let mut dependency_of = kw::Empty; + let mut dependency_of = None; let is_local = item_def_id.is_local(); let path = if is_local { String::new() @@ -112,8 +112,8 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { }; let first_defined_span = self.item_spans.get(&original_def_id).copied(); - let mut orig_crate_name = kw::Empty; - let mut orig_dependency_of = kw::Empty; + let mut orig_crate_name = None; + let mut orig_dependency_of = None; let orig_is_local = original_def_id.is_local(); let orig_path = if orig_is_local { String::new() @@ -127,11 +127,11 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { }; if first_defined_span.is_none() { - orig_crate_name = self.tcx.crate_name(original_def_id.krate); + orig_crate_name = Some(self.tcx.crate_name(original_def_id.krate)); if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) = self.tcx.extern_crate(original_def_id.krate) { - orig_dependency_of = self.tcx.crate_name(*inner_dependency_of); + orig_dependency_of = Some(self.tcx.crate_name(*inner_dependency_of)); } } @@ -140,7 +140,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { } else { match self.tcx.extern_crate(item_def_id.krate) { Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => { - dependency_of = self.tcx.crate_name(*inner_dependency_of); + dependency_of = Some(self.tcx.crate_name(*inner_dependency_of)); Duplicate::CrateDepends } _ => Duplicate::Crate, From 79b9664091e90c08a7abeab2bbc4a941bcdc3863 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Wed, 13 Nov 2024 13:13:03 -0800 Subject: [PATCH 303/546] Reduce visibility of most items in `rustc_codegen_llvm` --- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 6 +- .../rustc_codegen_llvm/src/llvm/archive_ro.rs | 6 +- .../rustc_codegen_llvm/src/llvm/diagnostic.rs | 20 +- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 44 ++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 182 +++++++++--------- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 20 +- 7 files changed, 144 insertions(+), 136 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 668795191a29..f083cfbd7d30 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -728,7 +728,7 @@ impl ThinBuffer { } } - pub unsafe fn from_raw_ptr(ptr: *mut llvm::ThinLTOBuffer) -> ThinBuffer { + pub(crate) unsafe fn from_raw_ptr(ptr: *mut llvm::ThinLTOBuffer) -> ThinBuffer { let mut ptr = NonNull::new(ptr).unwrap(); ThinBuffer(unsafe { ptr.as_mut() }) } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index f622646a5d9d..425381b0ffab 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -29,7 +29,7 @@ use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; use context::SimpleCx; use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; -pub(crate) use llvm_util::target_features_cfg; +use llvm_util::target_features_cfg; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; @@ -71,9 +71,7 @@ mod debuginfo; mod declare; mod errors; mod intrinsic; -// FIXME(Zalathar): Fix all the unreachable-pub warnings that would occur if -// this isn't pub, then make it not pub. -pub mod llvm; +mod llvm; mod llvm_util; mod mono_item; mod type_; diff --git a/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs index 63b2b15c5145..51bcc4d123d3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs @@ -5,17 +5,17 @@ use std::{slice, str}; use rustc_fs_util::path_to_c_string; -pub struct ArchiveRO { +pub(crate) struct ArchiveRO { pub raw: &'static mut super::Archive, } unsafe impl Send for ArchiveRO {} -pub struct Iter<'a> { +pub(crate) struct Iter<'a> { raw: &'a mut super::ArchiveIterator<'a>, } -pub struct Child<'a> { +pub(crate) struct Child<'a> { pub raw: &'a mut super::ArchiveChild<'a>, } diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index 11043b664f52..0e0f2b0eab01 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -3,13 +3,13 @@ use libc::c_uint; use rustc_span::InnerSpan; -pub use self::Diagnostic::*; -pub use self::OptimizationDiagnosticKind::*; +pub(crate) use self::Diagnostic::*; +use self::OptimizationDiagnosticKind::*; use super::{DiagnosticInfo, SMDiagnostic}; use crate::value::Value; #[derive(Copy, Clone, Debug)] -pub enum OptimizationDiagnosticKind { +pub(crate) enum OptimizationDiagnosticKind { OptimizationRemark, OptimizationMissed, OptimizationAnalysis, @@ -19,9 +19,10 @@ pub enum OptimizationDiagnosticKind { OptimizationRemarkOther, } -pub struct OptimizationDiagnostic<'ll> { +pub(crate) struct OptimizationDiagnostic<'ll> { pub kind: OptimizationDiagnosticKind, pub pass_name: String, + #[expect(dead_code)] pub function: &'ll Value, pub line: c_uint, pub column: c_uint, @@ -73,14 +74,14 @@ impl<'ll> OptimizationDiagnostic<'ll> { } } -pub struct SrcMgrDiagnostic { +pub(crate) struct SrcMgrDiagnostic { pub level: super::DiagnosticLevel, pub message: String, pub source: Option<(String, Vec)>, } impl SrcMgrDiagnostic { - pub unsafe fn unpack(diag: &SMDiagnostic) -> SrcMgrDiagnostic { + pub(crate) unsafe fn unpack(diag: &SMDiagnostic) -> SrcMgrDiagnostic { // Recover the post-substitution assembly code from LLVM for better // diagnostics. let mut have_source = false; @@ -120,7 +121,7 @@ impl SrcMgrDiagnostic { } #[derive(Clone)] -pub struct InlineAsmDiagnostic { +pub(crate) struct InlineAsmDiagnostic { pub level: super::DiagnosticLevel, pub cookie: u64, pub message: String, @@ -158,7 +159,7 @@ impl InlineAsmDiagnostic { } } -pub enum Diagnostic<'ll> { +pub(crate) enum Diagnostic<'ll> { Optimization(OptimizationDiagnostic<'ll>), InlineAsm(InlineAsmDiagnostic), PGO(&'ll DiagnosticInfo), @@ -166,11 +167,12 @@ pub enum Diagnostic<'ll> { Unsupported(&'ll DiagnosticInfo), /// LLVM has other types that we do not wrap here. + #[expect(dead_code)] UnknownDiagnostic(&'ll DiagnosticInfo), } impl<'ll> Diagnostic<'ll> { - pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self { + pub(crate) unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self { use super::DiagnosticKind as Dk; unsafe { diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index f6b238629075..79e4cc8aa774 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -31,20 +31,20 @@ unsafe extern "C" { #[repr(C)] #[derive(Copy, Clone, PartialEq)] -pub enum LLVMRustVerifierFailureAction { +pub(crate) enum LLVMRustVerifierFailureAction { LLVMAbortProcessAction = 0, LLVMPrintMessageAction = 1, LLVMReturnStatusAction = 2, } #[cfg(llvm_enzyme)] -pub use self::Enzyme_AD::*; +pub(crate) use self::Enzyme_AD::*; #[cfg(llvm_enzyme)] -pub mod Enzyme_AD { +pub(crate) mod Enzyme_AD { use libc::c_void; unsafe extern "C" { - pub fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); + pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); } unsafe extern "C" { static mut EnzymePrintPerf: c_void; @@ -56,42 +56,42 @@ pub mod Enzyme_AD { static mut EnzymeInline: c_void; static mut RustTypeRules: c_void; } - pub fn set_print_perf(print: bool) { + pub(crate) fn set_print_perf(print: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintPerf), print as u8); } } - pub fn set_print_activity(print: bool) { + pub(crate) fn set_print_activity(print: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintActivity), print as u8); } } - pub fn set_print_type(print: bool) { + pub(crate) fn set_print_type(print: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintType), print as u8); } } - pub fn set_print(print: bool) { + pub(crate) fn set_print(print: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrint), print as u8); } } - pub fn set_strict_aliasing(strict: bool) { + pub(crate) fn set_strict_aliasing(strict: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymeStrictAliasing), strict as u8); } } - pub fn set_loose_types(loose: bool) { + pub(crate) fn set_loose_types(loose: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(looseTypeAnalysis), loose as u8); } } - pub fn set_inline(val: bool) { + pub(crate) fn set_inline(val: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymeInline), val as u8); } } - pub fn set_rust_rules(val: bool) { + pub(crate) fn set_rust_rules(val: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(RustTypeRules), val as u8); } @@ -99,34 +99,34 @@ pub mod Enzyme_AD { } #[cfg(not(llvm_enzyme))] -pub use self::Fallback_AD::*; +pub(crate) use self::Fallback_AD::*; #[cfg(not(llvm_enzyme))] -pub mod Fallback_AD { +pub(crate) mod Fallback_AD { #![allow(unused_variables)] - pub fn set_inline(val: bool) { + pub(crate) fn set_inline(val: bool) { unimplemented!() } - pub fn set_print_perf(print: bool) { + pub(crate) fn set_print_perf(print: bool) { unimplemented!() } - pub fn set_print_activity(print: bool) { + pub(crate) fn set_print_activity(print: bool) { unimplemented!() } - pub fn set_print_type(print: bool) { + pub(crate) fn set_print_type(print: bool) { unimplemented!() } - pub fn set_print(print: bool) { + pub(crate) fn set_print(print: bool) { unimplemented!() } - pub fn set_strict_aliasing(strict: bool) { + pub(crate) fn set_strict_aliasing(strict: bool) { unimplemented!() } - pub fn set_loose_types(loose: bool) { + pub(crate) fn set_loose_types(loose: bool) { unimplemented!() } - pub fn set_rust_rules(val: bool) { + pub(crate) fn set_rust_rules(val: bool) { unimplemented!() } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 83efb3ea6603..3ce3761944b3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -32,10 +32,10 @@ use crate::llvm; /// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`, /// which has a different ABI from Rust or C++ `bool`. -pub type Bool = c_int; +pub(crate) type Bool = c_int; -pub const True: Bool = 1 as Bool; -pub const False: Bool = 0 as Bool; +pub(crate) const True: Bool = 1 as Bool; +pub(crate) const False: Bool = 0 as Bool; /// Wrapper for a raw enum value returned from LLVM's C APIs. /// @@ -44,7 +44,7 @@ pub const False: Bool = 0 as Bool; /// value and returns it. Instead, return this raw wrapper, then convert to the /// Rust-side enum explicitly. #[repr(transparent)] -pub struct RawEnum { +pub(crate) struct RawEnum { value: u32, /// We don't own or consume a `T`, but we can produce one. _rust_side_type: PhantomData T>, @@ -64,7 +64,7 @@ impl> RawEnum { #[derive(Copy, Clone, PartialEq)] #[repr(C)] #[allow(dead_code)] // Variants constructed by C++. -pub enum LLVMRustResult { +pub(crate) enum LLVMRustResult { Success, Failure, } @@ -83,7 +83,7 @@ pub enum LLVMRustResult { /// C++ API. #[derive(Copy, Clone, PartialEq)] #[repr(C)] -pub enum ModuleFlagMergeBehavior { +pub(crate) enum ModuleFlagMergeBehavior { Error = 1, Warning = 2, Require = 3, @@ -101,7 +101,7 @@ pub enum ModuleFlagMergeBehavior { /// See #[derive(Copy, Clone, PartialEq, Debug, TryFromU32)] #[repr(C)] -pub enum CallConv { +pub(crate) enum CallConv { CCallConv = 0, FastCallConv = 8, ColdCallConv = 9, @@ -126,7 +126,7 @@ pub enum CallConv { /// Must match the layout of `LLVMLinkage`. #[derive(Copy, Clone, PartialEq, TryFromU32)] #[repr(C)] -pub enum Linkage { +pub(crate) enum Linkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, LinkOnceAnyLinkage = 2, @@ -153,7 +153,7 @@ pub enum Linkage { /// Must match the layout of `LLVMVisibility`. #[repr(C)] #[derive(Copy, Clone, PartialEq, TryFromU32)] -pub enum Visibility { +pub(crate) enum Visibility { Default = 0, Hidden = 1, Protected = 2, @@ -171,8 +171,9 @@ impl Visibility { /// LLVMUnnamedAddr #[repr(C)] -pub enum UnnamedAddr { +pub(crate) enum UnnamedAddr { No, + #[expect(dead_code)] Local, Global, } @@ -180,7 +181,7 @@ pub enum UnnamedAddr { /// LLVMDLLStorageClass #[derive(Copy, Clone)] #[repr(C)] -pub enum DLLStorageClass { +pub(crate) enum DLLStorageClass { #[allow(dead_code)] Default = 0, DllImport = 1, // Function to be imported from DLL. @@ -193,7 +194,8 @@ pub enum DLLStorageClass { /// though it is not ABI compatible (since it's a C++ enum) #[repr(C)] #[derive(Copy, Clone, Debug)] -pub enum AttributeKind { +#[expect(dead_code, reason = "Some variants are unused, but are kept to match the C++")] +pub(crate) enum AttributeKind { AlwaysInline = 0, ByVal = 1, Cold = 2, @@ -241,7 +243,7 @@ pub enum AttributeKind { /// LLVMIntPredicate #[derive(Copy, Clone)] #[repr(C)] -pub enum IntPredicate { +pub(crate) enum IntPredicate { IntEQ = 32, IntNE = 33, IntUGT = 34, @@ -275,7 +277,7 @@ impl IntPredicate { /// LLVMRealPredicate #[derive(Copy, Clone)] #[repr(C)] -pub enum RealPredicate { +pub(crate) enum RealPredicate { RealPredicateFalse = 0, RealOEQ = 1, RealOGT = 2, @@ -321,7 +323,8 @@ impl RealPredicate { /// LLVMTypeKind #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] -pub enum TypeKind { +#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")] +pub(crate) enum TypeKind { Void = 0, Half = 1, Float = 2, @@ -373,7 +376,7 @@ impl TypeKind { /// LLVMAtomicRmwBinOp #[derive(Copy, Clone)] #[repr(C)] -pub enum AtomicRmwBinOp { +pub(crate) enum AtomicRmwBinOp { AtomicXchg = 0, AtomicAdd = 1, AtomicSub = 2, @@ -409,7 +412,7 @@ impl AtomicRmwBinOp { /// LLVMAtomicOrdering #[derive(Copy, Clone)] #[repr(C)] -pub enum AtomicOrdering { +pub(crate) enum AtomicOrdering { #[allow(dead_code)] NotAtomic = 0, Unordered = 1, @@ -438,7 +441,7 @@ impl AtomicOrdering { /// LLVMRustFileType #[derive(Copy, Clone)] #[repr(C)] -pub enum FileType { +pub(crate) enum FileType { AssemblyFile, ObjectFile, } @@ -446,7 +449,8 @@ pub enum FileType { /// LLVMMetadataType #[derive(Copy, Clone)] #[repr(C)] -pub enum MetadataType { +#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")] +pub(crate) enum MetadataType { MD_dbg = 0, MD_tbaa = 1, MD_prof = 2, @@ -470,7 +474,7 @@ pub enum MetadataType { /// LLVMRustAsmDialect #[derive(Copy, Clone, PartialEq)] #[repr(C)] -pub enum AsmDialect { +pub(crate) enum AsmDialect { Att, Intel, } @@ -478,7 +482,7 @@ pub enum AsmDialect { /// LLVMRustCodeGenOptLevel #[derive(Copy, Clone, PartialEq)] #[repr(C)] -pub enum CodeGenOptLevel { +pub(crate) enum CodeGenOptLevel { None, Less, Default, @@ -487,7 +491,7 @@ pub enum CodeGenOptLevel { /// LLVMRustPassBuilderOptLevel #[repr(C)] -pub enum PassBuilderOptLevel { +pub(crate) enum PassBuilderOptLevel { O0, O1, O2, @@ -499,7 +503,7 @@ pub enum PassBuilderOptLevel { /// LLVMRustOptStage #[derive(PartialEq)] #[repr(C)] -pub enum OptStage { +pub(crate) enum OptStage { PreLinkNoLTO, PreLinkThinLTO, PreLinkFatLTO, @@ -509,7 +513,7 @@ pub enum OptStage { /// LLVMRustSanitizerOptions #[repr(C)] -pub struct SanitizerOptions { +pub(crate) struct SanitizerOptions { pub sanitize_address: bool, pub sanitize_address_recover: bool, pub sanitize_cfi: bool, @@ -530,7 +534,7 @@ pub struct SanitizerOptions { /// LLVMRustRelocModel #[derive(Copy, Clone, PartialEq)] #[repr(C)] -pub enum RelocModel { +pub(crate) enum RelocModel { Static, PIC, DynamicNoPic, @@ -542,7 +546,7 @@ pub enum RelocModel { /// LLVMRustFloatABI #[derive(Copy, Clone, PartialEq)] #[repr(C)] -pub enum FloatAbi { +pub(crate) enum FloatAbi { Default, Soft, Hard, @@ -551,7 +555,7 @@ pub enum FloatAbi { /// LLVMRustCodeModel #[derive(Copy, Clone)] #[repr(C)] -pub enum CodeModel { +pub(crate) enum CodeModel { Tiny, Small, Kernel, @@ -564,7 +568,7 @@ pub enum CodeModel { #[derive(Copy, Clone)] #[repr(C)] #[allow(dead_code)] // Variants constructed by C++. -pub enum DiagnosticKind { +pub(crate) enum DiagnosticKind { Other, InlineAsm, StackSize, @@ -587,7 +591,7 @@ pub enum DiagnosticKind { #[derive(Copy, Clone)] #[repr(C)] #[allow(dead_code)] // Variants constructed by C++. -pub enum DiagnosticLevel { +pub(crate) enum DiagnosticLevel { Error, Warning, Note, @@ -597,7 +601,7 @@ pub enum DiagnosticLevel { /// LLVMRustArchiveKind #[derive(Copy, Clone)] #[repr(C)] -pub enum ArchiveKind { +pub(crate) enum ArchiveKind { K_GNU, K_BSD, K_DARWIN, @@ -607,15 +611,15 @@ pub enum ArchiveKind { unsafe extern "C" { // LLVMRustThinLTOData - pub type ThinLTOData; + pub(crate) type ThinLTOData; // LLVMRustThinLTOBuffer - pub type ThinLTOBuffer; + pub(crate) type ThinLTOBuffer; } /// LLVMRustThinLTOModule #[repr(C)] -pub struct ThinLTOModule { +pub(crate) struct ThinLTOModule { pub identifier: *const c_char, pub data: *const u8, pub len: usize, @@ -624,7 +628,8 @@ pub struct ThinLTOModule { /// LLVMThreadLocalMode #[derive(Copy, Clone)] #[repr(C)] -pub enum ThreadLocalMode { +pub(crate) enum ThreadLocalMode { + #[expect(dead_code)] NotThreadLocal, GeneralDynamic, LocalDynamic, @@ -635,7 +640,7 @@ pub enum ThreadLocalMode { /// LLVMRustChecksumKind #[derive(Copy, Clone)] #[repr(C)] -pub enum ChecksumKind { +pub(crate) enum ChecksumKind { None, MD5, SHA1, @@ -645,7 +650,7 @@ pub enum ChecksumKind { /// LLVMRustMemoryEffects #[derive(Copy, Clone)] #[repr(C)] -pub enum MemoryEffects { +pub(crate) enum MemoryEffects { None, ReadOnly, InaccessibleMemOnly, @@ -654,7 +659,8 @@ pub enum MemoryEffects { /// LLVMOpcode #[derive(Copy, Clone, PartialEq, Eq)] #[repr(C)] -pub enum Opcode { +#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")] +pub(crate) enum Opcode { Ret = 1, Br = 2, Switch = 3, @@ -735,48 +741,48 @@ struct InvariantOpaque<'a> { // Opaque pointer types unsafe extern "C" { - pub type Module; - pub type Context; - pub type Type; - pub type Value; - pub type ConstantInt; - pub type Attribute; - pub type Metadata; - pub type BasicBlock; - pub type Comdat; + pub(crate) type Module; + pub(crate) type Context; + pub(crate) type Type; + pub(crate) type Value; + pub(crate) type ConstantInt; + pub(crate) type Attribute; + pub(crate) type Metadata; + pub(crate) type BasicBlock; + pub(crate) type Comdat; } #[repr(C)] -pub struct Builder<'a>(InvariantOpaque<'a>); +pub(crate) struct Builder<'a>(InvariantOpaque<'a>); #[repr(C)] -pub struct PassManager<'a>(InvariantOpaque<'a>); +pub(crate) struct PassManager<'a>(InvariantOpaque<'a>); unsafe extern "C" { pub type TargetMachine; - pub type Archive; + pub(crate) type Archive; } #[repr(C)] -pub struct ArchiveIterator<'a>(InvariantOpaque<'a>); +pub(crate) struct ArchiveIterator<'a>(InvariantOpaque<'a>); #[repr(C)] -pub struct ArchiveChild<'a>(InvariantOpaque<'a>); +pub(crate) struct ArchiveChild<'a>(InvariantOpaque<'a>); unsafe extern "C" { - pub type Twine; - pub type DiagnosticInfo; - pub type SMDiagnostic; + pub(crate) type Twine; + pub(crate) type DiagnosticInfo; + pub(crate) type SMDiagnostic; } #[repr(C)] -pub struct RustArchiveMember<'a>(InvariantOpaque<'a>); +pub(crate) struct RustArchiveMember<'a>(InvariantOpaque<'a>); /// Opaque pointee of `LLVMOperandBundleRef`. #[repr(C)] pub(crate) struct OperandBundle<'a>(InvariantOpaque<'a>); #[repr(C)] -pub struct Linker<'a>(InvariantOpaque<'a>); +pub(crate) struct Linker<'a>(InvariantOpaque<'a>); unsafe extern "C" { - pub type DiagnosticHandler; + pub(crate) type DiagnosticHandler; } -pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void); +pub(crate) type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void); -pub mod debuginfo { +pub(crate) mod debuginfo { use std::ptr; use bitflags::bitflags; @@ -793,7 +799,7 @@ pub mod debuginfo { /// builder reference typically has a shorter lifetime than the LLVM /// session (`'ll`) that it participates in. #[repr(C)] - pub struct DIBuilder<'ll>(InvariantOpaque<'ll>); + pub(crate) struct DIBuilder<'ll>(InvariantOpaque<'ll>); /// Owning pointer to a `DIBuilder<'ll>` that will dispose of the builder /// when dropped. Use `.as_ref()` to get the underlying `&DIBuilder` @@ -822,22 +828,22 @@ pub mod debuginfo { } } - pub type DIDescriptor = Metadata; - pub type DILocation = Metadata; - pub type DIScope = DIDescriptor; - pub type DIFile = DIScope; - pub type DILexicalBlock = DIScope; - pub type DISubprogram = DIScope; - pub type DIType = DIDescriptor; - pub type DIBasicType = DIType; - pub type DIDerivedType = DIType; - pub type DICompositeType = DIDerivedType; - pub type DIVariable = DIDescriptor; - pub type DIGlobalVariableExpression = DIDescriptor; - pub type DIArray = DIDescriptor; - pub type DISubrange = DIDescriptor; - pub type DIEnumerator = DIDescriptor; - pub type DITemplateTypeParameter = DIDescriptor; + pub(crate) type DIDescriptor = Metadata; + pub(crate) type DILocation = Metadata; + pub(crate) type DIScope = DIDescriptor; + pub(crate) type DIFile = DIScope; + pub(crate) type DILexicalBlock = DIScope; + pub(crate) type DISubprogram = DIScope; + pub(crate) type DIType = DIDescriptor; + pub(crate) type DIBasicType = DIType; + pub(crate) type DIDerivedType = DIType; + pub(crate) type DICompositeType = DIDerivedType; + pub(crate) type DIVariable = DIDescriptor; + pub(crate) type DIGlobalVariableExpression = DIDescriptor; + pub(crate) type DIArray = DIDescriptor; + pub(crate) type DISubrange = DIDescriptor; + pub(crate) type DIEnumerator = DIDescriptor; + pub(crate) type DITemplateTypeParameter = DIDescriptor; bitflags! { /// Must match the layout of `LLVMDIFlags` in the LLVM-C API. @@ -846,7 +852,7 @@ pub mod debuginfo { /// assertions in `RustWrapper.cpp` used by `fromRust(LLVMDIFlags)`. #[repr(transparent)] #[derive(Clone, Copy, Default)] - pub struct DIFlags: u32 { + pub(crate) struct DIFlags: u32 { const FlagZero = 0; const FlagPrivate = 1; const FlagProtected = 2; @@ -886,7 +892,7 @@ pub mod debuginfo { bitflags! { #[repr(transparent)] #[derive(Clone, Copy, Default)] - pub struct DISPFlags: u32 { + pub(crate) struct DISPFlags: u32 { const SPFlagZero = 0; const SPFlagVirtual = 1; const SPFlagPureVirtual = 2; @@ -900,7 +906,7 @@ pub mod debuginfo { /// LLVMRustDebugEmissionKind #[derive(Copy, Clone)] #[repr(C)] - pub enum DebugEmissionKind { + pub(crate) enum DebugEmissionKind { NoDebug, FullDebug, LineTablesOnly, @@ -932,8 +938,9 @@ pub mod debuginfo { /// LLVMRustDebugNameTableKind #[derive(Clone, Copy)] #[repr(C)] - pub enum DebugNameTableKind { + pub(crate) enum DebugNameTableKind { Default, + #[expect(dead_code)] Gnu, None, } @@ -943,7 +950,7 @@ pub mod debuginfo { bitflags! { #[repr(transparent)] #[derive(Default)] - pub struct AllocKindFlags : u64 { + pub(crate) struct AllocKindFlags : u64 { const Unknown = 0; const Alloc = 1; const Realloc = 1 << 1; @@ -966,19 +973,20 @@ bitflags! { } unsafe extern "C" { - pub type ModuleBuffer; + pub(crate) type ModuleBuffer; } -pub type SelfProfileBeforePassCallback = +pub(crate) type SelfProfileBeforePassCallback = unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char); -pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void); +pub(crate) type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void); -pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void; -pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; +pub(crate) type GetSymbolsCallback = + unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void; +pub(crate) type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; #[derive(Copy, Clone)] #[repr(transparent)] -pub struct MetadataKindId(c_uint); +pub(crate) struct MetadataKindId(c_uint); impl From for MetadataKindId { fn from(value: MetadataType) -> Self { diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index a36226b25a24..6ca81c651ed4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -9,18 +9,18 @@ use libc::c_uint; use rustc_abi::{Align, Size, WrappingRange}; use rustc_llvm::RustString; -pub use self::CallConv::*; -pub use self::CodeGenOptSize::*; -pub use self::MetadataType::*; -pub use self::ffi::*; +pub(crate) use self::CallConv::*; +pub(crate) use self::CodeGenOptSize::*; +pub(crate) use self::MetadataType::*; +pub(crate) use self::ffi::*; use crate::common::AsCCharPtr; -pub mod archive_ro; -pub mod diagnostic; -pub mod enzyme_ffi; +pub(crate) mod archive_ro; +pub(crate) mod diagnostic; +pub(crate) mod enzyme_ffi; mod ffi; -pub use self::enzyme_ffi::*; +pub(crate) use self::enzyme_ffi::*; impl LLVMRustResult { pub(crate) fn into_result(self) -> Result<(), ()> { @@ -127,7 +127,7 @@ pub(crate) fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) } #[derive(Copy, Clone)] -pub enum AttributePlace { +pub(crate) enum AttributePlace { ReturnValue, Argument(u32), Function, @@ -145,7 +145,7 @@ impl AttributePlace { #[derive(Copy, Clone, PartialEq)] #[repr(C)] -pub enum CodeGenOptSize { +pub(crate) enum CodeGenOptSize { CodeGenOptSizeNone = 0, CodeGenOptSizeDefault = 1, CodeGenOptSizeAggressive = 2, From 867da30cc71017597d9ed731b03a45c79accd873 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 15:50:31 +1100 Subject: [PATCH 304/546] Avoid `kw::Empty` when dealing with `rustc_allowed_through_unstable_modules`. The existing code produces `Some(kw::Empty)` for these invalid forms: - a non-name-value, e.g. `#[rustc_allowed_through_unstable_modules]` - a non-string arg, e.g. `#[rustc_allowed_through_unstable_modules = 3]` The new code avoids the `kw::Empty` and is a little shorter. It will produce `None` in those cases, which means E0789 won't be produced if the `stable` attribute is missing for these invalid forms. This doesn't matter, because these invalid forms will trigger an "malformed `rustc_allowed_through_unstable_modules` attribute" anyway. --- compiler/rustc_attr_parsing/src/attributes/stability.rs | 8 ++------ compiler/rustc_error_codes/src/error_codes/E0789.md | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6d76456e83c8..bdad6b50186d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -5,7 +5,7 @@ use rustc_attr_data_structures::{ StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::{Span, Symbol, sym}; use super::util::parse_version; use super::{AcceptMapping, AttributeParser, SingleAttributeParser}; @@ -61,11 +61,7 @@ impl AttributeParser for StabilityParser { }), (&[sym::rustc_allowed_through_unstable_modules], |this, cx, args| { reject_outside_std!(cx); - this.allowed_through_unstable_modules = - Some(match args.name_value().and_then(|i| i.value_as_str()) { - Some(msg) => msg, - None => kw::Empty, - }); + this.allowed_through_unstable_modules = args.name_value().and_then(|i| i.value_as_str()) }), ]; diff --git a/compiler/rustc_error_codes/src/error_codes/E0789.md b/compiler/rustc_error_codes/src/error_codes/E0789.md index 2c0018cc799f..c7bc6cfde513 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0789.md +++ b/compiler/rustc_error_codes/src/error_codes/E0789.md @@ -14,7 +14,7 @@ Erroneous code example: #![unstable(feature = "foo_module", reason = "...", issue = "123")] -#[rustc_allowed_through_unstable_modules] +#[rustc_allowed_through_unstable_modules = "deprecation message"] // #[stable(feature = "foo", since = "1.0")] struct Foo; // ^^^ error: `rustc_allowed_through_unstable_modules` attribute must be From 90c541d637c0857c6d5b1c3bf835e2f02f7175a9 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 24 Mar 2025 13:56:45 +0900 Subject: [PATCH 305/546] ignore doctests only in specified targets add necessary lines fix ui test error --- src/librustdoc/html/markdown.rs | 9 +++++---- tests/rustdoc-ui/doctest/per-target-ignores.rs | 14 ++++++++++++++ tests/rustdoc-ui/doctest/per-target-ignores.stdout | 6 ++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/per-target-ignores.rs create mode 100644 tests/rustdoc-ui/doctest/per-target-ignores.stdout diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 5aab4199d43b..0d547a6a0d92 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1201,11 +1201,12 @@ impl LangString { seen_rust_tags = !seen_other_tags; } LangStringToken::LangToken(x) - if let Some(ignore) = x.strip_prefix("ignore-") - && enable_per_target_ignores => + if let Some(ignore) = x.strip_prefix("ignore-") => { - ignores.push(ignore.to_owned()); - seen_rust_tags = !seen_other_tags; + if enable_per_target_ignores { + ignores.push(ignore.to_owned()); + seen_rust_tags = !seen_other_tags; + } } LangStringToken::LangToken("rust") => { data.rust = true; diff --git a/tests/rustdoc-ui/doctest/per-target-ignores.rs b/tests/rustdoc-ui/doctest/per-target-ignores.rs new file mode 100644 index 000000000000..3dea7099b4be --- /dev/null +++ b/tests/rustdoc-ui/doctest/per-target-ignores.rs @@ -0,0 +1,14 @@ +//@ only-aarch64 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + +///```ignore-x86_64 +/// assert!(cfg!(not(target_arch = "x86_64"))); +///``` +pub fn foo() -> u8 { + 4 +} + +fn main() {} diff --git a/tests/rustdoc-ui/doctest/per-target-ignores.stdout b/tests/rustdoc-ui/doctest/per-target-ignores.stdout new file mode 100644 index 000000000000..fe7282144dd8 --- /dev/null +++ b/tests/rustdoc-ui/doctest/per-target-ignores.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/per-target-ignores.rs - foo (line 7) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From 501945a22e314bad511e08a187c0aa029df51038 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 18:00:14 +1100 Subject: [PATCH 306/546] Use `sym::dummy` for a dummy arg in `parse_fn_params`. --- compiler/rustc_parse/src/parser/item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f4df4044dd2e..123234fedceb 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2871,7 +2871,7 @@ impl<'a> Parser<'a> { // Skip every token until next possible arg or end. p.eat_to_tokens(&[exp!(Comma), exp!(CloseParen)]); // Create a placeholder argument for proper arg count (issue #34264). - Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)), guar)) + Ok(dummy_arg(Ident::new(sym::dummy, lo.to(p.prev_token.span)), guar)) }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; From c961d123d2df8d9fec6d997a6725b88eabe8d5de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Mar 2025 12:10:43 +0100 Subject: [PATCH 307/546] add FCW to warn about wasm ABI transition --- compiler/rustc_lint_defs/src/builtin.rs | 46 ++++++++++ compiler/rustc_monomorphize/messages.ftl | 7 ++ compiler/rustc_monomorphize/src/errors.rs | 9 ++ .../src/mono_checks/abi_check.rs | 80 ++++++++++++++--- compiler/rustc_target/src/callconv/wasm.rs | 3 + tests/ui/abi/compatibility.rs | 1 - tests/ui/lint/wasm_c_abi_transition.rs | 41 +++++++++ tests/ui/lint/wasm_c_abi_transition.stderr | 85 +++++++++++++++++++ 8 files changed, 259 insertions(+), 13 deletions(-) create mode 100644 tests/ui/lint/wasm_c_abi_transition.rs create mode 100644 tests/ui/lint/wasm_c_abi_transition.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 592c934997c0..8a761a0a0969 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -143,6 +143,7 @@ declare_lint_pass! { UNUSED_VARIABLES, USELESS_DEPRECATED, WARNINGS, + WASM_C_ABI, // tidy-alphabetical-end ] } @@ -5082,6 +5083,8 @@ declare_lint! { /// } /// ``` /// + /// This will produce: + /// /// ```text /// warning: ABI error: this function call uses a avx vector type, which is not enabled in the caller /// --> lint_example.rs:18:12 @@ -5125,3 +5128,46 @@ declare_lint! { reference: "issue #116558 ", }; } + +declare_lint! { + /// The `wasm_c_abi` lint detects usage of the `extern "C"` ABI of wasm that is affected + /// by a planned ABI change that has the goal of aligning Rust with the standard C ABI + /// of this target. + /// + /// ### Example + /// + /// ```rust,ignore (needs wasm32-unknown-unknown) + /// #[repr(C)] + /// struct MyType(i32, i32); + /// + /// extern "C" my_fun(x: MyType) {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: this function function definition is affected by the wasm ABI transition: it passes an argument of non-scalar type `MyType` + /// --> $DIR/wasm_c_abi_transition.rs:17:1 + /// | + /// | pub extern "C" fn my_fun(_x: MyType) {} + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #138762 + /// = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target + /// ``` + /// + /// ### Explanation + /// + /// Rust has historically implemented a non-spec-compliant C ABI on wasm32-unknown-unknown. This + /// has caused incompatibilities with other compilers and Wasm targets. In a future version + /// of Rust, this will be fixed, and therefore code relying on the non-spec-compliant C ABI will + /// stop functioning. + pub WASM_C_ABI, + Warn, + "detects code relying on rustc's non-spec-compliant wasm C ABI", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reference: "issue #138762 ", + }; +} diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index bdeab12ab503..aae2d79c1610 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -63,4 +63,11 @@ monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined monomorphize_unknown_cgu_collection_mode = unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode +monomorphize_wasm_c_abi_transition = + this function {$is_call -> + [true] call + *[false] definition + } involves an argument of type `{$ty}` which is affected by the wasm ABI transition + .help = the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target + monomorphize_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 8dafbbca905f..dffa372279f9 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -103,3 +103,12 @@ pub(crate) struct AbiRequiredTargetFeature<'a> { /// Whether this is a problem at a call site or at a declaration. pub is_call: bool, } + +#[derive(LintDiagnostic)] +#[diag(monomorphize_wasm_c_abi_transition)] +#[help] +pub(crate) struct WasmCAbiTransition<'a> { + pub ty: Ty<'a>, + /// Whether this is a problem at a call site or at a declaration. + pub is_call: bool, +} diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 06d6c3ab8050..f17f7261df58 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -3,11 +3,13 @@ use rustc_abi::{BackendRepr, RegKind}; use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::{self, traversal}; -use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt}; -use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES; +use rustc_middle::ty::layout::LayoutCx; +use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypingEnv}; +use rustc_session::lint::builtin::{ABI_UNSUPPORTED_VECTOR_TYPES, WASM_C_ABI}; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; -use rustc_target::callconv::{Conv, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, Conv, FnAbi, PassMode}; +use rustc_target::spec::{HasWasmCAbiOpt, WasmCAbi}; use crate::errors; @@ -26,13 +28,15 @@ fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool { /// for a certain function. /// `is_call` indicates whether this is a call-site check or a definition-site check; /// this is only relevant for the wording in the emitted error. -fn do_check_abi<'tcx>( +fn do_check_simd_vector_abi<'tcx>( tcx: TyCtxt<'tcx>, abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId, is_call: bool, span: impl Fn() -> Span, ) { + // We check this on all functions, including those using the "Rust" ABI. + // For the "Rust" ABI it would be a bug if the lint ever triggered, but better safe than sorry. let feature_def = tcx.sess.target.features_for_correct_vector_abi(); let codegen_attrs = tcx.codegen_fn_attrs(def_id); let have_feature = |feat: Symbol| { @@ -88,6 +92,60 @@ fn do_check_abi<'tcx>( } } +fn wasm_abi_safe<'tcx>(tcx: TyCtxt<'tcx>, arg: &ArgAbi<'tcx, Ty<'tcx>>) -> bool { + if matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) { + return true; + } + + // This matches `unwrap_trivial_aggregate` in the wasm ABI logic. + if arg.layout.is_aggregate() { + let cx = LayoutCx::new(tcx, TypingEnv::fully_monomorphized()); + if let Some(unit) = arg.layout.homogeneous_aggregate(&cx).ok().and_then(|ha| ha.unit()) { + let size = arg.layout.size; + // Ensure there's just a single `unit` element in `arg`. + if unit.size == size { + return true; + } + } + } + + false +} + +/// Warns against usage of `extern "C"` on wasm32-unknown-unknown that is affected by the +/// ABI transition. +fn do_check_wasm_abi<'tcx>( + tcx: TyCtxt<'tcx>, + abi: &FnAbi<'tcx, Ty<'tcx>>, + is_call: bool, + span: impl Fn() -> Span, +) { + // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`). + if !(tcx.sess.target.arch == "wasm32" + && tcx.sess.target.os == "unknown" + && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy + && abi.conv == Conv::C) + { + return; + } + // Warn against all types whose ABI will change. That's all arguments except for things passed as scalars. + // Return values are not affected by this change. + for arg_abi in abi.args.iter() { + if wasm_abi_safe(tcx, arg_abi) { + continue; + } + let span = span(); + tcx.emit_node_span_lint( + WASM_C_ABI, + CRATE_HIR_ID, + span, + errors::WasmCAbiTransition { ty: arg_abi.layout.ty, is_call }, + ); + // Let's only warn once per function. + break; + } +} + /// Checks that the ABI of a given instance of a function does not contain vector-passed arguments /// or return values for which the corresponding target feature is not enabled. fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { @@ -98,13 +156,10 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // function. return; }; - do_check_abi( - tcx, - abi, - instance.def_id(), - /*is_call*/ false, - || tcx.def_span(instance.def_id()), - ) + do_check_simd_vector_abi(tcx, abi, instance.def_id(), /*is_call*/ false, || { + tcx.def_span(instance.def_id()) + }); + do_check_wasm_abi(tcx, abi, /*is_call*/ false, || tcx.def_span(instance.def_id())); } /// Checks that a call expression does not try to pass a vector-passed argument which requires a @@ -141,7 +196,8 @@ fn check_call_site_abi<'tcx>( // ABI failed to compute; this will not get through codegen. return; }; - do_check_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, || span); + do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, || span); + do_check_wasm_abi(tcx, callee_abi, /*is_call*/ true, || span); } fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) { diff --git a/compiler/rustc_target/src/callconv/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs index 364a65511311..881168c98c32 100644 --- a/compiler/rustc_target/src/callconv/wasm.rs +++ b/compiler/rustc_target/src/callconv/wasm.rs @@ -10,6 +10,9 @@ where if val.layout.is_aggregate() { if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) { let size = val.layout.size; + // This size check also catches over-aligned scalars as `size` will be rounded up to a + // multiple of the alignment, and the default alignment of all scalar types on wasm + // equals their size. if unit.size == size { val.cast_to(unit); return true; diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 64e65ece85d6..be649029c863 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -62,7 +62,6 @@ //@[nvptx64] needs-llvm-components: nvptx #![feature(no_core, rustc_attrs, lang_items)] #![feature(unsized_fn_params, transparent_unions)] -#![no_std] #![no_core] #![allow(unused, improper_ctypes_definitions, internal_features)] diff --git a/tests/ui/lint/wasm_c_abi_transition.rs b/tests/ui/lint/wasm_c_abi_transition.rs new file mode 100644 index 000000000000..1fe81679e65d --- /dev/null +++ b/tests/ui/lint/wasm_c_abi_transition.rs @@ -0,0 +1,41 @@ +//@ compile-flags: --target wasm32-unknown-unknown +//@ needs-llvm-components: webassembly +//@ add-core-stubs +//@ build-fail + +#![feature(no_core)] +#![no_core] +#![crate_type = "lib"] +#![deny(wasm_c_abi)] + +extern crate minicore; +use minicore::*; + +pub extern "C" fn my_fun_trivial(_x: i32, _y: f32) {} + +#[repr(C)] +pub struct MyType(i32, i32); +pub extern "C" fn my_fun(_x: MyType) {} //~ERROR: wasm ABI transition +//~^WARN: previously accepted + +// This one is ABI-safe as it only wraps a single field, +// and the return type can be anything. +#[repr(C)] +pub struct MySafeType(i32); +pub extern "C" fn my_fun_safe(_x: MySafeType) -> MyType { loop {} } + +// This one not ABI-safe due to the alignment. +#[repr(C, align(16))] +pub struct MyAlignedType(i32); +pub extern "C" fn my_fun_aligned(_x: MyAlignedType) {} //~ERROR: wasm ABI transition +//~^WARN: previously accepted + +// Check call-site warning +extern "C" { + fn other_fun(x: MyType); +} + +pub fn call_other_fun(x: MyType) { + unsafe { other_fun(x) } //~ERROR: wasm ABI transition + //~^WARN: previously accepted +} diff --git a/tests/ui/lint/wasm_c_abi_transition.stderr b/tests/ui/lint/wasm_c_abi_transition.stderr new file mode 100644 index 000000000000..389710d5cb3a --- /dev/null +++ b/tests/ui/lint/wasm_c_abi_transition.stderr @@ -0,0 +1,85 @@ +error: this function definition involves an argument of type `MyType` which is affected by the wasm ABI transition + --> $DIR/wasm_c_abi_transition.rs:18:1 + | +LL | pub extern "C" fn my_fun(_x: MyType) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #138762 + = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target +note: the lint level is defined here + --> $DIR/wasm_c_abi_transition.rs:9:9 + | +LL | #![deny(wasm_c_abi)] + | ^^^^^^^^^^ + +error: this function definition involves an argument of type `MyAlignedType` which is affected by the wasm ABI transition + --> $DIR/wasm_c_abi_transition.rs:30:1 + | +LL | pub extern "C" fn my_fun_aligned(_x: MyAlignedType) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #138762 + = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target + +error: this function call involves an argument of type `MyType` which is affected by the wasm ABI transition + --> $DIR/wasm_c_abi_transition.rs:39:14 + | +LL | unsafe { other_fun(x) } + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #138762 + = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target + +error: aborting due to 3 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: this function definition involves an argument of type `MyType` which is affected by the wasm ABI transition + --> $DIR/wasm_c_abi_transition.rs:18:1 + | +LL | pub extern "C" fn my_fun(_x: MyType) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #138762 + = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target +note: the lint level is defined here + --> $DIR/wasm_c_abi_transition.rs:9:9 + | +LL | #![deny(wasm_c_abi)] + | ^^^^^^^^^^ + +Future breakage diagnostic: +error: this function definition involves an argument of type `MyAlignedType` which is affected by the wasm ABI transition + --> $DIR/wasm_c_abi_transition.rs:30:1 + | +LL | pub extern "C" fn my_fun_aligned(_x: MyAlignedType) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #138762 + = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target +note: the lint level is defined here + --> $DIR/wasm_c_abi_transition.rs:9:9 + | +LL | #![deny(wasm_c_abi)] + | ^^^^^^^^^^ + +Future breakage diagnostic: +error: this function call involves an argument of type `MyType` which is affected by the wasm ABI transition + --> $DIR/wasm_c_abi_transition.rs:39:14 + | +LL | unsafe { other_fun(x) } + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #138762 + = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target +note: the lint level is defined here + --> $DIR/wasm_c_abi_transition.rs:9:9 + | +LL | #![deny(wasm_c_abi)] + | ^^^^^^^^^^ + From 072ccce553dd83ebfdf0aaf99eb24f65133c368b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Mar 2025 22:59:56 +0100 Subject: [PATCH 308/546] make -Zwasm-c-abi=legacy suppress the lint --- compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 4 ++-- compiler/rustc_monomorphize/src/mono_checks/abi_check.rs | 9 +++++---- compiler/rustc_session/src/options.rs | 5 +++-- compiler/rustc_target/src/callconv/mod.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 5 ++++- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index bc9cde1b2a15..3a6b1f8d4efc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -332,7 +332,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id // please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs` // basically the commit introducing this comment should be reverted if let PassMode::Pair { .. } = fn_abi.ret.mode { - let _ = WasmCAbi::Legacy; + let _ = WasmCAbi::Legacy { with_lint: true }; span_bug!( tcx.def_span(def_id), "cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" @@ -384,7 +384,7 @@ fn wasm_type<'tcx>( BackendRepr::SimdVector { .. } => "v128", BackendRepr::Memory { .. } => { // FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed - let _ = WasmCAbi::Legacy; + let _ = WasmCAbi::Legacy { with_lint: true }; span_bug!( tcx.def_span(def_id), "cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index f17f7261df58..40740c3fdf65 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -92,6 +92,7 @@ fn do_check_simd_vector_abi<'tcx>( } } +/// Determines whether the given argument is passed the same way on the old and new wasm ABIs. fn wasm_abi_safe<'tcx>(tcx: TyCtxt<'tcx>, arg: &ArgAbi<'tcx, Ty<'tcx>>) -> bool { if matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) { return true; @@ -120,16 +121,16 @@ fn do_check_wasm_abi<'tcx>( is_call: bool, span: impl Fn() -> Span, ) { - // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`). + // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`), + // and only proceed if `wasm_c_abi_opt` indicates we should emit the lint. if !(tcx.sess.target.arch == "wasm32" && tcx.sess.target.os == "unknown" - && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy + && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy { with_lint: true } && abi.conv == Conv::C) { return; } - // Warn against all types whose ABI will change. That's all arguments except for things passed as scalars. - // Return values are not affected by this change. + // Warn against all types whose ABI will change. Return values are not affected by this change. for arg_abi in abi.args.iter() { if wasm_abi_safe(tcx, arg_abi) { continue; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b3be4b611f03..828230f2fe66 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1886,7 +1886,8 @@ pub mod parse { pub(crate) fn parse_wasm_c_abi(slot: &mut WasmCAbi, v: Option<&str>) -> bool { match v { Some("spec") => *slot = WasmCAbi::Spec, - Some("legacy") => *slot = WasmCAbi::Legacy, + // Explicitly setting the `-Z` flag suppresses the lint. + Some("legacy") => *slot = WasmCAbi::Legacy { with_lint: false }, _ => return false, } true @@ -2599,7 +2600,7 @@ written to standard error output)"), Requires `-Clto[=[fat,yes]]`"), wasi_exec_model: Option = (None, parse_wasi_exec_model, [TRACKED], "whether to build a wasi command or reactor"), - wasm_c_abi: WasmCAbi = (WasmCAbi::Legacy, parse_wasm_c_abi, [TRACKED], + wasm_c_abi: WasmCAbi = (WasmCAbi::Legacy { with_lint: true }, parse_wasm_c_abi, [TRACKED], "use spec-compliant C ABI for `wasm32-unknown-unknown` (default: legacy)"), write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED], "whether long type names should be written to files instead of being printed in errors"), diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 6d0ee3c7ee58..a52b2b76bc1e 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -705,7 +705,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), "wasm32" => { - if spec.os == "unknown" && cx.wasm_c_abi_opt() == WasmCAbi::Legacy { + if spec.os == "unknown" && matches!(cx.wasm_c_abi_opt(), WasmCAbi::Legacy { .. }) { wasm::compute_wasm_abi_info(self) } else { wasm::compute_c_abi_info(cx, self) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1887134c5757..1a823f47d9d9 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2234,7 +2234,10 @@ pub enum WasmCAbi { /// Spec-compliant C ABI. Spec, /// Legacy ABI. Which is non-spec-compliant. - Legacy, + Legacy { + /// Indicates whether the `wasm_c_abi` lint should be emitted. + with_lint: bool, + }, } pub trait HasWasmCAbiOpt { From 61e24e630d5eea7bbff63e46051de509ceb46c33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Mar 2025 18:42:01 +0100 Subject: [PATCH 309/546] allow wasm_c_abi in proc_macro bridge --- library/proc_macro/src/bridge/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 03c3e697cfe2..52cc8fba0438 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -7,6 +7,10 @@ //! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). #![deny(unsafe_code)] +// proc_macros anyway don't work on wasm hosts so while both sides of this bridge can +// be built with different versions of rustc, the wasm ABI changes don't really matter. +#![cfg_attr(bootstrap, allow(unknown_lints))] +#![allow(wasm_c_abi)] use std::hash::Hash; use std::ops::{Bound, Range}; From f756304655b8604327f7a906c9e55b74a5fedfd1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 10 Mar 2025 18:24:54 +0300 Subject: [PATCH 310/546] privacy: Visit types and traits in impls in type privacy lints --- compiler/rustc_privacy/src/lib.rs | 40 ++++++++++++++----- tests/ui/privacy/pub-priv-dep/pub-priv1.rs | 7 ++-- .../ui/privacy/pub-priv-dep/pub-priv1.stderr | 22 +++++++++- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ed00d97c31da..643b82f47530 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -72,7 +72,9 @@ impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> { pub trait DefIdVisitor<'tcx> { type Result: VisitorResult = (); const SHALLOW: bool = false; - const SKIP_ASSOC_TYS: bool = false; + fn skip_assoc_tys(&self) -> bool { + false + } fn tcx(&self) -> TyCtxt<'tcx>; fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) @@ -213,7 +215,7 @@ where } } ty::Alias(kind @ (ty::Inherent | ty::Weak | ty::Projection), data) => { - if V::SKIP_ASSOC_TYS { + if self.def_id_visitor.skip_assoc_tys() { // Visitors searching for minimal visibility/reachability want to // conservatively approximate associated types like `Type::Alias` // as visible/reachable even if `Type` is private. @@ -324,7 +326,9 @@ impl<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL, SHALLOW> { const SHALLOW: bool = SHALLOW; - const SKIP_ASSOC_TYS: bool = true; + fn skip_assoc_tys(&self) -> bool { + true + } fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -342,7 +346,7 @@ trait VisibilityLike: Sized { def_id: LocalDefId, ) -> Self; - // Returns an over-approximation (`SKIP_ASSOC_TYS` = true) of visibility due to + // Returns an over-approximation (`skip_assoc_tys()` = true) of visibility due to // associated types for which we can't determine visibility precisely. fn of_impl( def_id: LocalDefId, @@ -1352,6 +1356,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'tcx> { required_effective_vis: Option, in_assoc_ty: bool, in_primary_interface: bool, + skip_assoc_tys: bool, } impl SearchInterfaceForPrivateItemsVisitor<'_> { @@ -1398,6 +1403,14 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { self } + fn trait_ref(&mut self) -> &mut Self { + self.in_primary_interface = true; + if let Some(trait_ref) = self.tcx.impl_trait_ref(self.item_def_id) { + let _ = self.visit_trait(trait_ref.instantiate_identity()); + } + self + } + fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { if self.leaks_private_dep(def_id) { self.tcx.emit_node_span_lint( @@ -1495,6 +1508,9 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { type Result = ControlFlow<()>; + fn skip_assoc_tys(&self) -> bool { + self.skip_assoc_tys + } fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1531,6 +1547,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { required_effective_vis, in_assoc_ty: false, in_primary_interface: true, + skip_assoc_tys: false, } } @@ -1726,13 +1743,18 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { self.effective_visibilities, ); - // check that private components do not appear in the generics or predicates of inherent impls - // this check is intentionally NOT performed for impls of traits, per #90586 + let mut check = self.check(item.owner_id.def_id, impl_vis, Some(impl_ev)); + // Generics and predicates of trait impls are intentionally not checked + // for private components (#90586). if impl_.of_trait.is_none() { - self.check(item.owner_id.def_id, impl_vis, Some(impl_ev)) - .generics() - .predicates(); + check.generics().predicates(); } + // Skip checking private components in associated types, due to lack of full + // normalization they produce very ridiculous false positives. + // FIXME: Remove this when full normalization is implemented. + check.skip_assoc_tys = true; + check.ty().trait_ref(); + for impl_item_ref in impl_.items { let impl_item_vis = if impl_.of_trait.is_none() { min( diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs index 112eaf528be2..877029f3de37 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -77,15 +77,14 @@ pub type Alias = OtherType; pub struct PublicWithPrivateImpl; -// FIXME: This should trigger. -// See https://github.com/rust-lang/rust/issues/71043 impl OtherTrait for PublicWithPrivateImpl {} +//~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface pub trait PubTraitOnPrivate {} -// FIXME: This should trigger. -// See https://github.com/rust-lang/rust/issues/71043 impl PubTraitOnPrivate for OtherType {} +//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface +//~| ERROR type `OtherType` from private dependency 'priv_dep' in public interface pub struct AllowedPrivType { #[allow(exported_private_dependencies)] diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr index 53d461a5774a..adfe13424cdf 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -70,5 +70,25 @@ error: type `OtherType` from private dependency 'priv_dep' in public interface LL | pub type Alias = OtherType; | ^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: trait `OtherTrait` from private dependency 'priv_dep' in public interface + --> $DIR/pub-priv1.rs:80:1 + | +LL | impl OtherTrait for PublicWithPrivateImpl {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: type `OtherType` from private dependency 'priv_dep' in public interface + --> $DIR/pub-priv1.rs:85:1 + | +LL | impl PubTraitOnPrivate for OtherType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: type `OtherType` from private dependency 'priv_dep' in public interface + --> $DIR/pub-priv1.rs:85:1 + | +LL | impl PubTraitOnPrivate for OtherType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 14 previous errors From 502d57cb78082efa16ed661ddfb501c189f18321 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 25 Mar 2025 09:02:28 +0000 Subject: [PATCH 311/546] Deduplicate assoc item cfg handling --- compiler/rustc_builtin_macros/src/cfg_eval.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 5788966b6e7b..b3ba90731184 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -121,18 +121,11 @@ impl CfgEval<'_> { let item = parser.parse_item(ForceCollect::Yes)?.unwrap(); Annotatable::Item(self.flat_map_item(item).pop().unwrap()) } - Annotatable::AssocItem(_, AssocCtxt::Trait) => { + Annotatable::AssocItem(_, ctxt) => { let item = parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(); Annotatable::AssocItem( - self.flat_map_assoc_item(item, AssocCtxt::Trait).pop().unwrap(), - AssocCtxt::Trait, - ) - } - Annotatable::AssocItem(_, AssocCtxt::Impl) => { - let item = parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(); - Annotatable::AssocItem( - self.flat_map_assoc_item(item, AssocCtxt::Impl).pop().unwrap(), - AssocCtxt::Impl, + self.flat_map_assoc_item(item, ctxt).pop().unwrap(), + ctxt, ) } Annotatable::ForeignItem(_) => { From 7cdc456727fb663bf53232ec414a9001410ac843 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 25 Mar 2025 09:00:35 +0000 Subject: [PATCH 312/546] Track whether an assoc item is in a trait impl or an inherent impl --- compiler/rustc_ast/src/mut_visit.rs | 4 +- compiler/rustc_ast/src/visit.rs | 9 +- compiler/rustc_ast_lowering/src/item.rs | 31 ++---- .../rustc_ast_passes/src/ast_validation.rs | 6 +- compiler/rustc_builtin_macros/src/autodiff.rs | 6 +- compiler/rustc_expand/src/base.rs | 15 ++- compiler/rustc_expand/src/expand.rs | 101 +++++++++++++++--- compiler/rustc_expand/src/placeholders.rs | 14 ++- compiler/rustc_lint/src/early.rs | 4 +- .../rustc_resolve/src/build_reduced_graph.rs | 15 ++- compiler/rustc_resolve/src/late.rs | 4 +- compiler/rustc_resolve/src/lib.rs | 5 - compiler/rustc_resolve/src/macros.rs | 2 +- src/tools/rustfmt/src/visitor.rs | 3 +- 14 files changed, 151 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 4edd08643000..604555e2df74 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1318,7 +1318,9 @@ impl WalkItemKind for ItemKind { visit_polarity(vis, polarity); visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref)); vis.visit_ty(self_ty); - items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Impl)); + items.flat_map_in_place(|item| { + vis.flat_map_assoc_item(item, AssocCtxt::Impl { of_trait: of_trait.is_some() }) + }); } ItemKind::Trait(box Trait { safety, is_auto: _, generics, bounds, items }) => { visit_safety(vis, safety); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ce8d6df75afb..9f6a53248089 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -23,7 +23,7 @@ use crate::ptr::P; #[derive(Copy, Clone, Debug, PartialEq)] pub enum AssocCtxt { Trait, - Impl, + Impl { of_trait: bool }, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -422,7 +422,12 @@ impl WalkItemKind for ItemKind { try_visit!(visitor.visit_generics(generics)); visit_opt!(visitor, visit_trait_ref, of_trait); try_visit!(visitor.visit_ty(self_ty)); - walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl); + walk_list!( + visitor, + visit_assoc_item, + items, + AssocCtxt::Impl { of_trait: of_trait.is_some() } + ); } ItemKind::Struct(struct_definition, generics) | ItemKind::Union(struct_definition, generics) => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 518349343b3a..cf7ffde83613 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -7,7 +7,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, HirId, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; @@ -104,10 +103,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { } fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) { - let def_id = self.resolver.node_id_to_def_id[&item.id]; - let parent_id = self.tcx.local_parent(def_id); - let parent_hir = self.lower_node(parent_id).unwrap(); - self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt, parent_hir)) + self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt)) } fn lower_foreign_item(&mut self, item: &ForeignItem) { @@ -631,29 +627,18 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_assoc_item( - &mut self, - item: &AssocItem, - ctxt: AssocCtxt, - parent_hir: &'hir hir::OwnerInfo<'hir>, - ) -> hir::OwnerNode<'hir> { - let parent_item = parent_hir.node().expect_item(); - match parent_item.kind { - hir::ItemKind::Impl(impl_) => { - self.is_in_trait_impl = impl_.of_trait.is_some(); - } - hir::ItemKind::Trait(..) => {} - kind => { - span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr()) - } - } - + fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) -> hir::OwnerNode<'hir> { // Evaluate with the lifetimes in `params` in-scope. // This is used to track which lifetimes have already been defined, // and which need to be replicated when lowering an async fn. match ctxt { AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)), + AssocCtxt::Impl { of_trait } => { + if of_trait { + self.is_in_trait_impl = of_trait; + } + hir::OwnerNode::ImplItem(self.lower_impl_item(item)) + } } } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 75839e86b8d3..a1487ca74be8 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -860,7 +860,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.visit_trait_ref(t); this.visit_ty(self_ty); - walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); + walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true }); }); walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. @@ -913,7 +913,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { |this| this.visit_generics(generics), ); this.visit_ty(self_ty); - walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); + walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false }); }); walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. @@ -1414,7 +1414,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_defaultness(item.span, item.kind.defaultness()); } - if ctxt == AssocCtxt::Impl { + if let AssocCtxt::Impl { .. } = ctxt { match &item.kind { AssocItemKind::Const(box ConstItem { expr: None, .. }) => { self.dcx().emit_err(errors::AssocConstWithoutBody { diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 6591ed151cf6..5cd653c79456 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -157,7 +157,7 @@ mod llvm_enzyme { }; (sig.clone(), false) } - Annotatable::AssocItem(assoc_item, _) => { + Annotatable::AssocItem(assoc_item, Impl { of_trait: false }) => { let sig = match &assoc_item.kind { ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) => sig, _ => { @@ -296,7 +296,7 @@ mod llvm_enzyme { } Annotatable::Item(iitem.clone()) } - Annotatable::AssocItem(ref mut assoc_item, i @ Impl) => { + Annotatable::AssocItem(ref mut assoc_item, i @ Impl { of_trait: false }) => { if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { assoc_item.attrs.push(attr); } @@ -327,7 +327,7 @@ mod llvm_enzyme { kind: assoc_item, tokens: None, }); - Annotatable::AssocItem(d_fn, Impl) + Annotatable::AssocItem(d_fn, Impl { of_trait: false }) } else { let mut d_fn = ecx.item(span, d_ident, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 1dd152beb475..990d0f2e028a 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -153,7 +153,7 @@ impl Annotatable { pub fn expect_impl_item(self) -> P { match self { - Annotatable::AssocItem(i, AssocCtxt::Impl) => i, + Annotatable::AssocItem(i, AssocCtxt::Impl { .. }) => i, _ => panic!("expected Item"), } } @@ -403,6 +403,11 @@ pub trait MacResult { None } + /// Creates zero or more impl items. + fn make_trait_impl_items(self: Box) -> Option; 1]>> { + None + } + /// Creates zero or more trait items. fn make_trait_items(self: Box) -> Option; 1]>> { None @@ -516,6 +521,10 @@ impl MacResult for MacEager { self.impl_items } + fn make_trait_impl_items(self: Box) -> Option; 1]>> { + self.impl_items + } + fn make_trait_items(self: Box) -> Option; 1]>> { self.trait_items } @@ -613,6 +622,10 @@ impl MacResult for DummyResult { Some(SmallVec::new()) } + fn make_trait_impl_items(self: Box) -> Option; 1]>> { + Some(SmallVec::new()) + } + fn make_trait_items(self: Box) -> Option; 1]>> { Some(SmallVec::new()) } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index e2a557528504..d0bd8a89d9bd 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -188,9 +188,15 @@ ast_fragments! { ImplItems(SmallVec<[P; 1]>) { "impl item"; many fn flat_map_assoc_item; - fn visit_assoc_item(AssocCtxt::Impl); + fn visit_assoc_item(AssocCtxt::Impl { of_trait: false }); fn make_impl_items; } + TraitImplItems(SmallVec<[P; 1]>) { + "impl item"; + many fn flat_map_assoc_item; + fn visit_assoc_item(AssocCtxt::Impl { of_trait: true }); + fn make_trait_impl_items; + } ForeignItems(SmallVec<[P; 1]>) { "foreign item"; many fn flat_map_foreign_item; @@ -257,6 +263,7 @@ impl AstFragmentKind { AstFragmentKind::Items | AstFragmentKind::TraitItems | AstFragmentKind::ImplItems + | AstFragmentKind::TraitImplItems | AstFragmentKind::ForeignItems | AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true }, AstFragmentKind::Arms @@ -306,6 +313,9 @@ impl AstFragmentKind { AstFragmentKind::ImplItems => { AstFragment::ImplItems(items.map(Annotatable::expect_impl_item).collect()) } + AstFragmentKind::TraitImplItems => { + AstFragment::TraitImplItems(items.map(Annotatable::expect_impl_item).collect()) + } AstFragmentKind::TraitItems => { AstFragment::TraitItems(items.map(Annotatable::expect_trait_item).collect()) } @@ -347,10 +357,10 @@ pub enum InvocationKind { }, Attr { attr: ast::Attribute, - // Re-insertion position for inert attributes. + /// Re-insertion position for inert attributes. pos: usize, item: Annotatable, - // Required for resolving derive helper attributes. + /// Required for resolving derive helper attributes. derives: Vec, }, Derive { @@ -360,6 +370,8 @@ pub enum InvocationKind { }, GlobDelegation { item: P, + /// Whether this is a trait impl or an inherent impl + of_trait: bool, }, } @@ -388,7 +400,7 @@ impl Invocation { InvocationKind::Bang { span, .. } => *span, InvocationKind::Attr { attr, .. } => attr.span, InvocationKind::Derive { path, .. } => path.span, - InvocationKind::GlobDelegation { item } => item.span, + InvocationKind::GlobDelegation { item, .. } => item.span, } } @@ -397,7 +409,7 @@ impl Invocation { InvocationKind::Bang { span, .. } => span, InvocationKind::Attr { attr, .. } => &mut attr.span, InvocationKind::Derive { path, .. } => &mut path.span, - InvocationKind::GlobDelegation { item } => &mut item.span, + InvocationKind::GlobDelegation { item, .. } => &mut item.span, } } } @@ -820,7 +832,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!(), }, - InvocationKind::GlobDelegation { item } => { + InvocationKind::GlobDelegation { item, of_trait } => { let AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() }; let suffixes = match ext { SyntaxExtensionKind::GlobDelegation(expander) => match expander.expand(self.cx) @@ -829,7 +841,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ExpandResult::Retry(()) => { // Reassemble the original invocation for retrying. return ExpandResult::Retry(Invocation { - kind: InvocationKind::GlobDelegation { item }, + kind: InvocationKind::GlobDelegation { item, of_trait }, ..invoc }); } @@ -847,7 +859,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx, deleg, &item, &suffixes, item.span, true, ); fragment_kind.expect_from_annotatables( - single_delegations.map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl)), + single_delegations + .map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl { of_trait })), ) } }) @@ -973,6 +986,13 @@ pub fn parse_ast_fragment<'a>( } AstFragment::ImplItems(items) } + AstFragmentKind::TraitImplItems => { + let mut items = SmallVec::new(); + while let Some(item) = this.parse_impl_item(ForceCollect::No)? { + items.extend(item); + } + AstFragment::TraitImplItems(items) + } AstFragmentKind::ForeignItems => { let mut items = SmallVec::new(); while let Some(item) = this.parse_foreign_item(ForceCollect::No)? { @@ -1355,13 +1375,13 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::ImplItems; fn to_annotatable(self) -> Annotatable { - Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl) + Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl { of_trait: false }) } fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_impl_items() } fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl) + walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl { of_trait: false }) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1390,6 +1410,47 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> } } +struct TraitImplItemTag; +impl InvocationCollectorNode for AstNodeWrapper, TraitImplItemTag> { + type OutputTy = SmallVec<[P; 1]>; + type ItemKind = AssocItemKind; + const KIND: AstFragmentKind = AstFragmentKind::TraitImplItems; + fn to_annotatable(self) -> Annotatable { + Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl { of_trait: true }) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_trait_impl_items() + } + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl { of_trait: true }) + } + fn is_mac_call(&self) -> bool { + matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) + } + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + let item = self.wrapped.into_inner(); + match item.kind { + AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } + fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item)> { + match &self.wrapped.kind { + AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)), + _ => None, + } + } + fn delegation_item_kind(deleg: Box) -> Self::ItemKind { + AssocItemKind::Delegation(deleg) + } + fn from_item(item: ast::Item) -> Self { + AstNodeWrapper::new(P(item), TraitImplItemTag) + } + fn flatten_outputs(items: impl Iterator) -> Self::OutputTy { + items.flatten().collect() + } +} + impl InvocationCollectorNode for P { const KIND: AstFragmentKind = AstFragmentKind::ForeignItems; fn to_annotatable(self) -> Annotatable { @@ -1855,9 +1916,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_glob_delegation( &mut self, item: P, + of_trait: bool, kind: AstFragmentKind, ) -> AstFragment { - self.collect(kind, InvocationKind::GlobDelegation { item }) + self.collect(kind, InvocationKind::GlobDelegation { item, of_trait }) } /// If `item` is an attribute invocation, remove the attribute and return it together with @@ -2030,8 +2092,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let Some(suffixes) = &deleg.suffixes else { let traitless_qself = matches!(&deleg.qself, Some(qself) if qself.position == 0); - let item = match node.to_annotatable() { - Annotatable::AssocItem(item, AssocCtxt::Impl) => item, + let (item, of_trait) = match node.to_annotatable() { + Annotatable::AssocItem(item, AssocCtxt::Impl { of_trait }) => { + (item, of_trait) + } ann @ (Annotatable::Item(_) | Annotatable::AssocItem(..) | Annotatable::Stmt(_)) => { @@ -2046,7 +2110,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.cx.dcx().emit_err(GlobDelegationTraitlessQpath { span }); return Default::default(); } - return self.collect_glob_delegation(item, Node::KIND).make_ast::(); + return self + .collect_glob_delegation(item, of_trait, Node::KIND) + .make_ast::(); }; let single_delegations = build_single_delegations::( @@ -2126,7 +2192,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { ) -> SmallVec<[P; 1]> { match ctxt { AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)), - AssocCtxt::Impl => self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)), + AssocCtxt::Impl { of_trait: false } => { + self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)) + } + AssocCtxt::Impl { of_trait: true } => { + self.flat_map_node(AstNodeWrapper::new(node, TraitImplItemTag)) + } } } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 3a470924c7f6..a60a87244cc6 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -86,6 +86,17 @@ pub(crate) fn placeholder( kind: ast::AssocItemKind::MacCall(mac_placeholder()), tokens: None, })]), + AstFragmentKind::TraitImplItems => { + AstFragment::TraitImplItems(smallvec![P(ast::AssocItem { + id, + span, + ident, + vis, + attrs, + kind: ast::AssocItemKind::MacCall(mac_placeholder()), + tokens: None, + })]) + } AstFragmentKind::ForeignItems => { AstFragment::ForeignItems(smallvec![P(ast::ForeignItem { id, @@ -308,7 +319,8 @@ impl MutVisitor for PlaceholderExpander { let it = self.remove(item.id); match ctxt { AssocCtxt::Trait => it.make_trait_items(), - AssocCtxt::Impl => it.make_impl_items(), + AssocCtxt::Impl { of_trait: false } => it.make_impl_items(), + AssocCtxt::Impl { of_trait: true } => it.make_trait_impl_items(), } } _ => walk_flat_map_assoc_item(self, item, ctxt), diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 723b894c43bc..f9601fa5ef1d 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -241,7 +241,7 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> ast_visit::AssocCtxt::Trait => { lint_callback!(cx, check_trait_item, item); } - ast_visit::AssocCtxt::Impl => { + ast_visit::AssocCtxt::Impl { .. } => { lint_callback!(cx, check_impl_item, item); } } @@ -250,7 +250,7 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> ast_visit::AssocCtxt::Trait => { lint_callback!(cx, check_trait_item_post, item); } - ast_visit::AssocCtxt::Impl => { + ast_visit::AssocCtxt::Impl { .. } => { lint_callback!(cx, check_impl_item_post, item); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 763e9207a126..2e70019ba8ad 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -884,10 +884,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items do not add names to modules. - ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => { - self.r.trait_impl_items.insert(local_def_id); - } - ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} + ItemKind::Impl(box Impl { of_trait: Some(..), .. }) + | ItemKind::Impl { .. } + | ItemKind::ForeignMod(..) + | ItemKind::GlobalAsm(..) => {} ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => { unreachable!() @@ -1378,7 +1378,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { AssocCtxt::Trait => { self.visit_invoc_in_module(item.id); } - AssocCtxt::Impl => { + AssocCtxt::Impl { .. } => { let invoc_id = item.id.placeholder_to_expn_id(); if !self.r.glob_delegation_invoc_ids.contains(&invoc_id) { self.r @@ -1398,9 +1398,8 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let local_def_id = feed.key(); let def_id = local_def_id.to_def_id(); - if !(ctxt == AssocCtxt::Impl - && matches!(item.vis.kind, ast::VisibilityKind::Inherited) - && self.r.trait_impl_items.contains(&self.r.tcx.local_parent(local_def_id))) + if !(matches!(ctxt, AssocCtxt::Impl { of_trait: true }) + && matches!(item.vis.kind, ast::VisibilityKind::Inherited)) { // Trait impl item visibility is inherited from its trait when not specified // explicitly. In that case we cannot determine it here in early resolve, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index e04d0083548b..177a2d00ac3c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3376,7 +3376,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |i, s, c| MethodNotMemberOfTrait(i, s, c), ); - visit::walk_assoc_item(this, item, AssocCtxt::Impl) + visit::walk_assoc_item(this, item, AssocCtxt::Impl { of_trait: true }) }, ); @@ -3410,7 +3410,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |i, s, c| TypeNotMemberOfTrait(i, s, c), ); - visit::walk_assoc_item(this, item, AssocCtxt::Impl) + visit::walk_assoc_item(this, item, AssocCtxt::Impl { of_trait: true }) }); }, ); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ff31af0025b5..e37acdd1ce72 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1191,10 +1191,6 @@ pub struct Resolver<'ra, 'tcx> { /// and how the `impl Trait` fragments were introduced. invocation_parents: FxHashMap, - /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. - /// FIXME: Replace with a more general AST map (together with some other fields). - trait_impl_items: FxHashSet, - legacy_const_generic_args: FxHashMap>>, /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap, @@ -1558,7 +1554,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { def_id_to_node_id, placeholder_field_indices: Default::default(), invocation_parents, - trait_impl_items: Default::default(), legacy_const_generic_args: Default::default(), item_generics_num_lifetimes: Default::default(), main_def: Default::default(), diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 34441d313f59..aef98330e17e 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -264,7 +264,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang), InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive), - InvocationKind::GlobDelegation { ref item } => { + InvocationKind::GlobDelegation { ref item, .. } => { let ast::AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() }; deleg_impl = Some(self.invocation_parent(invoc_id)); // It is sufficient to consider glob delegation a bang macro for now. diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index a5cfc542a17c..5749d8c63faf 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -624,7 +624,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { // TODO(calebcartwright): Not sure the skip spans are correct let (ai, skip_span, assoc_ctxt) = match visitor_kind { AssocTraitItem(ai) => (*ai, ai.span(), visit::AssocCtxt::Trait), - AssocImplItem(ai) => (*ai, ai.span, visit::AssocCtxt::Impl), + // There is no difference between trait and inherent assoc item formatting + AssocImplItem(ai) => (*ai, ai.span, visit::AssocCtxt::Impl { of_trait: false }), _ => unreachable!(), }; skip_out_of_file_lines_range_visitor!(self, ai.span); From e88c49c454b965c4c60edf19d1305087c9758a29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Mar 2025 11:28:16 +0100 Subject: [PATCH 313/546] acquire more accurate HirId for ABI check lints --- .../src/mono_checks/abi_check.rs | 56 ++++++++++++------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 40740c3fdf65..0f5bdc8d7683 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -1,8 +1,8 @@ //! This module ensures that if a function's ABI requires a particular target feature, //! that target feature is enabled both on the callee and all callers. use rustc_abi::{BackendRepr, RegKind}; -use rustc_hir::CRATE_HIR_ID; -use rustc_middle::mir::{self, traversal}; +use rustc_hir::{CRATE_HIR_ID, HirId}; +use rustc_middle::mir::{self, Location, traversal}; use rustc_middle::ty::layout::LayoutCx; use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypingEnv}; use rustc_session::lint::builtin::{ABI_UNSUPPORTED_VECTOR_TYPES, WASM_C_ABI}; @@ -33,7 +33,7 @@ fn do_check_simd_vector_abi<'tcx>( abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId, is_call: bool, - span: impl Fn() -> Span, + loc: impl Fn() -> (Span, HirId), ) { // We check this on all functions, including those using the "Rust" ABI. // For the "Rust" ABI it would be a bug if the lint ever triggered, but better safe than sorry. @@ -50,10 +50,10 @@ fn do_check_simd_vector_abi<'tcx>( let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { Some((_, feature)) => feature, None => { - let span = span(); + let (span, hir_id) = loc(); tcx.emit_node_span_lint( ABI_UNSUPPORTED_VECTOR_TYPES, - CRATE_HIR_ID, + hir_id, span, errors::AbiErrorUnsupportedVectorType { span, @@ -66,10 +66,10 @@ fn do_check_simd_vector_abi<'tcx>( }; if !have_feature(Symbol::intern(feature)) { // Emit error. - let span = span(); + let (span, hir_id) = loc(); tcx.emit_node_span_lint( ABI_UNSUPPORTED_VECTOR_TYPES, - CRATE_HIR_ID, + hir_id, span, errors::AbiErrorDisabledVectorType { span, @@ -83,8 +83,9 @@ fn do_check_simd_vector_abi<'tcx>( } // The `vectorcall` ABI is special in that it requires SSE2 no matter which types are being passed. if abi.conv == Conv::X86VectorCall && !have_feature(sym::sse2) { + let (span, _hir_id) = loc(); tcx.dcx().emit_err(errors::AbiRequiredTargetFeature { - span: span(), + span, required_feature: "sse2", abi: "vectorcall", is_call, @@ -119,7 +120,7 @@ fn do_check_wasm_abi<'tcx>( tcx: TyCtxt<'tcx>, abi: &FnAbi<'tcx, Ty<'tcx>>, is_call: bool, - span: impl Fn() -> Span, + loc: impl Fn() -> (Span, HirId), ) { // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`), // and only proceed if `wasm_c_abi_opt` indicates we should emit the lint. @@ -135,10 +136,10 @@ fn do_check_wasm_abi<'tcx>( if wasm_abi_safe(tcx, arg_abi) { continue; } - let span = span(); + let (span, hir_id) = loc(); tcx.emit_node_span_lint( WASM_C_ABI, - CRATE_HIR_ID, + hir_id, span, errors::WasmCAbiTransition { ty: arg_abi.layout.ty, is_call }, ); @@ -157,10 +158,15 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // function. return; }; - do_check_simd_vector_abi(tcx, abi, instance.def_id(), /*is_call*/ false, || { - tcx.def_span(instance.def_id()) - }); - do_check_wasm_abi(tcx, abi, /*is_call*/ false, || tcx.def_span(instance.def_id())); + let loc = || { + let def_id = instance.def_id(); + ( + tcx.def_span(def_id), + def_id.as_local().map(|did| tcx.local_def_id_to_hir_id(did)).unwrap_or(CRATE_HIR_ID), + ) + }; + do_check_simd_vector_abi(tcx, abi, instance.def_id(), /*is_call*/ false, loc); + do_check_wasm_abi(tcx, abi, /*is_call*/ false, loc); } /// Checks that a call expression does not try to pass a vector-passed argument which requires a @@ -168,8 +174,8 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { fn check_call_site_abi<'tcx>( tcx: TyCtxt<'tcx>, callee: Ty<'tcx>, - span: Span, caller: InstanceKind<'tcx>, + loc: impl Fn() -> (Span, HirId) + Copy, ) { if callee.fn_sig(tcx).abi().is_rustic_abi() { // we directly handle the soundness of Rust ABIs @@ -197,8 +203,8 @@ fn check_call_site_abi<'tcx>( // ABI failed to compute; this will not get through codegen. return; }; - do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, || span); - do_check_wasm_abi(tcx, callee_abi, /*is_call*/ true, || span); + do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, loc); + do_check_wasm_abi(tcx, callee_abi, /*is_call*/ true, loc); } fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) { @@ -214,7 +220,19 @@ fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &m ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(callee_ty), ); - check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance); + check_call_site_abi(tcx, callee_ty, body.source.instance, || { + let loc = Location { + block: bb, + statement_index: body.basic_blocks[bb].statements.len(), + }; + ( + *fn_span, + body.source_info(loc) + .scope + .lint_root(&body.source_scopes) + .unwrap_or(CRATE_HIR_ID), + ) + }); } _ => {} } From 8524a7c4b7faab823f7e03d012b365bb05b82654 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 25 Mar 2025 10:31:05 +0000 Subject: [PATCH 314/546] Fix UWP reparse point check --- library/std/src/sys/fs/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 06bba019393a..15727c996837 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -547,7 +547,7 @@ impl File { ))?; attr.file_size = info.AllocationSize as u64; attr.number_of_links = Some(info.NumberOfLinks); - if attr.file_type().is_reparse_point() { + if attr.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), From 59e3380744d84c16c23e8d74438c515839306f99 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 25 Mar 2025 10:17:44 +0000 Subject: [PATCH 315/546] Avoid some more global state --- compiler/rustc_ast_lowering/src/delegation.rs | 16 ++++++-- compiler/rustc_ast_lowering/src/item.rs | 39 +++++++++++-------- compiler/rustc_ast_lowering/src/lib.rs | 2 - 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index efc1fa05c5f9..f7640c602d6f 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -61,8 +61,14 @@ pub(crate) struct DelegationResults<'hir> { impl<'hir> LoweringContext<'_, 'hir> { /// Defines whether the delegatee is an associated function whose first parameter is `self`. - pub(crate) fn delegatee_is_method(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool { - let sig_id = self.get_delegation_sig_id(item_id, path_id, span); + pub(crate) fn delegatee_is_method( + &self, + item_id: NodeId, + path_id: NodeId, + span: Span, + is_in_trait_impl: bool, + ) -> bool { + let sig_id = self.get_delegation_sig_id(item_id, path_id, span, is_in_trait_impl); let Ok(sig_id) = sig_id else { return false; }; @@ -88,9 +94,10 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, delegation: &Delegation, item_id: NodeId, + is_in_trait_impl: bool, ) -> DelegationResults<'hir> { let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); - let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span); + let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl); match sig_id { Ok(sig_id) => { let (param_count, c_variadic) = self.param_count(sig_id); @@ -110,8 +117,9 @@ impl<'hir> LoweringContext<'_, 'hir> { item_id: NodeId, path_id: NodeId, span: Span, + is_in_trait_impl: bool, ) -> Result { - let sig_id = if self.is_in_trait_impl { item_id } else { path_id }; + let sig_id = if is_in_trait_impl { item_id } else { path_id }; self.get_resolution_id(sig_id, span) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index cf7ffde83613..2b4b379525bc 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -404,10 +404,11 @@ impl<'hir> LoweringContext<'_, 'hir> { (trait_ref, lowered_ty) }); - self.is_in_trait_impl = trait_ref.is_some(); - let new_impl_items = self - .arena - .alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item))); + let new_impl_items = self.arena.alloc_from_iter( + impl_items + .iter() + .map(|item| self.lower_impl_item_ref(item, trait_ref.is_some())), + ); // `defaultness.has_value()` is never called for an `impl`, always `true` in order // to not cause an assertion failure inside the `lower_defaultness` function. @@ -484,7 +485,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Delegation(box delegation) => { debug_assert_ne!(ident.name, kw::Empty); let ident = self.lower_ident(ident); - let delegation_results = self.lower_delegation(delegation, id); + let delegation_results = self.lower_delegation(delegation, id, false); hir::ItemKind::Fn { ident, sig: delegation_results.sig, @@ -634,10 +635,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match ctxt { AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)), AssocCtxt::Impl { of_trait } => { - if of_trait { - self.is_in_trait_impl = of_trait; - } - hir::OwnerNode::ImplItem(self.lower_impl_item(item)) + hir::OwnerNode::ImplItem(self.lower_impl_item(item, of_trait)) } } } @@ -879,7 +877,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, kind, ty.is_some()) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, i.id); + let delegation_results = self.lower_delegation(delegation, i.id, false); let item_kind = hir::TraitItemKind::Fn( delegation_results.sig, hir::TraitFn::Provided(delegation_results.body_id), @@ -910,7 +908,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { - has_self: self.delegatee_is_method(i.id, delegation.id, i.span), + has_self: self.delegatee_is_method(i.id, delegation.id, i.span, false), }, AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") @@ -930,7 +928,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Err(guar)) } - fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { + fn lower_impl_item( + &mut self, + i: &AssocItem, + is_in_trait_impl: bool, + ) -> &'hir hir::ImplItem<'hir> { debug_assert_ne!(i.ident.name, kw::Empty); // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; @@ -966,7 +968,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, sig, i.id, - if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, + if is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_kind, attrs, ); @@ -1006,7 +1008,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, i.id); + let delegation_results = self.lower_delegation(delegation, i.id, is_in_trait_impl); ( delegation_results.generics, hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id), @@ -1029,7 +1031,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(item) } - fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef { + fn lower_impl_item_ref(&mut self, i: &AssocItem, is_in_trait_impl: bool) -> hir::ImplItemRef { hir::ImplItemRef { id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, ident: self.lower_ident(i.ident), @@ -1041,7 +1043,12 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { - has_self: self.delegatee_is_method(i.id, delegation.id, i.span), + has_self: self.delegatee_is_method( + i.id, + delegation.id, + i.span, + is_in_trait_impl, + ), }, AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e08850da4a7a..32e20f3f6f25 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -121,7 +121,6 @@ struct LoweringContext<'a, 'hir> { catch_scope: Option, loop_scope: Option, is_in_loop_condition: bool, - is_in_trait_impl: bool, is_in_dyn_type: bool, current_hir_id_owner: hir::OwnerId, @@ -173,7 +172,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { catch_scope: None, loop_scope: None, is_in_loop_condition: false, - is_in_trait_impl: false, is_in_dyn_type: false, coroutine_kind: None, task_context: None, From 6bea9c7a5465e27efbadced28322e6faf78bb174 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 12:50:47 +1100 Subject: [PATCH 316/546] rustdoc: remove useless `Symbol::is_empty` checks. There are a number of `is_empty` checks that can never fail. This commit removes them. --- src/librustdoc/clean/inline.rs | 12 +----- src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/html/render/sidebar.rs | 62 ++++++++++++++++----------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e973b89b2375..4fd669ab6d13 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -211,17 +211,7 @@ pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [hir: } pub(crate) fn item_relative_path(tcx: TyCtxt<'_>, def_id: DefId) -> Vec { - tcx.def_path(def_id) - .data - .into_iter() - .filter_map(|elem| { - // extern blocks (and a few others things) have an empty name. - match elem.data.get_opt_name() { - Some(s) if !s.is_empty() => Some(s), - _ => None, - } - }) - .collect() + tcx.def_path(def_id).data.into_iter().filter_map(|elem| elem.data.get_opt_name()).collect() } /// Record an external fully qualified name in the external_paths cache. diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 2648641e53e7..e74fd67fbdaf 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -288,7 +288,7 @@ impl DocFolder for CacheBuilder<'_, '_> { // Keep track of the fully qualified path for this item. let pushed = match item.name { - Some(n) if !n.is_empty() => { + Some(n) => { self.cache.stack.push(n); true } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 3130815af0bd..79719f008645 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -731,20 +731,20 @@ fn get_methods<'a>( ) -> Vec> { i.items .iter() - .filter_map(|item| match item.name { - Some(ref name) if !name.is_empty() && item.is_method() => { - if !for_deref || super::should_render_item(item, deref_mut, tcx) { - Some(Link::new( - get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::Method)), - name.as_str(), - )) - } else { - None - } + .filter_map(|item| { + if let Some(ref name) = item.name + && item.is_method() + && (!for_deref || super::should_render_item(item, deref_mut, tcx)) + { + Some(Link::new( + get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::Method)), + name.as_str(), + )) + } else { + None } - _ => None, }) - .collect::>() + .collect() } fn get_associated_constants<'a>( @@ -753,14 +753,19 @@ fn get_associated_constants<'a>( ) -> Vec> { i.items .iter() - .filter_map(|item| match item.name { - Some(ref name) if !name.is_empty() && item.is_associated_const() => Some(Link::new( - get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)), - name.as_str(), - )), - _ => None, + .filter_map(|item| { + if let Some(ref name) = item.name + && item.is_associated_const() + { + Some(Link::new( + get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)), + name.as_str(), + )) + } else { + None + } }) - .collect::>() + .collect() } fn get_associated_types<'a>( @@ -769,12 +774,17 @@ fn get_associated_types<'a>( ) -> Vec> { i.items .iter() - .filter_map(|item| match item.name { - Some(ref name) if !name.is_empty() && item.is_associated_type() => Some(Link::new( - get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)), - name.as_str(), - )), - _ => None, + .filter_map(|item| { + if let Some(ref name) = item.name + && item.is_associated_type() + { + Some(Link::new( + get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)), + name.as_str(), + )) + } else { + None + } }) - .collect::>() + .collect() } From 6df2d589338945e663a3a798a60db17db5f805b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 25 Mar 2025 12:37:52 +0100 Subject: [PATCH 317/546] Add function for linearizing `BuildStep` substeps --- src/build_helper/src/metrics.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index b6daac32a441..4ab61245c16b 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -156,25 +156,30 @@ impl BuildStep { child.find_by_type(r#type, result); } } + + /// Returns a Vec with all substeps, ordered by their hierarchical order. + /// The first element of the tuple is the depth of a given step. + fn linearize_steps(&self) -> Vec<(u32, &BuildStep)> { + let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); + + fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { + substeps.push((level, step)); + for child in &step.children { + visit(child, level + 1, substeps); + } + } + + visit(self, 0, &mut substeps); + substeps + } } /// Writes build steps into a nice indented table. pub fn format_build_steps(root: &BuildStep) -> String { use std::fmt::Write; - let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); - - fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { - substeps.push((level, step)); - for child in &step.children { - visit(child, level + 1, substeps); - } - } - - visit(root, 0, &mut substeps); - let mut output = String::new(); - for (level, step) in substeps { + for (level, step) in root.linearize_steps() { let label = format!( "{}{}", ".".repeat(level as usize), From 82796dd8585c0c160fe2a50b12f77455a7e0f8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 24 Mar 2025 00:01:30 +0100 Subject: [PATCH 318/546] Brace-ident-colon can certainly no longer start a block thanks to the removal of type ascription. --- compiler/rustc_parse/src/parser/expr.rs | 14 +--- tests/ui/parser/issues/issue-111692.rs | 10 ++- tests/ui/parser/issues/issue-111692.stderr | 30 +++---- ...-call-on-struct-literal-in-if-condition.rs | 2 +- ...l-on-struct-literal-in-if-condition.stderr | 4 +- tests/ui/parser/type-ascription-in-pattern.rs | 9 +-- .../parser/type-ascription-in-pattern.stderr | 80 ++++++++++++++----- 7 files changed, 88 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c48f91643e88..79d12ed4bbed 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3474,19 +3474,9 @@ impl<'a> Parser<'a> { } fn is_certainly_not_a_block(&self) -> bool { + // `{ ident, ` and `{ ident: ` cannot start a block. self.look_ahead(1, |t| t.is_ident()) - && ( - // `{ ident, ` cannot start a block. - self.look_ahead(2, |t| t == &token::Comma) - || self.look_ahead(2, |t| t == &token::Colon) - && ( - // `{ ident: token, ` cannot start a block. - self.look_ahead(4, |t| t == &token::Comma) - // `{ ident: ` cannot start a block unless it's a type ascription - // `ident: Type`. - || self.look_ahead(3, |t| !t.can_begin_type()) - ) - ) + && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon) } fn maybe_parse_struct_expr( diff --git a/tests/ui/parser/issues/issue-111692.rs b/tests/ui/parser/issues/issue-111692.rs index 56096f706a8a..de6de2227549 100644 --- a/tests/ui/parser/issues/issue-111692.rs +++ b/tests/ui/parser/issues/issue-111692.rs @@ -9,23 +9,25 @@ mod module { } fn test(x: module::Type) { - if x == module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal + if x == module::Type { x: module::C, y: 1 } { //~ ERROR struct literals are not allowed here } } fn test2(x: module::Type) { - if x ==module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal + if x ==module::Type { x: module::C, y: 1 } { //~ ERROR struct literals are not allowed here } } fn test3(x: module::Type) { - if x == Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal + use module::Type; + if x == Type { x: module::C, y: 1 } { //~ ERROR struct literals are not allowed here } } fn test4(x: module::Type) { - if x == demo_module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal + use module as demo_module; + if x == demo_module::Type { x: module::C, y: 1 } { //~ ERROR struct literals are not allowed here } } diff --git a/tests/ui/parser/issues/issue-111692.stderr b/tests/ui/parser/issues/issue-111692.stderr index 068b0483b0fd..979dfade1ba2 100644 --- a/tests/ui/parser/issues/issue-111692.stderr +++ b/tests/ui/parser/issues/issue-111692.stderr @@ -1,43 +1,43 @@ -error: invalid struct literal - --> $DIR/issue-111692.rs:12:21 +error: struct literals are not allowed here + --> $DIR/issue-111692.rs:12:13 | LL | if x == module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: you might need to surround the struct literal with parentheses +help: surround the struct literal with parentheses | LL | if x == (module::Type { x: module::C, y: 1 }) { | + + -error: invalid struct literal - --> $DIR/issue-111692.rs:17:20 +error: struct literals are not allowed here + --> $DIR/issue-111692.rs:17:12 | LL | if x ==module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: you might need to surround the struct literal with parentheses +help: surround the struct literal with parentheses | LL | if x ==(module::Type { x: module::C, y: 1 }) { | + + -error: invalid struct literal - --> $DIR/issue-111692.rs:23:13 +error: struct literals are not allowed here + --> $DIR/issue-111692.rs:24:13 | LL | if x == Type { x: module::C, y: 1 } { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: you might need to surround the struct literal with parentheses +help: surround the struct literal with parentheses | LL | if x == (Type { x: module::C, y: 1 }) { | + + -error: invalid struct literal - --> $DIR/issue-111692.rs:28:26 +error: struct literals are not allowed here + --> $DIR/issue-111692.rs:30:13 | LL | if x == demo_module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: you might need to surround the struct literal with parentheses +help: surround the struct literal with parentheses | LL | if x == (demo_module::Type { x: module::C, y: 1 }) { | + + diff --git a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs index 8be7c9ee8ac3..3211b6c7bb9d 100644 --- a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs +++ b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs @@ -7,7 +7,7 @@ impl Example { fn one() -> i32 { 1 } fn main() { - if Example { a: one(), }.is_pos() { //~ ERROR invalid struct literal + if Example { a: one(), }.is_pos() { //~ ERROR struct literals are not allowed here println!("Positive!"); } } diff --git a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr index f7822ba11246..8eba2230f8fb 100644 --- a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr +++ b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr @@ -1,10 +1,10 @@ -error: invalid struct literal +error: struct literals are not allowed here --> $DIR/method-call-on-struct-literal-in-if-condition.rs:10:8 | LL | if Example { a: one(), }.is_pos() { | ^^^^^^^^^^^^^^^^^^^^^ | -help: you might need to surround the struct literal with parentheses +help: surround the struct literal with parentheses | LL | if (Example { a: one(), }).is_pos() { | + + diff --git a/tests/ui/parser/type-ascription-in-pattern.rs b/tests/ui/parser/type-ascription-in-pattern.rs index fec168afba1d..18d7061d69c8 100644 --- a/tests/ui/parser/type-ascription-in-pattern.rs +++ b/tests/ui/parser/type-ascription-in-pattern.rs @@ -1,11 +1,10 @@ fn foo(x: bool) -> i32 { - match x { + match x { //~ ERROR struct literals are not allowed here x: i32 => x, //~ ERROR expected - //~^ ERROR mismatched types - true => 42., - false => 0.333, + true => 42., //~ ERROR expected identifier + false => 0.333, //~ ERROR expected identifier } -} +} //~ ERROR expected one of fn main() { match foo(true) { diff --git a/tests/ui/parser/type-ascription-in-pattern.stderr b/tests/ui/parser/type-ascription-in-pattern.stderr index 091907549936..135879f208b2 100644 --- a/tests/ui/parser/type-ascription-in-pattern.stderr +++ b/tests/ui/parser/type-ascription-in-pattern.stderr @@ -1,18 +1,64 @@ -error: expected one of `@` or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:3:10 +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>` + --> $DIR/type-ascription-in-pattern.rs:3:16 | +LL | match x { + | - while parsing this struct LL | x: i32 => x, - | ^ --- specifying the type of a pattern isn't supported - | | - | expected one of `@` or `|` + | -^^ expected one of 8 possible tokens + | | + | help: try adding a comma: `,` + +error: expected identifier, found keyword `true` + --> $DIR/type-ascription-in-pattern.rs:4:9 | -help: maybe write a path separator here +LL | match x { + | - while parsing this struct +LL | x: i32 => x, +LL | true => 42., + | ^^^^ expected identifier, found keyword + +error: expected identifier, found keyword `false` + --> $DIR/type-ascription-in-pattern.rs:5:9 | -LL | x::i32 => x, - | ~~ +LL | match x { + | - while parsing this struct +... +LL | false => 0.333, + | ^^^^^ expected identifier, found keyword + +error: struct literals are not allowed here + --> $DIR/type-ascription-in-pattern.rs:2:11 + | +LL | match x { + | ___________^ +LL | | x: i32 => x, +LL | | true => 42., +LL | | false => 0.333, +LL | | } + | |_____^ + | +help: surround the struct literal with parentheses + | +LL ~ match (x { +LL | x: i32 => x, +LL | true => 42., +LL | false => 0.333, +LL ~ }) + | + +error: expected one of `.`, `?`, `{`, or an operator, found `}` + --> $DIR/type-ascription-in-pattern.rs:7:1 + | +LL | match x { + | ----- while parsing this `match` expression +... +LL | } + | - expected one of `.`, `?`, `{`, or an operator +LL | } + | ^ unexpected token error: expected one of `...`, `..=`, `..`, or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:12:11 + --> $DIR/type-ascription-in-pattern.rs:11:11 | LL | 42: i32 => (), | ^ --- specifying the type of a pattern isn't supported @@ -20,7 +66,7 @@ LL | 42: i32 => (), | expected one of `...`, `..=`, `..`, or `|` error: expected `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:13:10 + --> $DIR/type-ascription-in-pattern.rs:12:10 | LL | _: f64 => (), | ^ --- specifying the type of a pattern isn't supported @@ -28,7 +74,7 @@ LL | _: f64 => (), | expected `|` error: expected one of `@` or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:14:10 + --> $DIR/type-ascription-in-pattern.rs:13:10 | LL | x: i32 => (), | ^ --- specifying the type of a pattern isn't supported @@ -40,15 +86,5 @@ help: maybe write a path separator here LL | x::i32 => (), | ~~ -error[E0308]: mismatched types - --> $DIR/type-ascription-in-pattern.rs:3:19 - | -LL | fn foo(x: bool) -> i32 { - | --- expected `i32` because of return type -LL | match x { -LL | x: i32 => x, - | ^ expected `i32`, found `bool` +error: aborting due to 8 previous errors -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0308`. From 9f336ce2eb0ba04de7f1ddd2e1b0958e7df15c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 24 Mar 2025 00:12:53 +0100 Subject: [PATCH 319/546] Remove now unreachable parse recovery code StructLiteralNeedingParens is no longer reachable always giving precedence to StructLiteralNotAllowedHere. As an aside: The former error struct shouldn't've existed in the first place. We should've just used the latter in this branch. --- compiler/rustc_parse/messages.ftl | 4 -- compiler/rustc_parse/src/errors.rs | 18 ------ .../rustc_parse/src/parser/diagnostics.rs | 64 ++++++------------- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_parse/src/parser/stmt.rs | 10 +-- 6 files changed, 24 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 6d4308cda1a6..3253222b8f23 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -757,10 +757,6 @@ parse_struct_literal_body_without_path = struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block -parse_struct_literal_needing_parens = - invalid struct literal - .suggestion = you might need to surround the struct literal with parentheses - parse_struct_literal_not_allowed_here = struct literals are not allowed here .suggestion = surround the struct literal with parentheses diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e090d9cf7600..f813c3380fcb 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1272,24 +1272,6 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg { pub after: Span, } -#[derive(Diagnostic)] -#[diag(parse_struct_literal_needing_parens)] -pub(crate) struct StructLiteralNeedingParens { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sugg: StructLiteralNeedingParensSugg, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] -pub(crate) struct StructLiteralNeedingParensSugg { - #[suggestion_part(code = "(")] - pub before: Span, - #[suggestion_part(code = ")")] - pub after: Span, -} - #[derive(Diagnostic)] #[diag(parse_unmatched_angle_brackets)] pub(crate) struct UnmatchedAngleBrackets { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index daa27b146690..ef044fe9d638 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -40,9 +40,8 @@ use crate::errors::{ HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, - SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, - UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, + TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, }; use crate::parser::attr::InnerAttrPolicy; @@ -949,7 +948,6 @@ impl<'a> Parser<'a> { lo: Span, s: BlockCheckMode, maybe_struct_name: token::Token, - can_be_struct_literal: bool, ) -> Option>> { if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) { // We might be having a struct literal where people forgot to include the path: @@ -971,49 +969,27 @@ impl<'a> Parser<'a> { // fn foo() -> Foo { // field: value, // } - let guar = err.delay_as_bug(); + // Suggest: + // fn foo() -> Foo { Path { + // field: value, + // } } + err.cancel(); self.restore_snapshot(snapshot); - if maybe_struct_name.is_ident() && can_be_struct_literal { - // Account for `if Example { a: one(), }.is_pos() {}`. - // expand `before` so that we take care of module path such as: - // `foo::Bar { ... } ` - // we expect to suggest `(foo::Bar { ... })` instead of `foo::(Bar { ... })` - let sm = self.psess.source_map(); - let before = maybe_struct_name.span.shrink_to_lo(); - if let Ok(extend_before) = sm.span_extend_prev_while(before, |t| { - t.is_alphanumeric() || t == ':' || t == '_' - }) { - Err(self.dcx().create_err(StructLiteralNeedingParens { - span: maybe_struct_name.span.to(expr.span), - sugg: StructLiteralNeedingParensSugg { - before: extend_before.shrink_to_lo(), - after: expr.span.shrink_to_hi(), - }, - })) - } else { - return None; - } - } else { - // Suggest: - // fn foo() -> Foo { Path { - // field: value, - // } } - self.dcx().emit_err(StructLiteralBodyWithoutPath { - span: expr.span, - sugg: StructLiteralBodyWithoutPathSugg { - before: expr.span.shrink_to_lo(), - after: expr.span.shrink_to_hi(), - }, - }); - Ok(self.mk_block( - thin_vec![self.mk_stmt_err(expr.span, guar)], - s, - lo.to(self.prev_token.span), - )) - } + let guar = self.dcx().emit_err(StructLiteralBodyWithoutPath { + span: expr.span, + sugg: StructLiteralBodyWithoutPathSugg { + before: expr.span.shrink_to_lo(), + after: expr.span.shrink_to_hi(), + }, + }); + Ok(self.mk_block( + thin_vec![self.mk_stmt_err(expr.span, guar)], + s, + lo.to(self.prev_token.span), + )) } (Err(err), Ok(tail)) => { - // We have a block tail that contains a somehow valid type ascription expr. + // We have a block tail that contains a somehow valid expr. err.cancel(); Ok(tail) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 79d12ed4bbed..92e83577f1b1 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2296,7 +2296,7 @@ impl<'a> Parser<'a> { }); } - let (attrs, blk) = self.parse_block_common(lo, blk_mode, true, None)?; + let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?; Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs)) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f4df4044dd2e..77e675ea91f2 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2529,7 +2529,7 @@ impl<'a> Parser<'a> { *sig_hi = self.prev_token.span; (AttrVec::new(), None) } else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() { - self.parse_block_common(self.token.span, BlockCheckMode::Default, false, None) + self.parse_block_common(self.token.span, BlockCheckMode::Default, None) .map(|(attrs, body)| (attrs, Some(body)))? } else if self.token == token::Eq { // Recover `fn foo() = $expr;`. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 368366c60d65..97cd4d2117f8 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -668,7 +668,7 @@ impl<'a> Parser<'a> { &mut self, loop_header: Option, ) -> PResult<'a, (AttrVec, P)> { - self.parse_block_common(self.token.span, BlockCheckMode::Default, true, loop_header) + self.parse_block_common(self.token.span, BlockCheckMode::Default, loop_header) } /// Parses a block. Inner attributes are allowed, block labels are not. @@ -679,7 +679,6 @@ impl<'a> Parser<'a> { &mut self, lo: Span, blk_mode: BlockCheckMode, - can_be_struct_literal: bool, loop_header: Option, ) -> PResult<'a, (AttrVec, P)> { maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block)); @@ -691,12 +690,7 @@ impl<'a> Parser<'a> { } let attrs = self.parse_inner_attributes()?; - let tail = match self.maybe_suggest_struct_literal( - lo, - blk_mode, - maybe_ident, - can_be_struct_literal, - ) { + let tail = match self.maybe_suggest_struct_literal(lo, blk_mode, maybe_ident) { Some(tail) => tail?, None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?, }; From 598f8658744db0dc0215545d2193accd3a1ce8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 24 Mar 2025 17:16:26 +0100 Subject: [PATCH 320/546] Combine several test files into one This makes it a lot easier to add smaller regression tests related to "incorrectly placed" struct literals. --- ...-call-on-struct-literal-in-if-condition.rs | 13 -- ...l-on-struct-literal-in-if-condition.stderr | 13 -- tests/ui/parser/struct-literal-in-for.rs | 17 -- tests/ui/parser/struct-literal-in-for.stderr | 31 --- tests/ui/parser/struct-literal-in-if.rs | 22 -- tests/ui/parser/struct-literal-in-if.stderr | 34 ---- .../struct-literal-in-match-discriminant.rs | 13 -- ...truct-literal-in-match-discriminant.stderr | 18 -- tests/ui/parser/struct-literal-in-while.rs | 22 -- .../ui/parser/struct-literal-in-while.stderr | 34 ---- .../struct-literal-restrictions-in-lamda.rs | 17 -- ...truct-literal-restrictions-in-lamda.stderr | 37 ---- .../ui/parser/struct-literal-variant-in-if.rs | 25 --- .../struct-literal-variant-in-if.stderr | 76 ------- .../struct-literals-in-invalid-places.rs | 72 +++++++ .../struct-literals-in-invalid-places.stderr | 191 ++++++++++++++++++ 16 files changed, 263 insertions(+), 372 deletions(-) delete mode 100644 tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs delete mode 100644 tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr delete mode 100644 tests/ui/parser/struct-literal-in-for.rs delete mode 100644 tests/ui/parser/struct-literal-in-for.stderr delete mode 100644 tests/ui/parser/struct-literal-in-if.rs delete mode 100644 tests/ui/parser/struct-literal-in-if.stderr delete mode 100644 tests/ui/parser/struct-literal-in-match-discriminant.rs delete mode 100644 tests/ui/parser/struct-literal-in-match-discriminant.stderr delete mode 100644 tests/ui/parser/struct-literal-in-while.rs delete mode 100644 tests/ui/parser/struct-literal-in-while.stderr delete mode 100644 tests/ui/parser/struct-literal-restrictions-in-lamda.rs delete mode 100644 tests/ui/parser/struct-literal-restrictions-in-lamda.stderr delete mode 100644 tests/ui/parser/struct-literal-variant-in-if.rs delete mode 100644 tests/ui/parser/struct-literal-variant-in-if.stderr create mode 100644 tests/ui/parser/struct-literals-in-invalid-places.rs create mode 100644 tests/ui/parser/struct-literals-in-invalid-places.stderr diff --git a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs deleted file mode 100644 index 3211b6c7bb9d..000000000000 --- a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub struct Example { a: i32 } - -impl Example { - fn is_pos(&self) -> bool { self.a > 0 } -} - -fn one() -> i32 { 1 } - -fn main() { - if Example { a: one(), }.is_pos() { //~ ERROR struct literals are not allowed here - println!("Positive!"); - } -} diff --git a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr deleted file mode 100644 index 8eba2230f8fb..000000000000 --- a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/method-call-on-struct-literal-in-if-condition.rs:10:8 - | -LL | if Example { a: one(), }.is_pos() { - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if (Example { a: one(), }).is_pos() { - | + + - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/struct-literal-in-for.rs b/tests/ui/parser/struct-literal-in-for.rs deleted file mode 100644 index 3227ae37bfd0..000000000000 --- a/tests/ui/parser/struct-literal-in-for.rs +++ /dev/null @@ -1,17 +0,0 @@ -struct Foo { - x: isize, -} - -impl Foo { - fn hi(&self) -> bool { - true - } -} - -fn main() { - for x in Foo { //~ ERROR struct literals are not allowed here - x: 3 //~^ ERROR `bool` is not an iterator - }.hi() { - println!("yo"); - } -} diff --git a/tests/ui/parser/struct-literal-in-for.stderr b/tests/ui/parser/struct-literal-in-for.stderr deleted file mode 100644 index 1c91eba68e39..000000000000 --- a/tests/ui/parser/struct-literal-in-for.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-in-for.rs:12:14 - | -LL | for x in Foo { - | ______________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ for x in (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error[E0277]: `bool` is not an iterator - --> $DIR/struct-literal-in-for.rs:12:14 - | -LL | for x in Foo { - | ______________^ -LL | | x: 3 -LL | | }.hi() { - | |__________^ `bool` is not an iterator - | - = help: the trait `Iterator` is not implemented for `bool` - = note: required for `bool` to implement `IntoIterator` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/struct-literal-in-if.rs b/tests/ui/parser/struct-literal-in-if.rs deleted file mode 100644 index c4a253c3da25..000000000000 --- a/tests/ui/parser/struct-literal-in-if.rs +++ /dev/null @@ -1,22 +0,0 @@ -struct Foo { - x: isize, -} - -impl Foo { - fn hi(&self) -> bool { - true - } -} - -fn main() { - if Foo { //~ ERROR struct literals are not allowed here - x: 3 - }.hi() { - println!("yo"); - } - if let true = Foo { //~ ERROR struct literals are not allowed here - x: 3 - }.hi() { - println!("yo"); - } -} diff --git a/tests/ui/parser/struct-literal-in-if.stderr b/tests/ui/parser/struct-literal-in-if.stderr deleted file mode 100644 index 8b72469fcf58..000000000000 --- a/tests/ui/parser/struct-literal-in-if.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-in-if.rs:12:8 - | -LL | if Foo { - | ________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ if (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error: struct literals are not allowed here - --> $DIR/struct-literal-in-if.rs:17:19 - | -LL | if let true = Foo { - | ___________________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ if let true = (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error: aborting due to 2 previous errors - diff --git a/tests/ui/parser/struct-literal-in-match-discriminant.rs b/tests/ui/parser/struct-literal-in-match-discriminant.rs deleted file mode 100644 index ce132df5a888..000000000000 --- a/tests/ui/parser/struct-literal-in-match-discriminant.rs +++ /dev/null @@ -1,13 +0,0 @@ -struct Foo { - x: isize, -} - -fn main() { - match Foo { //~ ERROR struct literals are not allowed here - x: 3 - } { - Foo { - x: x - } => {} - } -} diff --git a/tests/ui/parser/struct-literal-in-match-discriminant.stderr b/tests/ui/parser/struct-literal-in-match-discriminant.stderr deleted file mode 100644 index 5177f5f126e0..000000000000 --- a/tests/ui/parser/struct-literal-in-match-discriminant.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-in-match-discriminant.rs:6:11 - | -LL | match Foo { - | ___________^ -LL | | x: 3 -LL | | } { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ match (Foo { -LL | x: 3 -LL ~ }) { - | - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/struct-literal-in-while.rs b/tests/ui/parser/struct-literal-in-while.rs deleted file mode 100644 index 86931f7888dd..000000000000 --- a/tests/ui/parser/struct-literal-in-while.rs +++ /dev/null @@ -1,22 +0,0 @@ -struct Foo { - x: isize, -} - -impl Foo { - fn hi(&self) -> bool { - true - } -} - -fn main() { - while Foo { //~ ERROR struct literals are not allowed here - x: 3 - }.hi() { - println!("yo"); - } - while let true = Foo { //~ ERROR struct literals are not allowed here - x: 3 - }.hi() { - println!("yo"); - } -} diff --git a/tests/ui/parser/struct-literal-in-while.stderr b/tests/ui/parser/struct-literal-in-while.stderr deleted file mode 100644 index 13d003608a1b..000000000000 --- a/tests/ui/parser/struct-literal-in-while.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-in-while.rs:12:11 - | -LL | while Foo { - | ___________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ while (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error: struct literals are not allowed here - --> $DIR/struct-literal-in-while.rs:17:22 - | -LL | while let true = Foo { - | ______________________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ while let true = (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error: aborting due to 2 previous errors - diff --git a/tests/ui/parser/struct-literal-restrictions-in-lamda.rs b/tests/ui/parser/struct-literal-restrictions-in-lamda.rs deleted file mode 100644 index e185153dcf62..000000000000 --- a/tests/ui/parser/struct-literal-restrictions-in-lamda.rs +++ /dev/null @@ -1,17 +0,0 @@ -struct Foo { - x: isize, -} - -impl Foo { - fn hi(&self) -> bool { - true - } -} - -fn main() { - while || Foo { //~ ERROR struct literals are not allowed here - x: 3 //~^ ERROR mismatched types - }.hi() { - println!("yo"); - } -} diff --git a/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr b/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr deleted file mode 100644 index c715486e2da9..000000000000 --- a/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-restrictions-in-lamda.rs:12:14 - | -LL | while || Foo { - | ______________^ -LL | | x: 3 -LL | | }.hi() { - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ while || (Foo { -LL | x: 3 -LL ~ }).hi() { - | - -error[E0308]: mismatched types - --> $DIR/struct-literal-restrictions-in-lamda.rs:12:11 - | -LL | while || Foo { - | ___________^ -LL | | x: 3 -LL | | }.hi() { - | |__________^ expected `bool`, found closure - | - = note: expected type `bool` - found closure `{closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 12:13}` -help: use parentheses to call this closure - | -LL ~ while (|| Foo { -LL | x: 3 -LL ~ }.hi())() { - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/struct-literal-variant-in-if.rs b/tests/ui/parser/struct-literal-variant-in-if.rs deleted file mode 100644 index 4ef8effaf1f5..000000000000 --- a/tests/ui/parser/struct-literal-variant-in-if.rs +++ /dev/null @@ -1,25 +0,0 @@ -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -enum E { - V { field: bool }, - I { field1: bool, field2: usize }, - J { field: isize }, - K { field: &'static str}, -} -fn test_E(x: E) { - let field = true; - if x == E::V { field } {} - //~^ ERROR expected value, found struct variant `E::V` - //~| ERROR mismatched types - if x == E::I { field1: true, field2: 42 } {} - //~^ ERROR struct literals are not allowed here - if x == E::V { field: false } {} - //~^ ERROR struct literals are not allowed here - if x == E::J { field: -42 } {} - //~^ ERROR struct literals are not allowed here - if x == E::K { field: "" } {} - //~^ ERROR struct literals are not allowed here - let y: usize = (); - //~^ ERROR mismatched types -} - -fn main() {} diff --git a/tests/ui/parser/struct-literal-variant-in-if.stderr b/tests/ui/parser/struct-literal-variant-in-if.stderr deleted file mode 100644 index 15f059f145bb..000000000000 --- a/tests/ui/parser/struct-literal-variant-in-if.stderr +++ /dev/null @@ -1,76 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:13:13 - | -LL | if x == E::I { field1: true, field2: 42 } {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (E::I { field1: true, field2: 42 }) {} - | + + - -error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:15:13 - | -LL | if x == E::V { field: false } {} - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (E::V { field: false }) {} - | + + - -error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:17:13 - | -LL | if x == E::J { field: -42 } {} - | ^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (E::J { field: -42 }) {} - | + + - -error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:19:13 - | -LL | if x == E::K { field: "" } {} - | ^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (E::K { field: "" }) {} - | + + - -error[E0533]: expected value, found struct variant `E::V` - --> $DIR/struct-literal-variant-in-if.rs:10:13 - | -LL | if x == E::V { field } {} - | ^^^^ not a value - | -help: you might have meant to create a new value of the struct - | -LL | if x == (E::V { field }) {} - | + + - -error[E0308]: mismatched types - --> $DIR/struct-literal-variant-in-if.rs:10:20 - | -LL | if x == E::V { field } {} - | ---------------^^^^^-- - | | | - | | expected `()`, found `bool` - | expected this to be `()` - -error[E0308]: mismatched types - --> $DIR/struct-literal-variant-in-if.rs:21:20 - | -LL | let y: usize = (); - | ----- ^^ expected `usize`, found `()` - | | - | expected due to this - -error: aborting due to 7 previous errors - -Some errors have detailed explanations: E0308, E0533. -For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/struct-literals-in-invalid-places.rs b/tests/ui/parser/struct-literals-in-invalid-places.rs new file mode 100644 index 000000000000..89cdb30fc046 --- /dev/null +++ b/tests/ui/parser/struct-literals-in-invalid-places.rs @@ -0,0 +1,72 @@ +fn main() { + if Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + println!("yo"); + } + if let true = Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + println!("yo"); + } + + for x in Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + //~^ ERROR `bool` is not an iterator + println!("yo"); + } + + while Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + println!("yo"); + } + while let true = Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + println!("yo"); + } + + match Foo { x: 3 } { //~ ERROR struct literals are not allowed here + Foo { x: x } => {} + } + + let _ = |x: E| { + let field = true; + if x == E::V { field } {} + //~^ ERROR expected value, found struct variant `E::V` + //~| ERROR mismatched types + if x == E::I { field1: true, field2: 42 } {} + //~^ ERROR struct literals are not allowed here + if x == E::V { field: false } {} + //~^ ERROR struct literals are not allowed here + if x == E::J { field: -42 } {} + //~^ ERROR struct literals are not allowed here + if x == E::K { field: "" } {} + //~^ ERROR struct literals are not allowed here + let y: usize = (); + //~^ ERROR mismatched types + }; + + // Regression test for . + while || Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here + //~^ ERROR mismatched types + println!("yo"); + } + + // Regression test for . + if Foo { x: one(), }.hi() { //~ ERROR struct literals are not allowed here + println!("Positive!"); + } +} + +struct Foo { + x: isize, +} + +impl Foo { + fn hi(&self) -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +enum E { + V { field: bool }, + I { field1: bool, field2: usize }, + J { field: isize }, + K { field: &'static str}, +} + +fn one() -> isize { 1 } diff --git a/tests/ui/parser/struct-literals-in-invalid-places.stderr b/tests/ui/parser/struct-literals-in-invalid-places.stderr new file mode 100644 index 000000000000..ed094fc3e157 --- /dev/null +++ b/tests/ui/parser/struct-literals-in-invalid-places.stderr @@ -0,0 +1,191 @@ +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:2:8 + | +LL | if Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:5:19 + | +LL | if let true = Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if let true = (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:9:14 + | +LL | for x in Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | for x in (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:14:11 + | +LL | while Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | while (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:17:22 + | +LL | while let true = Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | while let true = (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:21:11 + | +LL | match Foo { x: 3 } { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | match (Foo { x: 3 }) { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:30:17 + | +LL | if x == E::I { field1: true, field2: 42 } {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if x == (E::I { field1: true, field2: 42 }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:32:17 + | +LL | if x == E::V { field: false } {} + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if x == (E::V { field: false }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:34:17 + | +LL | if x == E::J { field: -42 } {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if x == (E::J { field: -42 }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:36:17 + | +LL | if x == E::K { field: "" } {} + | ^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if x == (E::K { field: "" }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:43:14 + | +LL | while || Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | while || (Foo { x: 3 }).hi() { + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:49:8 + | +LL | if Foo { x: one(), }.hi() { + | ^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if (Foo { x: one(), }).hi() { + | + + + +error[E0277]: `bool` is not an iterator + --> $DIR/struct-literals-in-invalid-places.rs:9:14 + | +LL | for x in Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^^^^^^ `bool` is not an iterator + | + = help: the trait `Iterator` is not implemented for `bool` + = note: required for `bool` to implement `IntoIterator` + +error[E0533]: expected value, found struct variant `E::V` + --> $DIR/struct-literals-in-invalid-places.rs:27:17 + | +LL | if x == E::V { field } {} + | ^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | if x == (E::V { field }) {} + | + + + +error[E0308]: mismatched types + --> $DIR/struct-literals-in-invalid-places.rs:27:24 + | +LL | if x == E::V { field } {} + | ---------------^^^^^-- + | | | + | | expected `()`, found `bool` + | expected this to be `()` + | +help: you might have meant to return this value + | +LL | if x == E::V { return field; } {} + | ++++++ + + +error[E0308]: mismatched types + --> $DIR/struct-literals-in-invalid-places.rs:38:24 + | +LL | let y: usize = (); + | ----- ^^ expected `usize`, found `()` + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/struct-literals-in-invalid-places.rs:43:11 + | +LL | while || Foo { x: 3 }.hi() { + | ^^^^^^^^^^^^^^^^^^^^ expected `bool`, found closure + | + = note: expected type `bool` + found closure `{closure@$DIR/struct-literals-in-invalid-places.rs:43:11: 43:13}` +help: use parentheses to call this closure + | +LL | while (|| Foo { x: 3 }.hi())() { + | + +++ + +error: aborting due to 17 previous errors + +Some errors have detailed explanations: E0277, E0308, E0533. +For more information about an error, try `rustc --explain E0277`. From b501e58c2e8aa42c0b6f4f568c90f70e34a11170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 24 Mar 2025 17:39:38 +0100 Subject: [PATCH 321/546] Incorporate issue-111692.rs into the larger test file and add more test cases Note that issue-111692.rs was incorrectly named: It's a regression test for issue [#]112278, not for [#]111692. That's been addressed, too. --- src/tools/tidy/src/issues.txt | 1 - tests/ui/parser/issues/issue-111692.rs | 34 ------------- tests/ui/parser/issues/issue-111692.stderr | 46 ----------------- .../struct-literals-in-invalid-places.rs | 20 ++++++++ .../struct-literals-in-invalid-places.stderr | 49 +++++++++++++++++-- 5 files changed, 66 insertions(+), 84 deletions(-) delete mode 100644 tests/ui/parser/issues/issue-111692.rs delete mode 100644 tests/ui/parser/issues/issue-111692.stderr diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 4a929a376d78..a33e03d5861e 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3189,7 +3189,6 @@ ui/parser/issues/issue-108495-dec.rs ui/parser/issues/issue-110014.rs ui/parser/issues/issue-111148.rs ui/parser/issues/issue-111416.rs -ui/parser/issues/issue-111692.rs ui/parser/issues/issue-112188.rs ui/parser/issues/issue-112458.rs ui/parser/issues/issue-113110-non-item-at-module-root.rs diff --git a/tests/ui/parser/issues/issue-111692.rs b/tests/ui/parser/issues/issue-111692.rs deleted file mode 100644 index de6de2227549..000000000000 --- a/tests/ui/parser/issues/issue-111692.rs +++ /dev/null @@ -1,34 +0,0 @@ -mod module { - #[derive(Eq, PartialEq)] - pub struct Type { - pub x: u8, - pub y: u8, - } - - pub const C: u8 = 32u8; -} - -fn test(x: module::Type) { - if x == module::Type { x: module::C, y: 1 } { //~ ERROR struct literals are not allowed here - } -} - -fn test2(x: module::Type) { - if x ==module::Type { x: module::C, y: 1 } { //~ ERROR struct literals are not allowed here - } -} - - -fn test3(x: module::Type) { - use module::Type; - if x == Type { x: module::C, y: 1 } { //~ ERROR struct literals are not allowed here - } -} - -fn test4(x: module::Type) { - use module as demo_module; - if x == demo_module::Type { x: module::C, y: 1 } { //~ ERROR struct literals are not allowed here - } -} - -fn main() { } diff --git a/tests/ui/parser/issues/issue-111692.stderr b/tests/ui/parser/issues/issue-111692.stderr deleted file mode 100644 index 979dfade1ba2..000000000000 --- a/tests/ui/parser/issues/issue-111692.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: struct literals are not allowed here - --> $DIR/issue-111692.rs:12:13 - | -LL | if x == module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (module::Type { x: module::C, y: 1 }) { - | + + - -error: struct literals are not allowed here - --> $DIR/issue-111692.rs:17:12 - | -LL | if x ==module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x ==(module::Type { x: module::C, y: 1 }) { - | + + - -error: struct literals are not allowed here - --> $DIR/issue-111692.rs:24:13 - | -LL | if x == Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (Type { x: module::C, y: 1 }) { - | + + - -error: struct literals are not allowed here - --> $DIR/issue-111692.rs:30:13 - | -LL | if x == demo_module::Type { x: module::C, y: 1 } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: surround the struct literal with parentheses - | -LL | if x == (demo_module::Type { x: module::C, y: 1 }) { - | + + - -error: aborting due to 4 previous errors - diff --git a/tests/ui/parser/struct-literals-in-invalid-places.rs b/tests/ui/parser/struct-literals-in-invalid-places.rs index 89cdb30fc046..eed51b945831 100644 --- a/tests/ui/parser/struct-literals-in-invalid-places.rs +++ b/tests/ui/parser/struct-literals-in-invalid-places.rs @@ -45,12 +45,30 @@ fn main() { println!("yo"); } + // This uses `one()` over `1` as token `one` may begin a type and thus back when type ascription + // `$expr : $ty` still existed, `{ x: one` could've been the start of a block expr which used to + // make the compiler take a different execution path. Now it no longer makes a difference tho. + // Regression test for . if Foo { x: one(), }.hi() { //~ ERROR struct literals are not allowed here println!("Positive!"); } + + const FOO: Foo = Foo { x: 1 }; + // Below, test that we correctly parenthesize the struct literals. + + // Regression test for . + if FOO == self::Foo { x: one() } {} //~ ERROR struct literals are not allowed here + + if FOO == Foo::<> { x: one() } {} //~ ERROR struct literals are not allowed here + + fn env>() { + if FOO == ::Out { x: one() } {} //~ ERROR struct literals are not allowed here + //~^ ERROR usage of qualified paths in this context is experimental + } } +#[derive(PartialEq, Eq)] struct Foo { x: isize, } @@ -70,3 +88,5 @@ enum E { } fn one() -> isize { 1 } + +trait Trait { type Out; } diff --git a/tests/ui/parser/struct-literals-in-invalid-places.stderr b/tests/ui/parser/struct-literals-in-invalid-places.stderr index ed094fc3e157..39dc2d2efb75 100644 --- a/tests/ui/parser/struct-literals-in-invalid-places.stderr +++ b/tests/ui/parser/struct-literals-in-invalid-places.stderr @@ -120,7 +120,7 @@ LL | while || (Foo { x: 3 }).hi() { | + + error: struct literals are not allowed here - --> $DIR/struct-literals-in-invalid-places.rs:49:8 + --> $DIR/struct-literals-in-invalid-places.rs:53:8 | LL | if Foo { x: one(), }.hi() { | ^^^^^^^^^^^^^^^^^ @@ -130,6 +130,49 @@ help: surround the struct literal with parentheses LL | if (Foo { x: one(), }).hi() { | + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:61:15 + | +LL | if FOO == self::Foo { x: one() } {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if FOO == (self::Foo { x: one() }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:63:15 + | +LL | if FOO == Foo::<> { x: one() } {} + | ^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if FOO == (Foo::<> { x: one() }) {} + | + + + +error: struct literals are not allowed here + --> $DIR/struct-literals-in-invalid-places.rs:66:19 + | +LL | if FOO == ::Out { x: one() } {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: surround the struct literal with parentheses + | +LL | if FOO == (::Out { x: one() }) {} + | + + + +error[E0658]: usage of qualified paths in this context is experimental + --> $DIR/struct-literals-in-invalid-places.rs:66:19 + | +LL | if FOO == ::Out { x: one() } {} + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #86935 for more information + = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0277]: `bool` is not an iterator --> $DIR/struct-literals-in-invalid-places.rs:9:14 | @@ -185,7 +228,7 @@ help: use parentheses to call this closure LL | while (|| Foo { x: 3 }.hi())() { | + +++ -error: aborting due to 17 previous errors +error: aborting due to 21 previous errors -Some errors have detailed explanations: E0277, E0308, E0533. +Some errors have detailed explanations: E0277, E0308, E0533, E0658. For more information about an error, try `rustc --explain E0277`. From 8d5109aa6ea1b54a560774eb95ba7c1b8d404faa Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 23 Mar 2025 15:50:51 +0300 Subject: [PATCH 322/546] compiletest: Support matching on diagnostics without a span --- src/doc/rustc-dev-guide/src/tests/ui.md | 26 +++++- src/tools/compiletest/src/errors.rs | 55 +++++------- src/tools/compiletest/src/json.rs | 88 +++++++++++-------- src/tools/compiletest/src/runtest.rs | 4 +- src/tools/compiletest/src/runtest/ui.rs | 2 +- tests/rustdoc-ui/coverage/html.rs | 2 + tests/rustdoc-ui/deprecated-attrs.rs | 4 + tests/rustdoc-ui/doctest-output.rs | 2 + .../generate-link-to-definition-opt.rs | 2 + tests/rustdoc-ui/include-str-bare-urls.rs | 2 + tests/rustdoc-ui/lints/check.rs | 2 + tests/rustdoc-ui/remap-path-prefix-lint.rs | 2 + .../scrape-examples-fail-if-type-error.rs | 2 + .../scrape-examples-wrong-options-1.rs | 2 + .../scrape-examples-wrong-options-2.rs | 2 + .../use_both_out_dir_and_output_options.rs | 2 + tests/ui/asm/inline-syntax.rs | 5 ++ tests/ui/cfg/disallowed-cli-cfgs.rs | 2 + tests/ui/check-cfg/invalid-arguments.rs | 2 + tests/ui/codegen/duplicated-path-in-error.rs | 2 + tests/ui/consts/const-eval/const_fn_ptr.rs | 2 + .../ui/consts/const-eval/const_fn_ptr_fail.rs | 2 + .../consts/const-eval/const_fn_ptr_fail2.rs | 2 + tests/ui/consts/const-eval/issue-85155.rs | 3 + .../ui/consts/miri_unleashed/abi-mismatch.rs | 2 + tests/ui/consts/miri_unleashed/assoc_const.rs | 2 + tests/ui/consts/miri_unleashed/box.rs | 2 + .../miri_unleashed/const_refers_to_static.rs | 2 + tests/ui/consts/miri_unleashed/inline_asm.rs | 2 + .../miri_unleashed/mutable_references.rs | 2 + .../ui/consts/miri_unleashed/non_const_fn.rs | 2 + tests/ui/consts/miri_unleashed/ptr_arith.rs | 2 + .../miri_unleashed/static-no-inner-mut.rs | 2 + tests/ui/consts/miri_unleashed/tls.rs | 2 + tests/ui/dep-graph/dep-graph-dump.rs | 2 + tests/ui/deprecation/deprecated_ar.rs | 2 + .../deprecated_inline_threshold.rs | 6 ++ .../deprecated_no_stack_check_opt.rs | 2 + .../ui/did_you_mean/recursion_limit_deref.rs | 3 + .../edition-keywords-2018-2015-parsing.rs | 2 + .../edition-keywords-2018-2018-parsing.rs | 2 + ...orted_main_from_extern_crate_wrong_type.rs | 2 + tests/ui/errors/wrong-target-spec.rs | 2 + .../feature-gate-link-arg-attribute.rs | 2 + ...re-gate-native_link_modifiers_as_needed.rs | 2 + tests/ui/fmt/fmt_debug/invalid.rs | 2 + tests/ui/infinite/infinite-struct.rs | 2 + tests/ui/instrument-coverage/bad-value.rs | 3 + .../instrument-coverage/coverage-options.rs | 2 + .../branch-protection-missing-pac-ret.rs | 4 + .../invalid-llvm-passes.rs | 2 + .../need-crate-arg-ignore-tidy$x.rs | 3 + tests/ui/invalid-compile-flags/print.rs | 2 + .../invalid-module-declaration.rs | 2 + .../lang-item-generic-requirements.rs | 2 + tests/ui/link-native-libs/modifiers-bad.rs | 5 ++ .../link-native-libs/modifiers-override-2.rs | 2 + .../link-native-libs/msvc-non-utf8-output.rs | 2 + .../link-self-contained-consistency.rs | 3 + ...-detect-extern-generated-name-collision.rs | 2 + .../raw-dylib/windows/dlltool-failed.rs | 2 + .../raw-dylib/windows/invalid-dlltool.rs | 2 + tests/ui/lint/expansion-time.rs | 2 + tests/ui/lint/lint-unexported-no-mangle.rs | 7 ++ tests/ui/lto/lto-and-no-bitcode-in-rlib.rs | 2 + tests/ui/macros/include-single-expr.rs | 4 +- tests/ui/mir-dataflow/inits-1.rs | 2 + tests/ui/mir-dataflow/liveness-enum.rs | 2 + tests/ui/mir-dataflow/liveness-projection.rs | 2 + tests/ui/mir-dataflow/liveness-ptr.rs | 2 + tests/ui/mir-dataflow/uninits-1.rs | 2 + tests/ui/mir-dataflow/uninits-2.rs | 2 + tests/ui/mir/enable_passes_validation.rs | 3 + tests/ui/missing/missing-allocator.rs | 2 + .../missing_non_modrs_mod.rs | 2 + .../missing_non_modrs_mod_inline.rs | 2 + .../panic-handler-wrong-location.rs | 2 + tests/ui/parser/issues/issue-94340.rs | 3 + tests/ui/parser/unclosed-delimiter-in-dep.rs | 2 + .../patchable-function-entry-flags.rs | 3 + tests/ui/print-request/invalid-target.rs | 2 + .../proc-macro/inner-attr-non-inline-mod.rs | 5 +- .../inner-attr-non-inline-mod.stderr | 4 +- .../inner-attr-non-inline-mod.stdout | 30 +++---- tests/ui/proc-macro/pretty-print-hack-show.rs | 2 + tests/ui/resolve/parse-error-resolve.rs | 2 + .../caller-location-fnptr-rt-ctfe-equiv.rs | 2 + tests/ui/rmeta/no_optitimized_mir.rs | 2 + tests/ui/runtime/on-broken-pipe/default.rs | 2 + .../ui/runtime/on-broken-pipe/no-flag-arg.rs | 2 + .../runtime/on-broken-pipe/wrong-flag-arg.rs | 2 + tests/ui/rustc-env/min-stack-banana.rs | 3 + .../cfi/canonical-jump-tables-requires-cfi.rs | 2 + .../cfi/generalize-pointers-requires-cfi.rs | 2 + .../cfi/is-incompatible-with-kcfi.rs | 3 + .../cfi/normalize-integers-requires-cfi.rs | 2 + tests/ui/sanitizer/cfi/requires-lto.rs | 2 + ...-rustc-lto-requires-single-codegen-unit.rs | 2 + tests/ui/sanitizer/crt-static.rs | 2 + .../sanitizer/split-lto-unit-requires-lto.rs | 2 + .../warn-stack-protector-unsupported.rs | 4 + tests/ui/symbol-mangling-version/bad-value.rs | 4 + tests/ui/symbol-mangling-version/unstable.rs | 3 + ...d-softfloat-target-feature-flag-disable.rs | 2 + .../ui/target-feature/missing-plusminus-2.rs | 2 + tests/ui/target-feature/missing-plusminus.rs | 2 + .../similar-feature-suggestion.rs | 2 + tests/ui/target-feature/tied-features-cli.rs | 4 + .../tied-features-no-implication-1.rs | 2 + tests/ui/target-feature/unstable-feature.rs | 2 + .../target_modifiers/incompatible_regparm.rs | 2 + .../tool-attributes/duplicate-diagnostic.rs | 7 +- .../duplicate-diagnostic.stderr | 2 +- tests/ui/type/pattern_types/literals.rs | 3 + tests/ui/type/pattern_types/range_patterns.rs | 4 + tests/ui/unpretty/avoid-crash.rs | 2 + 116 files changed, 371 insertions(+), 105 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index c8536b0045cf..98bb9dee76c5 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -202,6 +202,9 @@ several ways to match the message with the line (see the examples below): * `~|`: Associates the error level and message with the *same* line as the *previous comment*. This is more convenient than using multiple carets when there are multiple messages associated with the same line. +* `~?`: Used to match error levels and messages with errors not having line + information. These can be placed on any line in the test file, but are + conventionally placed at the end. Example: @@ -270,10 +273,23 @@ fn main() { //~| ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields [E0023] ``` +#### Error without line information + +Use `//~?` to match an error without line information. +`//~?` is precise and will not match errors if their line information is available. +It should be preferred to using `error-pattern`, which is imprecise and non-exhaustive. + +```rust,ignore +//@ compile-flags: --print yyyy + +//~? ERROR unknown print request: `yyyy` +``` + ### `error-pattern` -The `error-pattern` [directive](directives.md) can be used for messages that don't -have a specific span. +The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't +have a specific span, or for compile time messages if imprecise matching is required due to +multi-line platform specific diagnostics. Let's think about this test: @@ -300,7 +316,9 @@ fn main() { } ``` -But for strict testing, try to use the `ERROR` annotation as much as possible. +But for strict testing, try to use the `ERROR` annotation as much as possible, +including `//~?` annotations for diagnostics without span. +For compile time diagnostics `error-pattern` should very rarely be necessary. ### Error levels @@ -353,7 +371,7 @@ would be a `.mir.stderr` and `.thir.stderr` file with the different outputs of the different revisions. > Note: cfg revisions also work inside the source code with `#[cfg]` attributes. -> +> > By convention, the `FALSE` cfg is used to have an always-false config. ## Controlling pass/fail expectations diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 37ef63ae42ea..c0566ef93b92 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -9,8 +9,6 @@ use std::sync::OnceLock; use regex::Regex; use tracing::*; -use self::WhichLine::*; - #[derive(Copy, Clone, Debug, PartialEq)] pub enum ErrorKind { Help, @@ -50,7 +48,7 @@ impl fmt::Display for ErrorKind { #[derive(Debug)] pub struct Error { - pub line_num: usize, + pub line_num: Option, /// What kind of message we expect (e.g., warning, error, suggestion). /// `None` if not specified or unknown message kind. pub kind: Option, @@ -63,17 +61,14 @@ impl Error { format!( "{: <10}line {: >3}: {}", self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(), - self.line_num, + self.line_num_str(), self.msg.cyan(), ) } -} -#[derive(PartialEq, Debug)] -enum WhichLine { - ThisLine, - FollowPrevious(usize), - AdjustBackward(usize), + pub fn line_num_str(&self) -> String { + self.line_num.map_or("?".to_string(), |line_num| line_num.to_string()) + } } /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE" @@ -105,12 +100,10 @@ pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec { .filter(|(_, line)| line.is_ok()) .filter_map(|(line_num, line)| { parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), revision).map( - |(which, error)| { - match which { - FollowPrevious(_) => {} - _ => last_nonfollow_error = Some(error.line_num), + |(follow_prev, error)| { + if !follow_prev { + last_nonfollow_error = error.line_num; } - error }, ) @@ -123,18 +116,19 @@ fn parse_expected( line_num: usize, line: &str, test_revision: Option<&str>, -) -> Option<(WhichLine, Error)> { +) -> Option<(bool, Error)> { // Matches comments like: // //~ // //~| // //~^ // //~^^^^^ + // //~? // //[rev1]~ // //[rev1,rev2]~^^ static RE: OnceLock = OnceLock::new(); let captures = RE - .get_or_init(|| Regex::new(r"//(?:\[(?P[\w\-,]+)])?~(?P\||\^*)").unwrap()) + .get_or_init(|| Regex::new(r"//(?:\[(?P[\w\-,]+)])?~(?P\?|\||\^*)").unwrap()) .captures(line)?; match (test_revision, captures.name("revs")) { @@ -151,11 +145,6 @@ fn parse_expected( (Some(_), None) | (None, None) => {} } - let (follow, adjusts) = match &captures["adjust"] { - "|" => (true, 0), - circumflexes => (false, circumflexes.len()), - }; - // Get the part of the comment after the sigil (e.g. `~^^` or ~|). let whole_match = captures.get(0).unwrap(); let (_, mut msg) = line.split_at(whole_match.end()); @@ -170,28 +159,24 @@ fn parse_expected( let msg = msg.trim().to_owned(); - let (which, line_num) = if follow { - assert_eq!(adjusts, 0, "use either //~| or //~^, not both."); - let line_num = last_nonfollow_error.expect( - "encountered //~| without \ - preceding //~^ line.", - ); - (FollowPrevious(line_num), line_num) + let line_num_adjust = &captures["adjust"]; + let (follow_prev, line_num) = if line_num_adjust == "|" { + (true, Some(last_nonfollow_error.expect("encountered //~| without preceding //~^ line"))) + } else if line_num_adjust == "?" { + (false, None) } else { - let which = if adjusts > 0 { AdjustBackward(adjusts) } else { ThisLine }; - let line_num = line_num - adjusts; - (which, line_num) + (false, Some(line_num - line_num_adjust.len())) }; debug!( - "line={} tag={:?} which={:?} kind={:?} msg={:?}", + "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}", line_num, whole_match.as_str(), - which, + follow_prev, kind, msg ); - Some((which, Error { line_num, kind, msg })) + Some((follow_prev, Error { line_num, kind, msg })) } #[cfg(test)] diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 0da93dcafa20..9bc26fedf8f4 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -2,7 +2,9 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::sync::OnceLock; +use regex::Regex; use serde::Deserialize; use crate::errors::{Error, ErrorKind}; @@ -213,36 +215,24 @@ fn push_expected_errors( // also ensure that `//~ ERROR E123` *always* works. The // assumption is that these multi-line error messages are on their // way out anyhow. - let with_code = |span: &DiagnosticSpan, text: &str| { - match diagnostic.code { - Some(ref code) => - // FIXME(#33000) -- it'd be better to use a dedicated - // UI harness than to include the line/col number like - // this, but some current tests rely on it. - // - // Note: Do NOT include the filename. These can easily - // cause false matches where the expected message - // appears in the filename, and hence the message - // changes but the test still passes. - { - format!( - "{}:{}: {}:{}: {} [{}]", - span.line_start, - span.column_start, - span.line_end, - span.column_end, - text, - code.code.clone() - ) - } - None => - // FIXME(#33000) -- it'd be better to use a dedicated UI harness - { - format!( - "{}:{}: {}:{}: {}", - span.line_start, span.column_start, span.line_end, span.column_end, text - ) + let with_code = |span: Option<&DiagnosticSpan>, text: &str| { + // FIXME(#33000) -- it'd be better to use a dedicated + // UI harness than to include the line/col number like + // this, but some current tests rely on it. + // + // Note: Do NOT include the filename. These can easily + // cause false matches where the expected message + // appears in the filename, and hence the message + // changes but the test still passes. + let span_str = match span { + Some(DiagnosticSpan { line_start, column_start, line_end, column_end, .. }) => { + format!("{line_start}:{column_start}: {line_end}:{column_end}") } + None => format!("?:?: ?:?"), + }; + match &diagnostic.code { + Some(code) => format!("{span_str}: {text} [{}]", code.code), + None => format!("{span_str}: {text}"), } }; @@ -251,19 +241,41 @@ fn push_expected_errors( // more structured shortly anyhow. let mut message_lines = diagnostic.message.lines(); if let Some(first_line) = message_lines.next() { - for span in primary_spans { - let msg = with_code(span, first_line); + let ignore = |s| { + static RE: OnceLock = OnceLock::new(); + RE.get_or_init(|| { + Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap() + }) + .is_match(s) + }; + + if primary_spans.is_empty() && !ignore(first_line) { + let msg = with_code(None, first_line); let kind = ErrorKind::from_str(&diagnostic.level).ok(); - expected_errors.push(Error { line_num: span.line_start, kind, msg }); + expected_errors.push(Error { line_num: None, kind, msg }); + } else { + for span in primary_spans { + let msg = with_code(Some(span), first_line); + let kind = ErrorKind::from_str(&diagnostic.level).ok(); + expected_errors.push(Error { line_num: Some(span.line_start), kind, msg }); + } } } for next_line in message_lines { - for span in primary_spans { + if primary_spans.is_empty() { expected_errors.push(Error { - line_num: span.line_start, + line_num: None, kind: None, - msg: with_code(span, next_line), + msg: with_code(None, next_line), }); + } else { + for span in primary_spans { + expected_errors.push(Error { + line_num: Some(span.line_start), + kind: None, + msg: with_code(Some(span), next_line), + }); + } } } @@ -272,7 +284,7 @@ fn push_expected_errors( if let Some(ref suggested_replacement) = span.suggested_replacement { for (index, line) in suggested_replacement.lines().enumerate() { expected_errors.push(Error { - line_num: span.line_start + index, + line_num: Some(span.line_start + index), kind: Some(ErrorKind::Suggestion), msg: line.to_string(), }); @@ -290,7 +302,7 @@ fn push_expected_errors( // Add notes for any labels that appear in the message. for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) { expected_errors.push(Error { - line_num: span.line_start, + line_num: Some(span.line_start), kind: Some(ErrorKind::Note), msg: span.label.clone().unwrap(), }); @@ -309,7 +321,7 @@ fn push_backtrace( ) { if Path::new(&expansion.span.file_name) == Path::new(&file_name) { expected_errors.push(Error { - line_num: expansion.span.line_start, + line_num: Some(expansion.span.line_start), kind: Some(ErrorKind::Note), msg: format!("in this expansion of {}", expansion.macro_decl_name), }); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 6e250ca12c93..c8a60b68da8b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -747,7 +747,7 @@ impl<'test> TestCx<'test> { self.error(&format!( "{}:{}: unexpected {}: '{}'", file_name, - actual_error.line_num, + actual_error.line_num_str(), actual_error .kind .as_ref() @@ -767,7 +767,7 @@ impl<'test> TestCx<'test> { self.error(&format!( "{}:{}: expected {} not found: {}", file_name, - expected_error.line_num, + expected_error.line_num_str(), expected_error.kind.as_ref().map_or("message".into(), |k| k.to_string()), expected_error.msg )); diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index 3329e10745f8..9b5b8b56b600 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -182,7 +182,7 @@ impl TestCx<'_> { } else if explicit && !expected_errors.is_empty() { let msg = format!( "line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead", - expected_errors[0].line_num, + expected_errors[0].line_num_str(), expected_errors[0].kind.unwrap_or(ErrorKind::Error), ); self.fatal(&msg); diff --git a/tests/rustdoc-ui/coverage/html.rs b/tests/rustdoc-ui/coverage/html.rs index 41e1ce1609dc..7fd080f07582 100644 --- a/tests/rustdoc-ui/coverage/html.rs +++ b/tests/rustdoc-ui/coverage/html.rs @@ -2,3 +2,5 @@ /// Foo pub struct Xo; + +//~? ERROR `--output-format=html` is not supported for the `--show-coverage` option diff --git a/tests/rustdoc-ui/deprecated-attrs.rs b/tests/rustdoc-ui/deprecated-attrs.rs index 3b59e05a012e..0ae65a5eaf7c 100644 --- a/tests/rustdoc-ui/deprecated-attrs.rs +++ b/tests/rustdoc-ui/deprecated-attrs.rs @@ -19,3 +19,7 @@ //~| NOTE see issue #44136 //~| NOTE no longer functions //~| NOTE `doc(plugins)` is now a no-op + +//~? WARN the `passes` flag no longer functions +//~? NOTE see issue #44136 +//~? HELP you may want to use --document-private-items diff --git a/tests/rustdoc-ui/doctest-output.rs b/tests/rustdoc-ui/doctest-output.rs index 720f2952980e..28364c3a3ea5 100644 --- a/tests/rustdoc-ui/doctest-output.rs +++ b/tests/rustdoc-ui/doctest-output.rs @@ -1 +1,3 @@ //@ compile-flags:-Z unstable-options --show-coverage --output-format=doctest + +//~? ERROR `--output-format=doctest` is not supported for the `--show-coverage` option diff --git a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.rs b/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.rs index babdbd0a6921..9d6ec0caf9f4 100644 --- a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.rs +++ b/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.rs @@ -5,3 +5,5 @@ //@ check-pass pub fn f() {} + +//~? WARN `--generate-link-to-definition` option can only be used with HTML output format diff --git a/tests/rustdoc-ui/include-str-bare-urls.rs b/tests/rustdoc-ui/include-str-bare-urls.rs index c452c88cdd3d..f80e28e8ca70 100644 --- a/tests/rustdoc-ui/include-str-bare-urls.rs +++ b/tests/rustdoc-ui/include-str-bare-urls.rs @@ -13,3 +13,5 @@ #![deny(rustdoc::bare_urls)] #![doc=include_str!("auxiliary/include-str-bare-urls.md")] + +//~? ERROR this URL is not a hyperlink diff --git a/tests/rustdoc-ui/lints/check.rs b/tests/rustdoc-ui/lints/check.rs index 61c9f1889529..0943f9f6053e 100644 --- a/tests/rustdoc-ui/lints/check.rs +++ b/tests/rustdoc-ui/lints/check.rs @@ -12,3 +12,5 @@ pub fn foo() {} //~^ WARN //~^^ WARN + +//~? WARN no documentation found for this crate's top-level module diff --git a/tests/rustdoc-ui/remap-path-prefix-lint.rs b/tests/rustdoc-ui/remap-path-prefix-lint.rs index f27863e825d9..d003e19f200d 100644 --- a/tests/rustdoc-ui/remap-path-prefix-lint.rs +++ b/tests/rustdoc-ui/remap-path-prefix-lint.rs @@ -8,3 +8,5 @@ /// pub struct Bar; + +//~? ERROR unopened HTML tag `script` diff --git a/tests/rustdoc-ui/scrape-examples/scrape-examples-fail-if-type-error.rs b/tests/rustdoc-ui/scrape-examples/scrape-examples-fail-if-type-error.rs index 4fb5c9ab36fa..c8e82d3a20b5 100644 --- a/tests/rustdoc-ui/scrape-examples/scrape-examples-fail-if-type-error.rs +++ b/tests/rustdoc-ui/scrape-examples/scrape-examples-fail-if-type-error.rs @@ -5,3 +5,5 @@ pub fn foo() { INVALID_FUNC(); //~^ ERROR could not resolve path } + +//~? ERROR Compilation failed, aborting rustdoc diff --git a/tests/rustdoc-ui/scrape-examples/scrape-examples-wrong-options-1.rs b/tests/rustdoc-ui/scrape-examples/scrape-examples-wrong-options-1.rs index df7b41e20f6f..3db7924dbe14 100644 --- a/tests/rustdoc-ui/scrape-examples/scrape-examples-wrong-options-1.rs +++ b/tests/rustdoc-ui/scrape-examples/scrape-examples-wrong-options-1.rs @@ -1 +1,3 @@ //@ compile-flags: -Z unstable-options --scrape-examples-target-crate foobar + +//~? ERROR must use --scrape-examples-output-path and --scrape-examples-target-crate together diff --git a/tests/rustdoc-ui/scrape-examples/scrape-examples-wrong-options-2.rs b/tests/rustdoc-ui/scrape-examples/scrape-examples-wrong-options-2.rs index ef270a08f48b..7b6a30291ce8 100644 --- a/tests/rustdoc-ui/scrape-examples/scrape-examples-wrong-options-2.rs +++ b/tests/rustdoc-ui/scrape-examples/scrape-examples-wrong-options-2.rs @@ -1 +1,3 @@ //@ compile-flags: -Z unstable-options --scrape-examples-output-path ex.calls + +//~? ERROR must use --scrape-examples-output-path and --scrape-examples-target-crate together diff --git a/tests/rustdoc-ui/use_both_out_dir_and_output_options.rs b/tests/rustdoc-ui/use_both_out_dir_and_output_options.rs index 62d3d955855e..42847203d489 100644 --- a/tests/rustdoc-ui/use_both_out_dir_and_output_options.rs +++ b/tests/rustdoc-ui/use_both_out_dir_and_output_options.rs @@ -1 +1,3 @@ //@ compile-flags: --output ./foo + +//~? ERROR cannot use both 'out-dir' and 'output' at once diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index adbda369b6a7..78f30d50d8c0 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -58,3 +58,8 @@ pub fn main() { global_asm!(".intel_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` // Global assembly errors don't have line numbers, so no error on ARM. + +//[arm_llvm_18]~? ERROR unknown directive +//[arm_llvm_18]~? ERROR unknown directive +//[arm]~? ERROR unknown directive +//[arm]~? ERROR unknown directive diff --git a/tests/ui/cfg/disallowed-cli-cfgs.rs b/tests/ui/cfg/disallowed-cli-cfgs.rs index cae9c65cb45a..e9661abf3abe 100644 --- a/tests/ui/cfg/disallowed-cli-cfgs.rs +++ b/tests/ui/cfg/disallowed-cli-cfgs.rs @@ -37,3 +37,5 @@ //@ [emscripten_wasm_eh_]compile-flags: --cfg emscripten_wasm_eh fn main() {} + +//~? ERROR unexpected `--cfg diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs index c6b1218ce27c..3bea128e3e42 100644 --- a/tests/ui/check-cfg/invalid-arguments.rs +++ b/tests/ui/check-cfg/invalid-arguments.rs @@ -36,3 +36,5 @@ //@ [unsafe_attr]compile-flags: --check-cfg=unsafe(cfg(foo)) fn main() {} + +//~? ERROR invalid `--check-cfg` argument diff --git a/tests/ui/codegen/duplicated-path-in-error.rs b/tests/ui/codegen/duplicated-path-in-error.rs index cff20dd9bd63..a446395de208 100644 --- a/tests/ui/codegen/duplicated-path-in-error.rs +++ b/tests/ui/codegen/duplicated-path-in-error.rs @@ -5,3 +5,5 @@ // the path of the dylib. fn main() {} + +//~? ERROR couldn't load codegen backend /non-existing-one.so diff --git a/tests/ui/consts/const-eval/const_fn_ptr.rs b/tests/ui/consts/const-eval/const_fn_ptr.rs index f8a2658f31e6..1d65eedb93d0 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr.rs +++ b/tests/ui/consts/const-eval/const_fn_ptr.rs @@ -34,3 +34,5 @@ fn main() { let z = foo(double, 2); assert_eq!(z, 4); } + +//~? WARN skipping const checks diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail.rs b/tests/ui/consts/const-eval/const_fn_ptr_fail.rs index a0f804722dbb..00bf0ed0eba0 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr_fail.rs +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail.rs @@ -10,3 +10,5 @@ const fn bar(x: usize) -> usize { } fn main() {} + +//~? WARN skipping const checks diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs b/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs index 7db8c6e81ab5..c6ae3af44270 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs @@ -24,3 +24,5 @@ fn main() { assert_eq!(Y, 4); assert_eq!(Z, 4); } + +//~? WARN skipping const checks diff --git a/tests/ui/consts/const-eval/issue-85155.rs b/tests/ui/consts/const-eval/issue-85155.rs index 95253a0b288f..cb5b3a08375d 100644 --- a/tests/ui/consts/const-eval/issue-85155.rs +++ b/tests/ui/consts/const-eval/issue-85155.rs @@ -19,3 +19,6 @@ fn main() { post_monomorphization_error::stdarch_intrinsic::<2>(); //~^ NOTE the above error was encountered while instantiating } + +//~? ERROR evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed +//~? NOTE erroneous constant encountered diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.rs b/tests/ui/consts/miri_unleashed/abi-mismatch.rs index ea640ae78d55..0a2b3f3abd62 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.rs +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.rs @@ -13,3 +13,5 @@ static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn //~| NOTE calling a function with calling convention C using calling convention Rust fn main() {} + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/assoc_const.rs b/tests/ui/consts/miri_unleashed/assoc_const.rs index 96b47ff4e5e2..812207ee8090 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.rs +++ b/tests/ui/consts/miri_unleashed/assoc_const.rs @@ -28,3 +28,5 @@ fn main() { // this test only causes errors due to the line below, so post-monomorphization let y = , String>>::F; } + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/box.rs b/tests/ui/consts/miri_unleashed/box.rs index 89df4526b077..1539083f09c2 100644 --- a/tests/ui/consts/miri_unleashed/box.rs +++ b/tests/ui/consts/miri_unleashed/box.rs @@ -9,3 +9,5 @@ static TEST_BAD: &mut i32 = { //~^ ERROR could not evaluate static initializer //~| NOTE calling non-const function `Box::::new` }; + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs index a6691fa2a2f1..fdccc17ab49a 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs @@ -31,3 +31,5 @@ const REF_IMMUT: &u8 = &MY_STATIC; const READ_IMMUT: u8 = *REF_IMMUT; fn main() {} + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/inline_asm.rs b/tests/ui/consts/miri_unleashed/inline_asm.rs index 8627a6bf8870..f1ce613b16e8 100644 --- a/tests/ui/consts/miri_unleashed/inline_asm.rs +++ b/tests/ui/consts/miri_unleashed/inline_asm.rs @@ -11,3 +11,5 @@ static TEST_BAD: () = { //~^ ERROR could not evaluate static initializer //~| NOTE inline assembly is not supported }; + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs index 039d0fadfcc4..e7fc5699236e 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -114,3 +114,5 @@ fn main() { } *OH_YES = 99; //~ ERROR cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item } + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/non_const_fn.rs b/tests/ui/consts/miri_unleashed/non_const_fn.rs index d3ffb61af118..201647ac8d88 100644 --- a/tests/ui/consts/miri_unleashed/non_const_fn.rs +++ b/tests/ui/consts/miri_unleashed/non_const_fn.rs @@ -9,3 +9,5 @@ static C: () = foo(); //~| NOTE calling non-const function `foo` fn main() {} + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.rs b/tests/ui/consts/miri_unleashed/ptr_arith.rs index 6dd8ab11e7cf..4e1183220792 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.rs +++ b/tests/ui/consts/miri_unleashed/ptr_arith.rs @@ -21,3 +21,5 @@ static PTR_INT_TRANSMUTE: () = unsafe { // their `PartialEq` impl is non-`const`. fn main() {} + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs index 126d78158fe0..7fa173d8d9d8 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs @@ -38,3 +38,5 @@ static RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; //~^ ERROR mutable pointer in final value fn main() {} + +//~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/tls.rs b/tests/ui/consts/miri_unleashed/tls.rs index b0c6c088361c..ab23a5249988 100644 --- a/tests/ui/consts/miri_unleashed/tls.rs +++ b/tests/ui/consts/miri_unleashed/tls.rs @@ -23,3 +23,5 @@ static TEST_BAD_REF: () = { }; fn main() {} + +//~? WARN skipping const checks diff --git a/tests/ui/dep-graph/dep-graph-dump.rs b/tests/ui/dep-graph/dep-graph-dump.rs index 7aede27d125c..5dc05045e828 100644 --- a/tests/ui/dep-graph/dep-graph-dump.rs +++ b/tests/ui/dep-graph/dep-graph-dump.rs @@ -4,3 +4,5 @@ //@ compile-flags: -Z dump-dep-graph fn main() {} + +//~? ERROR can't dump dependency graph without `-Z query-dep-graph` diff --git a/tests/ui/deprecation/deprecated_ar.rs b/tests/ui/deprecation/deprecated_ar.rs index 404d062e6a44..00862d2c00a2 100644 --- a/tests/ui/deprecation/deprecated_ar.rs +++ b/tests/ui/deprecation/deprecated_ar.rs @@ -2,3 +2,5 @@ //@ compile-flags: -Car=foo fn main() {} + +//~? WARN `-C ar`: this option is deprecated and does nothing diff --git a/tests/ui/deprecation/deprecated_inline_threshold.rs b/tests/ui/deprecation/deprecated_inline_threshold.rs index b54fa36397af..284a6d6798e4 100644 --- a/tests/ui/deprecation/deprecated_inline_threshold.rs +++ b/tests/ui/deprecation/deprecated_inline_threshold.rs @@ -6,3 +6,9 @@ //@[no_val] compile-flags: -Cinline-threshold fn main() {} + +//[good_val]~? WARN `-C inline-threshold`: this option is deprecated and does nothing +//[bad_val]~? WARN `-C inline-threshold`: this option is deprecated and does nothing +//[bad_val]~? ERROR incorrect value `asd` for codegen option `inline-threshold` +//[no_val]~? WARN `-C inline-threshold`: this option is deprecated and does nothing +//[no_val]~? ERROR codegen option `inline-threshold` requires a number diff --git a/tests/ui/deprecation/deprecated_no_stack_check_opt.rs b/tests/ui/deprecation/deprecated_no_stack_check_opt.rs index 62584ec23e33..e014c7e80aff 100644 --- a/tests/ui/deprecation/deprecated_no_stack_check_opt.rs +++ b/tests/ui/deprecation/deprecated_no_stack_check_opt.rs @@ -2,3 +2,5 @@ //@ compile-flags: -Cno-stack-check fn main() {} + +//~? WARN `-C no-stack-check`: this option is deprecated and does nothing diff --git a/tests/ui/did_you_mean/recursion_limit_deref.rs b/tests/ui/did_you_mean/recursion_limit_deref.rs index af4c4ddda69a..e53007388af2 100644 --- a/tests/ui/did_you_mean/recursion_limit_deref.rs +++ b/tests/ui/did_you_mean/recursion_limit_deref.rs @@ -51,3 +51,6 @@ fn main() { let x: &Bottom = &t; //~ ERROR mismatched types //~^ error recursion limit } + +//~? ERROR reached the recursion limit finding the struct tail for `K` +//~? ERROR reached the recursion limit finding the struct tail for `Bottom` diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs index c3dfcfb19cb4..f8d2755b9d79 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs @@ -28,3 +28,5 @@ pub fn check_async() { let _recovery_witness: () = 0; //~ ERROR mismatched types } + +//~? ERROR macro expansion ends with an incomplete expression diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs index 1447c49ef717..f4438472a0e6 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs @@ -39,3 +39,5 @@ pub fn check_async() { let _recovery_witness: () = 0; //~ ERROR mismatched types } + +//~? ERROR macro expansion ends with an incomplete expression diff --git a/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs index d8ae12d200f4..0b527baaafe7 100644 --- a/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs +++ b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs @@ -2,3 +2,5 @@ extern crate bad_main_functions; pub use bad_main_functions::boilerplate as main; + +//~? ERROR `main` function has wrong type diff --git a/tests/ui/errors/wrong-target-spec.rs b/tests/ui/errors/wrong-target-spec.rs index bc9038c1fab5..9b31c943e3e9 100644 --- a/tests/ui/errors/wrong-target-spec.rs +++ b/tests/ui/errors/wrong-target-spec.rs @@ -6,3 +6,5 @@ //@ compile-flags: --target x86_64_unknown-linux-musl fn main() {} + +//~? ERROR Error loading target specification: Could not find specification for target "x86_64_unknown-linux-musl" diff --git a/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs b/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs index c12ff5b04dc3..8e11a05c89be 100644 --- a/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs +++ b/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs @@ -7,3 +7,5 @@ extern "C" {} fn main() {} + +//[in_flag]~? ERROR unknown linking modifier `link-arg` diff --git a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs index c2965e42f276..c5859eec8db5 100644 --- a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs +++ b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs @@ -7,3 +7,5 @@ extern "C" {} fn main() {} + +//[in_flag]~? ERROR linking modifier `as-needed` is unstable diff --git a/tests/ui/fmt/fmt_debug/invalid.rs b/tests/ui/fmt/fmt_debug/invalid.rs index 09cb46f1ea6e..f2652fe277d1 100644 --- a/tests/ui/fmt/fmt_debug/invalid.rs +++ b/tests/ui/fmt/fmt_debug/invalid.rs @@ -2,3 +2,5 @@ //@ failure-status: 1 fn main() { } + +//~? ERROR incorrect value `invalid-value` for unstable option `fmt-debug` diff --git a/tests/ui/infinite/infinite-struct.rs b/tests/ui/infinite/infinite-struct.rs index 62f9702b9f41..fd47a4ec9cc6 100644 --- a/tests/ui/infinite/infinite-struct.rs +++ b/tests/ui/infinite/infinite-struct.rs @@ -15,3 +15,5 @@ struct Foo { //~ ERROR has infinite size struct Bar([T; 1]); fn main() {} + +//~? ERROR reached the recursion limit finding the struct tail for `Take` diff --git a/tests/ui/instrument-coverage/bad-value.rs b/tests/ui/instrument-coverage/bad-value.rs index 344173852916..d44f982ea46f 100644 --- a/tests/ui/instrument-coverage/bad-value.rs +++ b/tests/ui/instrument-coverage/bad-value.rs @@ -3,3 +3,6 @@ //@ [bad] compile-flags: -Cinstrument-coverage=bad-value fn main() {} + +//[blank]~? ERROR incorrect value `` for codegen option `instrument-coverage` +//[bad]~? ERROR incorrect value `bad-value` for codegen option `instrument-coverage` diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs index 7615a0fb2751..c3eae9625da9 100644 --- a/tests/ui/instrument-coverage/coverage-options.rs +++ b/tests/ui/instrument-coverage/coverage-options.rs @@ -17,3 +17,5 @@ //@ [bad] compile-flags: -Zcoverage-options=bad fn main() {} + +//[bad]~? ERROR incorrect value `bad` for unstable option `coverage-options` diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs index b4025080034a..2a39d579c51f 100644 --- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs +++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs @@ -15,3 +15,7 @@ #[lang = "sized"] trait Sized {} + +//[BADFLAGS]~? ERROR incorrect value `leaf` for unstable option `branch-protection` +//[BADFLAGSPC]~? ERROR incorrect value `pc` for unstable option `branch-protection` +//[BADTARGET]~? ERROR `-Zbranch-protection` is only supported on aarch64 diff --git a/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs b/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs index ddb46e597111..832821c9c883 100644 --- a/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs +++ b/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs @@ -2,3 +2,5 @@ //@ compile-flags: -Cpasses=unknown-pass fn main() {} + +//~? ERROR failed to run LLVM passes: unknown pass name 'unknown-pass' diff --git a/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.rs b/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.rs index b1ac4a4ae216..0e80b1dd178b 100644 --- a/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.rs +++ b/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.rs @@ -1,2 +1,5 @@ // issue: 113981 + pub fn main() {} + +//~? ERROR invalid character '$' in crate name: `need_crate_arg_ignore_tidy$x` diff --git a/tests/ui/invalid-compile-flags/print.rs b/tests/ui/invalid-compile-flags/print.rs index 0d0a9d22750d..4665bb2c5368 100644 --- a/tests/ui/invalid-compile-flags/print.rs +++ b/tests/ui/invalid-compile-flags/print.rs @@ -1 +1,3 @@ //@ compile-flags: --print yyyy + +//~? ERROR unknown print request: `yyyy` diff --git a/tests/ui/invalid-module-declaration/invalid-module-declaration.rs b/tests/ui/invalid-module-declaration/invalid-module-declaration.rs index 254d810d79db..1c6c282f4b7e 100644 --- a/tests/ui/invalid-module-declaration/invalid-module-declaration.rs +++ b/tests/ui/invalid-module-declaration/invalid-module-declaration.rs @@ -3,3 +3,5 @@ mod auxiliary { } fn main() {} + +//~? ERROR file not found for module `baz` diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs index 0f982df61e8e..90ed5f3f0efd 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.rs +++ b/tests/ui/lang-items/lang-item-generic-requirements.rs @@ -59,3 +59,5 @@ fn ice() { // use `start` fn main() {} + +//~? ERROR requires `copy` lang_item diff --git a/tests/ui/link-native-libs/modifiers-bad.rs b/tests/ui/link-native-libs/modifiers-bad.rs index 185201e0d842..4d6c8a278d4c 100644 --- a/tests/ui/link-native-libs/modifiers-bad.rs +++ b/tests/ui/link-native-libs/modifiers-bad.rs @@ -9,3 +9,8 @@ // Tests various illegal values for the "modifier" part of an `-l` flag. fn main() {} + +//[blank]~? ERROR invalid linking modifier syntax, expected '+' or '-' prefix +//[no-prefix]~? ERROR invalid linking modifier syntax, expected '+' or '-' prefix +//[prefix-only]~? ERROR unknown linking modifier `` +//[unknown]~? ERROR unknown linking modifier `ferris` diff --git a/tests/ui/link-native-libs/modifiers-override-2.rs b/tests/ui/link-native-libs/modifiers-override-2.rs index a462a741ac61..d132f2419d81 100644 --- a/tests/ui/link-native-libs/modifiers-override-2.rs +++ b/tests/ui/link-native-libs/modifiers-override-2.rs @@ -1,3 +1,5 @@ //@ compile-flags:-lstatic:+whole-archive,-whole-archive=foo fn main() {} + +//~? ERROR multiple `whole-archive` modifiers in a single `-l` option diff --git a/tests/ui/link-native-libs/msvc-non-utf8-output.rs b/tests/ui/link-native-libs/msvc-non-utf8-output.rs index 03b1f6516ab9..5cc4cd9a3d6d 100644 --- a/tests/ui/link-native-libs/msvc-non-utf8-output.rs +++ b/tests/ui/link-native-libs/msvc-non-utf8-output.rs @@ -3,3 +3,5 @@ //@ only-msvc //@ normalize-stderr: "(?:.|\n)*(⦺ⅈ⽯⭏⽽◃⡽⚞)(?:.|\n)*" -> "$1" pub fn main() {} + +//~? ERROR linking with ` diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.rs b/tests/ui/linkage-attr/link-self-contained-consistency.rs index def63233e941..082274338916 100644 --- a/tests/ui/linkage-attr/link-self-contained-consistency.rs +++ b/tests/ui/linkage-attr/link-self-contained-consistency.rs @@ -8,3 +8,6 @@ // ignore-tidy-linelength fn main() {} + +//[one]~? ERROR some `-C link-self-contained` components were both enabled and disabled: linker +//[many]~? ERROR some `-C link-self-contained` components were both enabled and disabled: crto, linker diff --git a/tests/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs b/tests/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs index b43df6341121..23848056ee1a 100644 --- a/tests/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs +++ b/tests/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs @@ -22,3 +22,5 @@ fn main() { println!("{:p}", &dep1::collision); } } + +//~? ERROR symbol `collision` is already defined diff --git a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs index e69a45379352..92cb60bb16d4 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs @@ -19,3 +19,5 @@ extern "C" { pub fn lib_main() { unsafe { f(42); } } + +//~? ERROR Dlltool could not create import library with diff --git a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs index 057242246f0e..0c78d799bad2 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs @@ -10,3 +10,5 @@ extern "C" { pub fn lib_main() { unsafe { f(42); } } + +//~? ERROR Error calling dlltool 'does_not_exist.exe': program not found diff --git a/tests/ui/lint/expansion-time.rs b/tests/ui/lint/expansion-time.rs index d0f26a87385c..3cb4b91ff2b8 100644 --- a/tests/ui/lint/expansion-time.rs +++ b/tests/ui/lint/expansion-time.rs @@ -31,3 +31,5 @@ fn main() { // WARN see in the stderr file, the warning points to the included file. include!("expansion-time-include.rs"); } + +//~? WARN include macro expected single expression in source diff --git a/tests/ui/lint/lint-unexported-no-mangle.rs b/tests/ui/lint/lint-unexported-no-mangle.rs index 63eeb3374d22..65a7fd9d7696 100644 --- a/tests/ui/lint/lint-unexported-no-mangle.rs +++ b/tests/ui/lint/lint-unexported-no-mangle.rs @@ -27,3 +27,10 @@ fn main() { foo(); bar(); } + +//~? WARN lint `private_no_mangle_fns` has been removed +//~? WARN lint `private_no_mangle_statics` has been removed +//~? WARN lint `private_no_mangle_fns` has been removed +//~? WARN lint `private_no_mangle_statics` has been removed +//~? WARN lint `private_no_mangle_fns` has been removed +//~? WARN lint `private_no_mangle_statics` has been removed diff --git a/tests/ui/lto/lto-and-no-bitcode-in-rlib.rs b/tests/ui/lto/lto-and-no-bitcode-in-rlib.rs index f742cd78697f..2f0aeb0b7ba9 100644 --- a/tests/ui/lto/lto-and-no-bitcode-in-rlib.rs +++ b/tests/ui/lto/lto-and-no-bitcode-in-rlib.rs @@ -1,3 +1,5 @@ //@ compile-flags: -C lto -C embed-bitcode=no fn main() {} + +//~? ERROR options `-C embed-bitcode=no` and `-C lto` are incompatible diff --git a/tests/ui/macros/include-single-expr.rs b/tests/ui/macros/include-single-expr.rs index c501f5d97ca5..e3ab1257b42a 100644 --- a/tests/ui/macros/include-single-expr.rs +++ b/tests/ui/macros/include-single-expr.rs @@ -1,6 +1,6 @@ -//@ error-pattern include macro expected single expression - fn main() { include!("include-single-expr-helper.rs"); include!("include-single-expr-helper-1.rs"); } + +//~? ERROR include macro expected single expression diff --git a/tests/ui/mir-dataflow/inits-1.rs b/tests/ui/mir-dataflow/inits-1.rs index 8fb1d4bc736d..3331809f3594 100644 --- a/tests/ui/mir-dataflow/inits-1.rs +++ b/tests/ui/mir-dataflow/inits-1.rs @@ -51,3 +51,5 @@ fn main() { foo(true, &mut S(13), S(14), S(15)); foo(false, &mut S(13), S(14), S(15)); } + +//~? ERROR stop_after_dataflow ended compilation diff --git a/tests/ui/mir-dataflow/liveness-enum.rs b/tests/ui/mir-dataflow/liveness-enum.rs index 5eb04ae8c8d3..515f36698fb4 100644 --- a/tests/ui/mir-dataflow/liveness-enum.rs +++ b/tests/ui/mir-dataflow/liveness-enum.rs @@ -20,3 +20,5 @@ fn foo() -> Option { } fn main() {} + +//~? ERROR stop_after_dataflow ended compilation diff --git a/tests/ui/mir-dataflow/liveness-projection.rs b/tests/ui/mir-dataflow/liveness-projection.rs index 486f31b635dc..edea6ee60f64 100644 --- a/tests/ui/mir-dataflow/liveness-projection.rs +++ b/tests/ui/mir-dataflow/liveness-projection.rs @@ -30,3 +30,5 @@ fn foo() { } fn main() {} + +//~? ERROR stop_after_dataflow ended compilation diff --git a/tests/ui/mir-dataflow/liveness-ptr.rs b/tests/ui/mir-dataflow/liveness-ptr.rs index 786da523a339..704949aa9c89 100644 --- a/tests/ui/mir-dataflow/liveness-ptr.rs +++ b/tests/ui/mir-dataflow/liveness-ptr.rs @@ -26,3 +26,5 @@ fn foo() -> i32 { } fn main() {} + +//~? ERROR stop_after_dataflow ended compilation diff --git a/tests/ui/mir-dataflow/uninits-1.rs b/tests/ui/mir-dataflow/uninits-1.rs index c2b4284a7b4f..c689512833d8 100644 --- a/tests/ui/mir-dataflow/uninits-1.rs +++ b/tests/ui/mir-dataflow/uninits-1.rs @@ -49,3 +49,5 @@ fn main() { foo(true, &mut S(13), S(14), S(15)); foo(false, &mut S(13), S(14), S(15)); } + +//~? ERROR stop_after_dataflow ended compilation diff --git a/tests/ui/mir-dataflow/uninits-2.rs b/tests/ui/mir-dataflow/uninits-2.rs index c584ee74afb4..04daf78e56f7 100644 --- a/tests/ui/mir-dataflow/uninits-2.rs +++ b/tests/ui/mir-dataflow/uninits-2.rs @@ -22,3 +22,5 @@ fn main() { foo(&mut S(13)); foo(&mut S(13)); } + +//~? ERROR stop_after_dataflow ended compilation diff --git a/tests/ui/mir/enable_passes_validation.rs b/tests/ui/mir/enable_passes_validation.rs index 957e7d4d96df..405ada77183b 100644 --- a/tests/ui/mir/enable_passes_validation.rs +++ b/tests/ui/mir/enable_passes_validation.rs @@ -19,3 +19,6 @@ //@[mixed] error-pattern: warning: MIR pass `ThisPassDoesNotExist` is unknown and will be ignored fn main() {} + +//[empty]~? ERROR incorrect value `` for unstable option `mir-enable-passes` +//[unprefixed]~? ERROR incorrect value `CheckAlignment` for unstable option `mir-enable-passes` diff --git a/tests/ui/missing/missing-allocator.rs b/tests/ui/missing/missing-allocator.rs index 3a65e657d0bc..60aa9fcc898b 100644 --- a/tests/ui/missing/missing-allocator.rs +++ b/tests/ui/missing/missing-allocator.rs @@ -16,3 +16,5 @@ fn oom(_: core::alloc::Layout) -> ! { } extern crate alloc; + +//~? ERROR no global memory allocator found but one is required diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.rs b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.rs index 4ff975af67d7..b1ac0756688f 100644 --- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.rs +++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.rs @@ -1,2 +1,4 @@ mod foo; fn main() {} + +//~? ERROR file not found for module `missing` diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.rs b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.rs index 9ebb4f1bdbdb..987fe1166d74 100644 --- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.rs +++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.rs @@ -1,2 +1,4 @@ mod foo_inline; fn main() {} + +//~? ERROR file not found for module `missing` diff --git a/tests/ui/panic-handler/panic-handler-wrong-location.rs b/tests/ui/panic-handler/panic-handler-wrong-location.rs index 49685ee45926..c91580ae0c4c 100644 --- a/tests/ui/panic-handler/panic-handler-wrong-location.rs +++ b/tests/ui/panic-handler/panic-handler-wrong-location.rs @@ -6,3 +6,5 @@ #[panic_handler] //~ ERROR `panic_impl` lang item must be applied to a function #[no_mangle] static X: u32 = 42; + +//~? ERROR `#[panic_handler]` function required, but not found diff --git a/tests/ui/parser/issues/issue-94340.rs b/tests/ui/parser/issues/issue-94340.rs index d0fb84a689a3..4f3dbc6acdd7 100644 --- a/tests/ui/parser/issues/issue-94340.rs +++ b/tests/ui/parser/issues/issue-94340.rs @@ -6,3 +6,6 @@ include!("auxiliary/issue-94340-inc.rs"); fn main() {} + +//~? ERROR an inner attribute is not permitted in this context +//~? ERROR an inner attribute is not permitted in this context diff --git a/tests/ui/parser/unclosed-delimiter-in-dep.rs b/tests/ui/parser/unclosed-delimiter-in-dep.rs index 4de83ee640a7..40f517f317ef 100644 --- a/tests/ui/parser/unclosed-delimiter-in-dep.rs +++ b/tests/ui/parser/unclosed-delimiter-in-dep.rs @@ -3,3 +3,5 @@ mod unclosed_delim_mod; fn main() { let _: usize = unclosed_delim_mod::new(); } + +//~? ERROR mismatched closing delimiter: `}` diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-flags.rs b/tests/ui/patchable-function-entry/patchable-function-entry-flags.rs index cb5bc62b6b34..2d5a0b0a7715 100644 --- a/tests/ui/patchable-function-entry/patchable-function-entry-flags.rs +++ b/tests/ui/patchable-function-entry/patchable-function-entry-flags.rs @@ -1,2 +1,5 @@ //@ compile-flags: -Z patchable-function-entry=1,2 + fn main() {} + +//~? ERROR incorrect value `1,2` for unstable option `patchable-function-entry` diff --git a/tests/ui/print-request/invalid-target.rs b/tests/ui/print-request/invalid-target.rs index 52f09ea73d73..573d5493b25c 100644 --- a/tests/ui/print-request/invalid-target.rs +++ b/tests/ui/print-request/invalid-target.rs @@ -2,3 +2,5 @@ //@ needs-llvm-components: x86 fn main() {} + +//~? ERROR only Apple targets currently support deployment version info diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.rs b/tests/ui/proc-macro/inner-attr-non-inline-mod.rs index d4336a7f3e1e..2dcdbf3c4022 100644 --- a/tests/ui/proc-macro/inner-attr-non-inline-mod.rs +++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.rs @@ -1,6 +1,4 @@ //@ compile-flags: -Z span-debug -//@ error-pattern:custom inner attributes are unstable -//@ error-pattern:inner macro attributes are unstable //@ proc-macro: test-macros.rs #![no_std] // Don't load unnecessary hygiene information from std @@ -15,3 +13,6 @@ mod module_with_attrs; //~| ERROR custom inner attributes are unstable fn main() {} + +//~? ERROR custom inner attributes are unstable +//~? ERROR inner macro attributes are unstable diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr b/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr index 025eec248188..c0a9385f4c68 100644 --- a/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr +++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr @@ -19,7 +19,7 @@ LL | #![print_attr] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: non-inline modules in proc macro input are unstable - --> $DIR/inner-attr-non-inline-mod.rs:13:1 + --> $DIR/inner-attr-non-inline-mod.rs:11:1 | LL | mod module_with_attrs; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | mod module_with_attrs; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: custom inner attributes are unstable - --> $DIR/inner-attr-non-inline-mod.rs:13:1 + --> $DIR/inner-attr-non-inline-mod.rs:11:1 | LL | mod module_with_attrs; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout b/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout index 450542f68c65..219794a8eb8c 100644 --- a/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout +++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout @@ -4,35 +4,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "deny", - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "unused_attributes", - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, ], - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, ], - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Ident { ident: "mod", - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Ident { ident: "module_with_attrs", - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Group { delimiter: Brace, @@ -40,38 +40,38 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "rustfmt", - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Punct { ch: ':', spacing: Joint, - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, Ident { ident: "skip", - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, ], - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, ], - span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:11:1: 11:23 (#0), }, ] diff --git a/tests/ui/proc-macro/pretty-print-hack-show.rs b/tests/ui/proc-macro/pretty-print-hack-show.rs index de6453c6a821..70f0d5f6ea97 100644 --- a/tests/ui/proc-macro/pretty-print-hack-show.rs +++ b/tests/ui/proc-macro/pretty-print-hack-show.rs @@ -18,3 +18,5 @@ mod second { } fn main() {} + +//~? ERROR using an old version of `rental` diff --git a/tests/ui/resolve/parse-error-resolve.rs b/tests/ui/resolve/parse-error-resolve.rs index 1e0772648afe..cb15ec764036 100644 --- a/tests/ui/resolve/parse-error-resolve.rs +++ b/tests/ui/resolve/parse-error-resolve.rs @@ -5,3 +5,5 @@ fn main() { let _ = "" + 1; //~ ERROR E0369 parse_error::Canonical.foo(); // ok, `parse_error.rs` had parse errors } + +//~? ERROR expected one of `+`, `,`, `::`, `=`, or `>`, found `From` diff --git a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs index ef970ebd14bc..2b21d3987b9c 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs @@ -30,3 +30,5 @@ fn main() { (CONSTANT.file(), CONSTANT.line(), CONSTANT.column()), ); } + +//~? WARN skipping const checks diff --git a/tests/ui/rmeta/no_optitimized_mir.rs b/tests/ui/rmeta/no_optitimized_mir.rs index 7d2e1b87215f..708cdfc803fa 100644 --- a/tests/ui/rmeta/no_optitimized_mir.rs +++ b/tests/ui/rmeta/no_optitimized_mir.rs @@ -9,3 +9,5 @@ extern crate rmeta_meta; fn main() { rmeta_meta::missing_optimized_mir(); } + +//~? ERROR missing optimized MIR for an item in the crate `rmeta_meta` diff --git a/tests/ui/runtime/on-broken-pipe/default.rs b/tests/ui/runtime/on-broken-pipe/default.rs index c10d1cfacc0c..61b7810e2a18 100644 --- a/tests/ui/runtime/on-broken-pipe/default.rs +++ b/tests/ui/runtime/on-broken-pipe/default.rs @@ -2,3 +2,5 @@ //@ check-fail fn main() {} + +//~? ERROR incorrect value `default` for unstable option `on-broken-pipe` diff --git a/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs b/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs index 2273291bfa77..bb49533c0231 100644 --- a/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs +++ b/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs @@ -2,3 +2,5 @@ //@ check-fail fn main() {} + +//~? ERROR unstable option `on-broken-pipe` requires either `kill`, `error`, or `inherit` diff --git a/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs index 14d0ac56b5a3..c4a07932bc20 100644 --- a/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs +++ b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs @@ -2,3 +2,5 @@ //@ check-fail fn main() {} + +//~? ERROR incorrect value `wrong` for unstable option `on-broken-pipe` diff --git a/tests/ui/rustc-env/min-stack-banana.rs b/tests/ui/rustc-env/min-stack-banana.rs index abbb68437100..dfde277714b9 100644 --- a/tests/ui/rustc-env/min-stack-banana.rs +++ b/tests/ui/rustc-env/min-stack-banana.rs @@ -1,2 +1,5 @@ //@ rustc-env:RUST_MIN_STACK=banana + fn main() {} + +//~? ERROR `RUST_MIN_STACK` should be a number of bytes, but was "banana" diff --git a/tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.rs b/tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.rs index 10c5bf6ea5e1..36f6e3bc95e1 100644 --- a/tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.rs +++ b/tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.rs @@ -6,3 +6,5 @@ #![feature(no_core)] #![no_core] #![no_main] + +//~? ERROR `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi` diff --git a/tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.rs b/tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.rs index 8ba13bd3639b..83277da528c9 100644 --- a/tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.rs +++ b/tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.rs @@ -7,3 +7,5 @@ #![feature(no_core)] #![no_core] #![no_main] + +//~? ERROR `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi` diff --git a/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.rs b/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.rs index c628709d7a1c..db8d11616440 100644 --- a/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.rs +++ b/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.rs @@ -10,3 +10,6 @@ #![feature(no_core)] #![no_core] #![no_main] + +//~? ERROR cfi sanitizer is not supported for this target +//~? ERROR `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi` diff --git a/tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.rs b/tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.rs index a7ecefbf7efb..b9d5b9623d5f 100644 --- a/tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.rs +++ b/tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.rs @@ -7,3 +7,5 @@ #![feature(no_core)] #![no_core] #![no_main] + +//~? ERROR `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi` diff --git a/tests/ui/sanitizer/cfi/requires-lto.rs b/tests/ui/sanitizer/cfi/requires-lto.rs index 5a34f696e054..db83f5f6bf02 100644 --- a/tests/ui/sanitizer/cfi/requires-lto.rs +++ b/tests/ui/sanitizer/cfi/requires-lto.rs @@ -6,3 +6,5 @@ #![feature(no_core)] #![no_core] #![no_main] + +//~? ERROR `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto` diff --git a/tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.rs b/tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.rs index 954e4ec3b853..4ef5b6756a49 100644 --- a/tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.rs +++ b/tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.rs @@ -6,3 +6,5 @@ #![feature(no_core)] #![no_core] #![no_main] + +//~? ERROR `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1` diff --git a/tests/ui/sanitizer/crt-static.rs b/tests/ui/sanitizer/crt-static.rs index c24faeca3dc8..b8bdf28351c3 100644 --- a/tests/ui/sanitizer/crt-static.rs +++ b/tests/ui/sanitizer/crt-static.rs @@ -4,3 +4,5 @@ #![feature(no_core)] #![no_core] #![no_main] + +//~? ERROR sanitizer is incompatible with statically linked libc diff --git a/tests/ui/sanitizer/split-lto-unit-requires-lto.rs b/tests/ui/sanitizer/split-lto-unit-requires-lto.rs index 35e610f03076..1d08ca7423fd 100644 --- a/tests/ui/sanitizer/split-lto-unit-requires-lto.rs +++ b/tests/ui/sanitizer/split-lto-unit-requires-lto.rs @@ -6,3 +6,5 @@ #![feature(no_core)] #![no_core] #![no_main] + +//~? ERROR `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto` diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.rs b/tests/ui/stack-protector/warn-stack-protector-unsupported.rs index 9205d4052ad4..dc61e35a089a 100644 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.rs +++ b/tests/ui/stack-protector/warn-stack-protector-unsupported.rs @@ -17,3 +17,7 @@ trait Sized {} trait Copy {} pub fn main(){} + +//[all]~? WARN `-Z stack-protector=all` is not supported for target nvptx64-nvidia-cuda and will be ignored +//[strong]~? WARN `-Z stack-protector=strong` is not supported for target nvptx64-nvidia-cuda and will be ignored +//[basic]~? WARN `-Z stack-protector=basic` is not supported for target nvptx64-nvidia-cuda and will be ignored diff --git a/tests/ui/symbol-mangling-version/bad-value.rs b/tests/ui/symbol-mangling-version/bad-value.rs index f6fa5c85f338..b0875f3a23cd 100644 --- a/tests/ui/symbol-mangling-version/bad-value.rs +++ b/tests/ui/symbol-mangling-version/bad-value.rs @@ -4,3 +4,7 @@ //@ [bad] compile-flags: -Csymbol-mangling-version=bad-value fn main() {} + +//[no-value]~? ERROR codegen option `symbol-mangling-version` requires one of +//[blank]~? ERROR incorrect value `` for codegen option `symbol-mangling-version` +//[bad]~? ERROR incorrect value `bad-value` for codegen option `symbol-mangling-version` diff --git a/tests/ui/symbol-mangling-version/unstable.rs b/tests/ui/symbol-mangling-version/unstable.rs index d5af8542996b..d79320ccccd5 100644 --- a/tests/ui/symbol-mangling-version/unstable.rs +++ b/tests/ui/symbol-mangling-version/unstable.rs @@ -7,3 +7,6 @@ //@ [hashed-ok] compile-flags: -Zunstable-options -Csymbol-mangling-version=hashed fn main() {} + +//[legacy]~? ERROR `-C symbol-mangling-version=legacy` requires `-Z unstable-options` +//[hashed]~? ERROR `-C symbol-mangling-version=hashed` requires `-Z unstable-options` diff --git a/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs b/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs index e34faf5a983c..7368ef120fa6 100644 --- a/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs @@ -7,3 +7,5 @@ #[lang = "sized"] pub trait Sized {} + +//~? WARN unstable feature specified for `-Ctarget-feature`: `x87` diff --git a/tests/ui/target-feature/missing-plusminus-2.rs b/tests/ui/target-feature/missing-plusminus-2.rs index 19f4bc6e7244..06291ab23ad5 100644 --- a/tests/ui/target-feature/missing-plusminus-2.rs +++ b/tests/ui/target-feature/missing-plusminus-2.rs @@ -4,3 +4,5 @@ #![feature(no_core)] #![no_core] + +//~? WARN unknown feature specified for `-Ctarget-feature`: `rdrand` diff --git a/tests/ui/target-feature/missing-plusminus.rs b/tests/ui/target-feature/missing-plusminus.rs index eb3e93c2ef7f..e8356e0fa355 100644 --- a/tests/ui/target-feature/missing-plusminus.rs +++ b/tests/ui/target-feature/missing-plusminus.rs @@ -1,2 +1,4 @@ //@ compile-flags: -Ctarget-feature=banana --crate-type=rlib //@ build-pass + +//~? WARN unknown feature specified for `-Ctarget-feature`: `banana` diff --git a/tests/ui/target-feature/similar-feature-suggestion.rs b/tests/ui/target-feature/similar-feature-suggestion.rs index 242d472b794e..b82d7e408c7c 100644 --- a/tests/ui/target-feature/similar-feature-suggestion.rs +++ b/tests/ui/target-feature/similar-feature-suggestion.rs @@ -4,3 +4,5 @@ #![feature(no_core)] #![no_core] + +//~? WARN unknown and unstable feature specified for `-Ctarget-feature`: `rdrnd` diff --git a/tests/ui/target-feature/tied-features-cli.rs b/tests/ui/target-feature/tied-features-cli.rs index 17c13826ce9e..ce1dc3224a19 100644 --- a/tests/ui/target-feature/tied-features-cli.rs +++ b/tests/ui/target-feature/tied-features-cli.rs @@ -18,3 +18,7 @@ trait Sized {} fn main() {} + +//[one]~? ERROR the target features paca, pacg must all be either enabled or disabled together +//[two]~? ERROR the target features paca, pacg must all be either enabled or disabled together +//[three]~? ERROR the target features paca, pacg must all be either enabled or disabled together diff --git a/tests/ui/target-feature/tied-features-no-implication-1.rs b/tests/ui/target-feature/tied-features-no-implication-1.rs index 0473ca319b8f..0a98a7eeccf4 100644 --- a/tests/ui/target-feature/tied-features-no-implication-1.rs +++ b/tests/ui/target-feature/tied-features-no-implication-1.rs @@ -18,3 +18,5 @@ trait Sized {} #[cfg(target_feature = "pacg")] pub unsafe fn foo() { } + +//~? ERROR the target features paca, pacg must all be either enabled or disabled together diff --git a/tests/ui/target-feature/unstable-feature.rs b/tests/ui/target-feature/unstable-feature.rs index c74c5ad5d779..f62c4dd938a0 100644 --- a/tests/ui/target-feature/unstable-feature.rs +++ b/tests/ui/target-feature/unstable-feature.rs @@ -4,3 +4,5 @@ #![feature(no_core)] #![no_core] + +//~? WARN unstable feature specified for `-Ctarget-feature`: `vaes` diff --git a/tests/ui/target_modifiers/incompatible_regparm.rs b/tests/ui/target_modifiers/incompatible_regparm.rs index befe573b276c..395c26fc2c02 100644 --- a/tests/ui/target_modifiers/incompatible_regparm.rs +++ b/tests/ui/target_modifiers/incompatible_regparm.rs @@ -14,3 +14,5 @@ #![no_core] extern crate wrong_regparm; + +//[allow_no_value]~? ERROR codegen option `unsafe-allow-abi-mismatch` requires a comma-separated list of strings diff --git a/tests/ui/tool-attributes/duplicate-diagnostic.rs b/tests/ui/tool-attributes/duplicate-diagnostic.rs index 5061bcb9e444..c36179611afc 100644 --- a/tests/ui/tool-attributes/duplicate-diagnostic.rs +++ b/tests/ui/tool-attributes/duplicate-diagnostic.rs @@ -1,13 +1,14 @@ //@ aux-build: p1.rs //@ aux-build: p2.rs -//@ error-pattern: duplicate diagnostic item in crate `p2` -//@ error-pattern: note: the diagnostic item is first defined in crate `p1` - #![feature(rustc_attrs)] extern crate p1; extern crate p2; #[rustc_diagnostic_item = "Foo"] pub struct Foo {} //~ ERROR duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo` + //~^ NOTE the diagnostic item is first defined in crate `p2` fn main() {} + +//~? ERROR duplicate diagnostic item in crate `p2` +//~? NOTE the diagnostic item is first defined in crate `p1` diff --git a/tests/ui/tool-attributes/duplicate-diagnostic.stderr b/tests/ui/tool-attributes/duplicate-diagnostic.stderr index 3cd438004c8e..16d78d03ae95 100644 --- a/tests/ui/tool-attributes/duplicate-diagnostic.stderr +++ b/tests/ui/tool-attributes/duplicate-diagnostic.stderr @@ -3,7 +3,7 @@ error: duplicate diagnostic item in crate `p2`: `Foo` = note: the diagnostic item is first defined in crate `p1` error: duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo` - --> $DIR/duplicate-diagnostic.rs:12:1 + --> $DIR/duplicate-diagnostic.rs:9:1 | LL | pub struct Foo {} | ^^^^^^^^^^^^^^ diff --git a/tests/ui/type/pattern_types/literals.rs b/tests/ui/type/pattern_types/literals.rs index 97a918645f3e..7fd630dab3ad 100644 --- a/tests/ui/type/pattern_types/literals.rs +++ b/tests/ui/type/pattern_types/literals.rs @@ -134,3 +134,6 @@ fn lit_at_wraparound_range_start() -> pattern_type!(u32 is 2..1) { } fn main() {} + +//~? ERROR pattern type ranges cannot wrap: 1..=0 +//~? ERROR pattern type ranges cannot wrap: 2..=0 diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs index dda7eb0ae4ec..21c1454d6cd5 100644 --- a/tests/ui/type/pattern_types/range_patterns.rs +++ b/tests/ui/type/pattern_types/range_patterns.rs @@ -40,3 +40,7 @@ type SignedWrap = pattern_type!(i8 is 120..=-120); //~ ERROR unknown layout fn main() { let x: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(42_u32) }; } + +//~? ERROR pattern type ranges cannot wrap: 1..=0 +//~? ERROR pattern type ranges cannot wrap: 5..=1 +//~? ERROR pattern type ranges cannot wrap: 120..=-120 diff --git a/tests/ui/unpretty/avoid-crash.rs b/tests/ui/unpretty/avoid-crash.rs index 7fcabfe6a8d4..64fa778bed47 100644 --- a/tests/ui/unpretty/avoid-crash.rs +++ b/tests/ui/unpretty/avoid-crash.rs @@ -2,3 +2,5 @@ //@ compile-flags: -o. -Zunpretty=ast-tree fn main() {} + +//~? ERROR failed to write `.` due to error From 813783e7115c58b5e70034f31be02201dac55407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 25 Mar 2025 13:43:25 +0100 Subject: [PATCH 323/546] Add diff of bootstrap steps --- src/build_helper/src/metrics.rs | 34 ++++++---- src/ci/citool/Cargo.lock | 7 ++ src/ci/citool/Cargo.toml | 1 + src/ci/citool/src/analysis.rs | 114 ++++++++++++++++++++++++++++++-- src/ci/citool/src/main.rs | 44 ++++++------ 5 files changed, 161 insertions(+), 39 deletions(-) diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index 4ab61245c16b..fdff9cd18cea 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -109,6 +109,8 @@ pub struct BuildStep { pub r#type: String, pub children: Vec, pub duration: Duration, + // Full name of the step, including all parent names + pub full_name: String, } impl BuildStep { @@ -116,7 +118,7 @@ impl BuildStep { /// The most important thing is that the build step aggregates the /// durations of all children, so that it can be easily accessed. pub fn from_invocation(invocation: &JsonInvocation) -> Self { - fn parse(node: &JsonNode) -> Option { + fn parse(node: &JsonNode, parent_name: &str) -> Option { match node { JsonNode::RustbuildStep { type_: kind, @@ -124,11 +126,14 @@ impl BuildStep { duration_excluding_children_sec, .. } => { - let children: Vec<_> = children.into_iter().filter_map(parse).collect(); + let full_name = format!("{parent_name}-{kind}"); + let children: Vec<_> = + children.into_iter().filter_map(|s| parse(s, &full_name)).collect(); let children_duration = children.iter().map(|c| c.duration).sum::(); Some(BuildStep { r#type: kind.to_string(), children, + full_name, duration: children_duration + Duration::from_secs_f64(*duration_excluding_children_sec), }) @@ -138,8 +143,13 @@ impl BuildStep { } let duration = Duration::from_secs_f64(invocation.duration_including_children_sec); - let children: Vec<_> = invocation.children.iter().filter_map(parse).collect(); - Self { r#type: "total".to_string(), children, duration } + + // The root "total" step is kind of a virtual step that encompasses all other steps, + // but it is not a real parent of the other steps. + // We thus start the parent name hierarchy here and use an empty string + // as the parent name of the top-level steps. + let children: Vec<_> = invocation.children.iter().filter_map(|s| parse(s, "")).collect(); + Self { r#type: "total".to_string(), children, duration, full_name: "total".to_string() } } pub fn find_all_by_type(&self, r#type: &str) -> Vec<&Self> { @@ -159,7 +169,7 @@ impl BuildStep { /// Returns a Vec with all substeps, ordered by their hierarchical order. /// The first element of the tuple is the depth of a given step. - fn linearize_steps(&self) -> Vec<(u32, &BuildStep)> { + pub fn linearize_steps(&self) -> Vec<(u32, &BuildStep)> { let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { @@ -180,14 +190,14 @@ pub fn format_build_steps(root: &BuildStep) -> String { let mut output = String::new(); for (level, step) in root.linearize_steps() { - let label = format!( - "{}{}", - ".".repeat(level as usize), - // Bootstrap steps can be generic and thus contain angle brackets (<...>). - // However, Markdown interprets these as HTML, so we need to escap ethem. - step.r#type.replace('<', "<").replace('>', ">") - ); + let label = format!("{}{}", ".".repeat(level as usize), escape_step_name(step)); writeln!(output, "{label:.<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap(); } output } + +/// Bootstrap steps can be generic and thus contain angle brackets (<...>). +/// However, Markdown interprets these as HTML, so we need to escap ethem. +pub fn escape_step_name(step: &BuildStep) -> String { + step.r#type.replace('<', "<").replace('>', ">") +} diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index c061ec6ebdce..800eaae07665 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "build_helper", "clap", "csv", + "diff", "glob-match", "insta", "serde", @@ -241,6 +242,12 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "displaydoc" version = "0.2.5" diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index dde09224afe8..f18436a12635 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" anyhow = "1" clap = { version = "4.5", features = ["derive"] } csv = "1" +diff = "0.1" glob-match = "0.2" serde = { version = "1", features = ["derive"] } serde_yaml = "0.9" diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 2088ce296209..ccc030511cbb 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -1,33 +1,134 @@ use std::collections::{BTreeMap, HashMap, HashSet}; +use std::fmt::Debug; use build_helper::metrics::{ - BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps, + BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name, + format_build_steps, }; use crate::metrics; use crate::metrics::{JobMetrics, JobName, get_test_suites}; use crate::utils::{output_details, pluralize}; -pub fn output_bootstrap_stats(metrics: &JsonRoot) { +/// Outputs durations of individual bootstrap steps from the gathered bootstrap invocations, +/// and also a table with summarized information about executed tests. +pub fn output_bootstrap_stats(metrics: &JsonRoot, parent_metrics: Option<&JsonRoot>) { if !metrics.invocations.is_empty() { println!("# Bootstrap steps"); - record_bootstrap_step_durations(&metrics); + record_bootstrap_step_durations(&metrics, parent_metrics); record_test_suites(&metrics); } } -fn record_bootstrap_step_durations(metrics: &JsonRoot) { +fn record_bootstrap_step_durations(metrics: &JsonRoot, parent_metrics: Option<&JsonRoot>) { + let parent_steps: HashMap = parent_metrics + .map(|metrics| { + metrics + .invocations + .iter() + .map(|invocation| { + (invocation.cmdline.clone(), BuildStep::from_invocation(invocation)) + }) + .collect() + }) + .unwrap_or_default(); + for invocation in &metrics.invocations { let step = BuildStep::from_invocation(invocation); let table = format_build_steps(&step); eprintln!("Step `{}`\n{table}\n", invocation.cmdline); - output_details(&invocation.cmdline, || { + output_details(&format!("{} (steps)", invocation.cmdline), || { println!("

{table}
"); }); + + // If there was a parent bootstrap invocation with the same cmdline, diff it + if let Some(parent_step) = parent_steps.get(&invocation.cmdline) { + let table = format_build_step_diffs(&step, parent_step); + + let duration_before = parent_step.duration.as_secs(); + let duration_after = step.duration.as_secs(); + output_details( + &format!("{} (diff) ({duration_before}s -> {duration_after}s)", invocation.cmdline), + || { + println!("{table}"); + }, + ); + } } eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len()); } +/// Creates a table that displays a diff between the durations of steps between +/// two bootstrap invocations. +/// It also shows steps that were missing before/after. +fn format_build_step_diffs(current: &BuildStep, parent: &BuildStep) -> String { + use std::fmt::Write; + + // Helper struct that compares steps by their full name + struct StepByName<'a>((u32, &'a BuildStep)); + + impl<'a> PartialEq for StepByName<'a> { + fn eq(&self, other: &Self) -> bool { + self.0.1.full_name.eq(&other.0.1.full_name) + } + } + + fn get_steps(step: &BuildStep) -> Vec { + step.linearize_steps().into_iter().map(|v| StepByName(v)).collect() + } + + let steps_before = get_steps(parent); + let steps_after = get_steps(current); + + let mut table = "| Step | Before | After | Change |\n".to_string(); + writeln!(table, "|:-----|-------:|------:|-------:|").unwrap(); + + // Try to match removed, added and same steps using a classic diff algorithm + for result in diff::slice(&steps_before, &steps_after) { + let (step, before, after, change) = match result { + // The step was found both before and after + diff::Result::Both(before, after) => { + let duration_before = before.0.1.duration; + let duration_after = after.0.1.duration; + let pct_change = duration_after.as_secs_f64() / duration_before.as_secs_f64(); + let pct_change = pct_change * 100.0; + // Normalize around 100, to get + for regression and - for improvements + let pct_change = pct_change - 100.0; + ( + before, + format!("{:.2}s", duration_before.as_secs_f64()), + format!("{:.2}s", duration_after.as_secs_f64()), + format!("{pct_change:.1}%"), + ) + } + // The step was only found in the parent, so it was likely removed + diff::Result::Left(removed) => ( + removed, + format!("{:.2}s", removed.0.1.duration.as_secs_f64()), + "".to_string(), + "(removed)".to_string(), + ), + // The step was only found in the current commit, so it was likely added + diff::Result::Right(added) => ( + added, + "".to_string(), + format!("{:.2}s", added.0.1.duration.as_secs_f64()), + "(added)".to_string(), + ), + }; + + let prefix = ".".repeat(step.0.0 as usize); + writeln!( + table, + "| {prefix}{} | {before} | {after} | {change} |", + escape_step_name(step.0.1), + ) + .unwrap(); + } + + table +} + fn record_test_suites(metrics: &JsonRoot) { let suites = metrics::get_test_suites(&metrics); @@ -82,8 +183,7 @@ fn render_table(suites: BTreeMap) -> String { table } -/// Computes a post merge CI analysis report of test differences -/// between the `parent` and `current` commits. +/// Outputs a report of test differences between the `parent` and `current` commits. pub fn output_test_diffs(job_metrics: HashMap) { let aggregated_test_diffs = aggregate_test_diffs(&job_metrics); report_test_diffs(aggregated_test_diffs); diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 5a84ecb5e47e..5f5c50dc43a0 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -144,31 +144,35 @@ fn postprocess_metrics( job_name: Option, ) -> anyhow::Result<()> { let metrics = load_metrics(&metrics_path)?; - output_bootstrap_stats(&metrics); - let (Some(parent), Some(job_name)) = (parent, job_name) else { - return Ok(()); - }; + if let (Some(parent), Some(job_name)) = (parent, job_name) { + // This command is executed also on PR builds, which might not have parent metrics + // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics + // due to missing permissions. + // To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs, + // we simply print an error if the parent metrics were not found, but otherwise exit + // successfully. + match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") { + Ok(parent_metrics) => { + output_bootstrap_stats(&metrics, Some(&parent_metrics)); - // This command is executed also on PR builds, which might not have parent metrics - // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics - // due to missing permissions. - // To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs, - // we simply print an error if the parent metrics were not found, but otherwise exit - // successfully. - match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") { - Ok(parent_metrics) => { - let job_metrics = HashMap::from([( - job_name, - JobMetrics { parent: Some(parent_metrics), current: metrics }, - )]); - output_test_diffs(job_metrics); - } - Err(error) => { - eprintln!("Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}"); + let job_metrics = HashMap::from([( + job_name, + JobMetrics { parent: Some(parent_metrics), current: metrics }, + )]); + output_test_diffs(job_metrics); + return Ok(()); + } + Err(error) => { + eprintln!( + "Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}" + ); + } } } + output_bootstrap_stats(&metrics, None); + Ok(()) } From 2bf0c2df147e98ead4297ccc6a62b2f7f6c48c3e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Mar 2025 22:43:44 +0000 Subject: [PATCH 324/546] Make printing define_opaque less goofy --- .../rustc_ast_pretty/src/pprust/state/item.rs | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 6236f8ecfb52..8486e8093781 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -652,13 +652,7 @@ impl<'a> State<'a> { ) { let ast::Fn { defaultness, generics, sig, contract, body, define_opaque } = func; - if let Some(define_opaque) = define_opaque { - for (_, path) in define_opaque { - self.word("define opaques from "); - self.print_path(path, false, 0); - self.word(","); - } - } + self.print_define_opaques(define_opaque); if body.is_some() { self.head(""); @@ -678,6 +672,24 @@ impl<'a> State<'a> { } } + fn print_define_opaques( + &mut self, + define_opaque: Option<&[(ast::NodeId, ast::Path)]>, + ) { + if let Some(define_opaque) = define_opaque { + self.word("#[define_opaque("); + for (i, (_, path)) in define_opaque.iter().enumerate() { + if i != 0 { + self.word_space(","); + } + + self.print_path(path, false, 0); + } + self.word(")]"); + } + self.hardbreak_if_not_bol(); + } + fn print_contract(&mut self, contract: &ast::FnContract) { if let Some(pred) = &contract.requires { self.word("rustc_requires"); From f8df298d74ad4a385ca0b14e65ae154a9b8fa5c5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Mar 2025 23:19:18 +0000 Subject: [PATCH 325/546] Allow defining opaques in statics and consts --- compiler/rustc_ast/src/ast.rs | 2 + compiler/rustc_ast/src/mut_visit.rs | 54 +++++++++----- compiler/rustc_ast/src/visit.rs | 53 ++++++++++++-- compiler/rustc_ast_lowering/src/item.rs | 70 ++++++++++++++----- .../rustc_ast_pretty/src/pprust/state/item.rs | 65 +++++++++++------ .../rustc_builtin_macros/src/define_opaque.rs | 5 ++ compiler/rustc_builtin_macros/src/test.rs | 1 + compiler/rustc_expand/src/build.rs | 11 ++- compiler/rustc_parse/src/parser/item.rs | 13 +++- compiler/rustc_resolve/src/def_collector.rs | 8 ++- compiler/rustc_resolve/src/late.rs | 51 ++++++++++---- .../clippy/clippy_utils/src/ast_utils/mod.rs | 8 +++ tests/ui/impl-trait/define-via-const.rs | 12 ++++ .../ui/type-alias-impl-trait/issue-53092-2.rs | 5 +- .../issue-53092-2.stderr | 51 +++++++++----- .../type-alias-impl-trait-const.rs | 10 +-- .../type-alias-impl-trait-const.stderr | 57 --------------- 17 files changed, 314 insertions(+), 162 deletions(-) create mode 100644 tests/ui/impl-trait/define-via-const.rs delete mode 100644 tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5b7545b33966..fd27be213261 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3535,6 +3535,7 @@ pub struct StaticItem { pub safety: Safety, pub mutability: Mutability, pub expr: Option>, + pub define_opaque: Option>, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3543,6 +3544,7 @@ pub struct ConstItem { pub generics: Generics, pub ty: P, pub expr: Option>, + pub define_opaque: Option>, } // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 4edd08643000..b8d85958bfd7 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -987,10 +987,7 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { } vis.visit_span(span); - for (id, path) in define_opaque.iter_mut().flatten() { - vis.visit_id(id); - vis.visit_path(path) - } + walk_define_opaques(vis, define_opaque); } FnKind::Closure(binder, coroutine_kind, decl, body) => { vis.visit_closure_binder(binder); @@ -1258,12 +1255,19 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); + walk_define_opaques(vis, define_opaque); } ItemKind::Const(item) => { - visit_const_item(item, vis); + walk_const_item(vis, item); } ItemKind::Fn(func) => { vis.visit_fn(FnKind::Fn(FnCtxt::Free, ident, visibility, &mut *func), span, id); @@ -1382,7 +1386,7 @@ impl WalkItemKind for AssocItemKind { ) { match self { AssocItemKind::Const(item) => { - visit_const_item(item, visitor); + walk_const_item(visitor, item); } AssocItemKind::Fn(func) => { visitor.visit_fn( @@ -1442,14 +1446,13 @@ impl WalkItemKind for AssocItemKind { } } -fn visit_const_item( - ConstItem { defaultness, generics, ty, expr }: &mut ConstItem, - visitor: &mut T, -) { - visit_defaultness(visitor, defaultness); - visitor.visit_generics(generics); - visitor.visit_ty(ty); - visit_opt(expr, |expr| visitor.visit_expr(expr)); +fn walk_const_item(vis: &mut T, item: &mut ConstItem) { + let ConstItem { defaultness, generics, ty, expr, define_opaque } = item; + visit_defaultness(vis, defaultness); + vis.visit_generics(generics); + vis.visit_ty(ty); + visit_opt(expr, |expr| vis.visit_expr(expr)); + walk_define_opaques(vis, define_opaque); } fn walk_fn_header(vis: &mut T, header: &mut FnHeader) { @@ -1526,9 +1529,16 @@ impl WalkItemKind for ForeignItemKind { visitor: &mut impl MutVisitor, ) { match self { - ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability: _, + expr, + safety: _, + define_opaque, + }) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); + walk_define_opaques(visitor, define_opaque); } ForeignItemKind::Fn(func) => { visitor.visit_fn( @@ -1929,6 +1939,18 @@ fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { } } +fn walk_define_opaques( + vis: &mut T, + define_opaque: &mut Option>, +) { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + vis.visit_id(id); + vis.visit_path(path) + } + } +} + /// Some value for the AST node that is valid but possibly meaningless. Similar /// to `Default` but not intended for wide use. The value will never be used /// meaningfully, it exists just to support unwinding in `visit_clobber` in the diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ce8d6df75afb..8c0be6f48399 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -16,6 +16,7 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; use rustc_span::{Ident, Span}; +use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; @@ -371,14 +372,28 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_rename) => {} ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)), - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } - ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + ItemKind::Const(box ConstItem { + defaultness: _, + generics, + ty, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } ItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Free, ident, vis, &*func); @@ -729,9 +744,16 @@ impl WalkItemKind for ForeignItemKind { visitor: &mut V, ) -> V::Result { match self { - ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability: _, + expr, + safety: _, + define_opaque, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } ForeignItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Foreign, ident, vis, &*func); @@ -907,9 +929,7 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu try_visit!(visitor.visit_fn_decl(decl)); visit_opt!(visitor, visit_contract, contract); visit_opt!(visitor, visit_block, body); - for (id, path) in define_opaque.iter().flatten() { - try_visit!(visitor.visit_path(path, *id)) - } + try_visit!(walk_define_opaques(visitor, define_opaque)); } FnKind::Closure(binder, coroutine_kind, decl, body) => { try_visit!(visitor.visit_closure_binder(binder)); @@ -933,10 +953,17 @@ impl WalkItemKind for AssocItemKind { visitor: &mut V, ) -> V::Result { match self { - AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + AssocItemKind::Const(box ConstItem { + defaultness: _, + generics, + ty, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } AssocItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, vis, &*func); @@ -1337,3 +1364,15 @@ pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) - } V::Result::output() } + +fn walk_define_opaques<'a, V: Visitor<'a>>( + visitor: &mut V, + define_opaque: &'a Option>, +) -> V::Result { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + try_visit!(visitor.visit_path(path, *id)); + } + } + V::Result::output() +} diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 219bf62c916d..c3031a65dd21 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -188,14 +188,21 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs) } - ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => { + ItemKind::Static(box ast::StaticItem { + ty: t, + safety: _, + mutability: m, + expr: e, + define_opaque, + }) => { debug_assert_ne!(ident.name, kw::Empty); let ident = self.lower_ident(ident); let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); + self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(ident, ty, *m, body_id) } - ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + ItemKind::Const(box ast::ConstItem { generics, ty, expr, define_opaque, .. }) => { debug_assert_ne!(ident.name, kw::Empty); let ident = self.lower_ident(ident); let (generics, (ty, body_id)) = self.lower_generics( @@ -206,6 +213,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) }, ); + self.lower_define_opaque(hir_id, &define_opaque); hir::ItemKind::Const(ident, ty, generics, body_id) } ItemKind::Fn(box Fn { @@ -243,7 +251,7 @@ impl<'hir> LoweringContext<'_, 'hir> { header: this.lower_fn_header(*header, hir::Safety::Safe, attrs), span: this.lower_span(*fn_sig_span), }; - this.lower_define_opaque(hir_id, &define_opaque); + this.lower_define_opaque(hir_id, define_opaque); let ident = this.lower_ident(ident); hir::ItemKind::Fn { ident, @@ -662,7 +670,7 @@ impl<'hir> LoweringContext<'_, 'hir> { owner_id, ident: self.lower_ident(i.ident), kind: match &i.kind { - ForeignItemKind::Fn(box Fn { sig, generics, .. }) => { + ForeignItemKind::Fn(box Fn { sig, generics, define_opaque, .. }) => { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (decl, fn_args)) = @@ -683,17 +691,31 @@ impl<'hir> LoweringContext<'_, 'hir> { // Unmarked safety in unsafe block defaults to unsafe. let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign functions cannot define opaque types"); + } + hir::ForeignItemKind::Fn( hir::FnSig { header, decl, span: self.lower_span(sig.span) }, fn_args, generics, ) } - ForeignItemKind::Static(box StaticItem { ty, mutability, expr: _, safety }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability, + expr: _, + safety, + define_opaque, + }) => { let ty = self .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); + } + hir::ForeignItemKind::Static(ty, *mutability, safety) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, @@ -801,7 +823,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ConstItem { generics, ty, expr, define_opaque, .. }) => { let (generics, kind) = self.lower_generics( generics, i.id, @@ -814,6 +836,18 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::TraitItemKind::Const(ty, body) }, ); + + if define_opaque.is_some() { + if expr.is_some() { + self.lower_define_opaque(hir_id, &define_opaque); + } else { + self.dcx().span_err( + i.span, + "only trait consts with default bodies can define opaque types", + ); + } + } + (generics, kind, expr.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, define_opaque, .. }) => { @@ -951,18 +985,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let (generics, kind) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( - generics, - i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| { - let ty = - this.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = this.lower_const_body(i.span, expr.as_deref()); + AssocItemKind::Const(box ConstItem { generics, ty, expr, define_opaque, .. }) => self + .lower_generics( + generics, + i.id, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| { + let ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let body = this.lower_const_body(i.span, expr.as_deref()); + this.lower_define_opaque(hir_id, &define_opaque); - hir::ImplItemKind::Const(ty, body) - }, - ), + hir::ImplItemKind::Const(ty, body) + }, + ), AssocItemKind::Fn(box Fn { sig, generics, body, contract, define_opaque, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 8486e8093781..d406a56c05da 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -37,18 +37,23 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(func) => { self.print_fn_full(ident, vis, attrs, &*func); } - ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => { - self.print_item_const( - ident, - Some(*mutability), - &ast::Generics::default(), - ty, - expr.as_deref(), - vis, - *safety, - ast::Defaultness::Final, - ) - } + ast::ForeignItemKind::Static(box ast::StaticItem { + ty, + mutability, + expr, + safety, + define_opaque, + }) => self.print_item_const( + ident, + Some(*mutability), + &ast::Generics::default(), + ty, + expr.as_deref(), + vis, + *safety, + ast::Defaultness::Final, + define_opaque.as_deref(), + ), ast::ForeignItemKind::TyAlias(box ast::TyAlias { defaultness, generics, @@ -86,7 +91,9 @@ impl<'a> State<'a> { vis: &ast::Visibility, safety: ast::Safety, defaultness: ast::Defaultness, + define_opaque: Option<&[(ast::NodeId, ast::Path)]>, ) { + self.print_define_opaques(define_opaque); self.head(""); self.print_visibility(vis); self.print_safety(safety); @@ -174,7 +181,13 @@ impl<'a> State<'a> { self.print_use_tree(tree); self.word(";"); } - ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => { + ast::ItemKind::Static(box StaticItem { + ty, + safety, + mutability: mutbl, + expr: body, + define_opaque, + }) => { self.print_safety(*safety); self.print_item_const( item.ident, @@ -185,9 +198,16 @@ impl<'a> State<'a> { &item.vis, ast::Safety::Default, ast::Defaultness::Final, + define_opaque.as_deref(), ); } - ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { + ast::ItemKind::Const(box ast::ConstItem { + defaultness, + generics, + ty, + expr, + define_opaque, + }) => { self.print_item_const( item.ident, None, @@ -197,6 +217,7 @@ impl<'a> State<'a> { &item.vis, ast::Safety::Default, *defaultness, + define_opaque.as_deref(), ); } ast::ItemKind::Fn(func) => { @@ -537,7 +558,13 @@ impl<'a> State<'a> { ast::AssocItemKind::Fn(func) => { self.print_fn_full(ident, vis, attrs, &*func); } - ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { + ast::AssocItemKind::Const(box ast::ConstItem { + defaultness, + generics, + ty, + expr, + define_opaque, + }) => { self.print_item_const( ident, None, @@ -547,6 +574,7 @@ impl<'a> State<'a> { vis, ast::Safety::Default, *defaultness, + define_opaque.as_deref(), ); } ast::AssocItemKind::Type(box ast::TyAlias { @@ -652,7 +680,7 @@ impl<'a> State<'a> { ) { let ast::Fn { defaultness, generics, sig, contract, body, define_opaque } = func; - self.print_define_opaques(define_opaque); + self.print_define_opaques(define_opaque.as_deref()); if body.is_some() { self.head(""); @@ -672,10 +700,7 @@ impl<'a> State<'a> { } } - fn print_define_opaques( - &mut self, - define_opaque: Option<&[(ast::NodeId, ast::Path)]>, - ) { + fn print_define_opaques(&mut self, define_opaque: Option<&[(ast::NodeId, ast::Path)]>) { if let Some(define_opaque) = define_opaque { self.word("#[define_opaque("); for (i, (_, path)) in define_opaque.iter().enumerate() { diff --git a/compiler/rustc_builtin_macros/src/define_opaque.rs b/compiler/rustc_builtin_macros/src/define_opaque.rs index 9777e772cf20..bd5c48e3d346 100644 --- a/compiler/rustc_builtin_macros/src/define_opaque.rs +++ b/compiler/rustc_builtin_macros/src/define_opaque.rs @@ -11,15 +11,20 @@ pub(crate) fn expand( let define_opaque = match &mut item { Annotatable::Item(p) => match &mut p.kind { ast::ItemKind::Fn(f) => Some(&mut f.define_opaque), + ast::ItemKind::Const(ct) => Some(&mut ct.define_opaque), + ast::ItemKind::Static(si) => Some(&mut si.define_opaque), _ => None, }, Annotatable::AssocItem(i, _assoc_ctxt) => match &mut i.kind { ast::AssocItemKind::Fn(func) => Some(&mut func.define_opaque), + ast::AssocItemKind::Const(ct) => Some(&mut ct.define_opaque), _ => None, }, Annotatable::Stmt(s) => match &mut s.kind { ast::StmtKind::Item(p) => match &mut p.kind { ast::ItemKind::Fn(f) => Some(&mut f.define_opaque), + ast::ItemKind::Const(ct) => Some(&mut ct.define_opaque), + ast::ItemKind::Static(si) => Some(&mut si.define_opaque), _ => None, }, _ => None, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index a05fff2dcd1c..239f8657284d 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -285,6 +285,7 @@ pub(crate) fn expand_test_or_bench( defaultness: ast::Defaultness::Final, generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + define_opaque: None, // test::TestDescAndFn { expr: Some( cx.expr_struct( diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index ee7f68cc2f01..2c9b5f40d0df 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -698,8 +698,14 @@ impl<'a> ExtCtxt<'a> { name, AttrVec::new(), ast::ItemKind::Static( - ast::StaticItem { ty, safety: ast::Safety::Default, mutability, expr: Some(expr) } - .into(), + ast::StaticItem { + ty, + safety: ast::Safety::Default, + mutability, + expr: Some(expr), + define_opaque: None, + } + .into(), ), ) } @@ -723,6 +729,7 @@ impl<'a> ExtCtxt<'a> { generics: ast::Generics::default(), ty, expr: Some(expr), + define_opaque: None, } .into(), ), diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f4df4044dd2e..38a2eab5544f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -265,6 +265,7 @@ impl<'a> Parser<'a> { generics, ty, expr, + define_opaque: None, })), ) } @@ -980,13 +981,20 @@ impl<'a> Parser<'a> { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, generics: Generics::default(), ty, expr, + define_opaque, })) } _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), @@ -1254,6 +1262,7 @@ impl<'a> Parser<'a> { mutability: Mutability::Not, expr, safety: Safety::Default, + define_opaque: None, })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1397,7 +1406,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, StaticItem { ty, safety, mutability, expr })) + Ok((ident, StaticItem { ty, safety, mutability, expr, define_opaque: None })) } /// Parse a constant item with the prefix `"const"` already parsed. diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 33f529851ae4..fcb638a117e3 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -244,7 +244,13 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { let def_kind = match fi.kind { - ForeignItemKind::Static(box StaticItem { ty: _, mutability, expr: _, safety }) => { + ForeignItemKind::Static(box StaticItem { + ty: _, + mutability, + expr: _, + safety, + define_opaque: _, + }) => { let safety = match safety { ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, ast::Safety::Safe(_) => hir::Safety::Safe, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f8808582353a..9cbdb83a30fa 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -36,6 +36,7 @@ use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; use smallvec::{SmallVec, smallvec}; +use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ @@ -2662,10 +2663,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, |this| visit::walk_item(this, item), ); - - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } ItemKind::Enum(_, ref generics) @@ -2751,7 +2749,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }); } - ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => { + ItemKind::Static(box ast::StaticItem { + ref ty, ref expr, ref define_opaque, .. + }) => { self.with_static_rib(def_kind, |this| { this.with_lifetime_rib( LifetimeRibKind::Elided(LifetimeRes::Static { @@ -2767,9 +2767,16 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static))); } }); + self.resolve_define_opaques(define_opaque); } - ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => { + ItemKind::Const(box ast::ConstItem { + ref generics, + ref ty, + ref expr, + ref define_opaque, + .. + }) => { self.with_generic_param_rib( &generics.params, RibKind::Item( @@ -2803,6 +2810,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }, ); + self.resolve_define_opaques(define_opaque); } ItemKind::Use(ref use_tree) => { @@ -3102,7 +3110,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for item in trait_items { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ast::ConstItem { + generics, + ty, + expr, + define_opaque, + .. + }) => { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, @@ -3135,13 +3149,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) }, ); + + self.resolve_define_opaques(define_opaque); } AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } AssocItemKind::Delegation(delegation) => { self.with_generic_param_rib( @@ -3306,7 +3320,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ast::ConstItem { + generics, ty, expr, define_opaque, .. + }) => { debug!("resolve_implementation AssocItemKind::Const"); self.with_generic_param_rib( &generics.params, @@ -3350,6 +3366,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); }, ); + self.resolve_define_opaques(define_opaque); } AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); @@ -3379,9 +3396,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, ); - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } AssocItemKind::Type(box TyAlias { generics, .. }) => { self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty()); @@ -5103,6 +5118,14 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }); } } + + fn resolve_define_opaques(&mut self, define_opaque: &Option>) { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); + } + } + } } /// Walks the whole crate in DFS order, visiting each item, counting the declared number of diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 54261079fcad..6023ae9cc7b1 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -336,12 +336,14 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { mutability: lm, expr: le, safety: ls, + define_opaque: _, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, safety: rs, + define_opaque: _, }), ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( @@ -350,12 +352,14 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { generics: lg, ty: lt, expr: le, + define_opaque: _, }), Const(box ConstItem { defaultness: rd, generics: rg, ty: rt, expr: re, + define_opaque: _, }), ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( @@ -490,12 +494,14 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { mutability: lm, expr: le, safety: ls, + define_opaque: _, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, safety: rs, + define_opaque: _, }), ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs, ( @@ -557,12 +563,14 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { generics: lg, ty: lt, expr: le, + define_opaque: _, }), Const(box ConstItem { defaultness: rd, generics: rg, ty: rt, expr: re, + define_opaque: _, }), ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( diff --git a/tests/ui/impl-trait/define-via-const.rs b/tests/ui/impl-trait/define-via-const.rs new file mode 100644 index 000000000000..a4b9123654c4 --- /dev/null +++ b/tests/ui/impl-trait/define-via-const.rs @@ -0,0 +1,12 @@ +//@ check-pass + +#![feature(type_alias_impl_trait)] + +type Closure = impl Fn(u32) -> u32; + +#[define_opaque(Closure)] +const ADDER: Closure = |x| x + 1; + +fn main() { + let z = (ADDER)(1); +} diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs index 5f44a9aa2dfa..1a530d27971a 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs @@ -2,14 +2,15 @@ #![allow(dead_code)] type Bug = impl Fn(T) -> U + Copy; +//~^ ERROR cycle detected when computing type of `Bug::{opaque#0}` #[define_opaque(Bug)] -//~^ ERROR: only functions and methods can define opaque types const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; +//~^ ERROR item does not constrain `Bug::{opaque#0}` #[define_opaque(Bug)] fn make_bug>() -> Bug { - |x| x.into() //~ ERROR is not satisfied + |x| x.into() } fn main() { diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr index 5739662ff80b..3062e55dc490 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -1,25 +1,42 @@ -error: only functions and methods can define opaque types - --> $DIR/issue-53092-2.rs:6:1 +error[E0391]: cycle detected when computing type of `Bug::{opaque#0}` + --> $DIR/issue-53092-2.rs:4:18 | -LL | #[define_opaque(Bug)] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing type of opaque `Bug::{opaque#0}`... + --> $DIR/issue-53092-2.rs:4:18 + | +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `CONST_BUG`... + --> $DIR/issue-53092-2.rs:8:1 + | +LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `Bug`... + = note: ...which requires normalizing `Bug`... + = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle +note: cycle used when checking that `Bug::{opaque#0}` is well-formed + --> $DIR/issue-53092-2.rs:4:18 + | +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0277]: the trait bound `U: From` is not satisfied - --> $DIR/issue-53092-2.rs:12:5 +error: item does not constrain `Bug::{opaque#0}` + --> $DIR/issue-53092-2.rs:8:7 | -LL | |x| x.into() - | ^^^^^^^^^^^^ the trait `From` is not implemented for `U` +LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^ | -note: required by a bound in `make_bug` - --> $DIR/issue-53092-2.rs:11:19 + = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` +note: this opaque type is supposed to be constrained + --> $DIR/issue-53092-2.rs:4:18 | -LL | fn make_bug>() -> Bug { - | ^^^^^^^ required by this bound in `make_bug` -help: consider restricting type parameter `U` with trait `From` - | -LL | type Bug> = impl Fn(T) -> U + Copy; - | +++++++++++++++++++++++ +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs index b5533eeecba5..e21627e14b09 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs @@ -1,19 +1,15 @@ +//@ check-pass + #![feature(type_alias_impl_trait)] -// Ensures that `const` items can not constrain an opaque `impl Trait`. use std::fmt::Debug; pub type Foo = impl Debug; -//~^ ERROR unconstrained opaque type #[define_opaque(Foo)] -//~^ ERROR only functions and methods can define opaque types const _FOO: Foo = 5; -//~^ ERROR mismatched types #[define_opaque(Foo)] -//~^ ERROR only functions and methods can define opaque types -static _BAR: Foo = 22_u32; -//~^ ERROR mismatched types +static _BAR: Foo = 22_i32; fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr deleted file mode 100644 index dc15da665f32..000000000000 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr +++ /dev/null @@ -1,57 +0,0 @@ -error: only functions and methods can define opaque types - --> $DIR/type-alias-impl-trait-const.rs:9:1 - | -LL | #[define_opaque(Foo)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: only functions and methods can define opaque types - --> $DIR/type-alias-impl-trait-const.rs:14:1 - | -LL | #[define_opaque(Foo)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-const.rs:6:16 - | -LL | pub type Foo = impl Debug; - | ^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same crate - -error[E0308]: mismatched types - --> $DIR/type-alias-impl-trait-const.rs:11:19 - | -LL | pub type Foo = impl Debug; - | ---------- the expected opaque type -... -LL | const _FOO: Foo = 5; - | ^ expected opaque type, found integer - | - = note: expected opaque type `Foo` - found type `{integer}` -note: this item must have a `#[define_opaque(Foo)]` attribute to be able to define hidden types - --> $DIR/type-alias-impl-trait-const.rs:11:7 - | -LL | const _FOO: Foo = 5; - | ^^^^ - -error[E0308]: mismatched types - --> $DIR/type-alias-impl-trait-const.rs:16:20 - | -LL | pub type Foo = impl Debug; - | ---------- the expected opaque type -... -LL | static _BAR: Foo = 22_u32; - | ^^^^^^ expected opaque type, found `u32` - | - = note: expected opaque type `Foo` - found type `u32` -note: this item must have a `#[define_opaque(Foo)]` attribute to be able to define hidden types - --> $DIR/type-alias-impl-trait-const.rs:16:8 - | -LL | static _BAR: Foo = 22_u32; - | ^^^^ - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0308`. From 0827f765864a17ac6354cc12ff353043cba62286 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Mar 2025 23:19:33 +0000 Subject: [PATCH 326/546] Test define opaques in extern items --- .../rustc_builtin_macros/src/define_opaque.rs | 5 ++++- tests/ui/impl-trait/define-via-extern.rs | 16 ++++++++++++++++ tests/ui/impl-trait/define-via-extern.stderr | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/ui/impl-trait/define-via-extern.rs create mode 100644 tests/ui/impl-trait/define-via-extern.stderr diff --git a/compiler/rustc_builtin_macros/src/define_opaque.rs b/compiler/rustc_builtin_macros/src/define_opaque.rs index bd5c48e3d346..cd02e81f5689 100644 --- a/compiler/rustc_builtin_macros/src/define_opaque.rs +++ b/compiler/rustc_builtin_macros/src/define_opaque.rs @@ -52,7 +52,10 @@ pub(crate) fn expand( .collect(), ); } else { - ecx.dcx().span_err(meta_item.span, "only functions and methods can define opaque types"); + ecx.dcx().span_err( + meta_item.span, + "only functions, statics, and consts can define opaque types", + ); } vec![item] diff --git a/tests/ui/impl-trait/define-via-extern.rs b/tests/ui/impl-trait/define-via-extern.rs new file mode 100644 index 000000000000..599c31ff917f --- /dev/null +++ b/tests/ui/impl-trait/define-via-extern.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +type Hi = impl Sized; + +extern "C" { + #[define_opaque(Hi)] fn foo(); + //~^ ERROR only functions, statics, and consts can define opaque types + + #[define_opaque(Hi)] static HI: Hi; + //~^ ERROR only functions, statics, and consts can define opaque types +} + +#[define_opaque(Hi)] +fn main() { + let _: Hi = 0; +} diff --git a/tests/ui/impl-trait/define-via-extern.stderr b/tests/ui/impl-trait/define-via-extern.stderr new file mode 100644 index 000000000000..4a0ca5edd47d --- /dev/null +++ b/tests/ui/impl-trait/define-via-extern.stderr @@ -0,0 +1,14 @@ +error: only functions, statics, and consts can define opaque types + --> $DIR/define-via-extern.rs:6:5 + | +LL | #[define_opaque(Hi)] fn foo(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: only functions, statics, and consts can define opaque types + --> $DIR/define-via-extern.rs:9:5 + | +LL | #[define_opaque(Hi)] static HI: Hi; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 1875905a94f72e043eb356efe30d40fe165fea20 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 25 Mar 2025 17:14:58 +0000 Subject: [PATCH 327/546] Rustup to rustc 1.87.0-nightly (f8c27dfe1 2025-03-24) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index a6b0bf5fba1a..ab650c05d357 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-23" +channel = "nightly-2025-03-25" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 2df6252bd61464c27b0f2612ac4749b02c31cade Mon Sep 17 00:00:00 2001 From: apiraino Date: Tue, 25 Mar 2025 18:28:19 +0100 Subject: [PATCH 328/546] update wg-prio triagebot config --- triagebot.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index ebbcfa4516b9..6dfae8b16a3e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -581,12 +581,12 @@ trigger_files = [ ] [notify-zulip."I-prioritize"] -zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts +zulip_stream = 245100 # #t-compiler/prioritization/alerts topic = "#{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* issue #{number} has been requested for prioritization. -# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#assign-priority-to-unprioritized-issues-with-i-prioritize-label) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization.html) - Priority? - Regression? - Notify people/groups? From ffee55c18c19c551d58a6d68e1b3feb7618d0455 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 20:52:17 +1100 Subject: [PATCH 329/546] rustdoc: Rearrange `Item`/`ItemInner`. The `Item` struct is 48 bytes and contains a `Box`; `ItemInner` is 104 bytes. This is an odd arrangement. Normally you'd have one of the following. - A single large struct, which avoids the allocation for the `Box`, but can result in lots of wasted space in unused parts of a container like `Vec`, `HashSet`, etc. - Or, something like `struct Item(Box)`, which requires the `Box` allocation but gives a very small Item size, which is good for containers like `Vec`. `Item`/`ItemInner` currently gets the worst of both worlds: it always requires a `Box`, but `Item` is also pretty big and so wastes space in containers. It would make sense to push it in one direction or the other. #138916 showed that the first option is a regression for rustdoc, so this commit does the second option, which improves speed and reduces memory usage. --- src/librustdoc/clean/auto_trait.rs | 8 ++-- src/librustdoc/clean/blanket_impl.rs | 8 ++-- src/librustdoc/clean/inline.rs | 14 +++---- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 46 +++++++++++++--------- src/librustdoc/formats/cache.rs | 1 - src/librustdoc/json/conversions.rs | 2 +- src/librustdoc/passes/propagate_doc_cfg.rs | 6 +-- 8 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 6ace626fdcd9..a48f5c623cd2 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -114,8 +114,8 @@ fn synthesize_auto_trait_impl<'tcx>( }; Some(clean::Item { - name: None, inner: Box::new(clean::ItemInner { + name: None, attrs: Default::default(), stability: None, kind: clean::ImplItem(Box::new(clean::Impl { @@ -127,10 +127,10 @@ fn synthesize_auto_trait_impl<'tcx>( polarity, kind: clean::ImplKind::Auto, })), + item_id: clean::ItemId::Auto { trait_: trait_def_id, for_: item_def_id }, + cfg: None, + inline_stmt_id: None, }), - item_id: clean::ItemId::Auto { trait_: trait_def_id, for_: item_def_id }, - cfg: None, - inline_stmt_id: None, }) } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index a6d9676dd84a..89245fee5155 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -83,9 +83,9 @@ pub(crate) fn synthesize_blanket_impls( cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id)); blanket_impls.push(clean::Item { - name: None, - item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, inner: Box::new(clean::ItemInner { + name: None, + item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, attrs: Default::default(), stability: None, kind: clean::ImplItem(Box::new(clean::Impl { @@ -122,9 +122,9 @@ pub(crate) fn synthesize_blanket_impls( None, ))), })), + cfg: None, + inline_stmt_id: None, }), - cfg: None, - inline_stmt_id: None, }); } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e973b89b2375..d9cef28b3d80 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -151,7 +151,7 @@ pub(crate) fn try_inline( let mut item = crate::clean::generate_item_with_correct_attrs(cx, kind, did, name, import_def_id, None); // The visibility needs to reflect the one from the reexport and not from the "source" DefId. - item.inline_stmt_id = import_def_id; + item.inner.inline_stmt_id = import_def_id; ret.push(item); Some(ret) } @@ -665,11 +665,11 @@ fn build_module_items( // Primitive types can't be inlined so generate an import instead. let prim_ty = clean::PrimitiveType::from(p); items.push(clean::Item { - name: None, - // We can use the item's `DefId` directly since the only information ever used - // from it is `DefId.krate`. - item_id: ItemId::DefId(did), inner: Box::new(clean::ItemInner { + name: None, + // We can use the item's `DefId` directly since the only information ever + // used from it is `DefId.krate`. + item_id: ItemId::DefId(did), attrs: Default::default(), stability: None, kind: clean::ImportItem(clean::Import::new_simple( @@ -689,9 +689,9 @@ fn build_module_items( }, true, )), + cfg: None, + inline_stmt_id: None, }), - cfg: None, - inline_stmt_id: None, }); } else if let Some(i) = try_inline(cx, res, item.ident.name, attrs, visited) { items.extend(i) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index de6dc088176f..ada370a8d52e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -210,7 +210,7 @@ fn generate_item_with_correct_attrs( let name = renamed.or(Some(name)); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, cfg); - item.inline_stmt_id = import_id; + item.inner.inline_stmt_id = import_id; item } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1207f2f0360f..356691e71b83 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -311,26 +311,31 @@ pub(crate) enum ExternalLocation { /// directly to the AST's concept of an item; it's a strict superset. #[derive(Clone)] pub(crate) struct Item { + pub(crate) inner: Box, +} + +// Why does the `Item`/`ItemInner` split exist? `Vec`s are common, and +// without the split `Item` would be a large type (100+ bytes) which results in +// lots of wasted space in the unused parts of a `Vec`. With the split, +// `Item` is just 8 bytes, and the wasted space is avoided, at the cost of an +// extra allocation per item. This is a performance win. +#[derive(Clone)] +pub(crate) struct ItemInner { /// The name of this item. /// Optional because not every item has a name, e.g. impls. pub(crate) name: Option, - pub(crate) inner: Box, - pub(crate) item_id: ItemId, - /// This is the `LocalDefId` of the `use` statement if the item was inlined. - /// The crate metadata doesn't hold this information, so the `use` statement - /// always belongs to the current crate. - pub(crate) inline_stmt_id: Option, - pub(crate) cfg: Option>, -} - -#[derive(Clone)] -pub(crate) struct ItemInner { /// Information about this item that is specific to what kind of item it is. /// E.g., struct vs enum vs function. pub(crate) kind: ItemKind, pub(crate) attrs: Attributes, /// The effective stability, filled out by the `propagate-stability` pass. pub(crate) stability: Option, + pub(crate) item_id: ItemId, + /// This is the `LocalDefId` of the `use` statement if the item was inlined. + /// The crate metadata doesn't hold this information, so the `use` statement + /// always belongs to the current crate. + pub(crate) inline_stmt_id: Option, + pub(crate) cfg: Option>, } impl std::ops::Deref for Item { @@ -488,11 +493,15 @@ impl Item { trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}"); Item { - item_id: def_id.into(), - inner: Box::new(ItemInner { kind, attrs, stability: None }), - name, - cfg, - inline_stmt_id: None, + inner: Box::new(ItemInner { + item_id: def_id.into(), + kind, + attrs, + stability: None, + name, + cfg, + inline_stmt_id: None, + }), } } @@ -2618,13 +2627,14 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(Crate, 56); // frequently moved by-value + static_assert_size!(Crate, 16); // frequently moved by-value static_assert_size!(DocFragment, 32); static_assert_size!(GenericArg, 32); static_assert_size!(GenericArgs, 24); static_assert_size!(GenericParamDef, 40); static_assert_size!(Generics, 16); - static_assert_size!(Item, 48); + static_assert_size!(Item, 8); + static_assert_size!(ItemInner, 136); static_assert_size!(ItemKind, 48); static_assert_size!(PathSegment, 32); static_assert_size!(Type, 32); diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 2648641e53e7..f8f7816f5a67 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -385,7 +385,6 @@ impl DocFolder for CacheBuilder<'_, '_> { // implementations elsewhere. let ret = if let clean::Item { inner: box clean::ItemInner { kind: clean::ImplItem(ref i), .. }, - .. } = item { // Figure out the id of this impl. This may map to a diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index a5351b350dd5..9d8eb70fbe07 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -43,7 +43,7 @@ impl JsonRenderer<'_> { let attrs = item.attributes(self.tcx, self.cache(), true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); - let clean::Item { name, item_id, .. } = item; + let clean::ItemInner { name, item_id, .. } = *item.inner; let id = self.id_from_item(&item); let inner = match item.kind { clean::KeywordItem => return None, diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 572c9bf7552f..eddafa9ba8e4 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -61,7 +61,7 @@ impl CfgPropagator<'_, '_> { let (_, cfg) = merge_attrs(self.cx, item.attrs.other_attrs.as_slice(), Some((&attrs, None))); - item.cfg = cfg; + item.inner.cfg = cfg; } } @@ -71,7 +71,7 @@ impl DocFolder for CfgPropagator<'_, '_> { self.merge_with_parent_attributes(&mut item); - let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) { + let new_cfg = match (self.parent_cfg.take(), item.inner.cfg.take()) { (None, None) => None, (Some(rc), None) | (None, Some(rc)) => Some(rc), (Some(mut a), Some(b)) => { @@ -81,7 +81,7 @@ impl DocFolder for CfgPropagator<'_, '_> { } }; self.parent_cfg = new_cfg.clone(); - item.cfg = new_cfg; + item.inner.cfg = new_cfg; let old_parent = if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) { From 154cb083e705feca7509143352887dd293db61b2 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:02:54 +0100 Subject: [PATCH 330/546] Override PartialOrd methods for bool I noticed that `PartialOrd` implementation for `bool` does not override the individual operator methods, unlike the other primitive types like `char` and integers. This commit extracts these `PartialOrd` overrides shared by the other primitive types into a macro and calls it on `bool` too. --- library/core/src/cmp.rs | 46 +++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 0b0dbf723b65..0dc2cc72e06c 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1810,9 +1810,9 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for $t { #[inline] - fn eq(&self, other: &$t) -> bool { (*self) == (*other) } + fn eq(&self, other: &Self) -> bool { *self == *other } #[inline] - fn ne(&self, other: &$t) -> bool { (*self) != (*other) } + fn ne(&self, other: &Self) -> bool { *self != *other } } )*) } @@ -1842,8 +1842,18 @@ mod impls { eq_impl! { () bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - macro_rules! chaining_methods_impl { - ($t:ty) => { + #[rustfmt::skip] + macro_rules! partial_ord_methods_primitive_impl { + () => { + #[inline(always)] + fn lt(&self, other: &Self) -> bool { *self < *other } + #[inline(always)] + fn le(&self, other: &Self) -> bool { *self <= *other } + #[inline(always)] + fn gt(&self, other: &Self) -> bool { *self > *other } + #[inline(always)] + fn ge(&self, other: &Self) -> bool { *self >= *other } + // These implementations are the same for `Ord` or `PartialOrd` types // because if either is NAN the `==` test will fail so we end up in // the `Break` case and the comparison will correctly return `false`. @@ -1876,7 +1886,7 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for $t { #[inline] - fn partial_cmp(&self, other: &$t) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { match (*self <= *other, *self >= *other) { (false, false) => None, (false, true) => Some(Greater), @@ -1884,16 +1894,8 @@ mod impls { (true, true) => Some(Equal), } } - #[inline(always)] - fn lt(&self, other: &$t) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &$t) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &$t) -> bool { (*self) > (*other) } - chaining_methods_impl!($t); + partial_ord_methods_primitive_impl!(); } )*) } @@ -1912,6 +1914,8 @@ mod impls { fn partial_cmp(&self, other: &bool) -> Option { Some(self.cmp(other)) } + + partial_ord_methods_primitive_impl!(); } partial_ord_impl! { f16 f32 f64 f128 } @@ -1921,25 +1925,17 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for $t { #[inline] - fn partial_cmp(&self, other: &$t) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(crate::intrinsics::three_way_compare(*self, *other)) } - #[inline(always)] - fn lt(&self, other: &$t) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &$t) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &$t) -> bool { (*self) > (*other) } - chaining_methods_impl!($t); + partial_ord_methods_primitive_impl!(); } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for $t { #[inline] - fn cmp(&self, other: &$t) -> Ordering { + fn cmp(&self, other: &Self) -> Ordering { crate::intrinsics::three_way_compare(*self, *other) } } From cd4439952224f402e8d66aabdcbcc4d07fbc6115 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 25 Mar 2025 21:05:08 +0100 Subject: [PATCH 331/546] Move Platform Support section to the bottom of rustc chapter book --- src/doc/rustc/src/SUMMARY.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index e258b0a76ffd..6e3056751855 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -14,6 +14,22 @@ - [Deny-by-default Lints](lints/listing/deny-by-default.md) - [JSON Output](json.md) - [Tests](tests/index.md) +- [Targets](targets/index.md) + - [Built-in Targets](targets/built-in.md) + - [Custom Targets](targets/custom.md) + - [Known Issues](targets/known-issues.md) +- [Profile-guided Optimization](profile-guided-optimization.md) +- [Instrumentation-based Code Coverage](instrument-coverage.md) +- [Linker-plugin-based LTO](linker-plugin-lto.md) +- [Checking Conditional Configurations](check-cfg.md) + - [Cargo Specifics](check-cfg/cargo-specifics.md) +- [Exploit Mitigations](exploit-mitigations.md) +- [Symbol Mangling](symbol-mangling/index.md) + - [v0 Symbol Format](symbol-mangling/v0.md) +- [Contributing to `rustc`](contributing.md) + +-------- + - [Platform Support](platform-support.md) - [Target Tier Policy](target-tier-policy.md) - [Template for Target-specific Documentation](platform-support/TEMPLATE.md) @@ -113,16 +129,3 @@ - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [xtensa-\*-none-elf](platform-support/xtensa.md) - [\*-nuttx-\*](platform-support/nuttx.md) -- [Targets](targets/index.md) - - [Built-in Targets](targets/built-in.md) - - [Custom Targets](targets/custom.md) - - [Known Issues](targets/known-issues.md) -- [Profile-guided Optimization](profile-guided-optimization.md) -- [Instrumentation-based Code Coverage](instrument-coverage.md) -- [Linker-plugin-based LTO](linker-plugin-lto.md) -- [Checking Conditional Configurations](check-cfg.md) - - [Cargo Specifics](check-cfg/cargo-specifics.md) -- [Exploit Mitigations](exploit-mitigations.md) -- [Symbol Mangling](symbol-mangling/index.md) - - [v0 Symbol Format](symbol-mangling/v0.md) -- [Contributing to `rustc`](contributing.md) From 4b22ac5296a7a40aebfc997eec122fbfe50164da Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Mar 2025 00:15:24 +0000 Subject: [PATCH 332/546] Ensure define_opaque is accounted for in HIR hash --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_middle/src/hir/mod.rs | 7 ++++++- compiler/rustc_middle/src/ty/context.rs | 3 ++- tests/incremental/define-opaques.rs | 19 +++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 tests/incremental/define-opaques.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6c380d77b493..a946f9562258 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -625,7 +625,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Don't hash unless necessary, because it's expensive. let (opt_hash_including_bodies, attrs_hash) = - self.tcx.hash_owner_nodes(node, &bodies, &attrs); + self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 68b9a4f56b96..347bc5ea3128 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -14,7 +14,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; use rustc_macros::{Decodable, Encodable, HashStable}; -use rustc_span::{ErrorGuaranteed, ExpnId}; +use rustc_span::{ErrorGuaranteed, ExpnId, Span}; use crate::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; @@ -157,6 +157,7 @@ impl<'tcx> TyCtxt<'tcx> { node: OwnerNode<'_>, bodies: &SortedMap>, attrs: &SortedMap, + define_opaque: Option<&[(Span, LocalDefId)]>, ) -> (Option, Option) { if self.needs_crate_hash() { self.with_stable_hashing_context(|mut hcx| { @@ -168,6 +169,10 @@ impl<'tcx> TyCtxt<'tcx> { let mut stable_hasher = StableHasher::new(); attrs.hash_stable(&mut hcx, &mut stable_hasher); + + // Hash the defined opaque types, which are not present in the attrs. + define_opaque.hash_stable(&mut hcx, &mut stable_hasher); + let h2 = stable_hasher.finish(); (Some(h1), Some(h2)) }) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f54dd2b0040a..834d1f2a4a8d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1288,7 +1288,8 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { let bodies = Default::default(); let attrs = hir::AttributeMap::EMPTY; - let (opt_hash_including_bodies, _) = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map); + let (opt_hash_including_bodies, _) = + self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, attrs.define_opaque); let node = node.into(); self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes { opt_hash_including_bodies, diff --git a/tests/incremental/define-opaques.rs b/tests/incremental/define-opaques.rs new file mode 100644 index 000000000000..d6eae2383412 --- /dev/null +++ b/tests/incremental/define-opaques.rs @@ -0,0 +1,19 @@ +//@ revisions: rpass1 cfail2 + +#![feature(type_alias_impl_trait)] + +pub type Foo = impl Sized; + +#[cfg_attr(rpass1, define_opaque())] +#[cfg_attr(cfail2, define_opaque(Foo))] +fn a() { + //[cfail2]~^ ERROR item does not constrain `Foo::{opaque#0}` + let _: Foo = b(); +} + +#[define_opaque(Foo)] +fn b() -> Foo { + () +} + +fn main() {} From ca9988ec49debec4cd567d0aa719e2ee108c038b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 20:17:29 +1100 Subject: [PATCH 333/546] Remove `kw::Empty` uses from `rustc_middle`. There are several places in `rustc_middle` that check for an empty lifetime name. These checks appear to be totally unnecessary, because empty lifetime names aren't produced here. (Empty lifetime names *are* possible in `hir::Lifetime`. Perhaps there was some confusion between it and the `rustc_middle` types?) This commit removes the `kw::Empty` checks. --- compiler/rustc_middle/src/ty/generics.rs | 4 +--- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 10 ++++------ compiler/rustc_middle/src/ty/region.rs | 6 ++---- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 85d9db7ee747..d4cc562e70cc 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -73,9 +73,7 @@ impl GenericParamDef { pub fn is_anonymous_lifetime(&self) -> bool { match self.kind { - GenericParamDefKind::Lifetime => { - self.name == kw::UnderscoreLifetime || self.name == kw::Empty - } + GenericParamDefKind::Lifetime => self.name == kw::UnderscoreLifetime, _ => false, } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6bdd0a0647d3..ac98cbc8d6cb 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -457,7 +457,7 @@ impl EarlyParamRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). pub fn has_name(&self) -> bool { - self.name != kw::UnderscoreLifetime && self.name != kw::Empty + self.name != kw::UnderscoreLifetime } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3ef8ecc59e40..3281cb4135a0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2591,11 +2591,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // to fit that into a short string. Hence the recommendation to use // `explain_region()` or `note_and_explain_region()`. match *region { - ty::ReEarlyParam(ref data) => { - if data.name != kw::Empty { - p!(write("{}", data.name)); - return Ok(()); - } + ty::ReEarlyParam(data) => { + p!(write("{}", data.name)); + return Ok(()); } ty::ReLateParam(ty::LateParamRegion { kind, .. }) => { if let Some(name) = kind.get_name() { @@ -2834,7 +2832,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { (name, ty::BoundRegionKind::Named(CRATE_DEF_ID.to_def_id(), name)) } - ty::BoundRegionKind::Named(def_id, kw::UnderscoreLifetime | kw::Empty) => { + ty::BoundRegionKind::Named(def_id, kw::UnderscoreLifetime) => { let name = next_name(self); if let Some(lt_idx) = lifetime_idx { diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index fb52cf96b029..c78306f2ca37 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -400,9 +400,7 @@ impl LateParamRegionKind { pub fn is_named(&self) -> bool { match *self { - LateParamRegionKind::Named(_, name) => { - name != kw::UnderscoreLifetime && name != kw::Empty - } + LateParamRegionKind::Named(_, name) => name != kw::UnderscoreLifetime, _ => false, } } @@ -475,7 +473,7 @@ impl core::fmt::Debug for BoundRegion { impl BoundRegionKind { pub fn is_named(&self) -> bool { match *self { - BoundRegionKind::Named(_, name) => name != kw::UnderscoreLifetime && name != kw::Empty, + BoundRegionKind::Named(_, name) => name != kw::UnderscoreLifetime, _ => false, } } From 0c162b19ec0bcf1488a2f797404de594e347e053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 26 Mar 2025 02:09:13 +0100 Subject: [PATCH 334/546] Revert "Make `MatchPairTree::place` non-optional" This reverts commit e3e74bc89a958e36c658fa809d98b4dd66d53cf8. The comment that was used to justify the change was outdated. --- .../src/builder/matches/match_pair.rs | 3 +-- compiler/rustc_mir_build/src/builder/matches/mod.rs | 12 ++++++++++-- compiler/rustc_mir_build/src/builder/matches/test.rs | 9 ++++++--- compiler/rustc_mir_build/src/builder/matches/util.rs | 8 ++++++-- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index f2ce0c46dd33..29d400a957b4 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -115,7 +115,6 @@ impl<'tcx> MatchPairTree<'tcx> { place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); } - // Place can be none if the pattern refers to a non-captured place in a closure. let place = place_builder.try_to_place(cx); let mut subpairs = Vec::new(); let test_case = match pattern.kind { @@ -321,7 +320,7 @@ impl<'tcx> MatchPairTree<'tcx> { if let Some(test_case) = test_case { // This pattern is refutable, so push a new match-pair node. match_pairs.push(MatchPairTree { - place: place.expect("refutable patterns should always have a place to inspect"), + place, test_case, subpairs, pattern_ty: pattern.ty, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index ea341b604e0b..56671763977b 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1279,7 +1279,13 @@ impl<'tcx> TestCase<'tcx> { #[derive(Debug, Clone)] pub(crate) struct MatchPairTree<'tcx> { /// This place... - place: Place<'tcx>, + /// + /// --- + /// This can be `None` if it referred to a non-captured place in a closure. + /// + /// Invariant: Can only be `None` when `test_case` is `Irrefutable`. + /// Therefore this must be `Some(_)` after simplification. + place: Option>, /// ... must pass this test... test_case: TestCase<'tcx>, @@ -2099,9 +2105,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Extract the match-pair from the highest priority candidate let match_pair = &candidates[0].match_pairs[0]; let test = self.pick_test_for_match_pair(match_pair); + // Unwrap is ok after simplification. + let match_place = match_pair.place.unwrap(); debug!(?test, ?match_pair); - (match_pair.place, test) + (match_place, test) } /// Given a test, we partition the input candidates into several buckets. diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index e5d61bc9e556..f92036a83e1e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -540,8 +540,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // than one, but it'd be very unusual to have two sides that // both require tests; you'd expect one side to be simplified // away.) - let (match_pair_index, match_pair) = - candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == test_place)?; + let (match_pair_index, match_pair) = candidate + .match_pairs + .iter() + .enumerate() + .find(|&(_, mp)| mp.place == Some(test_place))?; // If true, the match pair is completely entailed by its corresponding test // branch, so it can be removed. If false, the match pair is _compatible_ @@ -584,7 +587,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate .match_pairs .iter() - .any(|mp| mp.place == test_place && is_covering_range(&mp.test_case)) + .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case)) }; if sorted_candidates .get(&TestBranch::Failure) diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index ed3b652e4ef5..589e350a03fc 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -173,10 +173,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // } // ``` // Hence we fake borrow using a deep borrow. - self.fake_borrow(match_pair.place, FakeBorrowKind::Deep); + if let Some(place) = match_pair.place { + self.fake_borrow(place, FakeBorrowKind::Deep); + } } else { // Insert a Shallow borrow of any place that is switched on. - self.fake_borrow(match_pair.place, FakeBorrowKind::Shallow); + if let Some(place) = match_pair.place { + self.fake_borrow(place, FakeBorrowKind::Shallow); + } for subpair in &match_pair.subpairs { self.visit_match_pair(subpair); From c8a5b3677be3749b9f3eb9fafd912f8c4be5912e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 26 Mar 2025 02:18:13 +0100 Subject: [PATCH 335/546] MatchPairTree: update invariant comment --- compiler/rustc_mir_build/src/builder/matches/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 56671763977b..fb1d067865cf 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1283,8 +1283,8 @@ pub(crate) struct MatchPairTree<'tcx> { /// --- /// This can be `None` if it referred to a non-captured place in a closure. /// - /// Invariant: Can only be `None` when `test_case` is `Irrefutable`. - /// Therefore this must be `Some(_)` after simplification. + /// Invariant: Can only be `None` when `test_case` is `Or`. + /// Therefore this must be `Some(_)` after or-pattern expansion. place: Option>, /// ... must pass this test... From 1524060da6f65332917b6c62f7b68eadd0be2032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 26 Mar 2025 02:23:13 +0100 Subject: [PATCH 336/546] Add a regression test for TestCase::Or without place --- tests/ui/closures/upvar-or-pattern-issue-138958.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/ui/closures/upvar-or-pattern-issue-138958.rs diff --git a/tests/ui/closures/upvar-or-pattern-issue-138958.rs b/tests/ui/closures/upvar-or-pattern-issue-138958.rs new file mode 100644 index 000000000000..fe9ebc0a7e69 --- /dev/null +++ b/tests/ui/closures/upvar-or-pattern-issue-138958.rs @@ -0,0 +1,11 @@ +//@ edition:2024 +//@ check-pass + +pub fn f(x: (u32, u32)) { + let _ = || { + let ((0, a) | (a, _)) = x; + a + }; +} + +fn main() {} From ca6dad3eaba54b5bf6e587991055d89c7cd029e4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Mar 2025 03:51:41 +0000 Subject: [PATCH 337/546] hir::-ify internal lints --- compiler/rustc_lint/src/internal.rs | 89 ++++++++++++++++------------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index b359ee790a50..c0d9290a08e0 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -1,18 +1,15 @@ //! Some lints that are only useful in the compiler or crates that use compiler internals, such as //! Clippy. -use rustc_ast as ast; +use rustc_hir::HirId; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; -use rustc_hir::{ - AmbigArg, BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat, - PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Ty, TyKind, -}; use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::{Span, sym}; use tracing::debug; +use {rustc_ast as ast, rustc_hir as hir}; use crate::lints::{ BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, @@ -37,9 +34,12 @@ declare_tool_lint! { declare_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]); impl LateLintPass<'_> for DefaultHashTypes { - fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) { + fn check_path(&mut self, cx: &LateContext<'_>, path: &hir::Path<'_>, hir_id: HirId) { let Res::Def(rustc_hir::def::DefKind::Struct, def_id) = path.res else { return }; - if matches!(cx.tcx.hir_node(hir_id), Node::Item(Item { kind: ItemKind::Use(..), .. })) { + if matches!( + cx.tcx.hir_node(hir_id), + hir::Node::Item(hir::Item { kind: hir::ItemKind::Use(..), .. }) + ) { // Don't lint imports, only actual usages. return; } @@ -60,10 +60,10 @@ impl LateLintPass<'_> for DefaultHashTypes { /// get the `DefId` and `GenericArgsRef` of the function. fn typeck_results_of_method_fn<'tcx>( cx: &LateContext<'tcx>, - expr: &Expr<'_>, + expr: &hir::Expr<'_>, ) -> Option<(Span, DefId, ty::GenericArgsRef<'tcx>)> { match expr.kind { - ExprKind::MethodCall(segment, ..) + hir::ExprKind::MethodCall(segment, ..) if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { Some((segment.ident.span, def_id, cx.typeck_results().node_args(expr.hir_id))) @@ -102,7 +102,7 @@ declare_tool_lint! { declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]); impl LateLintPass<'_> for QueryStability { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return }; if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, args) { @@ -164,21 +164,25 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { } } - fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx, AmbigArg>) { + fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) { match &ty.kind { - TyKind::Path(QPath::Resolved(_, path)) => { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { if lint_ty_kind_usage(cx, &path.res) { let span = match cx.tcx.parent_hir_node(ty.hir_id) { - Node::PatExpr(PatExpr { kind: PatExprKind::Path(qpath), .. }) - | Node::Pat(Pat { - kind: PatKind::TupleStruct(qpath, ..) | PatKind::Struct(qpath, ..), + hir::Node::PatExpr(hir::PatExpr { + kind: hir::PatExprKind::Path(qpath), .. }) - | Node::Expr( - Expr { kind: ExprKind::Path(qpath), .. } - | &Expr { kind: ExprKind::Struct(qpath, ..), .. }, + | hir::Node::Pat(hir::Pat { + kind: + hir::PatKind::TupleStruct(qpath, ..) | hir::PatKind::Struct(qpath, ..), + .. + }) + | hir::Node::Expr( + hir::Expr { kind: hir::ExprKind::Path(qpath), .. } + | &hir::Expr { kind: hir::ExprKind::Struct(qpath, ..), .. }, ) => { - if let QPath::TypeRelative(qpath_ty, ..) = qpath + if let hir::QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { Some(path.span) @@ -223,7 +227,7 @@ fn lint_ty_kind_usage(cx: &LateContext<'_>, res: &Res) -> bool { } } -fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option { +fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &hir::Path<'_>) -> Option { match &path.res { Res::Def(_, def_id) => { if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(*def_id) { @@ -244,13 +248,17 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option { None } -fn gen_args(segment: &PathSegment<'_>) -> String { +fn gen_args(segment: &hir::PathSegment<'_>) -> String { if let Some(args) = &segment.args { let lifetimes = args .args .iter() .filter_map(|arg| { - if let GenericArg::Lifetime(lt) = arg { Some(lt.ident.to_string()) } else { None } + if let hir::GenericArg::Lifetime(lt) = arg { + Some(lt.ident.to_string()) + } else { + None + } }) .collect::>(); @@ -284,7 +292,7 @@ declare_tool_lint! { declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_INHERENT]); impl<'tcx> LateLintPass<'tcx> for TypeIr { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return }; let is_mod_inherent = |def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id); @@ -394,15 +402,15 @@ declare_tool_lint! { declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]); impl LateLintPass<'_> for Diagnostics { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - let collect_args_tys_and_spans = |args: &[Expr<'_>], reserve_one_extra: bool| { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + let collect_args_tys_and_spans = |args: &[hir::Expr<'_>], reserve_one_extra: bool| { let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra)); result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span))); result }; // Only check function calls and method calls. let (span, def_id, fn_gen_args, arg_tys_and_spans) = match expr.kind { - ExprKind::Call(callee, args) => { + hir::ExprKind::Call(callee, args) => { match cx.typeck_results().node_type(callee.hir_id).kind() { &ty::FnDef(def_id, fn_gen_args) => { (callee.span, def_id, fn_gen_args, collect_args_tys_and_spans(args, false)) @@ -410,7 +418,7 @@ impl LateLintPass<'_> for Diagnostics { _ => return, // occurs for fns passed as args } } - ExprKind::MethodCall(_segment, _recv, args, _span) => { + hir::ExprKind::MethodCall(_segment, _recv, args, _span) => { let Some((span, def_id, fn_gen_args)) = typeck_results_of_method_fn(cx, expr) else { return; @@ -514,8 +522,8 @@ impl Diagnostics { let mut is_inside_appropriate_impl = false; for (_hir_id, parent) in cx.tcx.hir_parent_iter(current_id) { debug!(?parent); - if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent - && let Impl { of_trait: Some(of_trait), .. } = impl_ + if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) = parent + && let hir::Impl { of_trait: Some(of_trait), .. } = impl_ && let Some(def_id) = of_trait.trait_def_id() && let Some(name) = cx.tcx.get_diagnostic_name(def_id) && matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic) @@ -543,8 +551,8 @@ declare_tool_lint! { declare_lint_pass!(BadOptAccess => [BAD_OPT_ACCESS]); impl LateLintPass<'_> for BadOptAccess { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - let ExprKind::Field(base, target) = expr.kind else { return }; + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + let hir::ExprKind::Field(base, target) = expr.kind else { return }; let Some(adt_def) = cx.typeck_results().expr_ty(base).ty_adt_def() else { return }; // Skip types without `#[rustc_lint_opt_ty]` - only so that the rest of the lint can be // avoided. @@ -581,9 +589,12 @@ declare_tool_lint! { declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]); impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { - if let ExprKind::Binary(BinOp { node: BinOpKind::Eq | BinOpKind::Ne, .. }, lhs, rhs) = - expr.kind + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) { + if let hir::ExprKind::Binary( + hir::BinOp { node: hir::BinOpKind::Eq | hir::BinOpKind::Ne, .. }, + lhs, + rhs, + ) = expr.kind { if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) { cx.emit_span_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag); @@ -592,9 +603,9 @@ impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt { } } -fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { +fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { match &expr.kind { - ExprKind::MethodCall(..) => cx + hir::ExprKind::MethodCall(..) => cx .typeck_results() .type_dependent_def_id(expr.hir_id) .is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)), @@ -617,11 +628,11 @@ declare_lint_pass!(SymbolInternStringLiteral => [SYMBOL_INTERN_STRING_LITERAL]); impl<'tcx> LateLintPass<'tcx> for SymbolInternStringLiteral { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if let ExprKind::Call(path, [arg]) = expr.kind - && let ExprKind::Path(ref qpath) = path.kind + if let hir::ExprKind::Call(path, [arg]) = expr.kind + && let hir::ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::SymbolIntern, def_id) - && let ExprKind::Lit(kind) = arg.kind + && let hir::ExprKind::Lit(kind) = arg.kind && let rustc_ast::LitKind::Str(_, _) = kind.node { cx.emit_span_lint( From 14804d1ed156604c52d5dd4a1ac4710f7ad31fa6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Mar 2025 04:09:07 +0000 Subject: [PATCH 338/546] Implement lint against using Interner and InferCtxtLike in random compiler crates --- compiler/rustc_lint/messages.ftl | 3 ++ compiler/rustc_lint/src/internal.rs | 39 +++++++++++++++++-- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/lints.rs | 5 +++ compiler/rustc_next_trait_solver/src/lib.rs | 1 + compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_type_ir/src/infer_ctxt.rs | 1 + compiler/rustc_type_ir/src/interner.rs | 1 + compiler/rustc_type_ir/src/lib.rs | 1 + .../import-of-type-ir-traits.rs | 16 ++++++++ .../import-of-type-ir-traits.stderr | 15 +++++++ 11 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 tests/ui-fulldeps/internal-lints/import-of-type-ir-traits.rs create mode 100644 tests/ui-fulldeps/internal-lints/import-of-type-ir-traits.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d51865810b9a..0a3eb434d3f1 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -799,6 +799,9 @@ lint_tykind_kind = usage of `ty::TyKind::` lint_type_ir_inherent_usage = do not use `rustc_type_ir::inherent` unless you're inside of the trait solver .note = the method or struct you're looking for is likely defined somewhere else downstream in the compiler +lint_type_ir_trait_usage = do not use `rustc_type_ir::Interner` or `rustc_type_ir::InferCtxtLike` unless you're inside of the trait solver + .note = the method or struct you're looking for is likely defined somewhere else downstream in the compiler + lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing .label = argument has type `{$arg_ty}` .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c0d9290a08e0..1d4be24ea9fa 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -15,7 +15,7 @@ use crate::lints::{ BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrInherentUsage, - UntranslatableDiag, + TypeIrTraitUsage, UntranslatableDiag, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -280,7 +280,7 @@ declare_tool_lint! { } declare_tool_lint! { - /// The `usage_of_type_ir_inherent` lint detects usage `rustc_type_ir::inherent`. + /// The `usage_of_type_ir_inherent` lint detects usage of `rustc_type_ir::inherent`. /// /// This module should only be used within the trait solver. pub rustc::USAGE_OF_TYPE_IR_INHERENT, @@ -289,9 +289,42 @@ declare_tool_lint! { report_in_external_macro: true } -declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_INHERENT]); +declare_tool_lint! { + /// The `usage_of_type_ir_traits` lint detects usage of `rustc_type_ir::Interner`, + /// or `rustc_infer::InferCtxtLike`. + /// + /// Methods of this trait should only be used within the type system abstraction layer, + /// and in the generic next trait solver implementation. Look for an analogously named + /// method on `TyCtxt` or `InferCtxt` (respectively). + pub rustc::USAGE_OF_TYPE_IR_TRAITS, + Allow, + "usage `rustc_type_ir`-specific abstraction traits outside of trait system", + report_in_external_macro: true +} + +declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_TRAITS]); impl<'tcx> LateLintPass<'tcx> for TypeIr { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + let res_def_id = match expr.kind { + hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => path.res.opt_def_id(), + hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::MethodCall(..) => { + cx.typeck_results().type_dependent_def_id(expr.hir_id) + } + _ => return, + }; + let Some(res_def_id) = res_def_id else { + return; + }; + if let Some(assoc_item) = cx.tcx.opt_associated_item(res_def_id) + && let Some(trait_def_id) = assoc_item.trait_container(cx.tcx) + && (cx.tcx.is_diagnostic_item(sym::type_ir_interner, trait_def_id) + | cx.tcx.is_diagnostic_item(sym::type_ir_infer_ctxt_like, trait_def_id)) + { + cx.emit_span_lint(USAGE_OF_TYPE_IR_TRAITS, expr.span, TypeIrTraitUsage); + } + } + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return }; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c38a75400181..cd474f1b7db2 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -645,6 +645,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT), LintId::of(USAGE_OF_TYPE_IR_INHERENT), + LintId::of(USAGE_OF_TYPE_IR_TRAITS), LintId::of(BAD_OPT_ACCESS), LintId::of(SPAN_USE_EQ_CTXT), ], diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 005863095729..036d68d13fa4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -943,6 +943,11 @@ pub(crate) struct TyQualified { #[note] pub(crate) struct TypeIrInherentUsage; +#[derive(LintDiagnostic)] +#[diag(lint_type_ir_trait_usage)] +#[note] +pub(crate) struct TypeIrTraitUsage; + #[derive(LintDiagnostic)] #[diag(lint_non_glob_import_type_ir_inherent)] pub(crate) struct NonGlobImportTypeIrInherent { diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index f6963a790675..f575fe03019e 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(rustc::usage_of_type_ir_inherent)] +#![cfg_attr(not(bootstrap), allow(rustc::usage_of_type_ir_traits))] // tidy-alphabetical-end pub mod canonicalizer; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3e4742439655..555764c26a63 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2118,7 +2118,9 @@ symbols! { type_changing_struct_update, type_const, type_id, + type_ir_infer_ctxt_like, type_ir_inherent, + type_ir_interner, type_length_limit, type_macros, type_name, diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 26c495106962..e512e8fc838f 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -102,6 +102,7 @@ impl TypingMode { } } +#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_infer_ctxt_like")] pub trait InferCtxtLike: Sized { type Interner: Interner; fn cx(&self) -> Self::Interner; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e765cb66d00a..8f86270d7dce 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -15,6 +15,7 @@ use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesDat use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, search_graph}; +#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_interner")] pub trait Interner: Sized + Copy diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 629121895091..4e2baca27854 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -6,6 +6,7 @@ feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] #![cfg_attr(feature = "nightly", allow(internal_features))] +#![cfg_attr(not(bootstrap), allow(rustc::usage_of_type_ir_traits))] // tidy-alphabetical-end extern crate self as rustc_type_ir; diff --git a/tests/ui-fulldeps/internal-lints/import-of-type-ir-traits.rs b/tests/ui-fulldeps/internal-lints/import-of-type-ir-traits.rs new file mode 100644 index 000000000000..3fdd65d6c87f --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/import-of-type-ir-traits.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Z unstable-options +//@ ignore-stage1 + +#![feature(rustc_private)] +#![deny(rustc::usage_of_type_ir_traits)] + +extern crate rustc_type_ir; + +use rustc_type_ir::Interner; + +fn foo(cx: I, did: I::DefId) { + let _ = cx.trait_is_unsafe(did); + //~^ ERROR do not use `rustc_type_ir::Interner` or `rustc_type_ir::InferCtxtLike` unless you're inside of the trait solver +} + +fn main() {} diff --git a/tests/ui-fulldeps/internal-lints/import-of-type-ir-traits.stderr b/tests/ui-fulldeps/internal-lints/import-of-type-ir-traits.stderr new file mode 100644 index 000000000000..df29a4945582 --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/import-of-type-ir-traits.stderr @@ -0,0 +1,15 @@ +error: do not use `rustc_type_ir::Interner` or `rustc_type_ir::InferCtxtLike` unless you're inside of the trait solver + --> $DIR/import-of-type-ir-traits.rs:12:13 + | +LL | let _ = cx.trait_is_unsafe(did); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the method or struct you're looking for is likely defined somewhere else downstream in the compiler +note: the lint level is defined here + --> $DIR/import-of-type-ir-traits.rs:5:9 + | +LL | #![deny(rustc::usage_of_type_ir_traits)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From 5f1e36f8ad96dadaf181cbb17294612316181a1e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Mar 2025 04:10:00 +0000 Subject: [PATCH 339/546] Stop using Interner in the compiler randomly --- compiler/rustc_monomorphize/src/collector.rs | 6 +++--- .../src/traits/select/candidate_assembly.rs | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 67fca1d7c294..679c614e9fa9 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -225,8 +225,8 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths}; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Interner, Ty, TyCtxt, - TypeFoldable, TypeVisitableExt, VtblEntry, + self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, + TypeVisitableExt, VtblEntry, }; use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; @@ -967,7 +967,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> { // `#[rustc_force_inline]` items should never be codegened. This should be caught by // the MIR validator. - tcx.delay_bug("attempt to codegen `#[rustc_force_inline]` item"); + tcx.dcx().delayed_bug("attempt to codegen `#[rustc_force_inline]` item"); } if def_id.is_local() { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index fc352499146e..4cfd8149b1e9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -16,7 +16,7 @@ use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; -use rustc_type_ir::{Interner, elaborate}; +use rustc_type_ir::elaborate; use tracing::{debug, instrument, trace}; use super::SelectionCandidate::*; @@ -802,7 +802,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::UnsafeBinder(_) => { // Only consider auto impls of unsafe traits when there are // no unsafe fields. - if self.tcx().trait_is_unsafe(def_id) && self_ty.has_unsafe_fields() { + if self.tcx().trait_def(def_id).safety.is_unsafe() + && self_ty.has_unsafe_fields() + { return; } From a475f5d18169c5333a97d9a5583be61f249b8f22 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sun, 16 Mar 2025 16:47:26 -0700 Subject: [PATCH 340/546] Fix typo in error message --- library/std/src/sys/net/connection/xous/tcpstream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs index 283b1fe9a33b..e8aea8b706a5 100644 --- a/library/std/src/sys/net/connection/xous/tcpstream.rs +++ b/library/std/src/sys/net/connection/xous/tcpstream.rs @@ -324,7 +324,7 @@ impl TcpStream { } Ok(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.local_port, 0, 0))) } - _ => Err(io::const_error!(io::ErrorKind::InvalidInput, "tnternal error")), + _ => Err(io::const_error!(io::ErrorKind::InvalidInput, "internal error")), } } From 6319bb38ccb316b193e35720c9df953e5ab01c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 18 Mar 2025 17:01:14 +0100 Subject: [PATCH 341/546] Avoiding calling queries when collecting active queries --- compiler/rustc_interface/src/util.rs | 44 +++--- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/query/plumbing.rs | 2 +- compiler/rustc_middle/src/values.rs | 4 +- compiler/rustc_query_impl/src/lib.rs | 11 +- compiler/rustc_query_impl/src/plumbing.rs | 97 ++++++++---- .../rustc_query_system/src/query/config.rs | 5 +- compiler/rustc_query_system/src/query/job.rs | 147 +++++++++++------- compiler/rustc_query_system/src/query/mod.rs | 100 ++++++++++-- .../rustc_query_system/src/query/plumbing.rs | 61 ++++---- 10 files changed, 313 insertions(+), 162 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 333786f0ca38..83d80938b4e3 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -18,7 +18,7 @@ use rustc_session::{EarlyDiagCtxt, Session, filesearch}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMapInputs; -use rustc_span::{Symbol, sym}; +use rustc_span::{SessionGlobals, Symbol, sym}; use rustc_target::spec::Target; use tracing::info; @@ -188,26 +188,11 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, // On deadlock, creates a new thread and forwards information in thread // locals to it. The new thread runs the deadlock handler. - // Get a `GlobalCtxt` reference from `CurrentGcx` as we cannot rely on having a - // `TyCtxt` TLS reference here. - let query_map = current_gcx2.access(|gcx| { - tls::enter_context(&tls::ImplicitCtxt::new(gcx), || { - tls::with(|tcx| { - match QueryCtxt::new(tcx).collect_active_jobs() { - Ok(query_map) => query_map, - Err(_) => { - // There was an unexpected error collecting all active jobs, which we need - // to find cycles to break. - // We want to avoid panicking in the deadlock handler, so we abort instead. - eprintln!("internal compiler error: failed to get query map in deadlock handler, aborting process"); - process::abort(); - } - } - }) - }) - }); - let query_map = FromDyn::from(query_map); + let current_gcx2 = current_gcx2.clone(); let registry = rayon_core::Registry::current(); + let session_globals = rustc_span::with_session_globals(|session_globals| { + session_globals as *const SessionGlobals as usize + }); thread::Builder::new() .name("rustc query cycle handler".to_string()) .spawn(move || { @@ -217,7 +202,24 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, // otherwise the compiler could just hang, process::abort(); }); - break_query_cycles(query_map.into_inner(), ®istry); + + // Get a `GlobalCtxt` reference from `CurrentGcx` as we cannot rely on having a + // `TyCtxt` TLS reference here. + current_gcx2.access(|gcx| { + tls::enter_context(&tls::ImplicitCtxt::new(gcx), || { + tls::with(|tcx| { + // Accessing session globals is sound as they outlive `GlobalCtxt`. + // They are needed to hash query keys containing spans or symbols. + let query_map = rustc_span::set_session_globals_then(unsafe { &*(session_globals as *const SessionGlobals) }, || { + // Ensure there was no errors collecting all active jobs. + // We need the complete map to ensure we find a cycle to break. + QueryCtxt::new(tcx).collect_active_jobs().ok().expect("failed to collect active queries in deadlock handler") + }); + break_query_cycles(query_map, ®istry); + }) + }) + }); + on_panic.disable(); }) .unwrap(); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 527c18addbe1..6093d0c6e844 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -30,7 +30,9 @@ use rustc_index::IndexVec; use rustc_lint_defs::LintId; use rustc_macros::rustc_queries; use rustc_query_system::ich::StableHashingContext; -use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached}; +use rustc_query_system::query::{ + QueryCache, QueryMode, QueryStackDeferred, QueryState, try_get_cached, +}; use rustc_session::Limits; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{ diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 4834444ed1d7..a099f7704170 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -488,7 +488,7 @@ macro_rules! define_callbacks { #[derive(Default)] pub struct QueryStates<'tcx> { $( - pub $name: QueryState<$($K)*>, + pub $name: QueryState<$($K)*, QueryStackDeferred<'tcx>>, )* } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 9450ce7ec444..39fcc686c555 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -88,7 +88,7 @@ impl<'tcx> Value> for Representability { if info.query.dep_kind == dep_kinds::representability && let Some(field_id) = info.query.def_id && let Some(field_id) = field_id.as_local() - && let Some(DefKind::Field) = info.query.def_kind + && let Some(DefKind::Field) = info.query.info.def_kind { let parent_id = tcx.parent(field_id.to_def_id()); let item_id = match tcx.def_kind(parent_id) { @@ -216,7 +216,7 @@ impl<'tcx, T> Value> for Result> continue; }; let frame_span = - frame.query.default_span(cycle[(i + 1) % cycle.len()].span); + frame.query.info.default_span(cycle[(i + 1) % cycle.len()].span); if frame_span.is_dummy() { continue; } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index a83c388c747b..30a9e718d236 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -26,8 +26,8 @@ use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryState, - get_query_incr, get_query_non_incr, + CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryStackDeferred, + QueryState, get_query_incr, get_query_non_incr, }; use rustc_query_system::{HandleCycleError, Value}; use rustc_span::{ErrorGuaranteed, Span}; @@ -84,7 +84,10 @@ where } #[inline(always)] - fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState + fn query_state<'a>( + self, + qcx: QueryCtxt<'tcx>, + ) -> &'a QueryState> where QueryCtxt<'tcx>: 'a, { @@ -93,7 +96,7 @@ where unsafe { &*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>) .byte_add(self.dynamic.query_state) - .cast::>() + .cast::>>() } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 55281cd5ac70..7f1d466b8692 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -3,8 +3,10 @@ //! manage the caches, and so forth. use std::num::NonZero; +use std::sync::Arc; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; use rustc_index::Idx; @@ -24,8 +26,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect, QueryStackFrame, - force_query, + QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect, + QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, force_query, }; use rustc_query_system::{QueryOverflow, QueryOverflowNote}; use rustc_serialize::{Decodable, Encodable}; @@ -65,7 +67,9 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> { } } -impl QueryContext for QueryCtxt<'_> { +impl<'tcx> QueryContext for QueryCtxt<'tcx> { + type QueryInfo = QueryStackDeferred<'tcx>; + #[inline] fn next_job_id(self) -> QueryJobId { QueryJobId( @@ -82,7 +86,9 @@ impl QueryContext for QueryCtxt<'_> { /// Returns a query map representing active query jobs. /// It returns an incomplete map as an error if it fails /// to take locks. - fn collect_active_jobs(self) -> Result { + fn collect_active_jobs( + self, + ) -> Result>, QueryMap>> { let mut jobs = QueryMap::default(); let mut complete = true; @@ -95,6 +101,13 @@ impl QueryContext for QueryCtxt<'_> { if complete { Ok(jobs) } else { Err(jobs) } } + fn lift_query_info( + self, + info: &QueryStackDeferred<'tcx>, + ) -> rustc_query_system::query::QueryStackFrameExtra { + info.extract() + } + // Interactions with on_disk_cache fn load_side_effect( self, @@ -159,7 +172,10 @@ impl QueryContext for QueryCtxt<'_> { self.sess.dcx().emit_fatal(QueryOverflow { span: info.job.span, - note: QueryOverflowNote { desc: info.query.description, depth }, + note: QueryOverflowNote { + desc: self.lift_query_info(&info.query.info).description, + depth, + }, suggested_limit, crate_name: self.crate_name(LOCAL_CRATE), }); @@ -298,39 +314,45 @@ macro_rules! should_ever_cache_on_disk { pub(crate) fn create_query_frame< 'tcx, - K: Copy + Key + for<'a> HashStable>, + K: Copy + DynSend + DynSync + Key + for<'a> HashStable> + 'tcx, >( tcx: TyCtxt<'tcx>, do_describe: fn(TyCtxt<'tcx>, K) -> String, key: K, kind: DepKind, name: &'static str, -) -> QueryStackFrame { - // If reduced queries are requested, we may be printing a query stack due - // to a panic. Avoid using `default_span` and `def_kind` in that case. - let reduce_queries = with_reduced_queries(); - - // Avoid calling queries while formatting the description - let description = ty::print::with_no_queries!(do_describe(tcx, key)); - let description = if tcx.sess.verbose_internals() { - format!("{description} [{name:?}]") - } else { - description - }; - let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries { - // The `def_span` query is used to calculate `default_span`, - // so exit to avoid infinite recursion. - None - } else { - Some(key.default_span(tcx)) - }; +) -> QueryStackFrame> { let def_id = key.key_as_def_id(); - let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries { - // Try to avoid infinite recursion. - None - } else { - def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) + + let extra = move || { + // If reduced queries are requested, we may be printing a query stack due + // to a panic. Avoid using `default_span` and `def_kind` in that case. + let reduce_queries = with_reduced_queries(); + + // Avoid calling queries while formatting the description + let description = ty::print::with_no_queries!(do_describe(tcx, key)); + let description = if tcx.sess.verbose_internals() { + format!("{description} [{name:?}]") + } else { + description + }; + let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries { + // The `def_span` query is used to calculate `default_span`, + // so exit to avoid infinite recursion. + None + } else { + Some(key.default_span(tcx)) + }; + + let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries { + // Try to avoid infinite recursion. + None + } else { + def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) + }; + QueryStackFrameExtra::new(description, span, def_kind) }; + let hash = || { tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); @@ -341,7 +363,11 @@ pub(crate) fn create_query_frame< }; let def_id_for_ty_in_cycle = key.def_id_for_ty_in_cycle(); - QueryStackFrame::new(description, span, def_id, def_kind, kind, def_id_for_ty_in_cycle, hash) + // SAFETY: None of the captures in `extra` have destructors that access 'tcx + // as they don't have destructors. + let info = unsafe { QueryStackDeferred::new(Arc::new(extra)) }; + + QueryStackFrame::new(info, kind, hash, def_id, def_id_for_ty_in_cycle) } pub(crate) fn encode_query_results<'a, 'tcx, Q>( @@ -688,7 +714,10 @@ macro_rules! define_queries { } } - pub(crate) fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) -> Option<()> { + pub(crate) fn try_collect_active_jobs<'tcx>( + tcx: TyCtxt<'tcx>, + qmap: &mut QueryMap>, + ) -> Option<()> { let make_query = |tcx, key| { let kind = rustc_middle::dep_graph::dep_kinds::$name; let name = stringify!($name); @@ -768,7 +797,9 @@ macro_rules! define_queries { // These arrays are used for iteration and can't be indexed by `DepKind`. - const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap) -> Option<()>] = + const TRY_COLLECT_ACTIVE_JOBS: &[ + for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap>) -> Option<()> + ] = &[$(query_impl::$name::try_collect_active_jobs),*]; const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[ diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 371b896400a5..e508eadb73b0 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -6,6 +6,7 @@ use std::hash::Hash; use rustc_data_structures::fingerprint::Fingerprint; use rustc_span::ErrorGuaranteed; +use super::QueryStackFrameExtra; use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; @@ -27,7 +28,7 @@ pub trait QueryConfig: Copy { fn format_value(self) -> fn(&Self::Value) -> String; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState + fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState where Qcx: 'a; @@ -57,7 +58,7 @@ pub trait QueryConfig: Copy { fn value_from_cycle_error( self, tcx: Qcx::DepContext, - cycle_error: &CycleError, + cycle_error: &CycleError, guar: ErrorGuaranteed, ) -> Self::Value; diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 402c78314729..de35cd79ea27 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::hash::Hash; use std::io::Write; use std::iter; @@ -12,6 +13,7 @@ use rustc_hir::def::DefKind; use rustc_session::Session; use rustc_span::{DUMMY_SP, Span}; +use super::QueryStackFrameExtra; use crate::dep_graph::DepContext; use crate::error::CycleStack; use crate::query::plumbing::CycleError; @@ -19,45 +21,54 @@ use crate::query::{QueryContext, QueryStackFrame}; /// Represents a span and a query key. #[derive(Clone, Debug)] -pub struct QueryInfo { +pub struct QueryInfo { /// The span corresponding to the reason for which this query was required. pub span: Span, - pub query: QueryStackFrame, + pub query: QueryStackFrame, } -pub type QueryMap = FxHashMap; +impl QueryInfo { + pub(crate) fn lift>( + &self, + qcx: Qcx, + ) -> QueryInfo { + QueryInfo { span: self.span, query: self.query.lift(qcx) } + } +} + +pub type QueryMap = FxHashMap>; /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct QueryJobId(pub NonZero); impl QueryJobId { - fn query(self, map: &QueryMap) -> QueryStackFrame { + fn query(self, map: &QueryMap) -> QueryStackFrame { map.get(&self).unwrap().query.clone() } - fn span(self, map: &QueryMap) -> Span { + fn span(self, map: &QueryMap) -> Span { map.get(&self).unwrap().job.span } - fn parent(self, map: &QueryMap) -> Option { + fn parent(self, map: &QueryMap) -> Option { map.get(&self).unwrap().job.parent } - fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { + fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { map.get(&self).unwrap().job.latch.as_ref() } } #[derive(Clone, Debug)] -pub struct QueryJobInfo { - pub query: QueryStackFrame, - pub job: QueryJob, +pub struct QueryJobInfo { + pub query: QueryStackFrame, + pub job: QueryJob, } /// Represents an active query job. -#[derive(Clone, Debug)] -pub struct QueryJob { +#[derive(Debug)] +pub struct QueryJob { pub id: QueryJobId, /// The span corresponding to the reason for which this query was required. @@ -67,17 +78,23 @@ pub struct QueryJob { pub parent: Option, /// The latch that is used to wait on this job. - latch: Option, + latch: Option>, } -impl QueryJob { +impl Clone for QueryJob { + fn clone(&self) -> Self { + Self { id: self.id, span: self.span, parent: self.parent, latch: self.latch.clone() } + } +} + +impl QueryJob { /// Creates a new query job. #[inline] pub fn new(id: QueryJobId, span: Span, parent: Option) -> Self { QueryJob { id, span, parent, latch: None } } - pub(super) fn latch(&mut self) -> QueryLatch { + pub(super) fn latch(&mut self) -> QueryLatch { if self.latch.is_none() { self.latch = Some(QueryLatch::new()); } @@ -97,12 +114,12 @@ impl QueryJob { } impl QueryJobId { - pub(super) fn find_cycle_in_stack( + pub(super) fn find_cycle_in_stack( &self, - query_map: QueryMap, + query_map: QueryMap, current_job: &Option, span: Span, - ) -> CycleError { + ) -> CycleError { // Find the waitee amongst `current_job` parents let mut cycle = Vec::new(); let mut current_job = Option::clone(current_job); @@ -136,7 +153,7 @@ impl QueryJobId { #[cold] #[inline(never)] - pub fn find_dep_kind_root(&self, query_map: QueryMap) -> (QueryJobInfo, usize) { + pub fn find_dep_kind_root(&self, query_map: QueryMap) -> (QueryJobInfo, usize) { let mut depth = 1; let info = query_map.get(&self).unwrap(); let dep_kind = info.query.dep_kind; @@ -156,25 +173,31 @@ impl QueryJobId { } #[derive(Debug)] -struct QueryWaiter { +struct QueryWaiter { query: Option, condvar: Condvar, span: Span, - cycle: Mutex>, + cycle: Mutex>>, } #[derive(Debug)] -struct QueryLatchInfo { +struct QueryLatchInfo { complete: bool, - waiters: Vec>, + waiters: Vec>>, } -#[derive(Clone, Debug)] -pub(super) struct QueryLatch { - info: Arc>, +#[derive(Debug)] +pub(super) struct QueryLatch { + info: Arc>>, } -impl QueryLatch { +impl Clone for QueryLatch { + fn clone(&self) -> Self { + Self { info: Arc::clone(&self.info) } + } +} + +impl QueryLatch { fn new() -> Self { QueryLatch { info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), @@ -182,7 +205,11 @@ impl QueryLatch { } /// Awaits for the query job to complete. - pub(super) fn wait_on(&self, query: Option, span: Span) -> Result<(), CycleError> { + pub(super) fn wait_on( + &self, + query: Option, + span: Span, + ) -> Result<(), CycleError> { let waiter = Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); self.wait_on_inner(&waiter); @@ -197,7 +224,7 @@ impl QueryLatch { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, waiter: &Arc) { + fn wait_on_inner(&self, waiter: &Arc>) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -232,7 +259,7 @@ impl QueryLatch { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. - fn extract_waiter(&self, waiter: usize) -> Arc { + fn extract_waiter(&self, waiter: usize) -> Arc> { let mut info = self.info.lock(); debug_assert!(!info.complete); // Remove the waiter from the list of waiters @@ -252,7 +279,11 @@ type Waiter = (QueryJobId, usize); /// For visits of resumable waiters it returns Some(Some(Waiter)) which has the /// required information to resume the waiter. /// If all `visit` calls returns None, this function also returns None. -fn visit_waiters(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option> +fn visit_waiters( + query_map: &QueryMap, + query: QueryJobId, + mut visit: F, +) -> Option> where F: FnMut(Span, QueryJobId) -> Option>, { @@ -282,8 +313,8 @@ where /// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. /// If a cycle is detected, this initial value is replaced with the span causing /// the cycle. -fn cycle_check( - query_map: &QueryMap, +fn cycle_check( + query_map: &QueryMap, query: QueryJobId, span: Span, stack: &mut Vec<(Span, QueryJobId)>, @@ -322,8 +353,8 @@ fn cycle_check( /// Finds out if there's a path to the compiler root (aka. code which isn't in a query) /// from `query` without going through any of the queries in `visited`. /// This is achieved with a depth first search. -fn connected_to_root( - query_map: &QueryMap, +fn connected_to_root( + query_map: &QueryMap, query: QueryJobId, visited: &mut FxHashSet, ) -> bool { @@ -344,7 +375,7 @@ fn connected_to_root( } // Deterministically pick an query from a list -fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T +fn pick_query<'a, I: Clone, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T where F: Fn(&T) -> (Span, QueryJobId), { @@ -369,10 +400,10 @@ where /// the function return true. /// If a cycle was not found, the starting query is removed from `jobs` and /// the function returns false. -fn remove_cycle( - query_map: &QueryMap, +fn remove_cycle( + query_map: &QueryMap, jobs: &mut Vec, - wakelist: &mut Vec>, + wakelist: &mut Vec>>, ) -> bool { let mut visited = FxHashSet::default(); let mut stack = Vec::new(); @@ -473,7 +504,10 @@ fn remove_cycle( /// uses a query latch and then resuming that waiter. /// There may be multiple cycles involved in a deadlock, so this searches /// all active queries for cycles before finally resuming all the waiters at once. -pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) { +pub fn break_query_cycles( + query_map: QueryMap, + registry: &rayon_core::Registry, +) { let mut wakelist = Vec::new(); let mut jobs: Vec = query_map.keys().cloned().collect(); @@ -520,7 +554,7 @@ pub fn report_cycle<'a>( ) -> Diag<'a> { assert!(!stack.is_empty()); - let span = stack[0].query.default_span(stack[1 % stack.len()].span); + let span = stack[0].query.info.default_span(stack[1 % stack.len()].span); let mut cycle_stack = Vec::new(); @@ -529,31 +563,31 @@ pub fn report_cycle<'a>( for i in 1..stack.len() { let query = &stack[i].query; - let span = query.default_span(stack[(i + 1) % stack.len()].span); - cycle_stack.push(CycleStack { span, desc: query.description.to_owned() }); + let span = query.info.default_span(stack[(i + 1) % stack.len()].span); + cycle_stack.push(CycleStack { span, desc: query.info.description.to_owned() }); } let mut cycle_usage = None; if let Some((span, ref query)) = *usage { cycle_usage = Some(crate::error::CycleUsage { - span: query.default_span(span), - usage: query.description.to_string(), + span: query.info.default_span(span), + usage: query.info.description.to_string(), }); } - let alias = if stack.iter().all(|entry| matches!(entry.query.def_kind, Some(DefKind::TyAlias))) - { - Some(crate::error::Alias::Ty) - } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) { - Some(crate::error::Alias::Trait) - } else { - None - }; + let alias = + if stack.iter().all(|entry| matches!(entry.query.info.def_kind, Some(DefKind::TyAlias))) { + Some(crate::error::Alias::Ty) + } else if stack.iter().all(|entry| entry.query.info.def_kind == Some(DefKind::TraitAlias)) { + Some(crate::error::Alias::Trait) + } else { + None + }; let cycle_diag = crate::error::Cycle { span, cycle_stack, - stack_bottom: stack[0].query.description.to_owned(), + stack_bottom: stack[0].query.info.description.to_owned(), alias, cycle_usage, stack_count, @@ -589,6 +623,7 @@ pub fn print_query_stack( let Some(query_info) = query_map.get(&query) else { break; }; + let query_extra = qcx.lift_query_info(&query_info.query.info); if Some(count_printed) < limit_frames || limit_frames.is_none() { // Only print to stderr as many stack frames as `num_frames` when present. // FIXME: needs translation @@ -596,7 +631,7 @@ pub fn print_query_stack( #[allow(rustc::untranslatable_diagnostic)] dcx.struct_failure_note(format!( "#{} [{:?}] {}", - count_printed, query_info.query.dep_kind, query_info.query.description + count_printed, query_info.query.dep_kind, query_extra.description )) .with_span(query_info.job.span) .emit(); @@ -609,7 +644,7 @@ pub fn print_query_stack( "#{} [{}] {}", count_total, qcx.dep_context().dep_kind_info(query_info.query.dep_kind).name, - query_info.query.description + query_extra.description ); } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 0d0c66aa978e..d9ee65328313 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -1,4 +1,9 @@ mod plumbing; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::mem::transmute; +use std::sync::Arc; + pub use self::plumbing::*; mod job; @@ -11,6 +16,7 @@ mod caches; pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; mod config; +use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::DiagInner; use rustc_hashes::Hash64; use rustc_hir::def::DefKind; @@ -25,31 +31,59 @@ use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIn /// /// This is mostly used in case of cycles for error reporting. #[derive(Clone, Debug)] -pub struct QueryStackFrame { - pub description: String, - span: Option, - pub def_id: Option, - pub def_kind: Option, - /// A def-id that is extracted from a `Ty` in a query key - pub def_id_for_ty_in_cycle: Option, +pub struct QueryStackFrame { + /// This field initially stores a `QueryStackDeferred` during collection, + /// but can later be changed to `QueryStackFrameExtra` containing concrete information + /// by calling `lift`. This is done so that collecting query does not need to invoke + /// queries, instead `lift` will call queries in a more appropriate location. + pub info: I, + pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. hash: Hash64, + pub def_id: Option, + /// A def-id that is extracted from a `Ty` in a query key + pub def_id_for_ty_in_cycle: Option, } -impl QueryStackFrame { +impl QueryStackFrame { #[inline] pub fn new( - description: String, - span: Option, - def_id: Option, - def_kind: Option, + info: I, dep_kind: DepKind, - def_id_for_ty_in_cycle: Option, hash: impl FnOnce() -> Hash64, + def_id: Option, + def_id_for_ty_in_cycle: Option, ) -> Self { - Self { description, span, def_id, def_kind, def_id_for_ty_in_cycle, dep_kind, hash: hash() } + Self { info, def_id, dep_kind, hash: hash(), def_id_for_ty_in_cycle } + } + + fn lift>( + &self, + qcx: Qcx, + ) -> QueryStackFrame { + QueryStackFrame { + info: qcx.lift_query_info(&self.info), + dep_kind: self.dep_kind, + hash: self.hash, + def_id: self.def_id, + def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle, + } + } +} + +#[derive(Clone, Debug)] +pub struct QueryStackFrameExtra { + pub description: String, + span: Option, + pub def_kind: Option, +} + +impl QueryStackFrameExtra { + #[inline] + pub fn new(description: String, span: Option, def_kind: Option) -> Self { + Self { description, span, def_kind } } // FIXME(eddyb) Get more valid `Span`s on queries. @@ -62,7 +96,37 @@ impl QueryStackFrame { } } -/// Track a 'side effects' for a particular query. +/// Track a 'side effect' for a particular query. +/// This is used to hold a closure which can create `QueryStackFrameExtra`. +#[derive(Clone)] +pub struct QueryStackDeferred<'tcx> { + _dummy: PhantomData<&'tcx ()>, + + // `extract` may contain references to 'tcx, but we can't tell drop checking that it won't + // access it in the destructor. + extract: Arc QueryStackFrameExtra + DynSync + DynSend>, +} + +impl<'tcx> QueryStackDeferred<'tcx> { + /// SAFETY: `extract` may not access 'tcx in its destructor. + pub unsafe fn new( + extract: Arc QueryStackFrameExtra + DynSync + DynSend + 'tcx>, + ) -> Self { + Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } } + } + + pub fn extract(&self) -> QueryStackFrameExtra { + (self.extract)() + } +} + +impl<'tcx> Debug for QueryStackDeferred<'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("QueryStackDeferred") + } +} + +/// Tracks 'side effects' for a particular query. /// This struct is saved to disk along with the query result, /// and loaded from disk if we mark the query as green. /// This allows us to 'replay' changes to global state @@ -81,12 +145,16 @@ pub enum QuerySideEffect { } pub trait QueryContext: HasDepContext { + type QueryInfo: Clone; + fn next_job_id(self) -> QueryJobId; /// Get the query information from the TLS context. fn current_query_job(self) -> Option; - fn collect_active_jobs(self) -> Result; + fn collect_active_jobs(self) -> Result, QueryMap>; + + fn lift_query_info(self, info: &Self::QueryInfo) -> QueryStackFrameExtra; /// Load a side effect associated to the node in the previous session. fn load_side_effect( diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3a9d80280c26..6ea8e3b92008 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -16,7 +16,7 @@ use rustc_errors::{Diag, FatalError, StashKey}; use rustc_span::{DUMMY_SP, Span}; use tracing::instrument; -use super::QueryConfig; +use super::{QueryConfig, QueryStackFrameExtra}; use crate::HandleCycleError; use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams}; use crate::ich::StableHashingContext; @@ -29,23 +29,23 @@ fn equivalent_key(k: &K) -> impl Fn(&(K, V)) -> bool + '_ { move |x| x.0 == *k } -pub struct QueryState { - active: Sharded>, +pub struct QueryState { + active: Sharded)>>, } /// Indicates the state of a query for a given key in a query map. -enum QueryResult { +enum QueryResult { /// An already executing query. The query job can be used to await for its completion. - Started(QueryJob), + Started(QueryJob), /// The query panicked. Queries trying to wait on this will raise a fatal error which will /// silently panic. Poisoned, } -impl QueryResult { +impl QueryResult { /// Unwraps the query job expecting that it has started. - fn expect_job(self) -> QueryJob { + fn expect_job(self) -> QueryJob { match self { Self::Started(job) => job, Self::Poisoned => { @@ -55,7 +55,7 @@ impl QueryResult { } } -impl QueryState +impl QueryState where K: Eq + Hash + Copy + Debug, { @@ -66,8 +66,8 @@ where pub fn try_collect_active_jobs( &self, qcx: Qcx, - make_query: fn(Qcx, K) -> QueryStackFrame, - jobs: &mut QueryMap, + make_query: fn(Qcx, K) -> QueryStackFrame, + jobs: &mut QueryMap, ) -> Option<()> { let mut active = Vec::new(); @@ -76,7 +76,7 @@ where for shard in self.active.try_lock_shards() { for (k, v) in shard?.iter() { if let QueryResult::Started(ref job) = *v { - active.push((*k, job.clone())); + active.push((*k, (*job).clone())); } } } @@ -92,19 +92,19 @@ where } } -impl Default for QueryState { - fn default() -> QueryState { +impl Default for QueryState { + fn default() -> QueryState { QueryState { active: Default::default() } } } /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -struct JobOwner<'tcx, K> +struct JobOwner<'tcx, K, I> where K: Eq + Hash + Copy, { - state: &'tcx QueryState, + state: &'tcx QueryState, key: K, } @@ -146,7 +146,7 @@ where } Stash => { let guar = if let Some(root) = cycle_error.cycle.first() - && let Some(span) = root.query.span + && let Some(span) = root.query.info.span { error.stash(span, StashKey::Cycle).unwrap() } else { @@ -157,7 +157,7 @@ where } } -impl<'tcx, K> JobOwner<'tcx, K> +impl<'tcx, K, I> JobOwner<'tcx, K, I> where K: Eq + Hash + Copy, { @@ -194,7 +194,7 @@ where } } -impl<'tcx, K> Drop for JobOwner<'tcx, K> +impl<'tcx, K, I> Drop for JobOwner<'tcx, K, I> where K: Eq + Hash + Copy, { @@ -222,10 +222,19 @@ where } #[derive(Clone, Debug)] -pub struct CycleError { +pub struct CycleError { /// The query and related span that uses the cycle. - pub usage: Option<(Span, QueryStackFrame)>, - pub cycle: Vec, + pub usage: Option<(Span, QueryStackFrame)>, + pub cycle: Vec>, +} + +impl CycleError { + fn lift>(&self, qcx: Qcx) -> CycleError { + CycleError { + usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift(qcx))), + cycle: self.cycle.iter().map(|info| info.lift(qcx)).collect(), + } + } } /// Checks whether there is already a value for this key in the in-memory @@ -262,10 +271,10 @@ where { // Ensure there was no errors collecting all active jobs. // We need the complete map to ensure we find a cycle to break. - let query_map = qcx.collect_active_jobs().expect("failed to collect active queries"); + let query_map = qcx.collect_active_jobs().ok().expect("failed to collect active queries"); let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span); - (mk_cycle(query, qcx, error), None) + (mk_cycle(query, qcx, error.lift(qcx)), None) } #[inline(always)] @@ -274,7 +283,7 @@ fn wait_for_query( qcx: Qcx, span: Span, key: Q::Key, - latch: QueryLatch, + latch: QueryLatch, current: Option, ) -> (Q::Value, Option) where @@ -314,7 +323,7 @@ where (v, Some(index)) } - Err(cycle) => (mk_cycle(query, qcx, cycle), None), + Err(cycle) => (mk_cycle(query, qcx, cycle.lift(qcx)), None), } } @@ -392,7 +401,7 @@ where fn execute_job( query: Q, qcx: Qcx, - state: &QueryState, + state: &QueryState, key: Q::Key, key_hash: u64, id: QueryJobId, From 781785d2b65f59295997272946be04182646bb39 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 26 Mar 2025 09:36:23 +0000 Subject: [PATCH 342/546] Don't deaggregate InvocationParent just to reaggregate it again --- compiler/rustc_resolve/src/def_collector.rs | 39 ++++++++------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index fcb638a117e3..6f48a75d6174 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -19,18 +19,15 @@ pub(crate) fn collect_definitions( fragment: &AstFragment, expansion: LocalExpnId, ) { - let InvocationParent { parent_def, impl_trait_context, in_attr } = - resolver.invocation_parents[&expansion]; - let mut visitor = DefCollector { resolver, parent_def, expansion, impl_trait_context, in_attr }; + let invocation_parent = resolver.invocation_parents[&expansion]; + let mut visitor = DefCollector { resolver, expansion, invocation_parent }; fragment.visit_with(&mut visitor); } /// Creates `DefId`s for nodes in the AST. struct DefCollector<'a, 'ra, 'tcx> { resolver: &'a mut Resolver<'ra, 'tcx>, - parent_def: LocalDefId, - impl_trait_context: ImplTraitContext, - in_attr: bool, + invocation_parent: InvocationParent, expansion: LocalExpnId, } @@ -42,7 +39,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { def_kind: DefKind, span: Span, ) -> LocalDefId { - let parent_def = self.parent_def; + let parent_def = self.invocation_parent.parent_def; debug!( "create_def(node_id={:?}, def_kind={:?}, parent_def={:?})", node_id, def_kind, parent_def @@ -60,9 +57,9 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { } fn with_parent(&mut self, parent_def: LocalDefId, f: F) { - let orig_parent_def = mem::replace(&mut self.parent_def, parent_def); + let orig_parent_def = mem::replace(&mut self.invocation_parent.parent_def, parent_def); f(self); - self.parent_def = orig_parent_def; + self.invocation_parent.parent_def = orig_parent_def; } fn with_impl_trait( @@ -70,9 +67,10 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { impl_trait_context: ImplTraitContext, f: F, ) { - let orig_itc = mem::replace(&mut self.impl_trait_context, impl_trait_context); + let orig_itc = + mem::replace(&mut self.invocation_parent.impl_trait_context, impl_trait_context); f(self); - self.impl_trait_context = orig_itc; + self.invocation_parent.impl_trait_context = orig_itc; } fn collect_field(&mut self, field: &'a FieldDef, index: Option) { @@ -96,14 +94,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { fn visit_macro_invoc(&mut self, id: NodeId) { let id = id.placeholder_to_expn_id(); - let old_parent = self.resolver.invocation_parents.insert( - id, - InvocationParent { - parent_def: self.parent_def, - impl_trait_context: self.impl_trait_context, - in_attr: self.in_attr, - }, - ); + let old_parent = self.resolver.invocation_parents.insert(id, self.invocation_parent); assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); } } @@ -367,7 +358,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { self.with_parent(def, |this| visit::walk_anon_const(this, constant)); return; } - _ => self.parent_def, + _ => self.invocation_parent.parent_def, }; self.with_parent(parent_def, |this| visit::walk_expr(this, expr)) @@ -382,13 +373,13 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // output or built artifacts, so replace them here... // Perhaps we should instead format APITs more robustly. let name = Symbol::intern(&pprust::ty_to_string(ty).replace('\n', " ")); - let kind = match self.impl_trait_context { + let kind = match self.invocation_parent.impl_trait_context { ImplTraitContext::Universal => DefKind::TyParam, ImplTraitContext::Existential => DefKind::OpaqueTy, ImplTraitContext::InBinding => return visit::walk_ty(self, ty), }; let id = self.create_def(*id, Some(name), kind, ty.span); - match self.impl_trait_context { + match self.invocation_parent.impl_trait_context { // Do not nest APIT, as we desugar them as `impl_trait: bounds`, // so the `impl_trait` node is not a parent to `bounds`. ImplTraitContext::Universal => visit::walk_ty(self, ty), @@ -459,9 +450,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_attribute(&mut self, attr: &'a Attribute) -> Self::Result { - let orig_in_attr = mem::replace(&mut self.in_attr, true); + let orig_in_attr = mem::replace(&mut self.invocation_parent.in_attr, true); visit::walk_attribute(self, attr); - self.in_attr = orig_in_attr; + self.invocation_parent.in_attr = orig_in_attr; } fn visit_inline_asm(&mut self, asm: &'a InlineAsm) { From b04e5b496323a8e0a7e4028bfb6252f348c10329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 26 Mar 2025 10:42:38 +0100 Subject: [PATCH 343/546] Collect items referenced from var_debug_info The collection is limited to full debuginfo builds to match behavior of FunctionCx::compute_per_local_var_debug_info. --- compiler/rustc_monomorphize/src/collector.rs | 7 +++++- tests/ui/mir/var_debug_ref.rs | 24 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/mir/var_debug_ref.rs diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 67fca1d7c294..ad9cec6fed90 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -231,7 +231,7 @@ use rustc_middle::ty::{ use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; use rustc_session::Limit; -use rustc_session::config::EntryFnType; +use rustc_session::config::{DebugInfo, EntryFnType}; use rustc_span::source_map::{Spanned, dummy_spanned, respan}; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; @@ -1235,6 +1235,11 @@ fn collect_items_of_instance<'tcx>( }; if mode == CollectionMode::UsedItems { + if tcx.sess.opts.debuginfo == DebugInfo::Full { + for var_debug_info in &body.var_debug_info { + collector.visit_var_debug_info(var_debug_info); + } + } for (bb, data) in traversal::mono_reachable(body, tcx, instance) { collector.visit_basic_block_data(bb, data) } diff --git a/tests/ui/mir/var_debug_ref.rs b/tests/ui/mir/var_debug_ref.rs new file mode 100644 index 000000000000..1dcf38b5bb9f --- /dev/null +++ b/tests/ui/mir/var_debug_ref.rs @@ -0,0 +1,24 @@ +// Regression test for #138942, where a function was incorrectly internalized, despite the fact +// that it was referenced by a var debug info from another code generation unit. +// +//@ build-pass +//@ revisions: limited full +//@ compile-flags: -Ccodegen-units=4 +//@[limited] compile-flags: -Cdebuginfo=limited +//@[full] compile-flags: -Cdebuginfo=full +trait Fun { + const FUN: &'static fn(); +} +impl Fun for () { + const FUN: &'static fn() = &(detail::f as fn()); +} +mod detail { + // Place `f` in a distinct module to generate a separate code generation unit. + #[inline(never)] + pub(super) fn f() {} +} +fn main() { + // SingleUseConsts represents "x" using VarDebugInfoContents::Const. + // It is the only reference to `f` remaining. + let x = <() as ::Fun>::FUN; +} From 6ca2af6434ec40ae91207628722fe6e731f6f358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 26 Mar 2025 13:04:06 +0100 Subject: [PATCH 344/546] Use a function to create `QueryStackDeferred` to ensure context is Copy --- compiler/rustc_query_impl/src/plumbing.rs | 74 +++++++++++--------- compiler/rustc_query_system/src/query/mod.rs | 10 ++- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 7f1d466b8692..3238c7a0912c 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -3,7 +3,6 @@ //! manage the caches, and so forth. use std::num::NonZero; -use std::sync::Arc; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{DynSend, DynSync}; @@ -312,6 +311,45 @@ macro_rules! should_ever_cache_on_disk { }; } +fn create_query_frame_extra<'tcx, K: Key + Copy + 'tcx>( + (tcx, key, kind, name, do_describe): ( + TyCtxt<'tcx>, + K, + DepKind, + &'static str, + fn(TyCtxt<'tcx>, K) -> String, + ), +) -> QueryStackFrameExtra { + let def_id = key.key_as_def_id(); + + // If reduced queries are requested, we may be printing a query stack due + // to a panic. Avoid using `default_span` and `def_kind` in that case. + let reduce_queries = with_reduced_queries(); + + // Avoid calling queries while formatting the description + let description = ty::print::with_no_queries!(do_describe(tcx, key)); + let description = if tcx.sess.verbose_internals() { + format!("{description} [{name:?}]") + } else { + description + }; + let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries { + // The `def_span` query is used to calculate `default_span`, + // so exit to avoid infinite recursion. + None + } else { + Some(key.default_span(tcx)) + }; + + let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries { + // Try to avoid infinite recursion. + None + } else { + def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) + }; + QueryStackFrameExtra::new(description, span, def_kind) +} + pub(crate) fn create_query_frame< 'tcx, K: Copy + DynSend + DynSync + Key + for<'a> HashStable> + 'tcx, @@ -324,35 +362,6 @@ pub(crate) fn create_query_frame< ) -> QueryStackFrame> { let def_id = key.key_as_def_id(); - let extra = move || { - // If reduced queries are requested, we may be printing a query stack due - // to a panic. Avoid using `default_span` and `def_kind` in that case. - let reduce_queries = with_reduced_queries(); - - // Avoid calling queries while formatting the description - let description = ty::print::with_no_queries!(do_describe(tcx, key)); - let description = if tcx.sess.verbose_internals() { - format!("{description} [{name:?}]") - } else { - description - }; - let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries { - // The `def_span` query is used to calculate `default_span`, - // so exit to avoid infinite recursion. - None - } else { - Some(key.default_span(tcx)) - }; - - let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries { - // Try to avoid infinite recursion. - None - } else { - def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) - }; - QueryStackFrameExtra::new(description, span, def_kind) - }; - let hash = || { tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); @@ -363,9 +372,8 @@ pub(crate) fn create_query_frame< }; let def_id_for_ty_in_cycle = key.def_id_for_ty_in_cycle(); - // SAFETY: None of the captures in `extra` have destructors that access 'tcx - // as they don't have destructors. - let info = unsafe { QueryStackDeferred::new(Arc::new(extra)) }; + let info = + QueryStackDeferred::new((tcx, key, kind, name, do_describe), create_query_frame_extra); QueryStackFrame::new(info, kind, hash, def_id, def_id_for_ty_in_cycle) } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index d9ee65328313..ef21af7dafba 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -108,10 +108,14 @@ pub struct QueryStackDeferred<'tcx> { } impl<'tcx> QueryStackDeferred<'tcx> { - /// SAFETY: `extract` may not access 'tcx in its destructor. - pub unsafe fn new( - extract: Arc QueryStackFrameExtra + DynSync + DynSend + 'tcx>, + pub fn new( + context: C, + extract: fn(C) -> QueryStackFrameExtra, ) -> Self { + let extract: Arc QueryStackFrameExtra + DynSync + DynSend + 'tcx> = + Arc::new(move || extract(context)); + // SAFETY: The `extract` closure does not access 'tcx in its destructor as the only + // captured variable is `context` which is Copy and cannot have a destructor. Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } } } From 92d802eda669d69481b99139523008df1c456ba8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 22 Mar 2025 21:42:34 +0300 Subject: [PATCH 345/546] expand: Leave traces when expanding `cfg` attributes --- .../rustc_ast_passes/src/ast_validation.rs | 3 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_expand/src/config.rs | 24 ++++++----- compiler/rustc_expand/src/expand.rs | 13 +++--- compiler/rustc_feature/src/builtin_attrs.rs | 12 ++++-- compiler/rustc_parse/src/validate_attr.rs | 9 ++--- compiler/rustc_passes/src/check_attr.rs | 6 +-- compiler/rustc_query_system/src/ich/mod.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- .../src/attrs/duplicated_attributes.rs | 3 +- .../clippy/clippy_lints/src/cfg_not_test.rs | 2 +- .../clippy_lints/src/methods/is_empty.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 8 ++-- tests/pretty/tests-are-sorted.pp | 3 -- .../cfg-attr-syntax-validation.rs | 1 - .../cfg-attr-syntax-validation.stderr | 14 +------ .../invalid-node-range-issue-129166.rs | 3 +- .../invalid-node-range-issue-129166.stderr | 8 ---- tests/ui/parser/attribute/attr-bad-meta-4.rs | 2 - .../parser/attribute/attr-bad-meta-4.stderr | 24 +---------- tests/ui/proc-macro/cfg-attr-trace.rs | 10 ++++- tests/ui/proc-macro/cfg-attr-trace.stdout | 40 +++++++++++++------ 24 files changed, 88 insertions(+), 108 deletions(-) delete mode 100644 tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index a1487ca74be8..da739b0e4532 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -334,8 +334,7 @@ impl<'a> AstValidator<'a> { .filter(|attr| { let arr = [ sym::allow, - sym::cfg, - sym::cfg_attr, + sym::cfg_trace, sym::cfg_attr_trace, sym::deny, sym::expect, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index cdb181794498..3dbfc191f8f5 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -593,7 +593,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) -> bool { - if attr.has_name(sym::cfg_attr_trace) { + if attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) { // It's not a valid identifier, so avoid printing it // to keep the printed code reasonably parse-able. return false; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index ada49eef7b2d..bcc2703c39b3 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -156,6 +156,19 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec .collect() } +pub(crate) fn attr_into_trace(mut attr: Attribute, trace_name: Symbol) -> Attribute { + match &mut attr.kind { + AttrKind::Normal(normal) => { + let NormalAttr { item, tokens } = &mut **normal; + item.path.segments[0].ident.name = trace_name; + // This makes the trace attributes unobservable to token-based proc macros. + *tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::default())); + } + AttrKind::DocComment(..) => unreachable!(), + } + attr +} + #[macro_export] macro_rules! configure { ($this:ident, $node:ident) => { @@ -280,16 +293,7 @@ impl<'a> StripUnconfigured<'a> { // A trace attribute left in AST in place of the original `cfg_attr` attribute. // It can later be used by lints or other diagnostics. - let mut trace_attr = cfg_attr.clone(); - match &mut trace_attr.kind { - AttrKind::Normal(normal) => { - let NormalAttr { item, tokens } = &mut **normal; - item.path.segments[0].ident.name = sym::cfg_attr_trace; - // This makes the trace attributes unobservable to token-based proc macros. - *tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::default())); - } - AttrKind::DocComment(..) => unreachable!(), - } + let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace); let Some((cfg_predicate, expanded_attrs)) = rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index d0bd8a89d9bd..22da1179feb9 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -33,7 +33,7 @@ use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, sym}; use smallvec::SmallVec; use crate::base::*; -use crate::config::StripUnconfigured; +use crate::config::{StripUnconfigured, attr_into_trace}; use crate::errors::{ EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, @@ -2003,7 +2003,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let attr_name = attr.ident().unwrap().name; // `#[cfg]` and `#[cfg_attr]` are special - they are // eagerly evaluated. - if attr_name != sym::cfg && attr_name != sym::cfg_attr_trace { + if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace { self.cx.sess.psess.buffer_lint( UNUSED_ATTRIBUTES, attr.span, @@ -2027,11 +2027,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ) -> (bool, Option) { let (res, meta_item) = self.cfg().cfg_true(&attr); if res { - // FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion, - // and some tools like rustdoc and clippy rely on that. Find a way to remove them - // while keeping the tools working. - self.cx.expanded_inert_attrs.mark(&attr); - node.visit_attrs(|attrs| attrs.insert(pos, attr)); + // A trace attribute left in AST in place of the original `cfg` attribute. + // It can later be used by lints or other diagnostics. + let trace_attr = attr_into_trace(attr, sym::cfg_trace); + node.visit_attrs(|attrs| attrs.insert(pos, trace_attr)); } (res, meta_item) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index fd936458f111..6fe65c88f712 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -760,10 +760,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(Word, List: r#""...""#), DuplicatesOk, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), - // Trace that is left when a `cfg_attr` attribute is expanded. - // The attribute is not gated, to avoid stability errors, but it cannot be used in stable or - // unstable code directly because `sym::cfg_attr_trace` is not a valid identifier, it can only - // be generated by the compiler. + // Traces that are left when `cfg` and `cfg_attr` attributes are expanded. + // The attributes are not gated, to avoid stability errors, but they cannot be used in stable + // or unstable code directly because `sym::cfg_(attr_)trace` are not valid identifiers, they + // can only be generated by the compiler. + ungated!( + cfg_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk, + EncodeCrossCrate::No + ), ungated!( cfg_attr_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk, EncodeCrossCrate::No diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 9ecde2a9eb50..6bbd650dcdfe 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -16,7 +16,8 @@ use rustc_span::{Span, Symbol, sym}; use crate::{errors, parse_in}; pub fn check_attr(psess: &ParseSess, attr: &Attribute) { - if attr.is_doc_comment() || attr.has_name(sym::cfg_attr_trace) { + if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) + { return; } @@ -215,11 +216,7 @@ pub fn check_builtin_meta_item( template: AttributeTemplate, deny_unsafety: bool, ) { - // Some special attributes like `cfg` must be checked - // before the generic check, so we skip them here. - let should_skip = |name| name == sym::cfg; - - if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { + if !is_attr_template_compatible(&template, &meta.kind) { emit_malformed_attribute(psess, style, meta.span, name, template); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9238c73cdb11..1e1fb42a48fe 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -272,6 +272,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::forbid | sym::cfg | sym::cfg_attr + | sym::cfg_trace | sym::cfg_attr_trace // need to be fixed | sym::cfi_encoding // FIXME(cfi_encoding) @@ -574,8 +575,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate const ALLOW_LIST: &[rustc_span::Symbol] = &[ // conditional compilation - sym::cfg, - sym::cfg_attr, + sym::cfg_trace, sym::cfg_attr_trace, // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`) sym::test, @@ -2656,7 +2656,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`) // in where clauses. After that, only `self.check_attributes` should be enough. - const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg, sym::cfg_attr, sym::cfg_attr_trace]; + const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg_trace, sym::cfg_attr_trace]; let spans = self .tcx .hir_attrs(where_predicate.hir_id) diff --git a/compiler/rustc_query_system/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs index 852d93b711f8..25778add60a9 100644 --- a/compiler/rustc_query_system/src/ich/mod.rs +++ b/compiler/rustc_query_system/src/ich/mod.rs @@ -8,7 +8,7 @@ mod hcx; mod impls_syntax; pub const IGNORED_ATTRIBUTES: &[Symbol] = &[ - sym::cfg, + sym::cfg_trace, // FIXME should this really be ignored? sym::rustc_if_this_changed, sym::rustc_then_this_would_need, sym::rustc_dirty, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3e4742439655..171f553e9c1a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -623,6 +623,7 @@ symbols! { cfg_target_has_atomic_equal_alignment, cfg_target_thread_local, cfg_target_vendor, + cfg_trace: "", // must not be a valid identifier cfg_ub_checks, cfg_version, cfi, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index de6dc088176f..6f660df4d7d4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2773,7 +2773,7 @@ fn add_without_unwanted_attributes<'hir>( if ident == sym::doc { filter_doc_attr(&mut normal.args, is_inline); attrs.push((Cow::Owned(attr), import_parent)); - } else if is_inline || ident != sym::cfg { + } else if is_inline || ident != sym::cfg_trace { // If it's not a `cfg()` attribute, we keep it. attrs.push((Cow::Owned(attr), import_parent)); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 27eb56a9858b..150b00dbb48a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1059,7 +1059,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator // `doc(cfg())` overrides `cfg()`). attrs .clone() - .filter(|attr| attr.has_name(sym::cfg)) + .filter(|attr| attr.has_name(sym::cfg_trace)) .filter_map(|attr| single(attr.meta_item_list()?)) .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index 5c486eb90cc2..4c84e61b1f26 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -37,7 +37,6 @@ fn check_duplicated_attr( let Some(ident) = attr.ident() else { return }; let name = ident.name; if name == sym::doc - || name == sym::cfg_attr || name == sym::cfg_attr_trace || name == sym::rustc_on_unimplemented || name == sym::reason { @@ -47,7 +46,7 @@ fn check_duplicated_attr( return; } if let Some(direct_parent) = parent.last() - && ["cfg", "cfg_attr"].contains(&direct_parent.as_str()) + && direct_parent == sym::cfg_trace.as_str() && [sym::all, sym::not, sym::any].contains(&name) { // FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs index 84136a2e6c28..7590fe96fd21 100644 --- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -32,7 +32,7 @@ declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); impl EarlyLintPass for CfgNotTest { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { - if attr.has_name(rustc_span::sym::cfg) && contains_not_test(attr.meta_item_list().as_deref(), false) { + if attr.has_name(rustc_span::sym::cfg_trace) && contains_not_test(attr.meta_item_list().as_deref(), false) { span_lint_and_then( cx, CFG_NOT_TEST, diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs index 7c190e123b72..4c81b22861b4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx .hir_parent_id_iter(id) - .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg))) + .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg_trace))) } /// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 1307ff79bc5d..668b0cb69e20 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2629,7 +2629,7 @@ pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir> pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { if let Res::Def(_, def_id) = path.res { - return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr); + return cx.tcx.has_attr(def_id, sym::cfg_trace) || cx.tcx.has_attr(def_id, sym::cfg_attr); } } false @@ -2699,7 +2699,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool { /// use [`is_in_cfg_test`] pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { tcx.hir_attrs(id).iter().any(|attr| { - if attr.has_name(sym::cfg) + if attr.has_name(sym::cfg_trace) && let Some(items) = attr.meta_item_list() && let [item] = &*items && item.has_name(sym::test) @@ -2723,11 +2723,11 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.has_attr(def_id, sym::cfg) + tcx.has_attr(def_id, sym::cfg_trace) || tcx .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id)) .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)) - .any(|attr| attr.has_name(sym::cfg)) + .any(|attr| attr.has_name(sym::cfg_trace)) } /// Walks up the HIR tree from the given expression in an attempt to find where the value is diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp index 31449b51dc3e..d6a2c0ff9796 100644 --- a/tests/pretty/tests-are-sorted.pp +++ b/tests/pretty/tests-are-sorted.pp @@ -10,7 +10,6 @@ extern crate std; //@ pp-exact:tests-are-sorted.pp extern crate test; -#[cfg(test)] #[rustc_test_marker = "m_test"] #[doc(hidden)] pub const m_test: test::TestDescAndFn = @@ -35,7 +34,6 @@ pub const m_test: test::TestDescAndFn = fn m_test() {} extern crate test; -#[cfg(test)] #[rustc_test_marker = "z_test"] #[doc(hidden)] pub const z_test: test::TestDescAndFn = @@ -61,7 +59,6 @@ pub const z_test: test::TestDescAndFn = fn z_test() {} extern crate test; -#[cfg(test)] #[rustc_test_marker = "a_test"] #[doc(hidden)] pub const a_test: test::TestDescAndFn = diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 9a041557c7cc..416145a0c156 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -29,7 +29,6 @@ macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] //~^ ERROR expected unsuffixed literal, found expression `concat!("nonexistent")` - //~| ERROR expected unsuffixed literal, found expression `concat!("nonexistent")` struct S10; } } diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 21a3712d9391..d02d0d70a8bc 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -65,19 +65,7 @@ LL | generate_s10!(concat!("nonexistent")); | = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal, found expression `concat!("nonexistent")` - --> $DIR/cfg-attr-syntax-validation.rs:30:25 - | -LL | #[cfg(feature = $expr)] - | ^^^^^ -... -LL | generate_s10!(concat!("nonexistent")); - | ------------------------------------- in this macro invocation - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0537, E0565. For more information about an error, try `rustc --explain E0537`. diff --git a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs index 794e6fad3fc2..7c42be3ed4d6 100644 --- a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs +++ b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs @@ -1,11 +1,12 @@ // This was triggering an assertion failure in `NodeRange::new`. +//@ check-pass + #![feature(cfg_eval)] #![feature(stmt_expr_attributes)] fn f() -> u32 { #[cfg_eval] #[cfg(not(FALSE))] 0 - //~^ ERROR removing an expression is not supported in this position } fn main() {} diff --git a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr deleted file mode 100644 index 0699e182bd5f..000000000000 --- a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: removing an expression is not supported in this position - --> $DIR/invalid-node-range-issue-129166.rs:7:17 - | -LL | #[cfg_eval] #[cfg(not(FALSE))] 0 - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs index 2d0c6dbb50ab..937390a6da5b 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs @@ -2,7 +2,6 @@ macro_rules! mac { ($attr_item: meta) => { #[cfg($attr_item)] //~^ ERROR expected unsuffixed literal, found `meta` metavariable - //~| ERROR expected unsuffixed literal, found `meta` metavariable struct S; } } @@ -11,7 +10,6 @@ mac!(an(arbitrary token stream)); #[cfg(feature = -1)] //~^ ERROR expected unsuffixed literal, found `-` -//~| ERROR expected unsuffixed literal, found `-` fn handler() {} fn main() {} diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr index dea574fd36d5..9c6ab5adadf7 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr @@ -1,5 +1,5 @@ error: expected unsuffixed literal, found `-` - --> $DIR/attr-bad-meta-4.rs:12:17 + --> $DIR/attr-bad-meta-4.rs:11:17 | LL | #[cfg(feature = -1)] | ^ @@ -15,25 +15,5 @@ LL | mac!(an(arbitrary token stream)); | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal, found `meta` metavariable - --> $DIR/attr-bad-meta-4.rs:3:15 - | -LL | #[cfg($attr_item)] - | ^^^^^^^^^^ -... -LL | mac!(an(arbitrary token stream)); - | -------------------------------- in this macro invocation - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: expected unsuffixed literal, found `-` - --> $DIR/attr-bad-meta-4.rs:12:17 - | -LL | #[cfg(feature = -1)] - | ^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/proc-macro/cfg-attr-trace.rs b/tests/ui/proc-macro/cfg-attr-trace.rs index b4927f7a730b..140dd10a7e04 100644 --- a/tests/ui/proc-macro/cfg-attr-trace.rs +++ b/tests/ui/proc-macro/cfg-attr-trace.rs @@ -3,6 +3,7 @@ //@ check-pass //@ proc-macro: test-macros.rs +#![feature(cfg_boolean_literals)] #![feature(cfg_eval)] #[macro_use] @@ -10,8 +11,13 @@ extern crate test_macros; #[cfg_eval] #[test_macros::print_attr] -#[cfg_attr(FALSE, test_macros::print_attr)] -#[cfg_attr(all(), test_macros::print_attr)] +#[cfg_attr(false, test_macros::print_attr)] +#[cfg_attr(true, test_macros::print_attr)] struct S; +#[cfg_eval] +#[test_macros::print_attr] +#[cfg(true)] +struct Z; + fn main() {} diff --git a/tests/ui/proc-macro/cfg-attr-trace.stdout b/tests/ui/proc-macro/cfg-attr-trace.stdout index 394c3887fe79..52f9ff4e05c5 100644 --- a/tests/ui/proc-macro/cfg-attr-trace.stdout +++ b/tests/ui/proc-macro/cfg-attr-trace.stdout @@ -4,59 +4,75 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: #0 bytes(271..272), + span: #0 bytes(305..306), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "test_macros", - span: #0 bytes(289..300), + span: #0 bytes(322..333), }, Punct { ch: ':', spacing: Joint, - span: #0 bytes(300..301), + span: #0 bytes(333..334), }, Punct { ch: ':', spacing: Alone, - span: #0 bytes(301..302), + span: #0 bytes(334..335), }, Ident { ident: "print_attr", - span: #0 bytes(302..312), + span: #0 bytes(335..345), }, ], - span: #0 bytes(272..314), + span: #0 bytes(306..347), }, Ident { ident: "struct", - span: #0 bytes(315..321), + span: #0 bytes(348..354), }, Ident { ident: "S", - span: #0 bytes(322..323), + span: #0 bytes(355..356), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(323..324), + span: #0 bytes(356..357), }, ] PRINT-ATTR INPUT (DISPLAY): struct S; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #0 bytes(315..321), + span: #0 bytes(348..354), }, Ident { ident: "S", - span: #0 bytes(322..323), + span: #0 bytes(355..356), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(323..324), + span: #0 bytes(356..357), + }, +] +PRINT-ATTR INPUT (DISPLAY): struct Z; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "struct", + span: #0 bytes(411..417), + }, + Ident { + ident: "Z", + span: #0 bytes(418..419), + }, + Punct { + ch: ';', + spacing: Alone, + span: #0 bytes(419..420), }, ] From a830c59f242c2e55da8a69cf5807c450b4a12a33 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 26 Mar 2025 12:39:07 +0000 Subject: [PATCH 346/546] Use the correct binder scope for elided lifetimes in assoc consts --- compiler/rustc_resolve/src/late.rs | 60 +++++++++++-------- .../consts/assoc-const-elided-lifetime.stderr | 2 - .../elided-lifetime.rs | 2 +- .../elided-lifetime.stderr | 20 +++---- .../static-trait-impl.rs | 2 +- .../static-trait-impl.stderr | 24 +++----- 6 files changed, 51 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 11d07407aa18..f4502bcee737 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3334,34 +3334,44 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, |this| { this.with_lifetime_rib( - LifetimeRibKind::StaticIfNoLifetimeInScope { - lint_id: item.id, - // In impls, it's not a hard error yet due to backcompat. - emit_lint: true, + // Until these are a hard error, we need to create them within the correct binder, + // Otherwise the lifetimes of this assoc const think they are lifetimes of the trait. + LifetimeRibKind::AnonymousCreateParameter { + binder: item.id, + report_in_path: true, }, |this| { - // If this is a trait impl, ensure the const - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - seen_trait_items, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); + this.with_lifetime_rib( + LifetimeRibKind::StaticIfNoLifetimeInScope { + lint_id: item.id, + // In impls, it's not a hard error yet due to backcompat. + emit_lint: true, + }, + |this| { + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + seen_trait_items, + |i, s, c| ConstNotMemberOfTrait(i, s, c), + ); - this.visit_generics(generics); - this.visit_ty(ty); - if let Some(expr) = expr { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); - } + this.visit_generics(generics); + this.visit_ty(ty); + if let Some(expr) = expr { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.resolve_const_body(expr, None); + } + }, + ) }, ); }, diff --git a/tests/ui/consts/assoc-const-elided-lifetime.stderr b/tests/ui/consts/assoc-const-elided-lifetime.stderr index 0c3e455eb2de..958215268357 100644 --- a/tests/ui/consts/assoc-const-elided-lifetime.stderr +++ b/tests/ui/consts/assoc-const-elided-lifetime.stderr @@ -35,8 +35,6 @@ note: cannot automatically infer `'static` because of other lifetimes in scope | LL | impl<'a> Foo<'a> { | ^^ -LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> }; - | ^^ help: use the `'static` lifetime | LL | const BAR: &'static () = &(); diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.rs b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs index 95d59f9b894e..ccf63f86fcf3 100644 --- a/tests/ui/consts/static-default-lifetime/elided-lifetime.rs +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs @@ -16,7 +16,7 @@ impl Bar for Foo<'_> { const STATIC: &str = ""; //~^ ERROR `&` without an explicit lifetime name cannot be used here //~| WARN this was previously accepted by the compiler but is being phased out - //~| ERROR const not compatible with trait + //~| ERROR lifetime parameters or bounds on const `STATIC` do not match the trait declaration } fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr index ec01225c6bfa..33873f5c5a50 100644 --- a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr @@ -39,21 +39,15 @@ help: use the `'static` lifetime LL | const STATIC: &'static str = ""; | +++++++ -error[E0308]: const not compatible with trait - --> $DIR/elided-lifetime.rs:16:5 +error[E0195]: lifetime parameters or bounds on const `STATIC` do not match the trait declaration + --> $DIR/elided-lifetime.rs:16:17 | +LL | const STATIC: &str; + | - lifetimes in impl do not match this const in trait +... LL | const STATIC: &str = ""; - | ^^^^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected reference `&'static _` - found reference `&_` -note: the anonymous lifetime as defined here... - --> $DIR/elided-lifetime.rs:16:19 - | -LL | const STATIC: &str = ""; - | ^ - = note: ...does not necessarily outlive the static lifetime + | ^ lifetimes do not match const in trait error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0195`. diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.rs b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs index 025fda4df581..b50bf01453dc 100644 --- a/tests/ui/consts/static-default-lifetime/static-trait-impl.rs +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs @@ -9,7 +9,7 @@ impl Bar<'_> for A { const STATIC: &str = ""; //~^ ERROR `&` without an explicit lifetime name cannot be used here //~| WARN this was previously accepted by the compiler but is being phased out - //~| ERROR const not compatible with trait + //~| ERROR lifetime parameters or bounds on const `STATIC` do not match the trait declaration } struct B; diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr index b8e2f412b492..116f28e84847 100644 --- a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr @@ -21,25 +21,15 @@ help: use the `'static` lifetime LL | const STATIC: &'static str = ""; | +++++++ -error[E0308]: const not compatible with trait - --> $DIR/static-trait-impl.rs:9:5 +error[E0195]: lifetime parameters or bounds on const `STATIC` do not match the trait declaration + --> $DIR/static-trait-impl.rs:9:17 | +LL | const STATIC: &'a str; + | - lifetimes in impl do not match this const in trait +... LL | const STATIC: &str = ""; - | ^^^^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected reference `&_` - found reference `&_` -note: the anonymous lifetime as defined here... - --> $DIR/static-trait-impl.rs:9:19 - | -LL | const STATIC: &str = ""; - | ^ -note: ...does not necessarily outlive the anonymous lifetime as defined here - --> $DIR/static-trait-impl.rs:8:10 - | -LL | impl Bar<'_> for A { - | ^^ + | ^ lifetimes do not match const in trait error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0195`. From c772573708cdc863d9fa03ca4973f9ab08ac9d43 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 16 Nov 2024 18:50:44 +0100 Subject: [PATCH 347/546] Test that env! works with incremental compilation This currently works because it's part of expansion, and that isn't yet tracked by the query system. But we want to ensure it continues working, even if that is changed. --- tests/incremental/env/env_macro.rs | 18 ++++++++++++++++++ tests/incremental/env/option_env_macro.rs | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/incremental/env/env_macro.rs create mode 100644 tests/incremental/env/option_env_macro.rs diff --git a/tests/incremental/env/env_macro.rs b/tests/incremental/env/env_macro.rs new file mode 100644 index 000000000000..0c026328874d --- /dev/null +++ b/tests/incremental/env/env_macro.rs @@ -0,0 +1,18 @@ +// Check that changes to environment variables are propagated to `env!`. +// +// This test is intentionally written to not use any `#[cfg(rpass*)]`, to +// _really_ test that we re-compile if the environment variable changes. + +//@ revisions: cfail1 rpass2 rpass3 cfail4 +//@ [cfail1]unset-rustc-env:EXAMPLE_ENV +//@ [rpass2]rustc-env:EXAMPLE_ENV=one +//@ [rpass2]exec-env:EXAMPLE_ENV=one +//@ [rpass3]rustc-env:EXAMPLE_ENV=two +//@ [rpass3]exec-env:EXAMPLE_ENV=two +//@ [cfail4]unset-rustc-env:EXAMPLE_ENV + +fn main() { + assert_eq!(env!("EXAMPLE_ENV"), std::env::var("EXAMPLE_ENV").unwrap()); + //[cfail1]~^ ERROR environment variable `EXAMPLE_ENV` not defined at compile time + //[cfail4]~^^ ERROR environment variable `EXAMPLE_ENV` not defined at compile time +} diff --git a/tests/incremental/env/option_env_macro.rs b/tests/incremental/env/option_env_macro.rs new file mode 100644 index 000000000000..44c3bfd69e05 --- /dev/null +++ b/tests/incremental/env/option_env_macro.rs @@ -0,0 +1,18 @@ +// Check that changes to environment variables are propagated to `option_env!`. +// +// This test is intentionally written to not use any `#[cfg(rpass*)]`, to +// _really_ test that we re-compile if the environment variable changes. + +//@ revisions: rpass1 rpass2 rpass3 rpass4 +//@ [rpass1]unset-rustc-env:EXAMPLE_ENV +//@ [rpass1]unset-exec-env:EXAMPLE_ENV +//@ [rpass2]rustc-env:EXAMPLE_ENV=one +//@ [rpass2]exec-env:EXAMPLE_ENV=one +//@ [rpass3]rustc-env:EXAMPLE_ENV=two +//@ [rpass3]exec-env:EXAMPLE_ENV=two +//@ [rpass4]unset-rustc-env:EXAMPLE_ENV +//@ [rpass4]unset-exec-env:EXAMPLE_ENV + +fn main() { + assert_eq!(option_env!("EXAMPLE_ENV"), std::env::var("EXAMPLE_ENV").ok().as_deref()); +} From 17db054141f909277a0c57b4698f420636a2c511 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 26 Mar 2025 15:46:05 +0100 Subject: [PATCH 348/546] Add `TyCtx::env_var_os` Along with `TyCtx::env_var` helper. These can be used to track environment variable accesses in the query system. Since `TyCtx::env_var_os` uses `OsStr`, this commit also adds the necessary trait implementations for that to work. --- .../src/stable_hasher.rs | 2 ++ compiler/rustc_interface/src/passes.rs | 28 ++++++++++++++++++- compiler/rustc_middle/src/query/erase.rs | 9 ++++++ compiler/rustc_middle/src/query/keys.rs | 10 +++++++ compiler/rustc_middle/src/query/mod.rs | 16 +++++++++++ compiler/rustc_middle/src/ty/context.rs | 11 ++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index ffbe54d62061..3a64c924cc22 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -564,6 +564,8 @@ where } } +impl_stable_traits_for_trivial_type!(::std::ffi::OsStr); + impl_stable_traits_for_trivial_type!(::std::path::Path); impl_stable_traits_for_trivial_type!(::std::path::PathBuf); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8be7ba7455e1..2440f0639c8a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1,5 +1,5 @@ use std::any::Any; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::io::{self, BufWriter, Write}; use std::path::{Path, PathBuf}; use std::sync::{Arc, LazyLock, OnceLock}; @@ -361,6 +361,31 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { ) } +fn env_var_os<'tcx>(tcx: TyCtxt<'tcx>, key: &'tcx OsStr) -> Option<&'tcx OsStr> { + let value = env::var_os(key); + + let value_tcx = value.as_ref().map(|value| { + let encoded_bytes = tcx.arena.alloc_slice(value.as_encoded_bytes()); + debug_assert_eq!(value.as_encoded_bytes(), encoded_bytes); + // SAFETY: The bytes came from `as_encoded_bytes`, and we assume that + // `alloc_slice` is implemented correctly, and passes the same bytes + // back (debug asserted above). + unsafe { OsStr::from_encoded_bytes_unchecked(encoded_bytes) } + }); + + // Also add the variable to Cargo's dependency tracking + // + // NOTE: This only works for passes run before `write_dep_info`. See that + // for extension points for configuring environment variables to be + // properly change-tracked. + tcx.sess.psess.env_depinfo.borrow_mut().insert(( + Symbol::intern(&key.to_string_lossy()), + value.as_ref().and_then(|value| value.to_str()).map(|value| Symbol::intern(&value)), + )); + + value_tcx +} + // Returns all the paths that correspond to generated files. fn generated_output_paths( tcx: TyCtxt<'_>, @@ -725,6 +750,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { |tcx, _| tcx.arena.alloc_from_iter(tcx.resolutions(()).stripped_cfg_items.steal()); providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1; providers.early_lint_checks = early_lint_checks; + providers.env_var_os = env_var_os; limits::provide(providers); proc_macro_decls::provide(providers); rustc_const_eval::provide(providers); diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 7bbaa0496d53..6c6b9a5510c6 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -1,3 +1,4 @@ +use std::ffi::OsStr; use std::intrinsics::transmute_unchecked; use std::mem::MaybeUninit; @@ -67,6 +68,10 @@ impl EraseType for &'_ [T] { type Result = [u8; size_of::<&'static [()]>()]; } +impl EraseType for &'_ OsStr { + type Result = [u8; size_of::<&'static OsStr>()]; +} + impl EraseType for &'_ ty::List { type Result = [u8; size_of::<&'static ty::List<()>>()]; } @@ -174,6 +179,10 @@ impl EraseType for Option<&'_ [T]> { type Result = [u8; size_of::>()]; } +impl EraseType for Option<&'_ OsStr> { + type Result = [u8; size_of::>()]; +} + impl EraseType for Option> { type Result = [u8; size_of::>>()]; } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 98314b5abfda..c382bcd726ff 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -1,5 +1,7 @@ //! Defines the set of legal keys that can be used in queries. +use std::ffi::OsStr; + use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId}; use rustc_hir::hir_id::{HirId, OwnerId}; use rustc_query_system::dep_graph::DepNodeIndex; @@ -498,6 +500,14 @@ impl Key for Option { } } +impl<'tcx> Key for &'tcx OsStr { + type Cache = DefaultCache; + + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. impl<'tcx, T: Clone> Key for CanonicalQueryInput<'tcx, T> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 527c18addbe1..850de3f0c2a3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -6,6 +6,7 @@ #![allow(unused_parens)] +use std::ffi::OsStr; use std::mem; use std::path::PathBuf; use std::sync::Arc; @@ -119,6 +120,21 @@ rustc_queries! { desc { "perform lints prior to AST lowering" } } + /// Tracked access to environment variables. + /// + /// Useful for the implementation of `std::env!`, `proc-macro`s change + /// detection and other changes in the compiler's behaviour that is easier + /// to control with an environment variable than a flag. + /// + /// NOTE: This currently does not work with dependency info in the + /// analysis, codegen and linking passes, place extra code at the top of + /// `rustc_interface::passes::write_dep_info` to make that work. + query env_var_os(key: &'tcx OsStr) -> Option<&'tcx OsStr> { + // Environment variables are global state + eval_always + desc { "get the value of an environment variable" } + } + query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { no_hash desc { "getting the resolver outputs" } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f54dd2b0040a..f2003762af34 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -7,6 +7,8 @@ pub mod tls; use std::assert_matches::{assert_matches, debug_assert_matches}; use std::borrow::Borrow; use std::cmp::Ordering; +use std::env::VarError; +use std::ffi::OsStr; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::{Bound, Deref}; @@ -1882,6 +1884,15 @@ impl<'tcx> TyCtxt<'tcx> { } None } + + /// Helper to get a tracked environment variable via. [`TyCtxt::env_var_os`] and converting to + /// UTF-8 like [`std::env::var`]. + pub fn env_var>(self, key: &'tcx K) -> Result<&'tcx str, VarError> { + match self.env_var_os(key.as_ref()) { + Some(value) => value.to_str().ok_or_else(|| VarError::NotUnicode(value.to_os_string())), + None => Err(VarError::NotPresent), + } + } } impl<'tcx> TyCtxtAt<'tcx> { From 632ce38c9a93a6ee890aedd99fcb1a61cabd0a46 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sun, 1 Dec 2024 11:55:46 +0100 Subject: [PATCH 349/546] Add environment variable tracking in places where it was convenient This won't work with Cargo's change tracking, but it should work with incremental. --- compiler/rustc_borrowck/src/nll.rs | 7 +++---- compiler/rustc_lint/src/non_local_def.rs | 6 ++++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index d0bd364425a5..8e7b6f083aca 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -1,9 +1,9 @@ //! The entry point of the NLL borrow checker. +use std::io; use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; -use std::{env, io}; use polonius_engine::{Algorithm, Output}; use rustc_index::IndexSlice; @@ -162,9 +162,8 @@ pub(crate) fn compute_regions<'a, 'tcx>( } if polonius_output { - let algorithm = - env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid")); - let algorithm = Algorithm::from_str(&algorithm).unwrap(); + let algorithm = infcx.tcx.env_var("POLONIUS_ALGORITHM").unwrap_or("Hybrid"); + let algorithm = Algorithm::from_str(algorithm).unwrap(); debug!("compute_regions: using polonius algorithm {:?}", algorithm); let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis"); Some(Box::new(Output::compute(polonius_facts, algorithm, false))) diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index f8e0a94f9ec2..9ed11d9cc82f 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -104,8 +104,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { // determining if we are in a doctest context can't currently be determined // by the code itself (there are no specific attributes), but fortunately rustdoc // sets a perma-unstable env var for libtest so we just reuse that for now - let is_at_toplevel_doctest = - || self.body_depth == 2 && std::env::var("UNSTABLE_RUSTDOC_TEST_PATH").is_ok(); + let is_at_toplevel_doctest = || { + self.body_depth == 2 + && cx.tcx.env_var_os("UNSTABLE_RUSTDOC_TEST_PATH".as_ref()).is_some() + }; match item.kind { ItemKind::Impl(impl_) => { From a7bafc0afc3dba988a7bf85198c493b20523eaa0 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 26 Mar 2025 15:23:47 +0100 Subject: [PATCH 350/546] Change the syntax of the internal `weak!` macro Change the syntax to include parameter names and a trailing semicolon. Motivation: - Mirror the `syscall!` macro. - Allow rustfmt to format it (when wrapped in parentheses). - For better documentation (having the parameter names available in the source code is a bit nicer). - Allow future improvements to this macro where we can sometimes use the symbol directly when it's statically known to be available. --- library/std/src/sys/fs/unix.rs | 16 +++--- library/std/src/sys/pal/unix/fd.rs | 52 ++++++++++++++----- library/std/src/sys/pal/unix/kernel_copy.rs | 16 +++--- .../std/src/sys/pal/unix/stack_overflow.rs | 30 ++++++++--- library/std/src/sys/pal/unix/thread.rs | 13 +++-- library/std/src/sys/pal/unix/time.rs | 7 ++- library/std/src/sys/pal/unix/weak.rs | 40 ++++++++------ library/std/src/sys/process/unix/unix.rs | 42 ++++++++------- library/std/src/sys/random/linux.rs | 8 +-- 9 files changed, 144 insertions(+), 80 deletions(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 7c3ed8029f7d..60e6559fa6b9 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -155,15 +155,15 @@ cfg_has_statx! {{ enum STATX_STATE{ Unknown = 0, Present, Unavailable } static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8); - syscall! { + syscall!( fn statx( fd: c_int, pathname: *const c_char, flags: c_int, mask: libc::c_uint, - statxbuf: *mut libc::statx - ) -> c_int - } + statxbuf: *mut libc::statx, + ) -> c_int; + ); let statx_availability = STATX_SAVED_STATE.load(Ordering::Relaxed); if statx_availability == STATX_STATE::Unavailable as u8 { @@ -1540,7 +1540,9 @@ impl File { let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?]; // futimens requires Android API level 19 cvt(unsafe { - weak!(fn futimens(c_int, *const libc::timespec) -> c_int); + weak!( + fn futimens(fd: c_int, times: *const libc::timespec) -> c_int; + ); match futimens.get() { Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()), None => return Err(io::const_error!( @@ -1556,7 +1558,9 @@ impl File { use crate::sys::{time::__timespec64, weak::weak}; // Added in glibc 2.34 - weak!(fn __futimens64(libc::c_int, *const __timespec64) -> libc::c_int); + weak!( + fn __futimens64(fd: c_int, times: *const __timespec64) -> c_int; + ); if let Some(futimens64) = __futimens64.get() { let to_timespec = |time: Option| time.map(|time| time.t.to_timespec64()) diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index f03c440e30e1..2ec8d01c13f4 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -232,14 +232,14 @@ impl FileDesc { // implementation if `preadv` is not available. #[cfg(all(target_os = "android", target_pointer_width = "64"))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - super::weak::syscall! { + super::weak::syscall!( fn preadv( fd: libc::c_int, iovec: *const libc::iovec, n_iovec: libc::c_int, - offset: off64_t - ) -> isize - } + offset: off64_t, + ) -> isize; + ); let ret = cvt(unsafe { preadv( @@ -257,7 +257,14 @@ impl FileDesc { // and its metadata from LLVM IR. #[no_sanitize(cfi)] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + super::weak::weak!( + fn preadv64( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t, + ) -> isize; + ); match preadv64.get() { Some(preadv) => { @@ -286,7 +293,14 @@ impl FileDesc { // use "weak" linking. #[cfg(target_vendor = "apple")] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - super::weak::weak!(fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + super::weak::weak!( + fn preadv( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t, + ) -> isize; + ); match preadv.get() { Some(preadv) => { @@ -428,14 +442,14 @@ impl FileDesc { // implementation if `pwritev` is not available. #[cfg(all(target_os = "android", target_pointer_width = "64"))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - super::weak::syscall! { + super::weak::syscall!( fn pwritev( fd: libc::c_int, iovec: *const libc::iovec, n_iovec: libc::c_int, - offset: off64_t - ) -> isize - } + offset: off64_t, + ) -> isize; + ); let ret = cvt(unsafe { pwritev( @@ -450,7 +464,14 @@ impl FileDesc { #[cfg(all(target_os = "android", target_pointer_width = "32"))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + super::weak::weak!( + fn pwritev64( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t, + ) -> isize; + ); match pwritev64.get() { Some(pwritev) => { @@ -479,7 +500,14 @@ impl FileDesc { // use "weak" linking. #[cfg(target_vendor = "apple")] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - super::weak::weak!(fn pwritev(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + super::weak::weak!( + fn pwritev( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t, + ) -> isize; + ); match pwritev.get() { Some(pwritev) => { diff --git a/library/std/src/sys/pal/unix/kernel_copy.rs b/library/std/src/sys/pal/unix/kernel_copy.rs index bbf29f325234..d42a7e2a7fc5 100644 --- a/library/std/src/sys/pal/unix/kernel_copy.rs +++ b/library/std/src/sys/pal/unix/kernel_copy.rs @@ -604,16 +604,16 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> _ => true, }; - syscall! { + syscall!( fn copy_file_range( fd_in: libc::c_int, off_in: *mut libc::loff_t, fd_out: libc::c_int, off_out: *mut libc::loff_t, len: libc::size_t, - flags: libc::c_uint - ) -> libc::ssize_t - } + flags: libc::c_uint, + ) -> libc::ssize_t; + ); fn probe_copy_file_range_support() -> u8 { // In some cases, we cannot determine availability from the first @@ -727,16 +727,16 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) -> // Android builds use feature level 14, but the libc wrapper for splice is // gated on feature level 21+, so we have to invoke the syscall directly. #[cfg(target_os = "android")] - syscall! { + syscall!( fn splice( srcfd: libc::c_int, src_offset: *const i64, dstfd: libc::c_int, dst_offset: *const i64, len: libc::size_t, - flags: libc::c_int - ) -> libc::ssize_t - } + flags: libc::c_int, + ) -> libc::ssize_t; + ); #[cfg(target_os = "linux")] use libc::splice; diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 4bd0cedd44cc..34b3948e3f67 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -424,18 +424,32 @@ mod imp { let pages = PAGES.get_or_init(|| { use crate::sys::weak::dlsym; - dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int); + dlsym!( + fn sysctlbyname( + name: *const libc::c_char, + oldp: *mut libc::c_void, + oldlenp: *mut libc::size_t, + newp: *const libc::c_void, + newlen: libc::size_t, + ) -> libc::c_int; + ); let mut guard: usize = 0; let mut size = size_of_val(&guard); let oid = c"security.bsd.stack_guard_page"; match sysctlbyname.get() { - Some(fcn) if unsafe { - fcn(oid.as_ptr(), - (&raw mut guard).cast(), - &raw mut size, - ptr::null_mut(), - 0) == 0 - } => guard, + Some(fcn) + if unsafe { + fcn( + oid.as_ptr(), + (&raw mut guard).cast(), + &raw mut size, + ptr::null_mut(), + 0, + ) == 0 + } => + { + guard + } _ => 1, } }); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index bb34c2fabe55..9078dd1c2316 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -193,11 +193,12 @@ impl Thread { // and its metadata from LLVM IR. #[no_sanitize(cfi)] pub fn set_name(name: &CStr) { - weak! { + weak!( fn pthread_setname_np( - libc::pthread_t, *const libc::c_char - ) -> libc::c_int - } + thread: libc::pthread_t, + name: *const libc::c_char, + ) -> libc::c_int; + ); if let Some(f) = pthread_setname_np.get() { #[cfg(target_os = "nto")] @@ -762,7 +763,9 @@ unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { // We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628) // We shouldn't really be using such an internal symbol, but there's currently // no other way to account for the TLS size. - dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); + dlsym!( + fn __pthread_get_minstack(attr: *const libc::pthread_attr_t) -> libc::size_t; + ); match __pthread_get_minstack.get() { None => libc::PTHREAD_STACK_MIN, diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index c0a3044660b7..b8469b1681f0 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -123,7 +123,12 @@ impl Timespec { // __clock_gettime64 was added to 32-bit arches in glibc 2.34, // and it handles both vDSO calls and ENOSYS fallbacks itself. - weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int); + weak!( + fn __clock_gettime64( + clockid: libc::clockid_t, + tp: *mut __timespec64, + ) -> libc::c_int; + ); if let Some(clock_gettime64) = __clock_gettime64.get() { let mut t = MaybeUninit::uninit(); diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index ce3f66a83748..e7f4e005cc48 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -29,7 +29,7 @@ use crate::{mem, ptr}; // We can use true weak linkage on ELF targets. #[cfg(all(unix, not(target_vendor = "apple")))] pub(crate) macro weak { - (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( let ref $name: ExternWeak $ret> = { unsafe extern "C" { #[linkage = "extern_weak"] @@ -62,10 +62,16 @@ impl ExternWeak { } pub(crate) macro dlsym { - (fn $name:ident($($t:ty),*) -> $ret:ty) => ( - dlsym!(fn $name($($t),*) -> $ret, stringify!($name)); + (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( + dlsym!( + #[link_name = stringify!($name)] + fn $name($($param : $t),*) -> $ret; + ); ), - (fn $name:ident($($t:ty),*) -> $ret:ty, $sym:expr) => ( + ( + #[link_name = $sym:expr] + fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty; + ) => ( static DLSYM: DlsymWeak $ret> = DlsymWeak::new(concat!($sym, '\0')); let $name = &DLSYM; @@ -143,15 +149,15 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( // FIXME(#115199): Rust currently omits weak function definitions // and its metadata from LLVM IR. #[no_sanitize(cfi)] - unsafe fn $name($($arg_name: $t),*) -> $ret { - weak! { fn $name($($t),*) -> $ret } + unsafe fn $name($($param: $t),*) -> $ret { + weak!(fn $name($($param: $t),*) -> $ret;); if let Some(fun) = $name.get() { - fun($($arg_name),*) + fun($($param),*) } else { super::os::set_errno(libc::ENOSYS); -1 @@ -162,16 +168,18 @@ pub(crate) macro syscall { #[cfg(any(target_os = "linux", target_os = "android"))] pub(crate) macro syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( - unsafe fn $name($($arg_name:$t),*) -> $ret { - weak! { fn $name($($t),*) -> $ret } + ( + fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty; + ) => ( + unsafe fn $name($($param: $t),*) -> $ret { + weak!(fn $name($($param: $t),*) -> $ret;); // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` // interposition, but if it's not found just use a raw syscall. if let Some(fun) = $name.get() { - fun($($arg_name),*) + fun($($param),*) } else { - libc::syscall(libc::${concat(SYS_, $name)}, $($arg_name),*) as $ret + libc::syscall(libc::${concat(SYS_, $name)}, $($param),*) as $ret } } ) @@ -179,9 +187,9 @@ pub(crate) macro syscall { #[cfg(any(target_os = "linux", target_os = "android"))] pub(crate) macro raw_syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( - unsafe fn $name($($arg_name:$t),*) -> $ret { - libc::syscall(libc::${concat(SYS_, $name)}, $($arg_name),*) as $ret + (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( + unsafe fn $name($($param: $t),*) -> $ret { + libc::syscall(libc::${concat(SYS_, $name)}, $($param),*) as $ret } ) } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 42542f81b654..191a09c8da91 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -461,18 +461,20 @@ impl Command { if #[cfg(target_os = "linux")] { use crate::sys::weak::weak; - weak! { + weak!( fn pidfd_spawnp( - *mut libc::c_int, - *const libc::c_char, - *const libc::posix_spawn_file_actions_t, - *const libc::posix_spawnattr_t, - *const *mut libc::c_char, - *const *mut libc::c_char - ) -> libc::c_int - } + pidfd: *mut libc::c_int, + path: *const libc::c_char, + file_actions: *const libc::posix_spawn_file_actions_t, + attrp: *const libc::posix_spawnattr_t, + argv: *const *mut libc::c_char, + envp: *const *mut libc::c_char, + ) -> libc::c_int; + ); - weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int } + weak!( + fn pidfd_getpid(pidfd: libc::c_int) -> libc::c_int; + ); static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0); const UNKNOWN: u8 = 0; @@ -593,19 +595,19 @@ impl Command { // https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addchdir.html. // The _np version is more widely available, though, so try that first. - weak! { + weak!( fn posix_spawn_file_actions_addchdir_np( - *mut libc::posix_spawn_file_actions_t, - *const libc::c_char - ) -> libc::c_int - } + file_actions: *mut libc::posix_spawn_file_actions_t, + path: *const libc::c_char, + ) -> libc::c_int; + ); - weak! { + weak!( fn posix_spawn_file_actions_addchdir( - *mut libc::posix_spawn_file_actions_t, - *const libc::c_char - ) -> libc::c_int - } + file_actions: *mut libc::posix_spawn_file_actions_t, + path: *const libc::c_char, + ) -> libc::c_int; + ); posix_spawn_file_actions_addchdir_np .get() diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index e3cb79285cd1..c0591ec0c152 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -73,13 +73,13 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) { // A weak symbol allows interposition, e.g. for perf measurements that want to // disable randomness for consistency. Otherwise, we'll try a raw syscall. // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28) - syscall! { + syscall!( fn getrandom( buffer: *mut libc::c_void, length: libc::size_t, - flags: libc::c_uint - ) -> libc::ssize_t - } + flags: libc::c_uint, + ) -> libc::ssize_t; + ); static GETRANDOM_AVAILABLE: AtomicBool = AtomicBool::new(true); static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true); From a86e0dacbce4e9bc624ef1ebd71a575c9dd0aa01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 26 Feb 2025 03:08:03 +0100 Subject: [PATCH 351/546] doc(hir::Place): clarify that places aren't always place expressions --- compiler/rustc_middle/src/hir/place.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 316ad80eb985..60ce8544aa0e 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -53,7 +53,10 @@ pub struct Projection<'tcx> { pub kind: ProjectionKind, } -/// A `Place` represents how a value is located in memory. +/// A `Place` represents how a value is located in memory. This does not +/// always correspond to a syntactic place expression. For example, when +/// processing a pattern, a `Place` can be used to refer to the sub-value +/// currently being inspected. /// /// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] @@ -67,7 +70,10 @@ pub struct Place<'tcx> { pub projections: Vec>, } -/// A `PlaceWithHirId` represents how a value is located in memory. +/// A `PlaceWithHirId` represents how a value is located in memory. This does not +/// always correspond to a syntactic place expression. For example, when +/// processing a pattern, a `Place` can be used to refer to the sub-value +/// currently being inspected. /// /// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] From 376c88ee6fb910fa32ac8966788e9b8e3569a74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 26 Feb 2025 03:41:10 +0100 Subject: [PATCH 352/546] ExprUseVisitor: add clarifying doc comments --- .../rustc_hir_typeck/src/expr_use_visitor.rs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index c71a5ea8b976..1b007200549f 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -1,6 +1,9 @@ //! A different sort of visitor for walking fn bodies. Unlike the //! normal visitor, which just walks the entire body in one shot, the //! `ExprUseVisitor` determines how expressions are being used. +//! +//! In the compiler, this is only used for upvar inference, but there +//! are many uses within clippy. use std::cell::{Ref, RefCell}; use std::ops::Deref; @@ -35,11 +38,8 @@ pub trait Delegate<'tcx> { /// The value found at `place` is moved, depending /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. /// - /// Use of a `Copy` type in a ByValue context is considered a use - /// by `ImmBorrow` and `borrow` is called instead. This is because - /// a shared borrow is the "minimum access" that would be needed - /// to perform a copy. - /// + /// If the value is `Copy`, [`copy`][Self::copy] is called instead, which + /// by default falls back to [`borrow`][Self::borrow]. /// /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic @@ -73,6 +73,10 @@ pub trait Delegate<'tcx> { /// The value found at `place` is being copied. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). + /// + /// If an implementation is not provided, use of a `Copy` type in a ByValue context is instead + /// considered a use by `ImmBorrow` and `borrow` is called instead. This is because a shared + /// borrow is the "minimum access" that would be needed to perform a copy. fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { // In most cases, copying data from `x` is equivalent to doing `*&x`, so by default // we treat a copy of `x` as a borrow of `x`. @@ -141,6 +145,8 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D { } } +/// This trait makes `ExprUseVisitor` usable with both [`FnCtxt`] +/// and [`LateContext`], depending on where in the compiler it is used. pub trait TypeInformationCtxt<'tcx> { type TypeckResults<'a>: Deref> where @@ -268,9 +274,9 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { } } -/// The ExprUseVisitor type +/// A visitor that reports how each expression is being used. /// -/// This is the code that actually walks the tree. +/// See [module-level docs][self] and [`Delegate`] for details. pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> { cx: Cx, /// We use a `RefCell` here so that delegates can mutate themselves, but we can @@ -1285,7 +1291,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.pat_ty_unadjusted(pat) } - /// Like `TypeckResults::pat_ty`, but ignores implicit `&` patterns. + /// Like [`Self::pat_ty_adjusted`], but ignores implicit `&` patterns. fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result, Cx::Error> { let base_ty = self.node_ty(pat.hir_id)?; trace!(?base_ty); From aab12930f5b71489f4c27db9d45897a2563a407e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 26 Feb 2025 03:49:46 +0100 Subject: [PATCH 353/546] ExprUseVisitor: error -> bug in helper names A name like "report_error" suggests that the error in question might be user facing. Use "bug" to make it clear that the error in question will be an ICE. --- .../rustc_hir_typeck/src/expr_use_visitor.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 1b007200549f..58bac159f37d 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -160,7 +160,7 @@ pub trait TypeInformationCtxt<'tcx> { fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; - fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error; + fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error; fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error>; @@ -195,7 +195,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { (**self).try_structurally_resolve_type(sp, ty) } - fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error { + fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error { self.dcx().span_delayed_bug(span, msg.to_string()) } @@ -245,7 +245,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { t } - fn report_error(&self, span: Span, msg: impl ToString) -> ! { + fn report_bug(&self, span: Span, msg: impl ToString) -> ! { span_bug!(span, "{}", msg.to_string()) } @@ -1218,7 +1218,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference /// tied to `x`. The type of `x'` will be a borrowed pointer. impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> { - fn resolve_type_vars_or_error( + fn resolve_type_vars_or_bug( &self, id: HirId, ty: Option>, @@ -1228,10 +1228,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let ty = self.cx.resolve_vars_if_possible(ty); self.cx.error_reported_in_ty(ty)?; if ty.is_ty_var() { - debug!("resolve_type_vars_or_error: infer var from {:?}", ty); + debug!("resolve_type_vars_or_bug: infer var from {:?}", ty); Err(self .cx - .report_error(self.cx.tcx().hir().span(id), "encountered type variable")) + .report_bug(self.cx.tcx().hir().span(id), "encountered type variable")) } else { Ok(ty) } @@ -1248,15 +1248,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } fn node_ty(&self, hir_id: HirId) -> Result, Cx::Error> { - self.resolve_type_vars_or_error(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) + self.resolve_type_vars_or_bug(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) } fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { - self.resolve_type_vars_or_error(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) + self.resolve_type_vars_or_bug(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) } fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { - self.resolve_type_vars_or_error( + self.resolve_type_vars_or_bug( expr.hir_id, self.cx.typeck_results().expr_ty_adjusted_opt(expr), ) @@ -1321,7 +1321,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx debug!("By-ref binding of non-derefable type"); Err(self .cx - .report_error(pat.span, "by-ref binding of non-derefable type")) + .report_bug(pat.span, "by-ref binding of non-derefable type")) } } } else { @@ -1610,7 +1610,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Some(ty) => ty, None => { debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); - return Err(self.cx.report_error( + return Err(self.cx.report_bug( self.cx.tcx().hir().span(node), "explicit deref of non-derefable type", )); @@ -1635,7 +1635,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else { return Err(self .cx - .report_error(span, "struct or tuple struct pattern not applied to an ADT")); + .report_bug(span, "struct or tuple struct pattern not applied to an ADT")); }; match res { @@ -1681,7 +1681,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let ty = self.cx.typeck_results().node_type(pat_hir_id); match self.cx.try_structurally_resolve_type(span, ty).kind() { ty::Tuple(args) => Ok(args.len()), - _ => Err(self.cx.report_error(span, "tuple pattern not applied to a tuple")), + _ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")), } } @@ -1860,7 +1860,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx debug!("explicit index of non-indexable type {:?}", place_with_id); return Err(self .cx - .report_error(pat.span, "explicit index of non-indexable type")); + .report_bug(pat.span, "explicit index of non-indexable type")); }; let elt_place = self.cat_projection( pat.hir_id, From f16195382c93e2aac65028618a6d506501229632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 26 Feb 2025 10:25:44 +0100 Subject: [PATCH 354/546] ExprUseVisitor: remove leftover mentions of mem-categorization In #124902, mem-categorization got merged into ExprUseVisitor itself. Adjust the comments that have become misleading or confusing following this change. --- .../rustc_hir_typeck/src/expr_use_visitor.rs | 63 ++++--------------- compiler/rustc_hir_typeck/src/upvar.rs | 10 +-- 2 files changed, 16 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 58bac159f37d..806604677fe0 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -867,7 +867,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } /// Walks the autoref `autoref` applied to the autoderef'd - /// `expr`. `base_place` is the mem-categorized form of `expr` + /// `expr`. `base_place` is `expr` represented as a place, /// after all relevant autoderefs have occurred. fn walk_autoref( &self, @@ -1170,53 +1170,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } -/// The job of the categorization methods is to analyze an expression to -/// determine what kind of memory is used in evaluating it (for example, -/// where dereferences occur and what kind of pointer is dereferenced; -/// whether the memory is mutable, etc.). +/// The job of the methods whose name starts with `cat_` is to analyze +/// expressions and construct the corresponding [`Place`]s. The `cat` +/// stands for "categorize", this is a leftover from long ago when +/// places were called "categorizations". /// -/// Categorization effectively transforms all of our expressions into -/// expressions of the following forms (the actual enum has many more -/// possibilities, naturally, but they are all variants of these base -/// forms): -/// ```ignore (not-rust) -/// E = rvalue // some computed rvalue -/// | x // address of a local variable or argument -/// | *E // deref of a ptr -/// | E.comp // access to an interior component -/// ``` -/// Imagine a routine ToAddr(Expr) that evaluates an expression and returns an -/// address where the result is to be found. If Expr is a place, then this -/// is the address of the place. If `Expr` is an rvalue, this is the address of -/// some temporary spot in memory where the result is stored. -/// -/// Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)` -/// as follows: -/// -/// - `cat`: what kind of expression was this? This is a subset of the -/// full expression forms which only includes those that we care about -/// for the purpose of the analysis. -/// - `mutbl`: mutability of the address `A`. -/// - `ty`: the type of data found at the address `A`. -/// -/// The resulting categorization tree differs somewhat from the expressions -/// themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is -/// decomposed into two operations: a dereference to reach the array data and -/// then an index to jump forward to the relevant item. -/// -/// ## By-reference upvars -/// -/// One part of the codegen which may be non-obvious is that we translate -/// closure upvars into the dereference of a borrowed pointer; this more closely -/// resembles the runtime codegen. So, for example, if we had: -/// -/// let mut x = 3; -/// let y = 5; -/// let inc = || x += y; -/// -/// Then when we categorize `x` (*within* the closure) we would yield a -/// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference -/// tied to `x`. The type of `x'` will be a borrowed pointer. +/// Note that a [`Place`] differs somewhat from the expression itself. For +/// example, auto-derefs are explicit. Also, an index `a[b]` is decomposed into +/// two operations: a dereference to reach the array data and then an index to +/// jump forward to the relevant item. impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> { fn resolve_type_vars_or_bug( &self, @@ -1239,10 +1201,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx None => { // FIXME: We shouldn't be relying on the infcx being tainted. self.cx.tainted_by_errors()?; - bug!( - "no type for node {} in mem_categorization", - self.cx.tcx().hir_id_to_string(id) - ); + bug!("no type for node {} in ExprUseVisitor", self.cx.tcx().hir_id_to_string(id)); } } } @@ -1517,7 +1476,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } - def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def), + def => span_bug!(span, "unexpected definition in ExprUseVisitor: {:?}", def), } } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index fc98a603dd85..d07bfade1570 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -18,12 +18,12 @@ //! from there). //! //! The fact that we are inferring borrow kinds as we go results in a -//! semi-hacky interaction with mem-categorization. In particular, -//! mem-categorization will query the current borrow kind as it -//! categorizes, and we'll return the *current* value, but this may get +//! semi-hacky interaction with the way `ExprUseVisitor` is computing +//! `Place`s. In particular, it will query the current borrow kind as it +//! goes, and we'll return the *current* value, but this may get //! adjusted later. Therefore, in this module, we generally ignore the -//! borrow kind (and derived mutabilities) that are returned from -//! mem-categorization, since they may be inaccurate. (Another option +//! borrow kind (and derived mutabilities) that `ExprUseVisitor` returns +//! within `Place`s, since they may be inaccurate. (Another option //! would be to use a unification scheme, where instead of returning a //! concrete borrow kind like `ty::ImmBorrow`, we return a //! `ty::InferBorrow(upvar_id)` or something like that, but this would From 908504ec2865186b2e2963e07d24b8849ba828e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 26 Mar 2025 16:22:26 +0100 Subject: [PATCH 355/546] ExprUseVisitor: use tracing::instrument as appropriate Replace debug! calls that output a worse version of what #[instrument] does. --- .../rustc_hir_typeck/src/expr_use_visitor.rs | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 806604677fe0..6fb289235de9 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -28,7 +28,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::infer::InferCtxtExt; -use tracing::{debug, trace}; +use tracing::{debug, instrument, trace}; use crate::fn_ctxt::FnCtxt; @@ -320,9 +320,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } + #[instrument(skip(self), level = "debug")] fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { - debug!("delegate_consume(place_with_id={:?})", place_with_id); - if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) { self.delegate.borrow_mut().copy(place_with_id, diag_expr_id); } else { @@ -330,9 +329,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } + #[instrument(skip(self), level = "debug")] pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { - debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id); - // `x.use` will do one of the following // * if it implements `Copy`, it will be a copy // * if it implements `UseCloned`, it will be a call to `clone` @@ -357,18 +355,16 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } // FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`. + #[instrument(skip(self), level = "debug")] pub fn consume_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { - debug!("consume_expr(expr={:?})", expr); - let place_with_id = self.cat_expr(expr)?; self.consume_or_copy(&place_with_id, place_with_id.hir_id); self.walk_expr(expr)?; Ok(()) } + #[instrument(skip(self), level = "debug")] pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { - debug!("consume_or_clone_expr(expr={:?})", expr); - let place_with_id = self.cat_expr(expr)?; self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id); self.walk_expr(expr)?; @@ -382,17 +378,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } + #[instrument(skip(self), level = "debug")] fn borrow_expr(&self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) -> Result<(), Cx::Error> { - debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk); - let place_with_id = self.cat_expr(expr)?; self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); self.walk_expr(expr) } + #[instrument(skip(self), level = "debug")] pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { - debug!("walk_expr(expr={:?})", expr); - self.walk_adjustment(expr)?; match expr.kind { @@ -739,9 +733,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// Indicates that the value of `blk` will be consumed, meaning either copied or moved /// depending on its type. + #[instrument(skip(self), level = "debug")] fn walk_block(&self, blk: &hir::Block<'_>) -> Result<(), Cx::Error> { - debug!("walk_block(blk.hir_id={})", blk.hir_id); - for stmt in blk.stmts { self.walk_stmt(stmt)?; } @@ -948,14 +941,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } /// The core driver for walking a pattern + #[instrument(skip(self), level = "debug")] fn walk_pat( &self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, has_guard: bool, ) -> Result<(), Cx::Error> { - debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard); - let tcx = self.cx.tcx(); self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { match pat.kind { @@ -1048,6 +1040,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing /// closure as the DefId. + #[instrument(skip(self), level = "debug")] fn walk_captures(&self, closure_expr: &hir::Closure<'_>) -> Result<(), Cx::Error> { fn upvar_is_local_variable( upvars: Option<&FxIndexMap>, @@ -1057,8 +1050,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure) } - debug!("walk_captures({:?})", closure_expr); - let tcx = self.cx.tcx(); let closure_def_id = closure_expr.def_id; // For purposes of this function, coroutine and closures are equivalent. From 1da5e60ac59661bca0d09b50839600fe0deeb0aa Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 26 Mar 2025 14:48:14 +0100 Subject: [PATCH 356/546] Don't record child scopes for patterns. They are unused. --- compiler/rustc_hir_analysis/src/check/region.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 255f5fee52a8..c81f75eb3198 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -221,8 +221,6 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir: } fn resolve_pat<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) { - visitor.record_child_scope(Scope { local_id: pat.hir_id.local_id, data: ScopeData::Node }); - // If this is a binding then record the lifetime of that binding. if let PatKind::Binding(..) = pat.kind { record_var_lifetime(visitor, pat.hir_id.local_id); From 227f93395a2cc86f6f66d26a68fdbd7955a8ec51 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 26 Mar 2025 14:49:07 +0100 Subject: [PATCH 357/546] Simplify RvalueCandidateType. There is no difference between the Patternand Borrow cases. Reduce it to a simple struct. --- .../rustc_hir_analysis/src/check/region.rs | 10 ++---- .../rustc_hir_typeck/src/rvalue_scopes.rs | 12 +++---- compiler/rustc_middle/src/middle/region.rs | 31 ++++++++----------- 3 files changed, 19 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index c81f75eb3198..a7007c5d831b 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -623,10 +623,7 @@ fn resolve_local<'tcx>( if is_binding_pat(pat) { visitor.scope_tree.record_rvalue_candidate( expr.hir_id, - RvalueCandidateType::Pattern { - target: expr.hir_id.local_id, - lifetime: blk_scope, - }, + RvalueCandidate { target: expr.hir_id.local_id, lifetime: blk_scope }, ); } } @@ -731,10 +728,7 @@ fn resolve_local<'tcx>( record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id); visitor.scope_tree.record_rvalue_candidate( subexpr.hir_id, - RvalueCandidateType::Borrow { - target: subexpr.hir_id.local_id, - lifetime: blk_id, - }, + RvalueCandidate { target: subexpr.hir_id.local_id, lifetime: blk_id }, ); } hir::ExprKind::Struct(_, fields, _) => { diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs index 98d7f777d6b8..973dc7141e64 100644 --- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs +++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs @@ -2,7 +2,7 @@ use hir::Node; use hir::def_id::DefId; use rustc_hir as hir; use rustc_middle::bug; -use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree}; +use rustc_middle::middle::region::{RvalueCandidate, Scope, ScopeTree}; use rustc_middle::ty::RvalueScopes; use tracing::debug; @@ -55,15 +55,11 @@ fn record_rvalue_scope_rec( fn record_rvalue_scope( rvalue_scopes: &mut RvalueScopes, expr: &hir::Expr<'_>, - candidate: &RvalueCandidateType, + candidate: &RvalueCandidate, ) { debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})"); - match candidate { - RvalueCandidateType::Borrow { lifetime, .. } - | RvalueCandidateType::Pattern { lifetime, .. } => { - record_rvalue_scope_rec(rvalue_scopes, expr, *lifetime) - } // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments - } + record_rvalue_scope_rec(rvalue_scopes, expr, candidate.lifetime) + // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments } pub(crate) fn resolve_rvalue_scopes<'a, 'tcx>( diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 66861519e17c..66ece8f0e52f 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -224,7 +224,7 @@ pub struct ScopeTree { /// and not the enclosing *statement*. Expressions that are not present in this /// table are not rvalue candidates. The set of rvalue candidates is computed /// during type check based on a traversal of the AST. - pub rvalue_candidates: HirIdMap, + pub rvalue_candidates: HirIdMap, /// Backwards incompatible scoping that will be introduced in future editions. /// This information is used later for linting to identify locals and @@ -308,15 +308,14 @@ pub struct ScopeTree { pub yield_in_scope: UnordMap>, } -/// Identifies the reason that a given expression is an rvalue candidate -/// (see the `rvalue_candidates` field for more information what rvalue -/// candidates in general). In constants, the `lifetime` field is None -/// to indicate that certain expressions escape into 'static and -/// should have no local cleanup scope. +/// See the `rvalue_candidates` field for more information on rvalue +/// candidates in general. +/// The `lifetime` field is None to indicate that certain expressions escape +/// into 'static and should have no local cleanup scope. #[derive(Debug, Copy, Clone, HashStable)] -pub enum RvalueCandidateType { - Borrow { target: hir::ItemLocalId, lifetime: Option }, - Pattern { target: hir::ItemLocalId, lifetime: Option }, +pub struct RvalueCandidate { + pub target: hir::ItemLocalId, + pub lifetime: Option, } #[derive(Debug, Copy, Clone, HashStable)] @@ -344,16 +343,12 @@ impl ScopeTree { self.var_map.insert(var, lifetime); } - pub fn record_rvalue_candidate(&mut self, var: HirId, candidate_type: RvalueCandidateType) { - debug!("record_rvalue_candidate(var={var:?}, type={candidate_type:?})"); - match &candidate_type { - RvalueCandidateType::Borrow { lifetime: Some(lifetime), .. } - | RvalueCandidateType::Pattern { lifetime: Some(lifetime), .. } => { - assert!(var.local_id != lifetime.local_id) - } - _ => {} + pub fn record_rvalue_candidate(&mut self, var: HirId, candidate: RvalueCandidate) { + debug!("record_rvalue_candidate(var={var:?}, candidate={candidate:?})"); + if let Some(lifetime) = &candidate.lifetime { + assert!(var.local_id != lifetime.local_id) } - self.rvalue_candidates.insert(var, candidate_type); + self.rvalue_candidates.insert(var, candidate); } /// Returns the narrowest scope that encloses `id`, if any. From 0ad0142a5be5c6aab4d0b5a897a7d11c78fbea12 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 26 Mar 2025 16:07:14 +0100 Subject: [PATCH 358/546] Don't set cx.parent to None; it seems unnecessary. --- compiler/rustc_hir_analysis/src/check/region.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index a7007c5d831b..4e4b97557365 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -849,13 +849,12 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { self.enter_body(body.value.hir_id, |this| { if this.tcx.hir_body_owner_kind(owner_id).is_fn_or_closure() { // The arguments and `self` are parented to the fn. - this.cx.var_parent = this.cx.parent.take(); + this.cx.var_parent = this.cx.parent; for param in body.params { this.visit_pat(param.pat); } // The body of the every fn is a root scope. - this.cx.parent = this.cx.var_parent; this.visit_expr(body.value) } else { // Only functions have an outer terminating (drop) scope, while From 2cc3fa32ef0ac964c3c99b14d0cbc422a10788bb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 26 Mar 2025 17:13:49 +0100 Subject: [PATCH 359/546] Remove ScopeDepth from var_parent. It was never used. --- .../rustc_hir_analysis/src/check/region.rs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 4e4b97557365..ba8124b11fc1 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -25,12 +25,18 @@ use tracing::debug; struct Context { /// The scope that contains any new variables declared, plus its depth in /// the scope tree. - var_parent: Option<(Scope, ScopeDepth)>, + var_parent: Option, /// Region parent of expressions, etc., plus its depth in the scope tree. parent: Option<(Scope, ScopeDepth)>, } +impl Context { + fn set_var_parent(&mut self) { + self.var_parent = self.parent.map(|(p, _)| p); + } +} + struct ScopeResolutionVisitor<'tcx> { tcx: TyCtxt<'tcx>, @@ -78,7 +84,7 @@ fn record_var_lifetime(visitor: &mut ScopeResolutionVisitor<'_>, var_id: hir::It // // extern fn isalnum(c: c_int) -> c_int } - Some((parent_scope, _)) => visitor.scope_tree.record_var_scope(var_id, parent_scope), + Some(parent_scope) => visitor.scope_tree.record_var_scope(var_id, parent_scope), } } @@ -113,7 +119,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi // itself has returned. visitor.enter_node_scope_with_dtor(blk.hir_id.local_id); - visitor.cx.var_parent = visitor.cx.parent; + visitor.cx.set_var_parent(); { // This block should be kept approximately in sync with @@ -132,7 +138,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi local_id: blk.hir_id.local_id, data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); - visitor.cx.var_parent = visitor.cx.parent; + visitor.cx.set_var_parent(); visitor.visit_stmt(statement); // We need to back out temporarily to the last enclosing scope // for the `else` block, so that even the temporaries receiving @@ -157,7 +163,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi local_id: blk.hir_id.local_id, data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); - visitor.cx.var_parent = visitor.cx.parent; + visitor.cx.set_var_parent(); visitor.visit_stmt(statement) } hir::StmtKind::Item(..) => { @@ -207,7 +213,7 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir: visitor.terminating_scopes.insert(arm.hir_id.local_id); visitor.enter_node_scope_with_dtor(arm.hir_id.local_id); - visitor.cx.var_parent = visitor.cx.parent; + visitor.cx.set_var_parent(); if let Some(expr) = arm.guard && !has_let_expr(expr) @@ -484,7 +490,7 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi ScopeData::IfThen }; visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); - visitor.cx.var_parent = visitor.cx.parent; + visitor.cx.set_var_parent(); visitor.visit_expr(cond); visitor.visit_expr(then); visitor.cx = expr_cx; @@ -499,7 +505,7 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi ScopeData::IfThen }; visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); - visitor.cx.var_parent = visitor.cx.parent; + visitor.cx.set_var_parent(); visitor.visit_expr(cond); visitor.visit_expr(then); visitor.cx = expr_cx; @@ -558,7 +564,7 @@ fn resolve_local<'tcx>( ) { debug!("resolve_local(pat={:?}, init={:?})", pat, init); - let blk_scope = visitor.cx.var_parent.map(|(p, _)| p); + let blk_scope = visitor.cx.var_parent; // As an exception to the normal rules governing temporary // lifetimes, initializers in a let have a temporary lifetime @@ -849,7 +855,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { self.enter_body(body.value.hir_id, |this| { if this.tcx.hir_body_owner_kind(owner_id).is_fn_or_closure() { // The arguments and `self` are parented to the fn. - this.cx.var_parent = this.cx.parent; + this.cx.set_var_parent(); for param in body.params { this.visit_pat(param.pat); } From 0a05677d22825f66018361c3b6a55148bfc85650 Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 26 Mar 2025 06:37:56 -0700 Subject: [PATCH 360/546] `lower_pat_expr`: use the pattern's type instead of the literal's This allows us to remove the field `treat_byte_string_as_slice` from `TypeckResults`, since the pattern's type contains everything necessary to get the correct lowering for byte string literal patterns. This leaves the implementation of `string_deref_patterns` broken, to be fixed in the next commit. --- compiler/rustc_hir_typeck/src/pat.rs | 4 --- compiler/rustc_hir_typeck/src/writeback.rs | 3 -- .../rustc_middle/src/ty/typeck_results.rs | 7 ----- .../src/thir/pattern/const_to_pat.rs | 31 ++----------------- .../rustc_mir_build/src/thir/pattern/mod.rs | 17 +++++++--- 5 files changed, 15 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index f1f956779c94..5a2cead33def 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -632,10 +632,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let tcx = self.tcx; trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); - self.typeck_results - .borrow_mut() - .treat_byte_string_as_slice - .insert(lt.hir_id.local_id); pat_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8)); } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index b63c0b6ab7e0..109023c513e3 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -81,9 +81,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.typeck_results.used_trait_imports = used_trait_imports; - wbcx.typeck_results.treat_byte_string_as_slice = - mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice); - debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results); self.tcx.arena.alloc(wbcx.typeck_results) diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 06054e22e760..3d3f4e2773a2 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -197,12 +197,6 @@ pub struct TypeckResults<'tcx> { /// formatting modified file tests/ui/coroutine/retain-resume-ref.rs pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>, - /// We sometimes treat byte string literals (which are of type `&[u8; N]`) - /// as `&[u8]`, depending on the pattern in which they are used. - /// This hashset records all instances where we behave - /// like this to allow `const_to_pat` to reliably handle this situation. - pub treat_byte_string_as_slice: ItemLocalSet, - /// Contains the data for evaluating the effect of feature `capture_disjoint_fields` /// on closure size. pub closure_size_eval: LocalDefIdMap>, @@ -237,7 +231,6 @@ impl<'tcx> TypeckResults<'tcx> { closure_fake_reads: Default::default(), rvalue_scopes: Default::default(), coroutine_stalled_predicates: Default::default(), - treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), offset_of_data: Default::default(), } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 667d59d858e3..372453688d24 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -58,25 +58,13 @@ struct ConstToPat<'tcx> { span: Span, id: hir::HirId, - treat_byte_string_as_slice: bool, - c: ty::Const<'tcx>, } impl<'tcx> ConstToPat<'tcx> { fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self { trace!(?pat_ctxt.typeck_results.hir_owner); - ConstToPat { - tcx: pat_ctxt.tcx, - typing_env: pat_ctxt.typing_env, - span, - id, - treat_byte_string_as_slice: pat_ctxt - .typeck_results - .treat_byte_string_as_slice - .contains(&id.local_id), - c, - } + ConstToPat { tcx: pat_ctxt.tcx, typing_env: pat_ctxt.typing_env, span, id, c } } fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { @@ -108,8 +96,6 @@ impl<'tcx> ConstToPat<'tcx> { uv: ty::UnevaluatedConst<'tcx>, ty: Ty<'tcx>, ) -> Box> { - trace!(self.treat_byte_string_as_slice); - // It's not *technically* correct to be revealing opaque types here as borrowcheck has // not run yet. However, CTFE itself uses `TypingMode::PostAnalysis` unconditionally even // during typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). @@ -307,21 +293,8 @@ impl<'tcx> ConstToPat<'tcx> { ty, ); } else { - // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when - // matching against references, you can only use byte string literals. - // The typechecker has a special case for byte string literals, by treating them - // as slices. This means we turn `&[T; N]` constants into slice patterns, which - // has no negative effects on pattern matching, even if we're actually matching on - // arrays. - let pointee_ty = match *pointee_ty.kind() { - ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => { - Ty::new_slice(tcx, elem_ty) - } - _ => *pointee_ty, - }; // References have the same valtree representation as their pointee. - let subpattern = self.valtree_to_pat(cv, pointee_ty); - PatKind::Deref { subpattern } + PatKind::Deref { subpattern: self.valtree_to_pat(cv, *pointee_ty) } } } }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 4bfeab44bf4b..66c2223efc8c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Lower the endpoint into a temporary `PatKind` that will then be // deconstructed to obtain the constant value and other data. - let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr); + let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr, None); // Unpeel any ascription or inline-const wrapper nodes. loop { @@ -294,7 +294,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Never => PatKind::Never, - hir::PatKind::Expr(value) => self.lower_pat_expr(value), + hir::PatKind::Expr(value) => self.lower_pat_expr(value, Some(ty)), hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); @@ -630,7 +630,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// - Paths (e.g. `FOO`, `foo::BAR`, `Option::None`) /// - Inline const blocks (e.g. `const { 1 + 1 }`) /// - Literals, possibly negated (e.g. `-128u8`, `"hello"`) - fn lower_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> { + fn lower_pat_expr( + &mut self, + expr: &'tcx hir::PatExpr<'tcx>, + pat_ty: Option>, + ) -> PatKind<'tcx> { let (lit, neg) = match &expr.kind { hir::PatExprKind::Path(qpath) => { return self.lower_path(qpath, expr.hir_id, expr.span).kind; @@ -641,7 +645,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatExprKind::Lit { lit, negated } => (lit, *negated), }; - let ct_ty = self.typeck_results.node_type(expr.hir_id); + // We handle byte string literal patterns by using the pattern's type instead of the + // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, + // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the + // pattern's type means we'll properly translate it to a slice reference pattern. This works + // because slices and arrays have the same valtree representation. + let ct_ty = pat_ty.unwrap_or_else(|| self.typeck_results.node_type(expr.hir_id)); let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind From 3779c6b7974f715c1fba0e6b559798a16178193c Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 26 Mar 2025 08:20:20 -0700 Subject: [PATCH 361/546] add a temporary workaround for `string_deref_patterns` --- .../rustc_mir_build/src/thir/pattern/mod.rs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 66c2223efc8c..d20e051548bf 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, Integer}; use rustc_errors::codes::*; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{self as hir, RangeEnd}; +use rustc_hir::{self as hir, LangItem, RangeEnd}; use rustc_index::Idx; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::thir::{ @@ -650,7 +650,26 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the // pattern's type means we'll properly translate it to a slice reference pattern. This works // because slices and arrays have the same valtree representation. - let ct_ty = pat_ty.unwrap_or_else(|| self.typeck_results.node_type(expr.hir_id)); + // HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if + // `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR. + // FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is + // superseded by a more general implementation of deref patterns. + let ct_ty = match pat_ty { + Some(pat_ty) + if let ty::Adt(def, _) = *pat_ty.kind() + && self.tcx.is_lang_item(def.did(), LangItem::String) => + { + if !self.tcx.features().string_deref_patterns() { + span_bug!( + expr.span, + "matching on `String` went through without enabling string_deref_patterns" + ); + } + self.typeck_results.node_type(expr.hir_id) + } + Some(pat_ty) => pat_ty, + None => self.typeck_results.node_type(expr.hir_id), + }; let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind From 2e5a76cd1e3a88b22fe4a38428cdabcbddfd0b4a Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Wed, 26 Mar 2025 14:32:35 -0400 Subject: [PATCH 362/546] Use cfg_match in core --- library/core/src/ffi/primitives.rs | 28 ++++--- library/core/src/internal_macros.rs | 77 ------------------- library/core/src/lib.rs | 1 + library/core/src/num/f32.rs | 23 +++--- library/core/src/slice/sort/select.rs | 8 +- library/core/src/slice/sort/stable/mod.rs | 16 ++-- library/core/src/slice/sort/unstable/mod.rs | 9 ++- .../core/src/slice/sort/unstable/quicksort.rs | 9 ++- 8 files changed, 53 insertions(+), 118 deletions(-) diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs index 0a70eb4da552..351bf9f83147 100644 --- a/library/core/src/ffi/primitives.rs +++ b/library/core/src/ffi/primitives.rs @@ -35,7 +35,7 @@ type_alias! { "c_float.md", c_float = f32; } type_alias! { "c_double.md", c_double = f64; } mod c_char_definition { - cfg_if! { + crate::cfg_match! { // These are the targets on which c_char is unsigned. Usually the // signedness is the same for all target_os values on a given architecture // but there are some exceptions (see isSignedCharDefault() in clang). @@ -105,7 +105,7 @@ mod c_char_definition { // architecture defaults). As we only have a target for userspace apps so there are no // special cases for L4Re below. // https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240 - if #[cfg(all( + all( not(windows), not(target_vendor = "apple"), not(target_os = "vita"), @@ -122,24 +122,27 @@ mod c_char_definition { target_arch = "s390x", target_arch = "xtensa", ) - ))] { + ) => { pub(super) type c_char = u8; - } else { - // On every other target, c_char is signed. + } + // On every other target, c_char is signed. + _ => { pub(super) type c_char = i8; } } } mod c_long_definition { - cfg_if! { - if #[cfg(any( + crate::cfg_match! { + any( all(target_pointer_width = "64", not(windows)), // wasm32 Linux ABI uses 64-bit long - all(target_arch = "wasm32", target_os = "linux")))] { + all(target_arch = "wasm32", target_os = "linux") + ) => { pub(super) type c_long = i64; pub(super) type c_ulong = u64; - } else { + } + _ => { // The minimal size of `long` in the C standard is 32 bits pub(super) type c_long = i32; pub(super) type c_ulong = u32; @@ -169,11 +172,12 @@ pub type c_ptrdiff_t = isize; pub type c_ssize_t = isize; mod c_int_definition { - cfg_if! { - if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] { + crate::cfg_match! { + any(target_arch = "avr", target_arch = "msp430") => { pub(super) type c_int = i16; pub(super) type c_uint = u16; - } else { + } + _ => { pub(super) type c_int = i32; pub(super) type c_uint = u32; } diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs index fe4fa80263c2..2aaefba2468b 100644 --- a/library/core/src/internal_macros.rs +++ b/library/core/src/internal_macros.rs @@ -120,80 +120,3 @@ macro_rules! impl_fn_for_zst { )+ } } - -/// A macro for defining `#[cfg]` if-else statements. -/// -/// `cfg_if` is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade -/// of `#[cfg]` cases, emitting the implementation which matches first. -/// -/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code without having to -/// rewrite each clause multiple times. -/// -/// # Example -/// -/// ```ignore(cannot-test-this-because-non-exported-macro) -/// cfg_if! { -/// if #[cfg(unix)] { -/// fn foo() { /* unix specific functionality */ } -/// } else if #[cfg(target_pointer_width = "32")] { -/// fn foo() { /* non-unix, 32-bit functionality */ } -/// } else { -/// fn foo() { /* fallback implementation */ } -/// } -/// } -/// -/// # fn main() {} -/// ``` -// This is a copy of `cfg_if!` from the `cfg_if` crate. -// The recursive invocations should use $crate if this is ever exported. -macro_rules! cfg_if { - // match if/else chains with a final `else` - ( - $( - if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* } - ) else+ - else { $( $e_tokens:tt )* } - ) => { - cfg_if! { - @__items () ; - $( - (( $i_meta ) ( $( $i_tokens )* )) , - )+ - (() ( $( $e_tokens )* )) , - } - }; - - // Internal and recursive macro to emit all the items - // - // Collects all the previous cfgs in a list at the beginning, so they can be - // negated. After the semicolon is all the remaining items. - (@__items ( $( $_:meta , )* ) ; ) => {}; - ( - @__items ( $( $no:meta , )* ) ; - (( $( $yes:meta )? ) ( $( $tokens:tt )* )) , - $( $rest:tt , )* - ) => { - // Emit all items within one block, applying an appropriate #[cfg]. The - // #[cfg] will require all `$yes` matchers specified and must also negate - // all previous matchers. - #[cfg(all( - $( $yes , )? - not(any( $( $no ),* )) - ))] - cfg_if! { @__identity $( $tokens )* } - - // Recurse to emit all other items in `$rest`, and when we do so add all - // our `$yes` matchers to the list of `$no` matchers as future emissions - // will have to negate everything we just matched as well. - cfg_if! { - @__items ( $( $no , )* $( $yes , )? ) ; - $( $rest , )* - } - }; - - // Internal macro to make __apply work out right for different match types, - // because of how macros match/expand stuff. - (@__identity $( $tokens:tt )* ) => { - $( $tokens )* - }; -} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e1ca69edcbbd..dc06aa4c38d5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -100,6 +100,7 @@ #![feature(bigint_helper_methods)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(cfg_match)] #![feature(closure_track_caller)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 79d864e1b196..53373584d555 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -14,7 +14,7 @@ use crate::convert::FloatToInt; use crate::num::FpCategory; use crate::panic::const_assert; -use crate::{intrinsics, mem}; +use crate::{cfg_match, intrinsics, mem}; /// The radix or base of the internal representation of `f32`. /// Use [`f32::RADIX`] instead. @@ -996,21 +996,22 @@ impl f32 { #[stable(feature = "num_midpoint", since = "1.85.0")] #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f32) -> f32 { - cfg_if! { + cfg_match! { // Allow faster implementation that have known good 64-bit float // implementations. Falling back to the branchy code on targets that don't // have 64-bit hardware floats or buggy implementations. // https://github.com/rust-lang/rust/pull/121062#issuecomment-2123408114 - if #[cfg(any( - target_arch = "x86_64", - target_arch = "aarch64", - all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "d"), - all(target_arch = "arm", target_feature = "vfp2"), - target_arch = "wasm32", - target_arch = "wasm64", - ))] { + any( + target_arch = "x86_64", + target_arch = "aarch64", + all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "d"), + all(target_arch = "arm", target_feature = "vfp2"), + target_arch = "wasm32", + target_arch = "wasm64", + ) => { ((self as f64 + other as f64) / 2.0) as f32 - } else { + } + _ => { const LO: f32 = f32::MIN_POSITIVE * 2.; const HI: f32 = f32::MAX / 2.; diff --git a/library/core/src/slice/sort/select.rs b/library/core/src/slice/sort/select.rs index 3358c03d30a9..c4808b1065d0 100644 --- a/library/core/src/slice/sort/select.rs +++ b/library/core/src/slice/sort/select.rs @@ -6,6 +6,7 @@ //! for pivot selection. Using this as a fallback ensures O(n) worst case running time with //! better performance than one would get using heapsort as fallback. +use crate::cfg_match; use crate::mem::{self, SizedTypeProperties}; #[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::shared::pivot::choose_pivot; @@ -41,10 +42,11 @@ where let min_idx = min_index(v, &mut is_less).unwrap(); v.swap(min_idx, index); } else { - cfg_if! { - if #[cfg(feature = "optimize_for_size")] { + cfg_match! { + feature = "optimize_for_size" => { median_of_medians(v, &mut is_less, index); - } else { + } + _ => { partition_at_index_loop(v, index, None, &mut is_less); } } diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs index 090367cdabad..a36e5f7801d4 100644 --- a/library/core/src/slice/sort/stable/mod.rs +++ b/library/core/src/slice/sort/stable/mod.rs @@ -2,12 +2,12 @@ #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::cmp; -use crate::intrinsics; use crate::mem::{MaybeUninit, SizedTypeProperties}; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::{ SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left, }; +use crate::{cfg_match, intrinsics}; pub(crate) mod merge; @@ -39,17 +39,18 @@ pub fn sort bool, BufT: BufGuard>(v: &mut [T], is_less return; } - cfg_if! { - if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] { + cfg_match! { + any(feature = "optimize_for_size", target_pointer_width = "16") => { // Unlike driftsort, mergesort only requires len / 2, // not len - len / 2. let alloc_len = len / 2; - cfg_if! { - if #[cfg(target_pointer_width = "16")] { + cfg_match! { + target_pointer_width = "16" => { let mut heap_buf = BufT::with_capacity(alloc_len); let scratch = heap_buf.as_uninit_slice_mut(); - } else { + } + _ => { // For small inputs 4KiB of stack storage suffices, which allows us to avoid // calling the (de-)allocator. Benchmarks showed this was quite beneficial. let mut stack_buf = AlignedStorage::::new(); @@ -65,7 +66,8 @@ pub fn sort bool, BufT: BufGuard>(v: &mut [T], is_less } tiny::mergesort(v, scratch, is_less); - } else { + } + _ => { // More advanced sorting methods than insertion sort are faster if called in // a hot loop for small inputs, but for general-purpose code the small // binary size of insertion sort is more important. The instruction cache in diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs index 2eb653c4601a..b6c2e05a06a0 100644 --- a/library/core/src/slice/sort/unstable/mod.rs +++ b/library/core/src/slice/sort/unstable/mod.rs @@ -1,11 +1,11 @@ //! This module contains the entry points for `slice::sort_unstable`. -use crate::intrinsics; use crate::mem::SizedTypeProperties; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::find_existing_run; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; +use crate::{cfg_match, intrinsics}; pub(crate) mod heapsort; pub(crate) mod quicksort; @@ -30,10 +30,11 @@ pub fn sort bool>(v: &mut [T], is_less: &mut F) { return; } - cfg_if! { - if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] { + cfg_match! { + any(feature = "optimize_for_size", target_pointer_width = "16") => { heapsort::heapsort(v, is_less); - } else { + } + _ => { // More advanced sorting methods than insertion sort are faster if called in // a hot loop for small inputs, but for general-purpose code the small // binary size of insertion sort is more important. The instruction cache in diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs index 68a161187169..7e6cfb559905 100644 --- a/library/core/src/slice/sort/unstable/quicksort.rs +++ b/library/core/src/slice/sort/unstable/quicksort.rs @@ -9,7 +9,7 @@ use crate::slice::sort::shared::pivot::choose_pivot; use crate::slice::sort::shared::smallsort::UnstableSmallSortTypeImpl; #[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::unstable::heapsort; -use crate::{intrinsics, ptr}; +use crate::{cfg_match, intrinsics, ptr}; /// Sorts `v` recursively. /// @@ -142,10 +142,11 @@ const fn inst_partition bool>() -> fn(&mut [T], &T, &mut if size_of::() <= MAX_BRANCHLESS_PARTITION_SIZE { // Specialize for types that are relatively cheap to copy, where branchless optimizations // have large leverage e.g. `u64` and `String`. - cfg_if! { - if #[cfg(feature = "optimize_for_size")] { + cfg_match! { + feature = "optimize_for_size" => { partition_lomuto_branchless_simple:: - } else { + } + _ => { partition_lomuto_branchless_cyclic:: } } From 3d58aec0da0badcfdb9c185d317d6aa1c14ffb6e Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 27 Mar 2025 02:48:53 +0800 Subject: [PATCH 363/546] Report compiletest pass mode if forced This is very non-obvious if it fails in PR CI. --- src/tools/compiletest/src/lib.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 3ec984edacbe..950566b2582a 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -22,6 +22,7 @@ pub mod util; use core::panic; use std::collections::HashSet; use std::ffi::OsString; +use std::fmt::Write; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -570,18 +571,22 @@ pub fn run_tests(config: Arc) { // easy to miss which tests failed, and as such fail to reproduce // the failure locally. - println!( - "Some tests failed in compiletest suite={}{} mode={} host={} target={}", - config.suite, - config - .compare_mode - .as_ref() - .map(|c| format!(" compare_mode={:?}", c)) - .unwrap_or_default(), - config.mode, - config.host, - config.target - ); + let mut msg = String::from("Some tests failed in compiletest"); + write!(msg, " suite={}", config.suite).unwrap(); + + if let Some(compare_mode) = config.compare_mode.as_ref() { + write!(msg, " compare_mode={}", compare_mode).unwrap(); + } + + if let Some(pass_mode) = config.force_pass_mode.as_ref() { + write!(msg, " pass_mode={}", pass_mode).unwrap(); + } + + write!(msg, " mode={}", config.mode).unwrap(); + write!(msg, " host={}", config.host).unwrap(); + write!(msg, " target={}", config.target).unwrap(); + + println!("{msg}"); std::process::exit(1); } From d1cd621b55a7def094f5cfecb99d2909b2d0e701 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 17 Feb 2024 04:31:46 +0100 Subject: [PATCH 364/546] Always emit native-static-libs note, even if it is empty --- compiler/rustc_codegen_ssa/src/back/link.rs | 14 +++++--------- .../ui/codegen/empty-static-libs-issue-108825.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 tests/ui/codegen/empty-static-libs-issue-108825.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index a564e0e391fe..2e614a1f06f1 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1560,17 +1560,13 @@ fn print_native_static_libs( match out { OutFileName::Real(path) => { out.overwrite(&lib_args.join(" "), sess); - if !lib_args.is_empty() { - sess.dcx().emit_note(errors::StaticLibraryNativeArtifactsToFile { path }); - } + sess.dcx().emit_note(errors::StaticLibraryNativeArtifactsToFile { path }); } OutFileName::Stdout => { - if !lib_args.is_empty() { - sess.dcx().emit_note(errors::StaticLibraryNativeArtifacts); - // Prefix for greppability - // Note: This must not be translated as tools are allowed to depend on this exact string. - sess.dcx().note(format!("native-static-libs: {}", lib_args.join(" "))); - } + sess.dcx().emit_note(errors::StaticLibraryNativeArtifacts); + // Prefix for greppability + // Note: This must not be translated as tools are allowed to depend on this exact string. + sess.dcx().note(format!("native-static-libs: {}", lib_args.join(" "))); } } } diff --git a/tests/ui/codegen/empty-static-libs-issue-108825.rs b/tests/ui/codegen/empty-static-libs-issue-108825.rs new file mode 100644 index 000000000000..46bd6d6b2da4 --- /dev/null +++ b/tests/ui/codegen/empty-static-libs-issue-108825.rs @@ -0,0 +1,16 @@ +//! Test that linking a no_std application still outputs the +//! `native-static-libs: ` note, even though it is empty. + +//@ compile-flags: -Cpanic=abort --print=native-static-libs +//@ build-pass +//@ error-pattern: note: native-static-libs: +//@ dont-check-compiler-stderr (libcore links `/defaultlib:msvcrt` or `/defaultlib:libcmt` on MSVC) +//@ ignore-pass (the note is emitted later in the compilation pipeline, needs build) + +#![crate_type = "staticlib"] +#![no_std] + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} From 8f735d0779a84e83a9db2cb4c93c7d0062d535a6 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Wed, 26 Mar 2025 17:32:52 -0400 Subject: [PATCH 365/546] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 307cbfda3119..a6c604d1b8a2 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 307cbfda3119f06600e43cd38283f4a746fe1f8b +Subproject commit a6c604d1b8a2f2a8ff1f3ba6092f9fda42f4b7e9 From af7359ee4fd25ac5fd92fa20c8b37405ac0d0c05 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 26 Mar 2025 12:10:47 -0700 Subject: [PATCH 366/546] Add release notes for 1.86.0 --- RELEASES.md | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 755e73a34c6b..3047a0c366a4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,125 @@ +Version 1.86.0 (2025-04-03) +========================== + + + +Language +-------- +- [Stabilize the ability to upcast a trait object to one of its supertraits.](https://github.com/rust-lang/rust/pull/134367) +- [Allow safe functions to be marked with the `#[target_feature]` attribute.](https://github.com/rust-lang/rust/pull/134090) +- [The `missing_abi` lint now warns-by-default.](https://github.com/rust-lang/rust/pull/132397) +- Rust now lints about double negations, to catch cases that might have intended to be a prefix decrement operator (`--x`) as written in other languages. This was previously a clippy lint, `clippy::double_neg`, and is [now available directly in Rust as `double_negations`.](https://github.com/rust-lang/rust/pull/126604) +- [More pointers are now detected as definitely not-null based on their alignment in const eval.](https://github.com/rust-lang/rust/pull/133700) +- [Empty `repr()` attribute applied to invalid items are now correctly rejected.](https://github.com/rust-lang/rust/pull/133925) +- [Inner attributes `#![test]` and `#![rustfmt::skip]` are no longer accepted in more places than intended.](https://github.com/rust-lang/rust/pull/134276) + + + +Compiler +-------- +- [Debug-assert that raw pointers are non-null on access.](https://github.com/rust-lang/rust/pull/134424) +- [Change `-O` to mean `-C opt-level=3` instead of `-C opt-level=2` to match Cargo's defaults.](https://github.com/rust-lang/rust/pull/135439) +- [Fix emission of `overflowing_literals` under certain macro environments.](https://github.com/rust-lang/rust/pull/136393) + + + +Platform Support +---------------- +- [Replace `i686-unknown-redox` target with `i586-unknown-redox`.](https://github.com/rust-lang/rust/pull/136698) +- [Increase baseline CPU of `i686-unknown-hurd-gnu` to Pentium 4.](https://github.com/rust-lang/rust/pull/136700) +- New tier 3 targets: + - [`{aarch64-unknown,x86_64-pc}-nto-qnx710_iosock`](https://github.com/rust-lang/rust/pull/133631). + For supporting Neutrino QNX 7.1 with `io-socket` network stack. + - [`{aarch64-unknown,x86_64-pc}-nto-qnx800`](https://github.com/rust-lang/rust/pull/133631). + For supporting Neutrino QNX 8.0 (`no_std`-only). + - [`{x86_64,i686}-win7-windows-gnu`](https://github.com/rust-lang/rust/pull/134609). + Intended for backwards compatibility with Windows 7. `{x86_64,i686}-win7-windows-msvc` are the Windows MSVC counterparts that already exist as Tier 3 targets. + - [`amdgcn-amd-amdhsa`](https://github.com/rust-lang/rust/pull/134740). + - [`x86_64-pc-cygwin`](https://github.com/rust-lang/rust/pull/134999). + - [`{mips,mipsel}-mti-none-elf`](https://github.com/rust-lang/rust/pull/135074). + Initial bare-metal support. + - [`m68k-unknown-none-elf`](https://github.com/rust-lang/rust/pull/135085). + - [`armv7a-nuttx-{eabi,eabihf}`, `aarch64-unknown-nuttx`, and `thumbv7a-nuttx-{eabi,eabihf}`](https://github.com/rust-lang/rust/pull/135757). + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + + + +Libraries +--------- +- The type of `FromBytesWithNulError` in `CStr::from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError>` was [changed from an opaque struct to an enum](https://github.com/rust-lang/rust/pull/134143), allowing users to examine why the conversion failed. +- [Remove `RustcDecodable` and `RustcEncodable`.](https://github.com/rust-lang/rust/pull/134272) +- [Deprecate libtest's `--logfile` option.](https://github.com/rust-lang/rust/pull/134283) +- [On recent versions of Windows, `std::fs::remove_file` will now remove read-only files.](https://github.com/rust-lang/rust/pull/134679) + + + +Stabilized APIs +--------------- + +- [`{float}::next_down`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.next_down) +- [`{float}::next_up`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.next_up) +- [`<[_]>::get_disjoint_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.get_disjoint_mut) +- [`<[_]>::get_disjoint_unchecked_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.get_disjoint_unchecked_mut) +- [`slice::GetDisjointMutError`](https://doc.rust-lang.org/stable/std/slice/enum.GetDisjointMutError.html) +- [`HashMap::get_disjoint_mut`](https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.get_disjoint_mut) +- [`HashMap::get_disjoint_unchecked_mut`](https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.get_disjoint_unchecked_mut) +- [`NonZero::count_ones`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.count_ones) +- [`Vec::pop_if`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.pop_if) +- [`sync::Once::wait`](https://doc.rust-lang.org/stable/std/sync/struct.Once.html#method.wait) +- [`sync::Once::wait_force`](https://doc.rust-lang.org/stable/std/sync/struct.Once.html#method.wait_force) +- [`sync::OnceLock::wait`](https://doc.rust-lang.org/stable/std/sync/struct.OnceLock.html#method.wait) + +These APIs are now stable in const contexts: + +- [`hint::black_box`](https://doc.rust-lang.org/stable/std/hint/fn.black_box.html) +- [`io::Cursor::get_mut`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.get_mut) +- [`io::Cursor::set_position`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.set_position) +- [`str::is_char_boundary`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.is_char_boundary) +- [`str::split_at`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at) +- [`str::split_at_checked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_checked) +- [`str::split_at_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_mut) +- [`str::split_at_mut_checked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_mut_checked) + + + +Cargo +----- +- [When merging, replace rather than combine configuration keys that refer to a program path and its arguments.](https://github.com/rust-lang/cargo/pull/15066/) +- [Error if both `--package` and `--workspace` are passed but the requested package is missing.](https://github.com/rust-lang/cargo/pull/15071/) This was previously silently ignored, which was considered a bug since missing packages should be reported. +- [Deprecate the token argument in `cargo login` to avoid shell history leaks.](https://github.com/rust-lang/cargo/pull/15057/) +- [Simplify the implementation of `SourceID` comparisons.](https://github.com/rust-lang/cargo/pull/14980/) This may potentially change behavior if the canonicalized URL compares differently in alternative registries. + + + +Rustdoc +----- +- [Add a sans-serif font setting.](https://github.com/rust-lang/rust/pull/133636) + + + +Compatibility Notes +------------------- +- [The `wasm_c_abi` future compatibility warning is now a hard error.](https://github.com/rust-lang/rust/pull/133951) + Users of `wasm-bindgen` should upgrade to at least version 0.2.89, otherwise compilation will fail. +- [Remove long-deprecated no-op attributes `#![no_start]` and `#![crate_id]`.](https://github.com/rust-lang/rust/pull/134300) +- The future incompatibility lint `cenum_impl_drop_cast` [has been made into a hard error.](https://github.com/rust-lang/rust/pull/135964) This means it is now an error to cast a field-less enum to an integer if the enum implements `Drop`. +- [SSE2 is now required for "i686" 32-bit x86 hard-float targets; disabling it causes a warning that will become a hard error eventually.](https://github.com/rust-lang/rust/pull/137037) + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Build the rustc on AArch64 Linux with ThinLTO + PGO.](https://github.com/rust-lang/rust/pull/133807) +The ARM 64-bit compiler (AArch64) on Linux is now optimized with ThinLTO and PGO, similar to the optimizations we have already performed for the x86-64 compiler on Linux. This should make it up to 30% faster. + + Version 1.85.1 (2025-03-18) ========================== From 74b7599230996968c476a5ea9b5e44be545e673e Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 26 Mar 2025 19:33:46 -0500 Subject: [PATCH 367/546] satisfy eslint --- src/librustdoc/html/static/js/search.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 651d12bb2e90..f3f4878b1627 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1,5 +1,5 @@ // ignore-tidy-filelength -/* global addClass, getNakedUrl, getSettingValue, getVar, nonnull, nonundef */ +/* global addClass, getNakedUrl, getSettingValue, getVar, nonundef */ /* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */ "use strict"; @@ -2489,7 +2489,7 @@ class DocSearch { } } catch (err) { query = newParsedQuery(userQuery); - if (Array.isArray(err) && err.every((elem) => typeof elem == 'string')) { + if (Array.isArray(err) && err.every(elem => typeof elem === "string")) { query.error = err; } else { // rethrow the error if it isn't a string array @@ -2797,7 +2797,7 @@ class DocSearch { }, this.searchIndex[result.id]); // To be sure than it some items aren't considered as duplicate. - obj.fullPath = res[2] + "|" + obj.ty + obj.fullPath = res[2] + "|" + obj.ty; if (duplicates.has(obj.fullPath)) { continue; From 713becd7daf6aa2d8b702bacf5681f237f315762 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 26 Mar 2025 18:54:35 +0100 Subject: [PATCH 368/546] refactor: Move Apple SDK names to rustc_codegen_ssa::back::apple --- compiler/rustc_codegen_ssa/messages.ftl | 2 -- compiler/rustc_codegen_ssa/src/back/apple.rs | 18 ++++++++++++ compiler/rustc_codegen_ssa/src/back/link.rs | 30 ++------------------ compiler/rustc_codegen_ssa/src/errors.rs | 7 ----- 4 files changed, 21 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 95912b016007..a33c0aa58349 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -391,8 +391,6 @@ codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified -codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` - codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]` codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs index bfa7635a869f..24995be6f944 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple.rs @@ -11,6 +11,24 @@ use crate::errors::AppleDeploymentTarget; #[cfg(test)] mod tests; +/// The canonical name of the desired SDK for a given target. +pub(super) fn sdk_name(target: &Target) -> &'static str { + match (&*target.os, &*target.abi) { + ("macos", "") => "MacOSX", + ("ios", "") => "iPhoneOS", + ("ios", "sim") => "iPhoneSimulator", + // Mac Catalyst uses the macOS SDK + ("ios", "macabi") => "MacOSX", + ("tvos", "") => "AppleTVOS", + ("tvos", "sim") => "AppleTVSimulator", + ("visionos", "") => "XROS", + ("visionos", "sim") => "XRSimulator", + ("watchos", "") => "WatchOS", + ("watchos", "sim") => "WatchSimulator", + (os, abi) => unreachable!("invalid os '{os}' / abi '{abi}' combination for Apple target"), + } +} + pub(super) fn macho_platform(target: &Target) -> u32 { match (&*target.os, &*target.abi) { ("macos", _) => object::macho::PLATFORM_MACOS, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 74597f6263d4..776f381ded4f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3201,9 +3201,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo } fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option { - let arch = &sess.target.arch; let os = &sess.target.os; - let llvm_target = &sess.target.llvm_target; if sess.target.vendor != "apple" || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "visionos" | "macos") || !matches!(flavor, LinkerFlavor::Darwin(..)) @@ -3215,31 +3213,9 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> return None; } - let sdk_name = match (arch.as_ref(), os.as_ref()) { - ("aarch64", "tvos") if llvm_target.ends_with("-simulator") => "appletvsimulator", - ("aarch64", "tvos") => "appletvos", - ("x86_64", "tvos") => "appletvsimulator", - ("arm", "ios") => "iphoneos", - ("aarch64", "ios") if llvm_target.contains("macabi") => "macosx", - ("aarch64", "ios") if llvm_target.ends_with("-simulator") => "iphonesimulator", - ("aarch64", "ios") => "iphoneos", - ("x86", "ios") => "iphonesimulator", - ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx", - ("x86_64", "ios") => "iphonesimulator", - ("x86_64", "watchos") => "watchsimulator", - ("arm64_32", "watchos") => "watchos", - ("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator", - ("aarch64", "watchos") => "watchos", - ("aarch64", "visionos") if llvm_target.ends_with("-simulator") => "xrsimulator", - ("aarch64", "visionos") => "xros", - ("arm", "watchos") => "watchos", - (_, "macos") => "macosx", - _ => { - sess.dcx().emit_err(errors::UnsupportedArch { arch, os }); - return None; - } - }; - let sdk_root = match get_apple_sdk_root(sdk_name) { + let sdk_name = apple::sdk_name(&sess.target).to_lowercase(); + + let sdk_root = match get_apple_sdk_root(&sdk_name) { Ok(s) => s, Err(e) => { sess.dcx().emit_err(e); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 0b7cad0c2fd8..9c4c205dfe55 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -738,13 +738,6 @@ pub enum ExtractBundledLibsError<'a> { ExtractSection { rlib: &'a Path, error: Box }, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_unsupported_arch)] -pub(crate) struct UnsupportedArch<'a> { - pub arch: &'a str, - pub os: &'a str, -} - #[derive(Diagnostic)] pub(crate) enum AppleDeploymentTarget { #[diag(codegen_ssa_apple_deployment_target_invalid)] From dffb0dbc3e2f28a82085025aec4aea6a6a28b611 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 27 Mar 2025 03:10:29 +0100 Subject: [PATCH 369/546] Document how the SDK is found if SDKROOT is not set I've intentionally used slightly vague language ("roughly"), as we don't want to guarantee the exact invocation of `xcrun`, just hint that it's close to that. --- src/doc/rustc/src/platform-support/apple-darwin.md | 3 ++- src/doc/rustc/src/platform-support/apple-ios-macabi.md | 3 ++- src/doc/rustc/src/platform-support/apple-ios.md | 3 ++- src/doc/rustc/src/platform-support/apple-tvos.md | 3 ++- src/doc/rustc/src/platform-support/apple-visionos.md | 3 ++- src/doc/rustc/src/platform-support/apple-watchos.md | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md index dba2c4b2aaf0..22c54d04b1eb 100644 --- a/src/doc/rustc/src/platform-support/apple-darwin.md +++ b/src/doc/rustc/src/platform-support/apple-darwin.md @@ -70,4 +70,5 @@ the `-mmacosx-version-min=...`, `-miphoneos-version-min=...` or similar flags to disambiguate. The path to the SDK can be passed to `rustc` using the common `SDKROOT` -environment variable. +environment variable, or will be inferred when compiling on host macOS using +roughly the same logic as `xcrun --sdk macosx --show-sdk-path`. diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md index a54656190d1f..79966d908d89 100644 --- a/src/doc/rustc/src/platform-support/apple-ios-macabi.md +++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md @@ -20,7 +20,8 @@ These targets are cross-compiled, and require the corresponding macOS SDK iOS-specific headers, as provided by Xcode 11 or higher. The path to the SDK can be passed to `rustc` using the common `SDKROOT` -environment variable. +environment variable, or will be inferred when compiling on host macOS using +roughly the same logic as `xcrun --sdk macosx --show-sdk-path`. ### OS version diff --git a/src/doc/rustc/src/platform-support/apple-ios.md b/src/doc/rustc/src/platform-support/apple-ios.md index cfb458fdb737..7f5dc361c49d 100644 --- a/src/doc/rustc/src/platform-support/apple-ios.md +++ b/src/doc/rustc/src/platform-support/apple-ios.md @@ -26,7 +26,8 @@ These targets are cross-compiled, and require the corresponding iOS SDK ARM64 targets, Xcode 12 or higher is required. The path to the SDK can be passed to `rustc` using the common `SDKROOT` -environment variable. +environment variable, or will be inferred when compiling on host macOS using +roughly the same logic as `xcrun --sdk iphoneos --show-sdk-path`. ### OS version diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md index 166bb1b6db29..fc46db20074f 100644 --- a/src/doc/rustc/src/platform-support/apple-tvos.md +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -20,7 +20,8 @@ These targets are cross-compiled, and require the corresponding tvOS SDK ARM64 targets, Xcode 12 or higher is required. The path to the SDK can be passed to `rustc` using the common `SDKROOT` -environment variable. +environment variable, or will be inferred when compiling on host macOS using +roughly the same logic as `xcrun --sdk appletvos --show-sdk-path`. ### OS version diff --git a/src/doc/rustc/src/platform-support/apple-visionos.md b/src/doc/rustc/src/platform-support/apple-visionos.md index a7bbae168a4f..7cf9549227d9 100644 --- a/src/doc/rustc/src/platform-support/apple-visionos.md +++ b/src/doc/rustc/src/platform-support/apple-visionos.md @@ -18,7 +18,8 @@ These targets are cross-compiled, and require the corresponding visionOS SDK (`XROS.sdk` or `XRSimulator.sdk`), as provided by Xcode 15 or newer. The path to the SDK can be passed to `rustc` using the common `SDKROOT` -environment variable. +environment variable, or will be inferred when compiling on host macOS using +roughly the same logic as `xcrun --sdk xros --show-sdk-path`. ### OS version diff --git a/src/doc/rustc/src/platform-support/apple-watchos.md b/src/doc/rustc/src/platform-support/apple-watchos.md index 0bf8cdf36142..7b12d9ebfd4b 100644 --- a/src/doc/rustc/src/platform-support/apple-watchos.md +++ b/src/doc/rustc/src/platform-support/apple-watchos.md @@ -24,7 +24,8 @@ These targets are cross-compiled, and require the corresponding watchOS SDK ARM64 targets, Xcode 12 or higher is required. The path to the SDK can be passed to `rustc` using the common `SDKROOT` -environment variable. +environment variable, or will be inferred when compiling on host macOS using +roughly the same logic as `xcrun --sdk watchos --show-sdk-path`. ### OS version From bd1ef0fad2e8172549a07fbf17dc1f9c4ceea078 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 27 Mar 2025 03:10:58 +0100 Subject: [PATCH 370/546] Invoke xcrun inside sess.time It can be a fairly expensive operation when the output is not cached, so it's nice to get some visibility into the runtime cost. --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 776f381ded4f..eb6aebf23203 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3215,7 +3215,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> let sdk_name = apple::sdk_name(&sess.target).to_lowercase(); - let sdk_root = match get_apple_sdk_root(&sdk_name) { + let sdk_root = match sess.time("get_apple_sdk_root", || get_apple_sdk_root(&sdk_name)) { Ok(s) => s, Err(e) => { sess.dcx().emit_err(e); From 89348e51e383a6300206e3356143fce812838921 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 27 Mar 2025 03:15:58 +0100 Subject: [PATCH 371/546] Emit better error messages when invoking xcrun Also allow the SDK path to be non-UTF-8. --- compiler/rustc_codegen_ssa/messages.ftl | 19 ++- compiler/rustc_codegen_ssa/src/back/apple.rs | 136 +++++++++++++++++- .../rustc_codegen_ssa/src/back/apple/tests.rs | 68 ++++++++- compiler/rustc_codegen_ssa/src/back/link.rs | 59 +++----- compiler/rustc_codegen_ssa/src/errors.rs | 29 +++- compiler/rustc_codegen_ssa/src/lib.rs | 1 + 6 files changed, 263 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index a33c0aa58349..954a60148093 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -10,8 +10,6 @@ codegen_ssa_apple_deployment_target_invalid = codegen_ssa_apple_deployment_target_too_low = deployment target in {$env_var} was set to {$version}, but the minimum supported by `rustc` is {$os_min} -codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error} - codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error} codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering @@ -400,3 +398,20 @@ codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to sp codegen_ssa_version_script_write_failure = failed to write version script: {$error} codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload + +codegen_ssa_xcrun_command_line_tools_insufficient = + when compiling for iOS, tvOS, visionOS or watchOS, you need a full installation of Xcode + +codegen_ssa_xcrun_failed_invoking = invoking `{$command_formatted}` to find {$sdk_name}.sdk failed: {$error} + +codegen_ssa_xcrun_found_developer_dir = found active developer directory at "{$developer_dir}" + +# `xcrun` already outputs a message about missing Xcode installation, so we only augment it with details about env vars. +codegen_ssa_xcrun_no_developer_dir = + pass the path of an Xcode installation via the DEVELOPER_DIR environment variable, or an SDK with the SDKROOT environment variable + +codegen_ssa_xcrun_sdk_path_warning = output of `xcrun` while finding {$sdk_name}.sdk + .note = {$stderr} + +codegen_ssa_xcrun_unsuccessful = failed running `{$command_formatted}` to find {$sdk_name}.sdk + .note = {$stdout}{$stderr} diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs index 24995be6f944..2c8b0ec418dd 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple.rs @@ -1,12 +1,18 @@ use std::env; +use std::ffi::OsString; use std::fmt::{Display, from_fn}; use std::num::ParseIntError; +use std::path::PathBuf; +use std::process::Command; +use itertools::Itertools; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::Session; use rustc_target::spec::Target; +use tracing::debug; -use crate::errors::AppleDeploymentTarget; +use crate::errors::{AppleDeploymentTarget, XcrunError, XcrunSdkPathWarning}; +use crate::fluent_generated as fluent; #[cfg(test)] mod tests; @@ -271,3 +277,131 @@ pub(super) fn add_version_to_llvm_target( format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}") } } + +pub(super) fn get_sdk_root(sess: &Session) -> Option { + let sdk_name = sdk_name(&sess.target); + + match xcrun_show_sdk_path(sdk_name, sess.verbose_internals()) { + Ok((path, stderr)) => { + // Emit extra stderr, such as if `-verbose` was passed, or if `xcrun` emitted a warning. + if !stderr.is_empty() { + sess.dcx().emit_warn(XcrunSdkPathWarning { sdk_name, stderr }); + } + Some(path) + } + Err(err) => { + let mut diag = sess.dcx().create_err(err); + + // Recognize common error cases, and give more Rust-specific error messages for those. + if let Some(developer_dir) = xcode_select_developer_dir() { + diag.arg("developer_dir", &developer_dir); + diag.note(fluent::codegen_ssa_xcrun_found_developer_dir); + if developer_dir.as_os_str().to_string_lossy().contains("CommandLineTools") { + if sdk_name != "MacOSX" { + diag.help(fluent::codegen_ssa_xcrun_command_line_tools_insufficient); + } + } + } else { + diag.help(fluent::codegen_ssa_xcrun_no_developer_dir); + } + + diag.emit(); + None + } + } +} + +/// Invoke `xcrun --sdk $sdk_name --show-sdk-path` to get the SDK path. +/// +/// The exact logic that `xcrun` uses is unspecified (see `man xcrun` for a few details), and may +/// change between macOS and Xcode versions, but it roughly boils down to finding the active +/// developer directory, and then invoking `xcodebuild -sdk $sdk_name -version` to get the SDK +/// details. +/// +/// Finding the developer directory is roughly done by looking at, in order: +/// - The `DEVELOPER_DIR` environment variable. +/// - The `/var/db/xcode_select_link` symlink (set by `xcode-select --switch`). +/// - `/Applications/Xcode.app` (hardcoded fallback path). +/// - `/Library/Developer/CommandLineTools` (hardcoded fallback path). +/// +/// Note that `xcrun` caches its result, but with a cold cache this whole operation can be quite +/// slow, especially so the first time it's run after a reboot. +fn xcrun_show_sdk_path( + sdk_name: &'static str, + verbose: bool, +) -> Result<(PathBuf, String), XcrunError> { + let mut cmd = Command::new("xcrun"); + if verbose { + cmd.arg("--verbose"); + } + // The `--sdk` parameter is the same as in xcodebuild, namely either an absolute path to an SDK, + // or the (lowercase) canonical name of an SDK. + cmd.arg("--sdk"); + cmd.arg(&sdk_name.to_lowercase()); + cmd.arg("--show-sdk-path"); + + // We do not stream stdout/stderr lines directly to the user, since whether they are warnings or + // errors depends on the status code at the end. + let output = cmd.output().map_err(|error| XcrunError::FailedInvoking { + sdk_name, + command_formatted: format!("{cmd:?}"), + error, + })?; + + // It is fine to do lossy conversion here, non-UTF-8 paths are quite rare on macOS nowadays + // (only possible with the HFS+ file system), and we only use it for error messages. + let stderr = String::from_utf8_lossy_owned(output.stderr); + if !stderr.is_empty() { + debug!(stderr, "original xcrun stderr"); + } + + // Some versions of `xcodebuild` output beefy errors when invoked via `xcrun`, + // but these are usually red herrings. + let stderr = stderr + .lines() + .filter(|line| { + !line.contains("Writing error result bundle") + && !line.contains("Requested but did not find extension point with identifier") + }) + .join("\n"); + + if output.status.success() { + Ok((stdout_to_path(output.stdout), stderr)) + } else { + // Output both stdout and stderr, since shims of `xcrun` (such as the one provided by + // nixpkgs), do not always use stderr for errors. + let stdout = String::from_utf8_lossy_owned(output.stdout).trim().to_string(); + Err(XcrunError::Unsuccessful { + sdk_name, + command_formatted: format!("{cmd:?}"), + stdout, + stderr, + }) + } +} + +/// Invoke `xcode-select --print-path`, and return the current developer directory. +/// +/// NOTE: We don't do any error handling here, this is only used as a canary in diagnostics (`xcrun` +/// will have already emitted the relevant error information). +fn xcode_select_developer_dir() -> Option { + let mut cmd = Command::new("xcode-select"); + cmd.arg("--print-path"); + let output = cmd.output().ok()?; + if !output.status.success() { + return None; + } + Some(stdout_to_path(output.stdout)) +} + +fn stdout_to_path(mut stdout: Vec) -> PathBuf { + // Remove trailing newline. + if let Some(b'\n') = stdout.last() { + let _ = stdout.pop().unwrap(); + } + #[cfg(unix)] + let path = ::from_vec(stdout); + #[cfg(not(unix))] // Unimportant, this is only used on macOS + let path = OsString::from(String::from_utf8(stdout).unwrap()); + PathBuf::from(path) +} diff --git a/compiler/rustc_codegen_ssa/src/back/apple/tests.rs b/compiler/rustc_codegen_ssa/src/back/apple/tests.rs index 7ccda5a8190c..8df740a4bcf7 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple/tests.rs @@ -1,4 +1,4 @@ -use super::{add_version_to_llvm_target, parse_version}; +use super::*; #[test] fn test_add_version_to_llvm_target() { @@ -19,3 +19,69 @@ fn test_parse_version() { assert_eq!(parse_version("10.12.6"), Ok((10, 12, 6))); assert_eq!(parse_version("9999.99.99"), Ok((9999, 99, 99))); } + +#[test] +#[cfg_attr(not(target_os = "macos"), ignore = "xcode-select is only available on macOS")] +fn lookup_developer_dir() { + let _developer_dir = xcode_select_developer_dir().unwrap(); +} + +#[test] +#[cfg_attr(not(target_os = "macos"), ignore = "xcrun is only available on macOS")] +fn lookup_sdk() { + let (sdk_path, stderr) = xcrun_show_sdk_path("MacOSX", false).unwrap(); + // Check that the found SDK is valid. + assert!(sdk_path.join("SDKSettings.plist").exists()); + assert_eq!(stderr, ""); + + // Test that the SDK root is a subdir of the developer directory. + if let Some(developer_dir) = xcode_select_developer_dir() { + // Only run this test if SDKROOT is not set (otherwise xcrun may look up via. that). + if std::env::var_os("SDKROOT").is_some() { + assert!(sdk_path.starts_with(&developer_dir)); + } + } +} + +#[test] +#[cfg_attr(not(target_os = "macos"), ignore = "xcrun is only available on macOS")] +fn lookup_sdk_verbose() { + let (_, stderr) = xcrun_show_sdk_path("MacOSX", true).unwrap(); + // Newer xcrun versions should emit something like this: + // + // xcrun: note: looking up SDK with 'xcodebuild -sdk macosx -version Path' + // xcrun: note: xcrun_db = '/var/.../xcrun_db' + // xcrun: note: lookup resolved to: '...' + // xcrun: note: database key is: ... + // + // Or if the value is already cached, something like this: + // + // xcrun: note: database key is: ... + // xcrun: note: lookup resolved in '/var/.../xcrun_db' : '...' + assert!( + stderr.contains("xcrun: note: lookup resolved"), + "stderr should contain lookup note: {stderr}", + ); +} + +#[test] +#[cfg_attr(not(target_os = "macos"), ignore = "xcrun is only available on macOS")] +fn try_lookup_invalid_sdk() { + // As a proxy for testing all the different ways that `xcrun` can fail, + // test the case where an SDK was not found. + let err = xcrun_show_sdk_path("invalid", false).unwrap_err(); + let XcrunError::Unsuccessful { stderr, .. } = err else { + panic!("unexpected error kind: {err:?}"); + }; + // Either one of (depending on if using Command Line Tools or full Xcode): + // xcrun: error: SDK "invalid" cannot be located + // xcodebuild: error: SDK "invalid" cannot be located. + assert!( + stderr.contains(r#"error: SDK "invalid" cannot be located"#), + "stderr should contain xcodebuild note: {stderr}", + ); + assert!( + stderr.contains("xcrun: error: unable to lookup item 'Path' in SDK 'invalid'"), + "stderr should contain xcrun note: {stderr}", + ); +} diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index eb6aebf23203..e66d549aabc4 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3213,15 +3213,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> return None; } - let sdk_name = apple::sdk_name(&sess.target).to_lowercase(); - - let sdk_root = match sess.time("get_apple_sdk_root", || get_apple_sdk_root(&sdk_name)) { - Ok(s) => s, - Err(e) => { - sess.dcx().emit_err(e); - return None; - } - }; + let sdk_root = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?; match flavor { LinkerFlavor::Darwin(Cc::Yes, _) => { @@ -3231,28 +3223,32 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> // This is admittedly a bit strange, as on most targets // `-isysroot` only applies to include header files, but on Apple // targets this also applies to libraries and frameworks. - cmd.cc_args(&["-isysroot", &sdk_root]); + cmd.cc_arg("-isysroot"); + cmd.cc_arg(&sdk_root); } LinkerFlavor::Darwin(Cc::No, _) => { - cmd.link_args(&["-syslibroot", &sdk_root]); + cmd.link_arg("-syslibroot"); + cmd.link_arg(&sdk_root); } _ => unreachable!(), } - Some(sdk_root.into()) + Some(sdk_root) } -fn get_apple_sdk_root(sdk_name: &str) -> Result> { - // Following what clang does - // (https://github.com/llvm/llvm-project/blob/ - // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678) - // to allow the SDK path to be set. (For clang, xcrun sets - // SDKROOT; for rustc, the user or build system can set it, or we - // can fall back to checking for xcrun on PATH.) +fn get_apple_sdk_root(sess: &Session) -> Option { if let Ok(sdkroot) = env::var("SDKROOT") { - let p = Path::new(&sdkroot); - match sdk_name { - // Ignore `SDKROOT` if it's clearly set for the wrong platform. + let p = PathBuf::from(&sdkroot); + + // Ignore invalid SDKs, similar to what clang does: + // https://github.com/llvm/llvm-project/blob/llvmorg-19.1.6/clang/lib/Driver/ToolChains/Darwin.cpp#L2212-L2229 + // + // NOTE: Things are complicated here by the fact that `rustc` can be run by Cargo to compile + // build scripts and proc-macros for the host, and thus we need to ignore SDKROOT if it's + // clearly set for the wrong platform. + // + // FIXME(madsmtm): Make this more robust (maybe read `SDKSettings.json` like Clang does?). + match &*apple::sdk_name(&sess.target).to_lowercase() { "appletvos" if sdkroot.contains("TVSimulator.platform") || sdkroot.contains("MacOSX.platform") => {} @@ -3279,26 +3275,11 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result {} // Ignore `SDKROOT` if it's not a valid path. _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} - _ => return Ok(sdkroot), + _ => return Some(p), } } - let res = - Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then( - |output| { - if output.status.success() { - Ok(String::from_utf8(output.stdout).unwrap()) - } else { - let error = String::from_utf8(output.stderr); - let error = format!("process exit with error: {}", error.unwrap()); - Err(io::Error::new(io::ErrorKind::Other, &error[..])) - } - }, - ); - match res { - Ok(output) => Ok(output.trim().to_string()), - Err(error) => Err(errors::AppleSdkRootError::SdkPath { sdk_name, error }), - } + apple::get_sdk_root(sess) } /// When using the linker flavors opting in to `lld`, add the necessary paths and arguments to diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 9c4c205dfe55..f52d29baf9dc 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -746,12 +746,6 @@ pub(crate) enum AppleDeploymentTarget { TooLow { env_var: &'static str, version: String, os_min: String }, } -#[derive(Diagnostic)] -pub(crate) enum AppleSdkRootError<'a> { - #[diag(codegen_ssa_apple_sdk_error_sdk_path)] - SdkPath { sdk_name: &'a str, error: Error }, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_read_file)] pub(crate) struct ReadFileError { @@ -1327,3 +1321,26 @@ pub(crate) struct MixedExportNameAndNoMangle { #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] pub removal_span: Span, } + +#[derive(Diagnostic, Debug)] +pub(crate) enum XcrunError { + #[diag(codegen_ssa_xcrun_failed_invoking)] + FailedInvoking { sdk_name: &'static str, command_formatted: String, error: std::io::Error }, + + #[diag(codegen_ssa_xcrun_unsuccessful)] + #[note] + Unsuccessful { + sdk_name: &'static str, + command_formatted: String, + stdout: String, + stderr: String, + }, +} + +#[derive(Diagnostic, Debug)] +#[diag(codegen_ssa_xcrun_sdk_path_warning)] +#[note] +pub(crate) struct XcrunSdkPathWarning { + pub sdk_name: &'static str, + pub stderr: String, +} diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 93c34a2f5764..d26d6edf3149 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -13,6 +13,7 @@ #![feature(let_chains)] #![feature(negative_impls)] #![feature(rustdoc_internals)] +#![feature(string_from_utf8_lossy_owned)] #![feature(trait_alias)] #![feature(try_blocks)] // tidy-alphabetical-end From 3237b5092bb2dd6bc72ccf38fd42a226eed09e77 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 27 Mar 2025 08:46:35 +0100 Subject: [PATCH 372/546] Add needs-threads to test. --- tests/ui/thread-local/spawn-hook-atexit.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/thread-local/spawn-hook-atexit.rs b/tests/ui/thread-local/spawn-hook-atexit.rs index cc517e8fa4c6..41fcbab1a812 100644 --- a/tests/ui/thread-local/spawn-hook-atexit.rs +++ b/tests/ui/thread-local/spawn-hook-atexit.rs @@ -1,4 +1,5 @@ // Regression test for https://github.com/rust-lang/rust/issues/138696 +//@ needs-threads //@ run-pass #![feature(rustc_private)] From 5a6ed74a6cae1b8bd994a9b2738896b425726c52 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Mar 2025 19:10:14 +1100 Subject: [PATCH 373/546] Remove `kw::Empty` uses from `src/librustdoc`. Much like the ones in the previous commit. --- src/librustdoc/clean/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index de6dc088176f..f72acaae02f2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1943,14 +1943,11 @@ fn clean_trait_object_lifetime_bound<'tcx>( // latter contrary to `clean_middle_region`. match *region { ty::ReStatic => Some(Lifetime::statik()), - ty::ReEarlyParam(region) if region.name != kw::Empty => Some(Lifetime(region.name)), - ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) - if name != kw::Empty => - { + ty::ReEarlyParam(region) => Some(Lifetime(region.name)), + ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) => { Some(Lifetime(name)) } - ty::ReEarlyParam(_) - | ty::ReBound(..) + ty::ReBound(..) | ty::ReLateParam(_) | ty::ReVar(_) | ty::RePlaceholder(_) From 215c2c2f494e18791f9321f072a7c05c2f17238e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 27 Mar 2025 11:05:49 +0100 Subject: [PATCH 374/546] Remove some asserts from the `download_ci_llvm` bootstrap test --- src/bootstrap/src/core/config/tests.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 068e237c2cdc..6d63709f4740 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -24,31 +24,11 @@ pub(crate) fn parse(config: &str) -> Config { #[test] fn download_ci_llvm() { - let config = parse(""); - let is_available = llvm::is_ci_llvm_available_for_target(&config, config.llvm_assertions); - if is_available { - assert!(config.llvm_from_ci); - } - - let config = Config::parse_inner( - Flags::parse(&[ - "check".to_string(), - "--config=/does/not/exist".to_string(), - "--ci".to_string(), - "false".to_string(), - ]), - |&_| toml::from_str("llvm.download-ci-llvm = true"), - ); - let is_available = llvm::is_ci_llvm_available_for_target(&config, config.llvm_assertions); - if is_available { - assert!(config.llvm_from_ci); - } - let config = parse("llvm.download-ci-llvm = false"); assert!(!config.llvm_from_ci); let if_unchanged_config = parse("llvm.download-ci-llvm = \"if-unchanged\""); - if if_unchanged_config.llvm_from_ci { + if if_unchanged_config.llvm_from_ci && if_unchanged_config.is_running_on_ci { let has_changes = if_unchanged_config .last_modified_commit(LLVM_INVALIDATION_PATHS, "download-ci-llvm", true) .is_none(); From 1f1c630a58297d49e92b79cf072559924b4f1123 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Mar 2025 23:33:54 +0100 Subject: [PATCH 375/546] Greatly simplify doctest parsing and information extraction --- src/librustdoc/doctest/make.rs | 471 ++++++++++----------------------- 1 file changed, 142 insertions(+), 329 deletions(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 9935074877bc..cb14608b35ae 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -5,11 +5,10 @@ use std::fmt::{self, Write as _}; use std::io; use std::sync::Arc; -use rustc_ast as ast; +use rustc_ast::{self as ast, HasAttrs}; +use rustc_errors::ColorConfig; use rustc_errors::emitter::stderr_destination; -use rustc_errors::{ColorConfig, FatalError}; use rustc_parse::new_parser_from_source_str; -use rustc_parse::parser::attr::InnerAttrPolicy; use rustc_session::parse::ParseSess; use rustc_span::FileName; use rustc_span::edition::Edition; @@ -21,6 +20,19 @@ use super::GlobalTestOptions; use crate::display::Joined as _; use crate::html::markdown::LangString; +#[derive(Default)] +struct ParseSourceInfo { + has_main_fn: bool, + found_extern_crate: bool, + supports_color: bool, + has_global_allocator: bool, + has_macro_def: bool, + everything_else: String, + crates: String, + crate_attrs: String, + maybe_crate_attrs: String, +} + /// This struct contains information about the doctest itself which is then used to generate /// doctest source code appropriately. pub(crate) struct DocTestBuilder { @@ -53,8 +65,23 @@ impl DocTestBuilder { !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate }); - let Some(SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else }) = - partition_source(source, edition) + let result = rustc_driver::catch_fatal_errors(|| { + rustc_span::create_session_if_not_set_then(edition, |_| { + parse_source(source, &crate_name) + }) + }); + + let Ok(Ok(ParseSourceInfo { + has_main_fn, + found_extern_crate, + supports_color, + has_global_allocator, + has_macro_def, + everything_else, + crates, + crate_attrs, + maybe_crate_attrs, + })) = result else { return Self::invalid( String::new(), @@ -65,35 +92,13 @@ impl DocTestBuilder { ); }; - // Uses librustc_ast to parse the doctest and find if there's a main fn and the extern - // crate already is included. - let Ok(( - ParseSourceInfo { - has_main_fn, - found_extern_crate, - supports_color, - has_global_allocator, - has_macro_def, - .. - }, - failed_ast, - )) = check_for_main_and_extern_crate( - crate_name, - source, - &everything_else, - &crates, - edition, - can_merge_doctests, - ) - else { - // If the parser panicked due to a fatal error, pass the test code through unchanged. - // The error will be reported during compilation. - return Self::invalid(crate_attrs, maybe_crate_attrs, crates, everything_else, test_id); - }; + debug!("crate_attrs:\n{crate_attrs}{maybe_crate_attrs}"); + debug!("crates:\n{crates}"); + debug!("after:\n{everything_else}"); + // If the AST returned an error, we don't want this doctest to be merged with the // others. Same if it contains `#[feature]` or `#[no_std]`. let can_be_merged = can_merge_doctests - && !failed_ast && !has_global_allocator && crate_attrs.is_empty() // If this is a merged doctest and a defined macro uses `$crate`, then the path will @@ -146,6 +151,7 @@ impl DocTestBuilder { if self.failed_ast { // If the AST failed to compile, no need to go generate a complete doctest, the error // will be better this way. + debug!("failed AST:\n{test_code}"); return (test_code.to_string(), 0); } let mut line_offset = 0; @@ -255,13 +261,6 @@ impl DocTestBuilder { } } -#[derive(PartialEq, Eq, Debug)] -enum ParsingResult { - Failed, - AstError, - Ok, -} - fn cancel_error_count(psess: &ParseSess) { // Reset errors so that they won't be reported as compiler bugs when dropping the // dcx. Any errors in the tests will be reported when the test file is compiled, @@ -270,17 +269,20 @@ fn cancel_error_count(psess: &ParseSess) { psess.dcx().reset_err_count(); } -fn parse_source( - source: String, - info: &mut ParseSourceInfo, - crate_name: &Option<&str>, -) -> ParsingResult { +const DOCTEST_CODE_WRAPPER: &str = "fn f(){"; + +fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { use rustc_errors::DiagCtxt; use rustc_errors::emitter::{Emitter, HumanEmitter}; - use rustc_parse::parser::ForceCollect; + // use rustc_parse::parser::ForceCollect; use rustc_span::source_map::FilePathMapping; - let filename = FileName::anon_source_code(&source); + let mut info = + ParseSourceInfo { found_extern_crate: crate_name.is_none(), ..Default::default() }; + + let wrapped_source = format!("{DOCTEST_CODE_WRAPPER}{source}\n}}"); + + let filename = FileName::anon_source_code(&wrapped_source); // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. @@ -299,15 +301,32 @@ fn parse_source( let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = match new_parser_from_source_str(&psess, filename, source) { + let mut parser = match new_parser_from_source_str(&psess, filename, wrapped_source) { Ok(p) => p, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); cancel_error_count(&psess); - return ParsingResult::Failed; + return Err(()); } }; - let mut parsing_result = ParsingResult::Ok; + + fn push_to_s( + s: &mut String, + source: &str, + span: rustc_span::Span, + prev_span_hi: &mut Option, + ) { + let extra_len = DOCTEST_CODE_WRAPPER.len(); + // We need to shift by 1 because we added `{` at the beginning of the source.we provided + // to the parser. + let lo = prev_span_hi.unwrap_or(span.lo().0 as usize - extra_len); + let mut hi = span.hi().0 as usize - extra_len; + if hi > source.len() { + hi = source.len(); + } + s.push_str(&source[lo..hi]); + *prev_span_hi = Some(hi); + } // Recurse through functions body. It is necessary because the doctest source code is // wrapped in a function to limit the number of AST errors. If we don't recurse into @@ -325,6 +344,8 @@ fn parse_source( } match item.kind { ast::ItemKind::Fn(ref fn_item) if !info.has_main_fn => { + // We only push if it's the top item because otherwise, we would duplicate + // its content since the top-level item was already added. if item.ident.name == sym::main && is_top_level { info.has_main_fn = true; } @@ -334,7 +355,6 @@ fn parse_source( ast::StmtKind::Item(ref item) => { check_item(item, info, crate_name, false) } - ast::StmtKind::MacCall(..) => info.found_macro = true, _ => {} } } @@ -350,295 +370,88 @@ fn parse_source( }; } } - ast::ItemKind::MacCall(..) => info.found_macro = true, - ast::ItemKind::MacroDef(..) => info.has_macro_def = true, + ast::ItemKind::MacroDef(..) => { + info.has_macro_def = true; + } _ => {} } } - loop { - match parser.parse_item(ForceCollect::No) { - Ok(Some(item)) => { - check_item(&item, info, crate_name, true); + let mut prev_span_hi = None; + let not_crate_attrs = [sym::forbid, sym::allow, sym::warn, sym::deny]; + let parsed = parser.parse_item(rustc_parse::parser::ForceCollect::No); - if info.has_main_fn && info.found_extern_crate { - break; + debug!("+++++> {parsed:#?}"); + + let result = match parsed { + Ok(Some(ref item)) + if let ast::ItemKind::Fn(ref fn_item) = item.kind + && let Some(ref body) = fn_item.body => + { + for attr in &item.attrs { + let attr_name = attr.name_or_empty(); + + if attr.style == ast::AttrStyle::Outer || not_crate_attrs.contains(&attr_name) { + // There is one exception to these attributes: + // `#![allow(internal_features)]`. If this attribute is used, we need to + // consider it only as a crate-level attribute. + if attr_name == sym::allow + && let Some(list) = attr.meta_item_list() + && list.iter().any(|sub_attr| { + sub_attr.name_or_empty().as_str() == "internal_features" + }) + { + push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi); + } else { + push_to_s( + &mut info.maybe_crate_attrs, + source, + attr.span, + &mut prev_span_hi, + ); + } + } else { + push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi); } } - Ok(None) => break, - Err(e) => { - parsing_result = ParsingResult::AstError; - e.cancel(); - break; + for stmt in &body.stmts { + match stmt.kind { + ast::StmtKind::Item(ref item) => check_item(&item, &mut info, crate_name, true), + ast::StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => { + cancel_error_count(&psess); + return Err(()); + } + _ => {} + } + + // Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to + // tweak the span to include the attributes as well. + let mut span = stmt.span; + if let Some(attr) = stmt.kind.attrs().first() { + span = span.with_lo(attr.span.lo()); + } + if info.everything_else.is_empty() + && (!info.maybe_crate_attrs.is_empty() || !info.crate_attrs.is_empty()) + { + // We add potential backlines into attributes if there are some. + push_to_s( + &mut info.maybe_crate_attrs, + source, + span.shrink_to_lo(), + &mut prev_span_hi, + ); + } + push_to_s(&mut info.everything_else, source, span, &mut prev_span_hi); } + Ok(info) } - - // The supplied item is only used for diagnostics, - // which are swallowed here anyway. - parser.maybe_consume_incorrect_semicolon(None); - } - - cancel_error_count(&psess); - parsing_result -} - -#[derive(Default)] -struct ParseSourceInfo { - has_main_fn: bool, - found_extern_crate: bool, - found_macro: bool, - supports_color: bool, - has_global_allocator: bool, - has_macro_def: bool, -} - -fn check_for_main_and_extern_crate( - crate_name: Option<&str>, - original_source_code: &str, - everything_else: &str, - crates: &str, - edition: Edition, - can_merge_doctests: bool, -) -> Result<(ParseSourceInfo, bool), FatalError> { - let result = rustc_driver::catch_fatal_errors(|| { - rustc_span::create_session_if_not_set_then(edition, |_| { - let mut info = - ParseSourceInfo { found_extern_crate: crate_name.is_none(), ..Default::default() }; - - let mut parsing_result = - parse_source(format!("{crates}{everything_else}"), &mut info, &crate_name); - // No need to double-check this if the "merged doctests" feature isn't enabled (so - // before the 2024 edition). - if can_merge_doctests && parsing_result != ParsingResult::Ok { - // If we found an AST error, we want to ensure it's because of an expression being - // used outside of a function. - // - // To do so, we wrap in a function in order to make sure that the doctest AST is - // correct. For example, if your doctest is `foo::bar()`, if we don't wrap it in a - // block, it would emit an AST error, which would be problematic for us since we - // want to filter out such errors which aren't "real" errors. - // - // The end goal is to be able to merge as many doctests as possible as one for much - // faster doctests run time. - parsing_result = parse_source( - format!("{crates}\nfn __doctest_wrap(){{{everything_else}\n}}"), - &mut info, - &crate_name, - ); - } - - (info, parsing_result) - }) - }); - let (mut info, parsing_result) = match result { - Err(..) | Ok((_, ParsingResult::Failed)) => return Err(FatalError), - Ok((info, parsing_result)) => (info, parsing_result), + Err(e) => { + e.cancel(); + Err(()) + } + _ => Err(()), }; - // If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't - // see it. In that case, run the old text-based scan to see if they at least have a main - // function written inside a macro invocation. See - // https://github.com/rust-lang/rust/issues/56898 - if info.found_macro - && !info.has_main_fn - && original_source_code - .lines() - .map(|line| { - let comment = line.find("//"); - if let Some(comment_begins) = comment { &line[0..comment_begins] } else { line } - }) - .any(|code| code.contains("fn main")) - { - info.has_main_fn = true; - } - - Ok((info, parsing_result != ParsingResult::Ok)) -} - -enum AttrKind { - CrateAttr, - Attr, -} - -/// Returns `Some` if the attribute is complete and `Some(true)` if it is an attribute that can be -/// placed at the crate root. -fn check_if_attr_is_complete(source: &str, edition: Edition) -> Option { - if source.is_empty() { - // Empty content so nothing to check in here... - return None; - } - let not_crate_attrs = [sym::forbid, sym::allow, sym::warn, sym::deny]; - - rustc_driver::catch_fatal_errors(|| { - rustc_span::create_session_if_not_set_then(edition, |_| { - use rustc_errors::DiagCtxt; - use rustc_errors::emitter::HumanEmitter; - use rustc_span::source_map::FilePathMapping; - - let filename = FileName::anon_source_code(source); - // Any errors in parsing should also appear when the doctest is compiled for real, so just - // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. - let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); - - let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); - - let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); - let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = match new_parser_from_source_str(&psess, filename, source.to_owned()) { - Ok(p) => p, - Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); - // If there is an unclosed delimiter, an error will be returned by the - // tokentrees. - return None; - } - }; - // If a parsing error happened, it's very likely that the attribute is incomplete. - let ret = match parser.parse_attribute(InnerAttrPolicy::Permitted) { - Ok(attr) => { - let attr_name = attr.name_or_empty(); - - if not_crate_attrs.contains(&attr_name) { - // There is one exception to these attributes: - // `#![allow(internal_features)]`. If this attribute is used, we need to - // consider it only as a crate-level attribute. - if attr_name == sym::allow - && let Some(list) = attr.meta_item_list() - && list.iter().any(|sub_attr| { - sub_attr.name_or_empty().as_str() == "internal_features" - }) - { - Some(AttrKind::CrateAttr) - } else { - Some(AttrKind::Attr) - } - } else { - Some(AttrKind::CrateAttr) - } - } - Err(e) => { - e.cancel(); - None - } - }; - ret - }) - }) - .unwrap_or(None) -} - -fn handle_attr(mod_attr_pending: &mut String, source_info: &mut SourceInfo, edition: Edition) { - if let Some(attr_kind) = check_if_attr_is_complete(mod_attr_pending, edition) { - let push_to = match attr_kind { - AttrKind::CrateAttr => &mut source_info.crate_attrs, - AttrKind::Attr => &mut source_info.maybe_crate_attrs, - }; - push_to.push_str(mod_attr_pending); - push_to.push('\n'); - // If it's complete, then we can clear the pending content. - mod_attr_pending.clear(); - } else { - mod_attr_pending.push('\n'); - } -} - -#[derive(Default)] -struct SourceInfo { - crate_attrs: String, - maybe_crate_attrs: String, - crates: String, - everything_else: String, -} - -fn partition_source(s: &str, edition: Edition) -> Option { - #[derive(Copy, Clone, PartialEq)] - enum PartitionState { - Attrs, - Crates, - Other, - } - let mut source_info = SourceInfo::default(); - let mut state = PartitionState::Attrs; - let mut mod_attr_pending = String::new(); - - for line in s.lines() { - let trimline = line.trim(); - - // FIXME(misdreavus): if a doc comment is placed on an extern crate statement, it will be - // shunted into "everything else" - match state { - PartitionState::Attrs => { - state = if trimline.starts_with("#![") { - mod_attr_pending = line.to_owned(); - handle_attr(&mut mod_attr_pending, &mut source_info, edition); - continue; - } else if trimline.chars().all(|c| c.is_whitespace()) - || (trimline.starts_with("//") && !trimline.starts_with("///")) - { - PartitionState::Attrs - } else if trimline.starts_with("extern crate") - || trimline.starts_with("#[macro_use] extern crate") - { - PartitionState::Crates - } else { - // First we check if the previous attribute was "complete"... - if !mod_attr_pending.is_empty() { - // If not, then we append the new line into the pending attribute to check - // if this time it's complete... - mod_attr_pending.push_str(line); - if !trimline.is_empty() { - handle_attr(&mut mod_attr_pending, &mut source_info, edition); - } - continue; - } else { - PartitionState::Other - } - }; - } - PartitionState::Crates => { - state = if trimline.starts_with("extern crate") - || trimline.starts_with("#[macro_use] extern crate") - || trimline.chars().all(|c| c.is_whitespace()) - || (trimline.starts_with("//") && !trimline.starts_with("///")) - { - PartitionState::Crates - } else { - PartitionState::Other - }; - } - PartitionState::Other => {} - } - - match state { - PartitionState::Attrs => { - source_info.crate_attrs.push_str(line); - source_info.crate_attrs.push('\n'); - } - PartitionState::Crates => { - source_info.crates.push_str(line); - source_info.crates.push('\n'); - } - PartitionState::Other => { - source_info.everything_else.push_str(line); - source_info.everything_else.push('\n'); - } - } - } - - if !mod_attr_pending.is_empty() { - debug!("invalid doctest code: {s:?}"); - return None; - } - - source_info.everything_else = source_info.everything_else.trim().to_string(); - - debug!("crate_attrs:\n{}{}", source_info.crate_attrs, source_info.maybe_crate_attrs); - debug!("crates:\n{}", source_info.crates); - debug!("after:\n{}", source_info.everything_else); - - Some(source_info) + cancel_error_count(&psess); + result } From 01fb7c3ac6223ca5657987e73401f7eb64609e01 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Mar 2025 16:44:59 +0100 Subject: [PATCH 376/546] Update rustdoc-ui tests --- tests/rustdoc-ui/extract-doctests.stdout | 2 +- tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/rustdoc-ui/extract-doctests.stdout b/tests/rustdoc-ui/extract-doctests.stdout index fa8604cae948..b11531b844ee 100644 --- a/tests/rustdoc-ui/extract-doctests.stdout +++ b/tests/rustdoc-ui/extract-doctests.stdout @@ -1 +1 @@ -{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":"#![allow(unused)]\nfn main() {\nlet\n}","name":"$DIR/extract-doctests.rs - (line 13)"}]} \ No newline at end of file +{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]} \ No newline at end of file diff --git a/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout index a05b51699894..c0d2515998f2 100644 --- a/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout +++ b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout @@ -5,11 +5,11 @@ test remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) . failures: ---- remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) stdout ---- -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `is` +error: expected one of `!` or `::`, found `is` --> remapped_path/remap-path-prefix-invalid-doctest.rs:11:6 | LL | this is not real code - | ^^ expected one of 8 possible tokens + | ^^ expected one of `!` or `::` error: aborting due to 1 previous error From 6f7e8d441a81ed89e14ad5ce53dcbe52ab0af64c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 Mar 2025 13:47:21 +0100 Subject: [PATCH 377/546] Correctly handle `fn main` in macro --- src/librustdoc/doctest/make.rs | 43 +++++++++++++++++++++++---------- src/librustdoc/doctest/tests.rs | 10 ++++---- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index cb14608b35ae..810f53636ce4 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -5,15 +5,17 @@ use std::fmt::{self, Write as _}; use std::io; use std::sync::Arc; -use rustc_ast::{self as ast, HasAttrs}; +use rustc_ast::token::{Delimiter, TokenKind}; +use rustc_ast::tokenstream::TokenTree; +use rustc_ast::{self as ast, HasAttrs, StmtKind}; use rustc_errors::ColorConfig; use rustc_errors::emitter::stderr_destination; use rustc_parse::new_parser_from_source_str; use rustc_session::parse::ParseSess; -use rustc_span::FileName; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; +use rustc_span::{FileName, kw}; use tracing::debug; use super::GlobalTestOptions; @@ -319,7 +321,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result source.len() { hi = source.len(); @@ -351,11 +353,8 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - check_item(item, info, crate_name, false) - } - _ => {} + if let StmtKind::Item(ref item) = stmt.kind { + check_item(item, info, crate_name, false) } } } @@ -381,8 +380,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result {parsed:#?}"); - let result = match parsed { Ok(Some(ref item)) if let ast::ItemKind::Fn(ref fn_item) = item.kind @@ -416,11 +413,31 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result check_item(&item, &mut info, crate_name, true), - ast::StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => { + StmtKind::Item(ref item) => check_item(&item, &mut info, crate_name, true), + StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => { cancel_error_count(&psess); return Err(()); } + StmtKind::MacCall(ref mac_call) if !info.has_main_fn => { + let mut iter = mac_call.mac.args.tokens.iter(); + + while let Some(token) = iter.next() { + if let TokenTree::Token(token, _) = token + && let TokenKind::Ident(name, _) = token.kind + && name == kw::Fn + && let Some(TokenTree::Token(fn_token, _)) = iter.peek() + && let TokenKind::Ident(fn_name, _) = fn_token.kind + && fn_name == sym::main + && let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = { + iter.next(); + iter.peek() + } + { + info.has_main_fn = true; + break; + } + } + } _ => {} } @@ -433,7 +450,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result Date: Fri, 7 Mar 2025 15:20:14 +0100 Subject: [PATCH 378/546] Correctly handle line comments in attributes and generate extern crates outside of wrapping function --- src/librustdoc/doctest/make.rs | 50 +++++++++++++------ src/librustdoc/doctest/tests.rs | 30 +++++++++-- tests/run-make/rustdoc-error-lines/rmake.rs | 6 +-- .../rustdoc-ui/doctest/display-output.stdout | 6 +-- tests/rustdoc-ui/doctest/extern-crate.rs | 23 +++++++++ tests/rustdoc-ui/doctest/extern-crate.stdout | 6 +++ tests/rustdoc/playground.rs | 2 +- 7 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/extern-crate.rs create mode 100644 tests/rustdoc-ui/doctest/extern-crate.stdout diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 810f53636ce4..0ed2d37f74c1 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -176,9 +176,24 @@ impl DocTestBuilder { // Now push any outer attributes from the example, assuming they // are intended to be crate attributes. - prog.push_str(&self.crate_attrs); - prog.push_str(&self.maybe_crate_attrs); - prog.push_str(&self.crates); + if !self.crate_attrs.is_empty() { + prog.push_str(&self.crate_attrs); + if !self.crate_attrs.ends_with('\n') { + prog.push('\n'); + } + } + if !self.maybe_crate_attrs.is_empty() { + prog.push_str(&self.maybe_crate_attrs); + if !self.maybe_crate_attrs.ends_with('\n') { + prog.push('\n'); + } + } + if !self.crates.is_empty() { + prog.push_str(&self.crates); + if !self.crates.ends_with('\n') { + prog.push('\n'); + } + } // Don't inject `extern crate std` because it's already injected by the // compiler. @@ -276,7 +291,6 @@ const DOCTEST_CODE_WRAPPER: &str = "fn f(){"; fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { use rustc_errors::DiagCtxt; use rustc_errors::emitter::{Emitter, HumanEmitter}; - // use rustc_parse::parser::ForceCollect; use rustc_span::source_map::FilePathMapping; let mut info = @@ -338,7 +352,8 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result, is_top_level: bool, - ) { + ) -> bool { + let mut is_crate = false; if !info.has_global_allocator && item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator) { @@ -354,12 +369,13 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { + is_crate = true; if !info.found_extern_crate && let Some(crate_name) = crate_name { @@ -374,6 +390,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result {} } + is_crate } let mut prev_span_hi = None; @@ -412,8 +429,11 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result check_item(&item, &mut info, crate_name, true), + StmtKind::Item(ref item) => { + is_crate = check_item(&item, &mut info, crate_name, true); + } StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => { cancel_error_count(&psess); return Err(()); @@ -450,15 +470,15 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result $DIR/display-output.rs:11:5 + --> $DIR/display-output.rs:12:5 | LL | let x = 12; | ^ help: if this is intentional, prefix it with an underscore: `_x` @@ -19,13 +19,13 @@ LL | #![warn(unused)] = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` warning: unused variable: `x` - --> $DIR/display-output.rs:13:8 + --> $DIR/display-output.rs:14:8 | LL | fn foo(x: &dyn std::fmt::Display) {} | ^ help: if this is intentional, prefix it with an underscore: `_x` warning: function `foo` is never used - --> $DIR/display-output.rs:13:4 + --> $DIR/display-output.rs:14:4 | LL | fn foo(x: &dyn std::fmt::Display) {} | ^^^ diff --git a/tests/rustdoc-ui/doctest/extern-crate.rs b/tests/rustdoc-ui/doctest/extern-crate.rs new file mode 100644 index 000000000000..0415d33bb723 --- /dev/null +++ b/tests/rustdoc-ui/doctest/extern-crate.rs @@ -0,0 +1,23 @@ +//@ check-pass +//@ compile-flags:--test --test-args=--test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" + +// This test ensures that crate imports are placed outside of the `main` function +// so they work all the time (even in 2015 edition). + +/// ```rust +/// #![feature(test)] +/// +/// extern crate test; +/// use test::Bencher; +/// +/// #[bench] +/// fn bench_xor_1000_ints(b: &mut Bencher) { +/// b.iter(|| { +/// (0..1000).fold(0, |old, new| old ^ new); +/// }); +/// } +/// ``` +/// +pub fn foo() {} diff --git a/tests/rustdoc-ui/doctest/extern-crate.stdout b/tests/rustdoc-ui/doctest/extern-crate.stdout new file mode 100644 index 000000000000..b103343afdd5 --- /dev/null +++ b/tests/rustdoc-ui/doctest/extern-crate.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/extern-crate.rs - foo (line 9) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc/playground.rs index db2d1669df60..65dad2a5195d 100644 --- a/tests/rustdoc/playground.rs +++ b/tests/rustdoc/playground.rs @@ -24,4 +24,4 @@ //@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "" //@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "" -//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "" +//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "" From a3bafca14aa8e6ef1694f416ca00215e49771b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 25 Mar 2025 22:36:05 +0100 Subject: [PATCH 379/546] Add job duration changes stats in post-merge analysis --- src/ci/citool/src/analysis.rs | 55 +++++++++++++++++++++++++++++++++-- src/ci/citool/src/main.rs | 7 +++-- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 2b001f28b0eb..fc18e438aab9 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -1,10 +1,11 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt::Debug; use build_helper::metrics::{ BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name, format_build_steps, }; +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::time::Duration; use crate::metrics; use crate::metrics::{JobMetrics, JobName, get_test_suites}; @@ -184,11 +185,61 @@ fn render_table(suites: BTreeMap) -> String { } /// Outputs a report of test differences between the `parent` and `current` commits. -pub fn output_test_diffs(job_metrics: HashMap) { +pub fn output_test_diffs(job_metrics: &HashMap) { let aggregated_test_diffs = aggregate_test_diffs(&job_metrics); report_test_diffs(aggregated_test_diffs); } +/// Prints the ten largest differences in bootstrap durations. +pub fn output_largest_duration_changes(job_metrics: &HashMap) { + struct Entry<'a> { + job: &'a JobName, + before: Duration, + after: Duration, + change: f64, + } + + let mut changes: Vec = vec![]; + for (job, metrics) in job_metrics { + if let Some(parent) = &metrics.parent { + let duration_before = parent + .invocations + .iter() + .map(|i| BuildStep::from_invocation(i).duration) + .sum::(); + let duration_after = metrics + .current + .invocations + .iter() + .map(|i| BuildStep::from_invocation(i).duration) + .sum::(); + let pct_change = duration_after.as_secs_f64() / duration_before.as_secs_f64(); + let pct_change = pct_change * 100.0; + // Normalize around 100, to get + for regression and - for improvements + let pct_change = pct_change - 100.0; + changes.push(Entry { + job, + before: duration_before, + after: duration_after, + change: pct_change, + }); + } + } + changes.sort_by(|e1, e2| e1.change.partial_cmp(&e2.change).unwrap().reverse()); + + println!("# Job duration changes"); + for (index, entry) in changes.into_iter().take(10).enumerate() { + println!( + "{}. `{}`: {:.1}s -> {:.1}s ({:.1}%)", + index + 1, + entry.job, + entry.before.as_secs_f64(), + entry.after.as_secs_f64(), + entry.change + ); + } +} + #[derive(Default)] struct TestSuiteRecord { passed: u64, diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 5f5c50dc43a0..6db5eab458cc 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -15,7 +15,7 @@ use clap::Parser; use jobs::JobDatabase; use serde_yaml::Value; -use crate::analysis::output_test_diffs; +use crate::analysis::{output_largest_duration_changes, output_test_diffs}; use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; use crate::jobs::RunType; @@ -160,7 +160,7 @@ fn postprocess_metrics( job_name, JobMetrics { parent: Some(parent_metrics), current: metrics }, )]); - output_test_diffs(job_metrics); + output_test_diffs(&job_metrics); return Ok(()); } Err(error) => { @@ -180,7 +180,8 @@ fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow let metrics = download_auto_job_metrics(&db, &parent, ¤t)?; println!("\nComparing {parent} (parent) -> {current} (this PR)\n"); - output_test_diffs(metrics); + output_test_diffs(&metrics); + output_largest_duration_changes(&metrics); Ok(()) } From 4a4367535339d119a6a3c4f515c8912667b30be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 27 Mar 2025 11:25:25 +0100 Subject: [PATCH 380/546] Add cache for job metrics --- src/ci/citool/src/metrics.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs index 086aa5009f34..a816fb3c4f16 100644 --- a/src/ci/citool/src/metrics.rs +++ b/src/ci/citool/src/metrics.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::path::Path; +use std::path::{Path, PathBuf}; use anyhow::Context; use build_helper::metrics::{JsonNode, JsonRoot, TestSuite}; @@ -74,6 +74,17 @@ Maybe it was newly added?"#, } pub fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result { + // Best effort cache to speed-up local re-executions of citool + let cache_path = PathBuf::from(".citool-cache").join(sha).join(format!("{job_name}.json")); + if cache_path.is_file() { + if let Ok(metrics) = std::fs::read_to_string(&cache_path) + .map_err(|err| err.into()) + .and_then(|data| anyhow::Ok::(serde_json::from_str::(&data)?)) + { + return Ok(metrics); + } + } + let url = get_metrics_url(job_name, sha); let mut response = ureq::get(&url).call()?; if !response.status().is_success() { @@ -87,6 +98,13 @@ pub fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result Date: Thu, 27 Mar 2025 11:29:48 +0100 Subject: [PATCH 381/546] Add a note about interpreting job duration changes --- src/ci/citool/src/analysis.rs | 9 +++++++++ src/ci/citool/src/utils.rs | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index fc18e438aab9..2e1ede126dc3 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -238,6 +238,15 @@ pub fn output_largest_duration_changes(job_metrics: &HashMap {summary} - " ); func(); From d0353f5c7ac0c73c6ae97623ac3e01fab1f657ae Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 27 Mar 2025 17:25:22 +0800 Subject: [PATCH 382/546] Add ui test for struct construction by calling syntax Signed-off-by: xizheyin --- ...struct-construct-with-call-issue-138931.rs | 25 +++++++++++ ...ct-construct-with-call-issue-138931.stderr | 45 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/ui/structs/struct-construct-with-call-issue-138931.rs create mode 100644 tests/ui/structs/struct-construct-with-call-issue-138931.stderr diff --git a/tests/ui/structs/struct-construct-with-call-issue-138931.rs b/tests/ui/structs/struct-construct-with-call-issue-138931.rs new file mode 100644 index 000000000000..5d50eb14bff1 --- /dev/null +++ b/tests/ui/structs/struct-construct-with-call-issue-138931.rs @@ -0,0 +1,25 @@ +struct PersonOnlyName { + name: String +} + +struct PersonWithAge { + name: String, + age: u8, + height: u8, +} + + + +fn main() { + let wilfred = PersonOnlyName("Name1".to_owned()); + //~^ ERROR expected function, tuple struct or tuple variant, found struct `PersonOnlyName` [E0423] + + let bill = PersonWithAge( //~ ERROR expected function, tuple struct or tuple variant, found struct `PersonWithAge` [E0423] + "Name2".to_owned(), + 20, + 180, + ); + + let person = PersonWithAge("Name3".to_owned()); + //~^ ERROR expected function, tuple struct or tuple variant, found struct `PersonWithAge` [E0423] +} diff --git a/tests/ui/structs/struct-construct-with-call-issue-138931.stderr b/tests/ui/structs/struct-construct-with-call-issue-138931.stderr new file mode 100644 index 000000000000..af68b37a891e --- /dev/null +++ b/tests/ui/structs/struct-construct-with-call-issue-138931.stderr @@ -0,0 +1,45 @@ +error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonOnlyName` + --> $DIR/struct-construct-with-call-issue-138931.rs:14:19 + | +LL | / struct PersonOnlyName { +LL | | name: String +LL | | } + | |_- `PersonOnlyName` defined here +... +LL | let wilfred = PersonOnlyName("Name1".to_owned()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `PersonOnlyName { name: val }` + +error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonWithAge` + --> $DIR/struct-construct-with-call-issue-138931.rs:17:16 + | +LL | / struct PersonWithAge { +LL | | name: String, +LL | | age: u8, +LL | | height: u8, +LL | | } + | |_- `PersonWithAge` defined here +... +LL | let bill = PersonWithAge( + | ________________^ +LL | | "Name2".to_owned(), +LL | | 20, +LL | | 180, +LL | | ); + | |_____^ help: use struct literal syntax instead: `PersonWithAge { name: val, age: val, height: val }` + +error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonWithAge` + --> $DIR/struct-construct-with-call-issue-138931.rs:23:18 + | +LL | / struct PersonWithAge { +LL | | name: String, +LL | | age: u8, +LL | | height: u8, +LL | | } + | |_- `PersonWithAge` defined here +... +LL | let person = PersonWithAge("Name3".to_owned()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `PersonWithAge { name: val, age: val, height: val }` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0423`. From be13105d737545a4a5f0aa0709342b4db8f2f1e3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Mar 2025 12:55:30 +0100 Subject: [PATCH 383/546] Improve comment and test for generated doctest with code comments --- src/librustdoc/doctest/make.rs | 5 +++-- src/librustdoc/doctest/tests.rs | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 0ed2d37f74c1..512343693bc2 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -85,6 +85,8 @@ impl DocTestBuilder { maybe_crate_attrs, })) = result else { + // If the AST returned an error, we don't want this doctest to be merged with the + // others. return Self::invalid( String::new(), String::new(), @@ -98,8 +100,7 @@ impl DocTestBuilder { debug!("crates:\n{crates}"); debug!("after:\n{everything_else}"); - // If the AST returned an error, we don't want this doctest to be merged with the - // others. Same if it contains `#[feature]` or `#[no_std]`. + // If it contains `#[feature]` or `#[no_std]`, we don't want it to be merged either. let can_be_merged = can_merge_doctests && !has_global_allocator && crate_attrs.is_empty() diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 59cc33558ed5..4833ea040515 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -405,7 +405,9 @@ fn check_split_args() { #[test] fn comment_in_attrs() { - // if input already has a fn main, it should insert a space before it + // If there is an inline code comment after attributes, we need to ensure that + // a backline will be added to prevent generating code "inside" it (and thus generating) + // invalid code. let opts = default_global_opts(""); let input = "\ #![feature(rustdoc_internals)] @@ -424,4 +426,24 @@ fn main() { .to_string(); let (output, len) = make_test(input, None, false, &opts, None); assert_eq!((output, len), (expected, 2)); + + // And same, if there is a `main` function provided by the user, we ensure that it's + // correctly separated. + let input = "\ +#![feature(rustdoc_internals)] +#![allow(internal_features)] +#![doc(rust_logo)] +//! This crate has the Rust(tm) branding on it. +fn main() {}"; + let expected = "\ +#![allow(unused)] +#![feature(rustdoc_internals)] +#![allow(internal_features)] +#![doc(rust_logo)] +//! This crate has the Rust(tm) branding on it. + +fn main() {}" + .to_string(); + let (output, len) = make_test(input, None, false, &opts, None); + assert_eq!((output, len), (expected, 1)); } From f333ad8656af7a43559805a9a321da8cf618d0c1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Mar 2025 13:00:49 +0100 Subject: [PATCH 384/546] Improve code comment --- src/librustdoc/doctest/make.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 512343693bc2..46226a8bc717 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -334,8 +334,8 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result, ) { let extra_len = DOCTEST_CODE_WRAPPER.len(); - // We need to shift by 1 because we added `{` at the beginning of the source.we provided - // to the parser. + // We need to shift by the length of `DOCTEST_CODE_WRAPPER` because we + // added it at the beginning of the source we provided to the parser. let lo = prev_span_hi.unwrap_or(0); let mut hi = span.hi().0 as usize - extra_len; if hi > source.len() { From 8327bb6ad3c6a6975ed7a0a408614b8d90c8d0ad Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Mar 2025 13:01:25 +0100 Subject: [PATCH 385/546] Add `expect` to the list of non-crate attributes for doctest generation --- src/librustdoc/doctest/make.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 46226a8bc717..abb626025a8c 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -395,7 +395,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result Date: Thu, 27 Mar 2025 17:28:15 +0800 Subject: [PATCH 386/546] Improve suggest construct with literal syntax instead of calling Signed-off-by: xizheyin --- .../rustc_resolve/src/late/diagnostics.rs | 106 ++++++++++++------ ...ct-construct-with-call-issue-138931.stderr | 17 ++- 2 files changed, 88 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3d666055a94f..97dd9faf6dec 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1681,41 +1681,81 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // the struct literal syntax at all, as that will cause a subsequent error. let fields = this.r.field_idents(def_id); let has_fields = fields.as_ref().is_some_and(|f| !f.is_empty()); - let (fields, applicability) = match fields { - Some(fields) => { - let fields = if let Some(old_fields) = old_fields { - fields - .iter() - .enumerate() - .map(|(idx, new)| (new, old_fields.get(idx))) - .map(|(new, old)| { - if let Some(Some(old)) = old - && new.as_str() != old - { - format!("{new}: {old}") - } else { - new.to_string() - } - }) - .collect::>() - } else { - fields - .iter() - .map(|f| format!("{f}{tail}")) - .collect::>() - }; - (fields.join(", "), applicability) - } - None => ("/* fields */".to_string(), Applicability::HasPlaceholders), - }; - let pad = if has_fields { " " } else { "" }; - err.span_suggestion( + if let PathSource::Expr(Some(Expr { + kind: ExprKind::Call(path, args), span, - format!("use struct {descr} syntax instead"), - format!("{path_str} {{{pad}{fields}{pad}}}"), - applicability, - ); + .. + })) = source + && !args.is_empty() + && let Some(fields) = &fields + && args.len() == fields.len() + // Make sure we have same number of args as fields + { + let path_span = path.span; + let mut parts = Vec::new(); + + // Start with the opening brace + parts.push(( + path_span.shrink_to_hi().until(args[0].span), + "{".to_owned(), + )); + + for (field, arg) in fields.iter().zip(args.iter()) { + // Add the field name before the argument + parts.push((arg.span.shrink_to_lo(), format!("{}: ", field))); + } + + // Add the closing brace + parts.push(( + args.last().unwrap().span.shrink_to_hi().until(span.shrink_to_hi()), + "}".to_owned(), + )); + + err.multipart_suggestion_verbose( + format!("use struct {descr} syntax instead of calling"), + parts, + applicability, + ); + } else { + let (fields, applicability) = match fields { + Some(fields) => { + let fields = if let Some(old_fields) = old_fields { + fields + .iter() + .enumerate() + .map(|(idx, new)| (new, old_fields.get(idx))) + .map(|(new, old)| { + if let Some(Some(old)) = old + && new.as_str() != old + { + format!("{new}: {old}") + } else { + new.to_string() + } + }) + .collect::>() + } else { + fields + .iter() + .map(|f| format!("{f}{tail}")) + .collect::>() + }; + + (fields.join(", "), applicability) + } + None => { + ("/* fields */".to_string(), Applicability::HasPlaceholders) + } + }; + let pad = if has_fields { " " } else { "" }; + err.span_suggestion( + span, + format!("use struct {descr} syntax instead"), + format!("{path_str} {{{pad}{fields}{pad}}}"), + applicability, + ); + } } if let PathSource::Expr(Some(Expr { kind: ExprKind::Call(path, args), diff --git a/tests/ui/structs/struct-construct-with-call-issue-138931.stderr b/tests/ui/structs/struct-construct-with-call-issue-138931.stderr index af68b37a891e..acae01df5636 100644 --- a/tests/ui/structs/struct-construct-with-call-issue-138931.stderr +++ b/tests/ui/structs/struct-construct-with-call-issue-138931.stderr @@ -7,7 +7,13 @@ LL | | } | |_- `PersonOnlyName` defined here ... LL | let wilfred = PersonOnlyName("Name1".to_owned()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `PersonOnlyName { name: val }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use struct literal syntax instead of calling + | +LL - let wilfred = PersonOnlyName("Name1".to_owned()); +LL + let wilfred = PersonOnlyName{name: "Name1".to_owned()}; + | error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonWithAge` --> $DIR/struct-construct-with-call-issue-138931.rs:17:16 @@ -25,7 +31,14 @@ LL | | "Name2".to_owned(), LL | | 20, LL | | 180, LL | | ); - | |_____^ help: use struct literal syntax instead: `PersonWithAge { name: val, age: val, height: val }` + | |_____^ + | +help: use struct literal syntax instead of calling + | +LL ~ let bill = PersonWithAge{name: "Name2".to_owned(), +LL ~ age: 20, +LL ~ height: 180}; + | error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonWithAge` --> $DIR/struct-construct-with-call-issue-138931.rs:23:18 From 6c2161a07c8f54e5b2838087a9a7406a789c98e8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 27 Mar 2025 14:11:11 +0100 Subject: [PATCH 387/546] Mark test as only-unix. --- tests/ui/thread-local/spawn-hook-atexit.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/thread-local/spawn-hook-atexit.rs b/tests/ui/thread-local/spawn-hook-atexit.rs index 41fcbab1a812..b084e0bb3878 100644 --- a/tests/ui/thread-local/spawn-hook-atexit.rs +++ b/tests/ui/thread-local/spawn-hook-atexit.rs @@ -1,4 +1,5 @@ // Regression test for https://github.com/rust-lang/rust/issues/138696 +//@ only-unix //@ needs-threads //@ run-pass From 2004dacef2fe6e9b75e56db04587579111679b82 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Mar 2025 14:32:29 +0100 Subject: [PATCH 388/546] Improve code --- src/librustdoc/doctest/make.rs | 63 ++++++++++++++++------------------ 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index abb626025a8c..93be35200060 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -25,7 +25,7 @@ use crate::html::markdown::LangString; #[derive(Default)] struct ParseSourceInfo { has_main_fn: bool, - found_extern_crate: bool, + already_has_extern_crate: bool, supports_color: bool, has_global_allocator: bool, has_macro_def: bool, @@ -48,7 +48,7 @@ pub(crate) struct DocTestBuilder { pub(crate) crates: String, pub(crate) everything_else: String, pub(crate) test_id: Option, - pub(crate) failed_ast: bool, + pub(crate) invalid_ast: bool, pub(crate) can_be_merged: bool, } @@ -75,7 +75,7 @@ impl DocTestBuilder { let Ok(Ok(ParseSourceInfo { has_main_fn, - found_extern_crate, + already_has_extern_crate, supports_color, has_global_allocator, has_macro_def, @@ -114,9 +114,9 @@ impl DocTestBuilder { maybe_crate_attrs, crates, everything_else, - already_has_extern_crate: found_extern_crate, + already_has_extern_crate, test_id, - failed_ast: false, + invalid_ast: false, can_be_merged, } } @@ -137,7 +137,7 @@ impl DocTestBuilder { everything_else, already_has_extern_crate: false, test_id, - failed_ast: true, + invalid_ast: true, can_be_merged: false, } } @@ -151,10 +151,10 @@ impl DocTestBuilder { opts: &GlobalTestOptions, crate_name: Option<&str>, ) -> (String, usize) { - if self.failed_ast { + if self.invalid_ast { // If the AST failed to compile, no need to go generate a complete doctest, the error // will be better this way. - debug!("failed AST:\n{test_code}"); + debug!("invalid AST:\n{test_code}"); return (test_code.to_string(), 0); } let mut line_offset = 0; @@ -279,7 +279,7 @@ impl DocTestBuilder { } } -fn cancel_error_count(psess: &ParseSess) { +fn reset_error_count(psess: &ParseSess) { // Reset errors so that they won't be reported as compiler bugs when dropping the // dcx. Any errors in the tests will be reported when the test file is compiled, // Note that we still need to cancel the errors above otherwise `Diag` will panic on @@ -295,7 +295,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result) -> Result p, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); - cancel_error_count(&psess); + reset_error_count(&psess); return Err(()); } }; - fn push_to_s( - s: &mut String, - source: &str, - span: rustc_span::Span, - prev_span_hi: &mut Option, - ) { + fn push_to_s(s: &mut String, source: &str, span: rustc_span::Span, prev_span_hi: &mut usize) { let extra_len = DOCTEST_CODE_WRAPPER.len(); // We need to shift by the length of `DOCTEST_CODE_WRAPPER` because we // added it at the beginning of the source we provided to the parser. - let lo = prev_span_hi.unwrap_or(0); let mut hi = span.hi().0 as usize - extra_len; if hi > source.len() { hi = source.len(); } - s.push_str(&source[lo..hi]); - *prev_span_hi = Some(hi); + s.push_str(&source[*prev_span_hi..hi]); + *prev_span_hi = hi; } // Recurse through functions body. It is necessary because the doctest source code is @@ -354,7 +348,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result, is_top_level: bool, ) -> bool { - let mut is_crate = false; + let mut is_extern_crate = false; if !info.has_global_allocator && item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator) { @@ -370,17 +364,17 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - is_crate = true; - if !info.found_extern_crate + is_extern_crate = true; + if !info.already_has_extern_crate && let Some(crate_name) = crate_name { - info.found_extern_crate = match original { + info.already_has_extern_crate = match original { Some(name) => name.as_str() == *crate_name, None => item.ident.as_str() == *crate_name, }; @@ -391,10 +385,10 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result {} } - is_crate + is_extern_crate } - let mut prev_span_hi = None; + let mut prev_span_hi = 0; let not_crate_attrs = [sym::forbid, sym::allow, sym::warn, sym::deny, sym::expect]; let parsed = parser.parse_item(rustc_parse::parser::ForceCollect::No); @@ -430,13 +424,13 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - is_crate = check_item(&item, &mut info, crate_name, true); + is_extern_crate = check_item(&item, &mut info, crate_name, true); } StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => { - cancel_error_count(&psess); + reset_error_count(&psess); return Err(()); } StmtKind::MacCall(ref mac_call) if !info.has_main_fn => { @@ -471,11 +465,12 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result) -> Result Err(()), }; - cancel_error_count(&psess); + reset_error_count(&psess); result } From 3371d498b1d6853598b9bedaf1e71d4c3f1d538b Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 27 Mar 2025 15:41:46 +0100 Subject: [PATCH 389/546] std: get rid of pre-Vista fallback code We haven't had any Windows XP targets for a long while now... --- library/std/src/sys/pal/windows/pipe.rs | 28 ++++++------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index 8521cf4162f5..c78524649226 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -74,7 +74,6 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res let ours; let mut name; let mut tries = 0; - let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS; loop { tries += 1; name = format!( @@ -96,7 +95,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res c::PIPE_TYPE_BYTE | c::PIPE_READMODE_BYTE | c::PIPE_WAIT - | reject_remote_clients_flag, + | c::PIPE_REJECT_REMOTE_CLIENTS, 1, PIPE_BUFFER_CAPACITY, PIPE_BUFFER_CAPACITY, @@ -112,30 +111,15 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res // // Don't try again too much though as this could also perhaps be a // legit error. - // If `ERROR_INVALID_PARAMETER` is returned, this probably means we're - // running on pre-Vista version where `PIPE_REJECT_REMOTE_CLIENTS` is - // not supported, so we continue retrying without it. This implies - // reduced security on Windows versions older than Vista by allowing - // connections to this pipe from remote machines. - // Proper fix would increase the number of FFI imports and introduce - // significant amount of Windows XP specific code with no clean - // testing strategy - // For more info, see https://github.com/rust-lang/rust/pull/37677. if handle == c::INVALID_HANDLE_VALUE { let error = api::get_last_error(); - if tries < 10 { - if error == WinError::ACCESS_DENIED { - continue; - } else if reject_remote_clients_flag != 0 - && error == WinError::INVALID_PARAMETER - { - reject_remote_clients_flag = 0; - tries -= 1; - continue; - } + if tries < 10 && error == WinError::ACCESS_DENIED { + continue; + } else { + return Err(io::Error::from_raw_os_error(error.code as i32)); } - return Err(io::Error::from_raw_os_error(error.code as i32)); } + ours = Handle::from_raw_handle(handle); break; } From 1494da4ffbfab8d0b7a62dd37d9f4a77f1038840 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Mar 2025 16:23:41 +0100 Subject: [PATCH 390/546] Add new regression test for doctest --- src/librustdoc/doctest/tests.rs | 131 ++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 4833ea040515..949ed837db3a 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -447,3 +447,134 @@ fn main() {}" let (output, len) = make_test(input, None, false, &opts, None); assert_eq!((output, len), (expected, 1)); } + +#[test] +fn comments() { + let opts = default_global_opts(""); + let input = r##" +//! A doc comment that applies to the implicit anonymous module of this crate + +pub mod outer_module { + + //! - Inner line doc + //!! - Still an inner line doc (but with a bang at the beginning) + + /*! - Inner block doc */ + /*!! - Still an inner block doc (but with a bang at the beginning) */ + + // - Only a comment + /// - Outer line doc (exactly 3 slashes) + //// - Only a comment + + /* - Only a comment */ + /** - Outer block doc (exactly) 2 asterisks */ + /*** - Only a comment */ + + pub mod inner_module {} + + pub mod nested_comments { + /* In Rust /* we can /* nest comments */ */ */ + + // All three types of block comments can contain or be nested inside + // any other type: + + /* /* */ /** */ /*! */ */ + /*! /* */ /** */ /*! */ */ + /** /* */ /** */ /*! */ */ + pub mod dummy_item {} + } + + pub mod degenerate_cases { + // empty inner line doc + //! + + // empty inner block doc + /*!*/ + + // empty line comment + // + + // empty outer line doc + /// + + // empty block comment + /**/ + + pub mod dummy_item {} + + // empty 2-asterisk block isn't a doc block, it is a block comment + /***/ + + } + + /* The next one isn't allowed because outer doc comments + require an item that will receive the doc */ + + /// Where is my item? +} +"##; + let expected = " +//! A doc comment that applies to the implicit anonymous module of this crate + +pub mod outer_module { + + //! - Inner line doc + //!! - Still an inner line doc (but with a bang at the beginning) + + /*! - Inner block doc */ + /*!! - Still an inner block doc (but with a bang at the beginning) */ + + // - Only a comment + /// - Outer line doc (exactly 3 slashes) + //// - Only a comment + + /* - Only a comment */ + /** - Outer block doc (exactly) 2 asterisks */ + /*** - Only a comment */ + + pub mod inner_module {} + + pub mod nested_comments { + /* In Rust /* we can /* nest comments */ */ */ + + // All three types of block comments can contain or be nested inside + // any other type: + + /* /* */ /** */ /*! */ */ + /*! /* */ /** */ /*! */ */ + /** /* */ /** */ /*! */ */ + pub mod dummy_item {} + } + + pub mod degenerate_cases { + // empty inner line doc + //! + + // empty inner block doc + /*!*/ + + // empty line comment + // + + // empty outer line doc + /// + + // empty block comment + /**/ + + pub mod dummy_item {} + + // empty 2-asterisk block isn't a doc block, it is a block comment + /***/ + + } + + /* The next one isn't allowed because outer doc comments + require an item that will receive the doc */ + + /// Where is my item? +} +".to_string(); + let (output, len) = make_test(input, None, false, &opts, None); + assert_eq!((output, len), (expected, 0)); +} \ No newline at end of file From 49f1e9cd8d31b65416408f4975feb5eded4d6158 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Mar 2025 14:43:11 +0100 Subject: [PATCH 391/546] Remove recursion in `check_item` --- src/librustdoc/doctest/make.rs | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 93be35200060..55b57292b33a 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -342,12 +342,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result, - is_top_level: bool, - ) -> bool { + fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) -> bool { let mut is_extern_crate = false; if !info.has_global_allocator && item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator) @@ -355,19 +350,12 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { + ast::ItemKind::Fn(_) if !info.has_main_fn => { // We only push if it's the top item because otherwise, we would duplicate // its content since the top-level item was already added. - if item.ident.name == sym::main && is_top_level { + if item.ident.name == sym::main { info.has_main_fn = true; } - if let Some(ref body) = fn_item.body { - for stmt in &body.stmts { - if let StmtKind::Item(ref item) = stmt.kind { - is_extern_crate |= check_item(item, info, crate_name, false); - } - } - } } ast::ItemKind::ExternCrate(original) => { is_extern_crate = true; @@ -427,7 +415,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - is_extern_crate = check_item(&item, &mut info, crate_name, true); + is_extern_crate = check_item(&item, &mut info, crate_name); } StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => { reset_error_count(&psess); From 77eb97d9a983f213cff1df7e02a4a96273653482 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 27 Mar 2025 11:59:04 -0400 Subject: [PATCH 392/546] librustdoc: also stabilize iteration order here --- src/librustdoc/html/markdown.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b067dbf750e7..7606128e9e88 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1726,6 +1726,7 @@ pub(crate) fn markdown_links<'md, R>( md: &'md str, preprocess_link: impl Fn(MarkdownLink) -> Option, ) -> Vec { + use itertools::Itertools; if md.is_empty() { return vec![]; } @@ -1884,7 +1885,7 @@ pub(crate) fn markdown_links<'md, R>( let mut links = Vec::new(); let mut refdefs = FxIndexMap::default(); - for (label, refdef) in event_iter.reference_definitions().iter() { + for (label, refdef) in event_iter.reference_definitions().iter().sorted_by_key(|x| x.0) { refdefs.insert(label.to_string(), (false, refdef.dest.to_string(), refdef.span.clone())); } From 27cca0a161ff913852f8344636e17489ef37672b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 27 Mar 2025 11:36:29 +0100 Subject: [PATCH 393/546] Add CI metadata to bootstrap metrics This will allow us to provide links to CI workflows, jobs and summaries in the post-merge analysis report. --- .github/workflows/ci.yml | 2 ++ src/bootstrap/src/utils/metrics.rs | 22 +++++++++++++++++++--- src/build_helper/src/metrics.rs | 13 +++++++++++++ src/ci/citool/src/analysis.rs | 4 ++-- src/ci/docker/run.sh | 2 ++ 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25397006ee23..51dd0f81ed14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,8 @@ jobs: env: CI_JOB_NAME: ${{ matrix.name }} CI_JOB_DOC_URL: ${{ matrix.doc_url }} + GITHUB_WORKFLOW_RUN_ID: ${{ github.run_id }} + GITHUB_REPOSITORY: ${{ github.repository }} CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs. HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index 885fff9c32c5..862c44496241 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -9,9 +9,10 @@ use std::fs::File; use std::io::BufWriter; use std::time::{Duration, Instant, SystemTime}; +use build_helper::ci::CiEnv; use build_helper::metrics::{ - JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats, Test, - TestOutcome, TestSuite, TestSuiteMetadata, + CiMetadata, JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats, + Test, TestOutcome, TestSuite, TestSuiteMetadata, }; use sysinfo::{CpuRefreshKind, RefreshKind, System}; @@ -217,7 +218,12 @@ impl BuildMetrics { children: steps.into_iter().map(|step| self.prepare_json_step(step)).collect(), }); - let json = JsonRoot { format_version: CURRENT_FORMAT_VERSION, system_stats, invocations }; + let json = JsonRoot { + format_version: CURRENT_FORMAT_VERSION, + system_stats, + invocations, + ci_metadata: get_ci_metadata(CiEnv::current()), + }; t!(std::fs::create_dir_all(dest.parent().unwrap())); let mut file = BufWriter::new(t!(File::create(&dest))); @@ -245,6 +251,16 @@ impl BuildMetrics { } } +fn get_ci_metadata(ci_env: CiEnv) -> Option { + if ci_env != CiEnv::GitHubActions { + return None; + } + let workflow_run_id = + std::env::var("GITHUB_WORKFLOW_RUN_ID").ok().and_then(|id| id.parse::().ok())?; + let repository = std::env::var("GITHUB_REPOSITORY").ok()?; + Some(CiMetadata { workflow_run_id, repository }) +} + struct MetricsState { finished_steps: Vec, running_steps: Vec, diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index fdff9cd18cea..8b82e62a3277 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -9,6 +9,19 @@ pub struct JsonRoot { pub format_version: usize, pub system_stats: JsonInvocationSystemStats, pub invocations: Vec, + #[serde(default)] + pub ci_metadata: Option, +} + +/// Represents metadata about bootstrap's execution in CI. +#[derive(Serialize, Deserialize)] +pub struct CiMetadata { + /// GitHub run ID of the workflow where bootstrap was executed. + /// Note that the run ID will be shared amongst all jobs executed in that workflow. + pub workflow_run_id: u64, + /// Full name of a GitHub repository where bootstrap was executed in CI. + /// e.g. `rust-lang-ci/rust`. + pub repository: String, } #[derive(Serialize, Deserialize)] diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 2e1ede126dc3..7fbfad467c64 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -1,11 +1,11 @@ +use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt::Debug; +use std::time::Duration; use build_helper::metrics::{ BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name, format_build_steps, }; -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::time::Duration; use crate::metrics; use crate::metrics::{JobMetrics, JobName, get_test_suites}; diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 2805bb1118d8..00d791eeb6b3 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -355,6 +355,8 @@ docker \ --env GITHUB_ACTIONS \ --env GITHUB_REF \ --env GITHUB_STEP_SUMMARY="/checkout/obj/${SUMMARY_FILE}" \ + --env GITHUB_WORKFLOW_RUN_ID \ + --env GITHUB_REPOSITORY \ --env RUST_BACKTRACE \ --env TOOLSTATE_REPO_ACCESS_TOKEN \ --env TOOLSTATE_REPO \ From eaa0613e8d767ca7b6527a79e9bdf90e84bb17fa Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 26 Mar 2025 18:12:21 +0530 Subject: [PATCH 394/546] feat(config): Add ChangeId enum for suppressing warnings Introduces the `ChangeId` enum to allow suppressing `change_id` warnings. Now, `ChangeId` supports both numeric values and the string literal `"ignore"`. Numeric values behave as expected, while `"ignore"` is used to suppress warning messages. --- src/bootstrap/src/bin/main.rs | 90 +++++++++++++------------ src/bootstrap/src/core/config/config.rs | 31 +++++++-- src/bootstrap/src/core/config/tests.rs | 5 +- src/bootstrap/src/lib.rs | 2 +- 4 files changed, 75 insertions(+), 53 deletions(-) diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 443131dc7f3c..5df9902a9778 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -11,8 +11,8 @@ use std::str::FromStr; use std::{env, process}; use bootstrap::{ - Build, CONFIG_CHANGE_HISTORY, Config, Flags, Subcommand, debug, find_recent_config_change_ids, - human_readable_changes, t, + Build, CONFIG_CHANGE_HISTORY, ChangeId, Config, Flags, Subcommand, debug, + find_recent_config_change_ids, human_readable_changes, t, }; #[cfg(feature = "tracing")] use tracing::instrument; @@ -155,51 +155,53 @@ fn check_version(config: &Config) -> Option { let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id; let warned_id_path = config.out.join("bootstrap").join(".last-warned-change-id"); - if let Some(mut id) = config.change_id { - if id == latest_change_id { - return None; + let mut id = match config.change_id { + Some(ChangeId::Id(id)) if id == latest_change_id => return None, + Some(ChangeId::Ignore) => return None, + Some(ChangeId::Id(id)) => id, + None => { + msg.push_str("WARNING: The `change-id` is missing in the `bootstrap.toml`. This means that you will not be able to track the major changes made to the bootstrap configurations.\n"); + msg.push_str("NOTE: to silence this warning, "); + msg.push_str(&format!( + "add `change-id = {latest_change_id}` at the top of `bootstrap.toml`" + )); + return Some(msg); } - - // Always try to use `change-id` from .last-warned-change-id first. If it doesn't exist, - // then use the one from the bootstrap.toml. This way we never show the same warnings - // more than once. - if let Ok(t) = fs::read_to_string(&warned_id_path) { - let last_warned_id = usize::from_str(&t) - .unwrap_or_else(|_| panic!("{} is corrupted.", warned_id_path.display())); - - // We only use the last_warned_id if it exists in `CONFIG_CHANGE_HISTORY`. - // Otherwise, we may retrieve all the changes if it's not the highest value. - // For better understanding, refer to `change_tracker::find_recent_config_change_ids`. - if CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == last_warned_id) { - id = last_warned_id; - } - }; - - let changes = find_recent_config_change_ids(id); - - if changes.is_empty() { - return None; - } - - msg.push_str("There have been changes to x.py since you last updated:\n"); - msg.push_str(&human_readable_changes(&changes)); - - msg.push_str("NOTE: to silence this warning, "); - msg.push_str(&format!( - "update `bootstrap.toml` to use `change-id = {latest_change_id}` instead" - )); - - if io::stdout().is_terminal() { - t!(fs::write(warned_id_path, latest_change_id.to_string())); - } - } else { - msg.push_str("WARNING: The `change-id` is missing in the `bootstrap.toml`. This means that you will not be able to track the major changes made to the bootstrap configurations.\n"); - msg.push_str("NOTE: to silence this warning, "); - msg.push_str(&format!( - "add `change-id = {latest_change_id}` at the top of `bootstrap.toml`" - )); }; + // Always try to use `change-id` from .last-warned-change-id first. If it doesn't exist, + // then use the one from the bootstrap.toml. This way we never show the same warnings + // more than once. + if let Ok(t) = fs::read_to_string(&warned_id_path) { + let last_warned_id = usize::from_str(&t) + .unwrap_or_else(|_| panic!("{} is corrupted.", warned_id_path.display())); + + // We only use the last_warned_id if it exists in `CONFIG_CHANGE_HISTORY`. + // Otherwise, we may retrieve all the changes if it's not the highest value. + // For better understanding, refer to `change_tracker::find_recent_config_change_ids`. + if CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == last_warned_id) { + id = last_warned_id; + } + }; + + let changes = find_recent_config_change_ids(id); + + if changes.is_empty() { + return None; + } + + msg.push_str("There have been changes to x.py since you last updated:\n"); + msg.push_str(&human_readable_changes(&changes)); + + msg.push_str("NOTE: to silence this warning, "); + msg.push_str(&format!( + "update `bootstrap.toml` to use `change-id = {latest_change_id}` instead" + )); + + if io::stdout().is_terminal() { + t!(fs::write(warned_id_path, latest_change_id.to_string())); + } + Some(msg) } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index cf4ef4ee310d..96316d4d0fdb 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -193,7 +193,7 @@ pub enum GccCiMode { /// `bootstrap.example.toml`. #[derive(Default, Clone)] pub struct Config { - pub change_id: Option, + pub change_id: Option, pub bypass_bootstrap_lock: bool, pub ccache: Option, /// Call Build::ninja() instead of this. @@ -700,14 +700,32 @@ pub(crate) struct TomlConfig { profile: Option, } +/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`. +#[derive(Clone, Debug, PartialEq)] +pub enum ChangeId { + Ignore, + Id(usize), +} + /// Since we use `#[serde(deny_unknown_fields)]` on `TomlConfig`, we need a wrapper type /// for the "change-id" field to parse it even if other fields are invalid. This ensures /// that if deserialization fails due to other fields, we can still provide the changelogs /// to allow developers to potentially find the reason for the failure in the logs.. #[derive(Deserialize, Default)] pub(crate) struct ChangeIdWrapper { - #[serde(alias = "change-id")] - pub(crate) inner: Option, + #[serde(alias = "change-id", default, deserialize_with = "deserialize_change_id")] + pub(crate) inner: Option, +} + +fn deserialize_change_id<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + let value = toml::Value::deserialize(deserializer)?; + Ok(match value { + toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore), + toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)), + _ => return Err(serde::de::Error::custom("expected \"ignore\" or an integer")), + }) } /// Describes how to handle conflicts in merging two [`TomlConfig`] @@ -1351,10 +1369,11 @@ impl Config { toml::from_str(&contents) .and_then(|table: toml::Value| TomlConfig::deserialize(table)) .inspect_err(|_| { - if let Ok(Some(changes)) = toml::from_str(&contents) - .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table)) - .map(|change_id| change_id.inner.map(crate::find_recent_config_change_ids)) + if let Ok(ChangeIdWrapper { inner: Some(ChangeId::Id(id)) }) = + toml::from_str::(&contents) + .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table)) { + let changes = crate::find_recent_config_change_ids(id); if !changes.is_empty() { println!( "WARNING: There have been changes to x.py since you last updated:\n{}", diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 068e237c2cdc..ac36910c4e05 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -10,6 +10,7 @@ use serde::Deserialize; use super::flags::Flags; use super::{ChangeIdWrapper, Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; +use crate::ChangeId; use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; @@ -171,7 +172,7 @@ runner = "x86_64-runner" ) }, ); - assert_eq!(config.change_id, Some(1), "setting top-level value"); + assert_eq!(config.change_id, Some(ChangeId::Id(1)), "setting top-level value"); assert_eq!( config.rust_lto, crate::core::config::RustcLto::Fat, @@ -311,7 +312,7 @@ fn parse_change_id_with_unknown_field() { "#; let change_id_wrapper: ChangeIdWrapper = toml::from_str(config).unwrap(); - assert_eq!(change_id_wrapper.inner, Some(3461)); + assert_eq!(change_id_wrapper.inner, Some(ChangeId::Id(3461))); } #[test] diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index c47cd8b452f9..843d474f92de 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -45,8 +45,8 @@ mod core; mod utils; pub use core::builder::PathSet; -pub use core::config::Config; pub use core::config::flags::{Flags, Subcommand}; +pub use core::config::{ChangeId, Config}; #[cfg(feature = "tracing")] use tracing::{instrument, span}; From 02444322c0ee0362ae01c35da5495c75232e72da Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 26 Mar 2025 18:25:47 +0530 Subject: [PATCH 395/546] add changeInfo to change tracker --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 1a101b02f709..78887a42a000 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -390,4 +390,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "The default configuration filename has changed from `config.toml` to `bootstrap.toml`. `config.toml` is deprecated but remains supported for backward compatibility.", }, + ChangeInfo { + change_id: 138986, + severity: ChangeSeverity::Info, + summary: "You can now use `change_id = \"ignore\"` to suppress `change_id` warnings in the console.", + }, ]; From 1437dec79942f1367b4cc7756e2f080261c34f3a Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 27 Mar 2025 12:39:48 -0400 Subject: [PATCH 396/546] rustc_resolve: prevent iteration of refids for completeness This came up in review, and it should help some future author not introduce non-deterministic output here. --- compiler/rustc_resolve/src/rustdoc.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 9fda1eb4dc45..a32fe6990160 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -8,7 +8,8 @@ use pulldown_cmark::{ use rustc_ast as ast; use rustc_ast::attr::AttributeExt; use rustc_ast::util::comments::beautify_doc_string; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::unord::UnordSet; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, kw, sym}; @@ -423,7 +424,7 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { ); let mut links = Vec::new(); - let mut refids = FxHashSet::default(); + let mut refids = UnordSet::default(); while let Some(event) = event_iter.next() { match event { From 5d274408d4b8b845f490912dcdadcc717f18fcca Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Mar 2025 17:43:29 +0100 Subject: [PATCH 397/546] Only take outer attributes into account when generating content between first non-crate items and the crate items --- src/librustdoc/doctest/make.rs | 8 +- src/librustdoc/doctest/tests.rs | 131 ++++---------------------------- 2 files changed, 19 insertions(+), 120 deletions(-) diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 55b57292b33a..56b1e76ae8cf 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use rustc_ast::token::{Delimiter, TokenKind}; use rustc_ast::tokenstream::TokenTree; -use rustc_ast::{self as ast, HasAttrs, StmtKind}; +use rustc_ast::{self as ast, AttrStyle, HasAttrs, StmtKind}; use rustc_errors::ColorConfig; use rustc_errors::emitter::stderr_destination; use rustc_parse::new_parser_from_source_str; @@ -388,7 +388,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result) -> Result Date: Thu, 27 Mar 2025 17:44:43 +0000 Subject: [PATCH 398/546] Do not trim paths in MIR validator --- compiler/rustc_mir_transform/src/validate.rs | 9 ++++- tests/ui/mir/inline-causes-trimmed-paths.rs | 36 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tests/ui/mir/inline-causes-trimmed-paths.rs diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 231d7c2ef022..ae7aef08fe61 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -12,6 +12,7 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Upcast, Variance, }; @@ -543,7 +544,13 @@ pub(super) fn validate_types<'tcx>( caller_body: &Body<'tcx>, ) -> Vec<(Location, String)> { let mut type_checker = TypeChecker { body, caller_body, tcx, typing_env, failures: Vec::new() }; - type_checker.visit_body(body); + // The type checker formats a bunch of strings with type names in it, but these strings + // are not always going to be encountered on the error path since the inliner also uses + // the validator, and there are certain kinds of inlining (even for valid code) that + // can cause validation errors (mostly around where clauses and rigid projections). + with_no_trimmed_paths!({ + type_checker.visit_body(body); + }); type_checker.failures } diff --git a/tests/ui/mir/inline-causes-trimmed-paths.rs b/tests/ui/mir/inline-causes-trimmed-paths.rs new file mode 100644 index 000000000000..d626ab4e1d9c --- /dev/null +++ b/tests/ui/mir/inline-causes-trimmed-paths.rs @@ -0,0 +1,36 @@ +//@ build-pass +//@ compile-flags: -Zinline-mir + +trait Storage { + type Buffer: ?Sized; +} + +struct Array; +impl Storage for Array { + type Buffer = [(); N]; +} + +struct Slice; +impl Storage for Slice { + type Buffer = [()]; +} + +struct Wrap { + _b: S::Buffer, +} + +fn coerce(this: &Wrap>) -> &Wrap +where + Array: Storage, +{ + coerce_again(this) +} + +fn coerce_again(this: &Wrap>) -> &Wrap { + this +} + +fn main() { + let inner: Wrap> = Wrap { _b: [(); 1] }; + let _: &Wrap = coerce(&inner); +} From ed0a7988282e5bac6080197fb7a920c35e300ac3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Mar 2025 17:45:18 +0000 Subject: [PATCH 399/546] Drive-by get rid of a bunch of unnecessary :? --- compiler/rustc_mir_transform/src/validate.rs | 48 ++++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index ae7aef08fe61..e7930f0a1e3f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -57,7 +57,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { ty::Coroutine(..) => ExternAbi::Rust, // No need to do MIR validation on error bodies ty::Error(_) => return, - _ => span_bug!(body.span, "unexpected body ty: {body_ty:?}"), + _ => span_bug!(body.span, "unexpected body ty: {body_ty}"), }; ty::layout::fn_can_unwind(tcx, Some(def_id), body_abi) @@ -662,7 +662,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ProjectionElem::Index(index) => { let index_ty = self.body.local_decls[index].ty; if index_ty != self.tcx.types.usize { - self.fail(location, format!("bad index ({index_ty:?} != usize)")) + self.fail(location, format!("bad index ({index_ty} != usize)")) } } ProjectionElem::Deref @@ -671,10 +671,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty; if base_ty.is_box() { - self.fail( - location, - format!("{base_ty:?} dereferenced after ElaborateBoxDerefs"), - ) + self.fail(location, format!("{base_ty} dereferenced after ElaborateBoxDerefs")) } } ProjectionElem::Field(f, ty) => { @@ -687,7 +684,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { this.fail( location, format!( - "Field projection `{place_ref:?}.{f:?}` specified type `{ty:?}`, but actual type is `{f_ty:?}`" + "Field projection `{place_ref:?}.{f:?}` specified type `{ty}`, but actual type is `{f_ty}`" ) ) } @@ -813,7 +810,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail( location, format!( - "Failed subtyping {ty:#?} and {:#?}", + "Failed subtyping {ty} and {}", place_ref.ty(&self.body.local_decls, self.tcx).ty ), ) @@ -833,7 +830,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail( location, format!( - "Cannot unwrap unsafe binder {binder_ty:?} into type {unwrapped_ty:?}" + "Cannot unwrap unsafe binder {binder_ty:?} into type {unwrapped_ty}" ), ); } @@ -848,7 +845,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if ty.is_union() || ty.is_enum() { self.fail( START_BLOCK.start_location(), - format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name), + format!("invalid type {ty} in debuginfo for {:?}", debuginfo.name), ); } if projection.is_empty() { @@ -1071,15 +1068,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self.mir_assign_valid_types(a, b) { self.fail( location, - format!("Cannot {op:?} compare incompatible types {a:?} and {b:?}"), + format!("Cannot {op:?} compare incompatible types {a} and {b}"), ); } } else if a != b { self.fail( location, - format!( - "Cannot perform binary op {op:?} on unequal types {a:?} and {b:?}" - ), + format!("Cannot perform binary op {op:?} on unequal types {a} and {b}"), ); } } @@ -1088,7 +1083,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Offset => { check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..)); if b != self.tcx.types.isize && b != self.tcx.types.usize { - self.fail(location, format!("Cannot offset by non-isize type {b:?}")); + self.fail(location, format!("Cannot offset by non-isize type {b}")); } } Eq | Lt | Le | Ne | Ge | Gt => { @@ -1320,7 +1315,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { { self.fail( location, - format!("Cannot transmute from non-`Sized` type {op_ty:?}"), + format!("Cannot transmute from non-`Sized` type {op_ty}"), ); } if !self @@ -1347,7 +1342,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => { let fail_out_of_bounds = |this: &mut Self, location, field, ty| { - this.fail(location, format!("Out of bounds field {field:?} for {ty:?}")); + this.fail(location, format!("Out of bounds field {field:?} for {ty}")); }; let mut current_ty = *container; @@ -1381,7 +1376,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { _ => { self.fail( location, - format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"), + format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty}"), ); return; } @@ -1410,7 +1405,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) { self.fail( location, - format!("Cannot wrap {unwrapped_ty:?} into unsafe binder {binder_ty:?}"), + format!("Cannot wrap {unwrapped_ty} into unsafe binder {binder_ty:?}"), ); } } @@ -1496,24 +1491,27 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // since CopyNonOverlapping is parametrized by 1 type, // we only need to check that they are equal and not keep an extra parameter. if !self.mir_assign_valid_types(op_src_ty, op_dst_ty) { - self.fail(location, format!("bad arg ({op_src_ty:?} != {op_dst_ty:?})")); + self.fail(location, format!("bad arg ({op_src_ty} != {op_dst_ty})")); } let op_cnt_ty = count.ty(&self.body.local_decls, self.tcx); if op_cnt_ty != self.tcx.types.usize { - self.fail(location, format!("bad arg ({op_cnt_ty:?} != usize)")) + self.fail(location, format!("bad arg ({op_cnt_ty} != usize)")) } } StatementKind::SetDiscriminant { place, .. } => { if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) { self.fail(location, "`SetDiscriminant`is not allowed until deaggregation"); } - let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind(); - if !matches!(pty, ty::Adt(..) | ty::Coroutine(..) | ty::Alias(ty::Opaque, ..)) { + let pty = place.ty(&self.body.local_decls, self.tcx).ty; + if !matches!( + pty.kind(), + ty::Adt(..) | ty::Coroutine(..) | ty::Alias(ty::Opaque, ..) + ) { self.fail( location, format!( - "`SetDiscriminant` is only allowed on ADTs and coroutines, not {pty:?}" + "`SetDiscriminant` is only allowed on ADTs and coroutines, not {pty}" ), ); } @@ -1562,7 +1560,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if ScalarInt::try_from_uint(value, size).is_none() { self.fail( location, - format!("the value {value:#x} is not a proper {switch_ty:?}"), + format!("the value {value:#x} is not a proper {switch_ty}"), ) } } From bec69704c0ee6b3c6b1854b104b964fc17d8c36f Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Thu, 27 Mar 2025 18:29:06 +0000 Subject: [PATCH 400/546] Use `abs_diff` where applicable --- compiler/rustc_errors/src/snippet.rs | 6 +----- compiler/rustc_span/src/edit_distance.rs | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index 8485d7087cfc..f09c2ed5534a 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -159,11 +159,7 @@ impl Annotation { /// Length of this annotation as displayed in the stderr output pub(crate) fn len(&self) -> usize { // Account for usize underflows - if self.end_col.display > self.start_col.display { - self.end_col.display - self.start_col.display - } else { - self.start_col.display - self.end_col.display - } + self.end_col.display.abs_diff(self.start_col.display) } pub(crate) fn has_label(&self) -> bool { diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 8a2baaa42e2a..4f3202b694c1 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -118,7 +118,7 @@ pub fn edit_distance_with_substrings(a: &str, b: &str, limit: usize) -> Option Date: Thu, 27 Mar 2025 15:40:03 -0400 Subject: [PATCH 401/546] saethlin goes on vacation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index ebbcfa4516b9..7e1e1bc57716 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1098,6 +1098,7 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "jyn514", "ChrisDenton", + "saethlin", ] [[assign.warn_non_default_branch.exceptions]] From 65624d9ea5c2aee3f3c7729f3b8d72c0920df6e6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 26 Mar 2025 20:32:14 -0500 Subject: [PATCH 402/546] tester.js: ignore displayTypeSignature if it is null --- src/tools/rustdoc-js/tester.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index ea575f27799a..f70fc917770c 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -451,7 +451,7 @@ function loadSearchJS(doc_folder, resource_suffix) { if (!Object.prototype.hasOwnProperty.call(entry, key)) { continue; } - if (key === "displayTypeSignature") { + if (key === "displayTypeSignature" && entry.displayTypeSignature !== null) { const {type, mappedNames, whereClause} = await entry.displayTypeSignature; entry.displayType = arrayToCode(type); From 4924e0a067946d7b810dcc777ffd8370c29da80a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 26 Mar 2025 15:51:41 +1100 Subject: [PATCH 403/546] Add a HIR pretty-printing test focused on lifetimes. HIR printing currently gets very little testing. This increases coverage a bit, with a focus on lifetimes. There are some FIXME comments for cases that are printed in a dubious fashion. This PR won't address those; the point of adding this test is to ensure that the subsequent commits don't hurt pretty-printing. --- tests/pretty/hir-lifetimes.pp | 96 +++++++++++++++++++++++++++++++++++ tests/pretty/hir-lifetimes.rs | 91 +++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 tests/pretty/hir-lifetimes.pp create mode 100644 tests/pretty/hir-lifetimes.rs diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp new file mode 100644 index 000000000000..df3aba516b9c --- /dev/null +++ b/tests/pretty/hir-lifetimes.pp @@ -0,0 +1,96 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-lifetimes.pp + +// This tests the pretty-printing of lifetimes in lots of ways. + +#![allow(unused)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +struct Foo<'a> { + x: &'a u32, +} + +impl <'a> Foo<'a> { + fn f<'b>(x: &'b u32) { } +} + +impl Foo<'_> { + fn a(x: &'_ u32) { } + + fn b(x: &'_ u32) { } + + fn c(x: &'_ u32, y: &'static u32) { } + + // FIXME: `'a` before `self` is omitted + fn d<'a>(&self, x: &'a u32) { } + + // FIXME: impl Traits printed as just `/*impl Trait*/`, ugh + fn iter1<'a>(&self) + -> /*impl Trait*/ { #[lang = "Range"]{ start: 0, end: 1,} } + + fn iter2(&self) + -> /*impl Trait*/ { #[lang = "Range"]{ start: 0, end: 1,} } +} + +fn a(x: Foo<'_>) { } + +fn b<'a>(x: Foo<'a>) { } + +struct Bar<'a, 'b, 'c, T> { + x: &'a u32, + y: &'b &'c u32, + z: T, +} + +fn f1<'a, 'b, T>(x: Bar<'a, 'b, '_, T>) { } + +fn f2(x: Bar<'_, '_, '_, u32>) { } + +trait MyTrait<'a, 'b> { + fn f(&self, x: Foo<'a>, y: Foo<'b>); +} + +impl <'a, 'b, 'c, T> MyTrait<'a, 'b> for Bar<'a, 'b, 'c, T> { + fn f(&self, x: Foo<'a>, y: Foo<'b>) { } +} + +fn g(x: &'_ dyn for<'a, 'b> MyTrait<'a, 'b>) { } + +trait Blah { } + +type T<'a> = dyn Blah + 'a; + +type Q<'a> = dyn MyTrait<'a, 'a> + 'a; + +fn h<'b, F>(f: F, y: Foo<'b>) where F: for<'d> MyTrait<'d, 'b> { } + +// FIXME(?): attr printing is weird +#[attr = Repr([ReprC])] +struct S<'a>(&'a u32); + +extern "C" { + unsafe fn g1(s: S<>); + unsafe fn g2(s: S<'_>); + unsafe fn g3<'a>(s: S<'a>); +} + +struct St<'a> { + x: &'a u32, +} + +fn f() { { let _ = St{ x: &0,}; }; { let _ = St{ x: &0,}; }; } + +struct Name<'a>(&'a str); + +const A: Name<> = Name("a"); +const B: &'_ str = ""; +static C: &'_ str = ""; +static D: &'static str = ""; + +fn tr(_: Box) { } + +fn main() { } diff --git a/tests/pretty/hir-lifetimes.rs b/tests/pretty/hir-lifetimes.rs new file mode 100644 index 000000000000..1379be343924 --- /dev/null +++ b/tests/pretty/hir-lifetimes.rs @@ -0,0 +1,91 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-lifetimes.pp + +// This tests the pretty-printing of lifetimes in lots of ways. + +#![allow(unused)] + +struct Foo<'a> { + x: &'a u32, +} + +impl<'a> Foo<'a> { + fn f<'b>(x: &'b u32) {} +} + +impl Foo<'_> { + fn a(x: &u32) {} + + fn b(x: &'_ u32) {} + + fn c(x: &'_ u32, y: &'static u32) {} + + // FIXME: `'a` before `self` is omitted + fn d<'a>(&'a self, x: &'a u32) {} + + // FIXME: impl Traits printed as just `/*impl Trait*/`, ugh + fn iter1<'a>(&self) -> impl Iterator + 'a { 0..1 } + + fn iter2(&self) -> impl Iterator + '_ { 0..1 } +} + +fn a(x: Foo<'_>) {} + +fn b<'a>(x: Foo<'a>) {} + +struct Bar<'a, 'b, 'c, T> { + x: &'a u32, + y: &'b &'c u32, + z: T, +} + +fn f1<'a, 'b, T>(x: Bar<'a, 'b, '_, T>) {} + +fn f2(x: Bar<'_, '_, '_, u32>) {} + +trait MyTrait<'a, 'b> { + fn f(&self, x: Foo<'a>, y: Foo<'b>); +} + +impl<'a, 'b, 'c, T> MyTrait<'a, 'b> for Bar<'a, 'b, 'c, T> { + fn f(&self, x: Foo<'a>, y: Foo<'b>) {} +} + +fn g(x: &dyn for<'a, 'b> MyTrait<'a, 'b>) {} + +trait Blah {} + +type T<'a> = dyn Blah + 'a; + +type Q<'a> = dyn MyTrait<'a, 'a> + 'a; + +fn h<'b, F>(f: F, y: Foo<'b>) where F: for<'d> MyTrait<'d, 'b> {} + +// FIXME(?): attr printing is weird +#[repr(C)] +struct S<'a>(&'a u32); + +extern "C" { + fn g1(s: S); + fn g2(s: S<'_>); + fn g3<'a>(s: S<'a>); +} + +struct St<'a> { x: &'a u32 } + +fn f() { + _ = St { x: &0 }; + _ = St::<'_> { x: &0 }; +} + +struct Name<'a>(&'a str); + +const A: Name = Name("a"); +const B: &str = ""; +static C: &'_ str = ""; +static D: &'static str = ""; + +fn tr(_: Box) {} + +fn main() {} From c6d8d654962768e349b4ed1c80f2e7418b10a092 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 08:56:33 +1100 Subject: [PATCH 404/546] Remove `LifetimeSuggestionPosition` and `Lifetime::suggestion_position`. They both are only used in `Lifetime::suggestion`. This commit inlines and removes them. --- compiler/rustc_hir/src/hir.rs | 57 ++++++++++++----------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 751c379b21a6..b91fb41cb4d6 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -139,19 +139,6 @@ impl fmt::Display for Lifetime { } } -pub enum LifetimeSuggestionPosition { - /// The user wrote `'a` or `'_`. - Normal, - /// The user wrote `&type` or `&mut type`. - Ampersand, - /// The user wrote `Path` and omitted the `<'_>`. - ElidedPath, - /// The user wrote `Path`, and omitted the `'_,`. - ElidedPathArgument, - /// The user wrote `dyn Trait` and omitted the `+ '_`. - ObjectDefault, -} - impl Lifetime { pub fn is_elided(&self) -> bool { self.res.is_elided() @@ -161,33 +148,27 @@ impl Lifetime { self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime } - pub fn suggestion_position(&self) -> (LifetimeSuggestionPosition, Span) { - if self.ident.name == kw::Empty { - if self.ident.span.is_empty() { - (LifetimeSuggestionPosition::ElidedPathArgument, self.ident.span) - } else { - (LifetimeSuggestionPosition::ElidedPath, self.ident.span.shrink_to_hi()) - } - } else if self.res == LifetimeName::ImplicitObjectLifetimeDefault { - (LifetimeSuggestionPosition::ObjectDefault, self.ident.span) - } else if self.ident.span.is_empty() { - (LifetimeSuggestionPosition::Ampersand, self.ident.span) - } else { - (LifetimeSuggestionPosition::Normal, self.ident.span) - } - } - pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) { debug_assert!(new_lifetime.starts_with('\'')); - let (pos, span) = self.suggestion_position(); - let code = match pos { - LifetimeSuggestionPosition::Normal => format!("{new_lifetime}"), - LifetimeSuggestionPosition::Ampersand => format!("{new_lifetime} "), - LifetimeSuggestionPosition::ElidedPath => format!("<{new_lifetime}>"), - LifetimeSuggestionPosition::ElidedPathArgument => format!("{new_lifetime}, "), - LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lifetime}"), - }; - (span, code) + + if self.ident.name == kw::Empty { + if self.ident.span.is_empty() { + // The user wrote `Path`, and omitted the `'_,`. + (self.ident.span, format!("{new_lifetime}, ")) + } else { + // The user wrote `Path` and omitted the `<'_>`. + (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) + } + } else if self.res == LifetimeName::ImplicitObjectLifetimeDefault { + // The user wrote `dyn Trait` and omitted the `+ '_`. + (self.ident.span, format!("+ {new_lifetime}")) + } else if self.ident.span.is_empty() { + // The user wrote `&type` or `&mut type`. + (self.ident.span, format!("{new_lifetime} ")) + } else { + // The user wrote `'a` or `'_`. + (self.ident.span, format!("{new_lifetime}")) + } } } From cfd00f9c16d9b3ab98d6e06125c6baa83dfa4a03 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 18:51:00 +1100 Subject: [PATCH 405/546] Remove `ImplicitObjectLifetimeDefault` case from `suggestion`. It has no effect on anything in the test suite. This means it can also be rewritten as a neater pairwise `match`. --- compiler/rustc_hir/src/hir.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b91fb41cb4d6..89249eab3510 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -151,23 +151,18 @@ impl Lifetime { pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) { debug_assert!(new_lifetime.starts_with('\'')); - if self.ident.name == kw::Empty { - if self.ident.span.is_empty() { - // The user wrote `Path`, and omitted the `'_,`. - (self.ident.span, format!("{new_lifetime}, ")) - } else { - // The user wrote `Path` and omitted the `<'_>`. - (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) - } - } else if self.res == LifetimeName::ImplicitObjectLifetimeDefault { - // The user wrote `dyn Trait` and omitted the `+ '_`. - (self.ident.span, format!("+ {new_lifetime}")) - } else if self.ident.span.is_empty() { + match (self.ident.name.is_empty(), self.ident.span.is_empty()) { + // The user wrote `Path`, and omitted the `'_,`. + (true, true) => (self.ident.span, format!("{new_lifetime}, ")), + + // The user wrote `Path` and omitted the `<'_>`. + (true, false) => (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")), + // The user wrote `&type` or `&mut type`. - (self.ident.span, format!("{new_lifetime} ")) - } else { + (false, true) => (self.ident.span, format!("{new_lifetime} ")), + // The user wrote `'a` or `'_`. - (self.ident.span, format!("{new_lifetime}")) + (false, false) => (self.ident.span, format!("{new_lifetime}")), } } } From d4870874158d70e3f6863412ea729dd70d1baf7b Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 27 Mar 2025 17:24:21 -0500 Subject: [PATCH 406/546] search.js: revert usage of nonundef for now (not available under test) specifically, `storage.js` is not loaded during `rustdoc-js` and `rustdoc-js-std` tests. --- src/librustdoc/html/static/js/search.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index f3f4878b1627..dce5fddb3177 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1,5 +1,5 @@ // ignore-tidy-filelength -/* global addClass, getNakedUrl, getSettingValue, getVar, nonundef */ +/* global addClass, getNakedUrl, getSettingValue, getVar */ /* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */ "use strict"; @@ -353,7 +353,8 @@ function getFilteredNextElem(query, parserState, elems, isInGenerics) { const typeFilterElem = elems.pop(); checkExtraTypeFilterCharacters(start, parserState); // typeFilterElem is not undefined. If it was, the elems.length check would have fired. - parserState.typeFilter = nonundef(typeFilterElem).normalizedPathLast; + // @ts-expect-error + parserState.typeFilter = typeFilterElem.normalizedPathLast; parserState.pos += 1; parserState.totalElems -= 1; query.literalSearch = false; From 8d2c63f514a74752a3186b0bf3e8f3aef57dc12e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 08:21:28 +1100 Subject: [PATCH 407/546] Don't use `kw::Empty` in `hir::Lifetime::ident`. `hir::Lifetime::ident` currently sometimes uses `kw::Empty` for elided lifetimes and sometimes uses `kw::UnderscoreLifetime`, and the distinction is used when creating some error suggestions, e.g. in `Lifetime::suggestion` and `ImplicitLifetimeFinder::visit_ty`. I found this *really* confusing, and it took me a while to understand what was going on. This commit replaces all uses of `kw::Empty` in `hir::Lifetime::ident` with `kw::UnderscoreLifetime`. It adds a new field `hir::Lifetime::is_path_anon` that mostly replaces the old empty/underscore distinction and makes things much clearer. Some other notable changes: - Adds a big comment to `Lifetime` talking about permissable field values. - Adds some assertions in `new_named_lifetime` about what ident values are permissible for the different `LifetimeRes` values. - Adds a `Lifetime::new` constructor that does some checking to make sure the `is_elided` and `is_anonymous` states are valid. - `add_static_impl_trait_suggestion` now looks at `Lifetime::res` instead of the ident when creating the suggestion. This is the one case where `is_path_anon` doesn't replace the old empty/underscore distinction. - A couple of minor pretty-printing improvements. --- compiler/rustc_ast_lowering/src/item.rs | 4 +- compiler/rustc_ast_lowering/src/lib.rs | 47 +++++++--- compiler/rustc_ast_lowering/src/path.rs | 7 +- .../src/diagnostics/region_errors.rs | 6 +- compiler/rustc_hir/src/hir.rs | 93 ++++++++++++++++--- compiler/rustc_hir/src/hir/tests.rs | 1 + compiler/rustc_trait_selection/src/errors.rs | 19 ++-- tests/pretty/hir-lifetimes.pp | 4 +- tests/ui/stats/input-stats.stderr | 6 +- 9 files changed, 136 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c03d5e53d976..43bf951eddc6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,7 @@ use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, PredicateOrigin}; +use rustc_hir::{self as hir, HirId, IsAnonInPath, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -1823,7 +1823,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } GenericParamKind::Lifetime => { let lt_id = self.next_node_id(); - let lifetime = self.new_named_lifetime(id, lt_id, ident); + let lifetime = self.new_named_lifetime(id, lt_id, ident, IsAnonInPath::No); hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { lifetime, bounds, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ced9064fd9f4..d5d6dcd8d631 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -55,7 +55,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, ParamName, TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, IsAnonInPath, ItemLocalMap, LangItem, ParamName, + TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -1755,7 +1756,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime { - self.new_named_lifetime(l.id, l.id, l.ident) + self.new_named_lifetime(l.id, l.id, l.ident, IsAnonInPath::No) + } + + fn lower_lifetime_anon_in_path(&mut self, id: NodeId, span: Span) -> &'hir hir::Lifetime { + self.new_named_lifetime(id, id, Ident::new(kw::UnderscoreLifetime, span), IsAnonInPath::Yes) } #[instrument(level = "debug", skip(self))] @@ -1764,28 +1769,43 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: NodeId, new_id: NodeId, ident: Ident, + is_anon_in_path: IsAnonInPath, ) -> &'hir hir::Lifetime { + debug_assert_ne!(ident.name, kw::Empty); let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); let res = match res { LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param), LifetimeRes::Fresh { param, .. } => { + debug_assert_eq!(ident.name, kw::UnderscoreLifetime); let param = self.local_def_id(param); hir::LifetimeName::Param(param) } - LifetimeRes::Infer => hir::LifetimeName::Infer, - LifetimeRes::Static { .. } => hir::LifetimeName::Static, + LifetimeRes::Infer => { + debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + hir::LifetimeName::Infer + } + LifetimeRes::Static { .. } => { + debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); + hir::LifetimeName::Static + } LifetimeRes::Error => hir::LifetimeName::Error, LifetimeRes::ElidedAnchor { .. } => { panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span); } }; + #[cfg(debug_assertions)] + if is_anon_in_path == IsAnonInPath::Yes { + debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + } + debug!(?res); - self.arena.alloc(hir::Lifetime { - hir_id: self.lower_node_id(new_id), - ident: self.lower_ident(ident), + self.arena.alloc(hir::Lifetime::new( + self.lower_node_id(new_id), + self.lower_ident(ident), res, - }) + is_anon_in_path, + )) } fn lower_generic_params_mut( @@ -2369,11 +2389,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// when the bound is written, even if it is written with `'_` like in /// `Box`. In those cases, `lower_lifetime` is invoked. fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime { - let r = hir::Lifetime { - hir_id: self.next_id(), - ident: Ident::new(kw::Empty, self.lower_span(span)), - res: hir::LifetimeName::ImplicitObjectLifetimeDefault, - }; + let r = hir::Lifetime::new( + self.next_id(), + Ident::new(kw::UnderscoreLifetime, self.lower_span(span)), + hir::LifetimeName::ImplicitObjectLifetimeDefault, + IsAnonInPath::No, + ); debug!("elided_dyn_bound: r={:?}", r); self.arena.alloc(r) } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index d00c797755f3..c464c159c34c 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_session::parse::add_feature_diagnostics; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -450,10 +450,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { 0, (start.as_u32()..end.as_u32()).map(|i| { let id = NodeId::from_u32(i); - let l = self.lower_lifetime(&Lifetime { - id, - ident: Ident::new(kw::Empty, elided_lifetime_span), - }); + let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span); GenericArg::Lifetime(l) }), ); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 6b11f1a3681f..50a18b04de4e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -513,14 +513,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ty::VarianceDiagInfo::Invariant { ty, param_index } => { let (desc, note) = match ty.kind() { ty::RawPtr(ty, mutbl) => { - assert_eq!(*mutbl, rustc_hir::Mutability::Mut); + assert_eq!(*mutbl, hir::Mutability::Mut); ( format!("a mutable pointer to `{}`", ty), "mutable pointers are invariant over their type parameter".to_string(), ) } ty::Ref(_, inner_ty, mutbl) => { - assert_eq!(*mutbl, rustc_hir::Mutability::Mut); + assert_eq!(*mutbl, hir::Mutability::Mut); ( format!("a mutable reference to `{inner_ty}`"), "mutable references are invariant over their type parameter" @@ -887,7 +887,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Skip `async` desugaring `impl Future`. } if let TyKind::TraitObject(_, lt) = alias_ty.kind { - if lt.ident.name == kw::Empty { + if lt.res == hir::LifetimeName::ImplicitObjectLifetimeDefault { spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string())); } else { spans_suggs.push((lt.ident.span, "'a".to_string())); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 89249eab3510..e3e96894ed1f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -35,20 +35,60 @@ use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +pub enum IsAnonInPath { + No, + Yes, +} + +/// A lifetime. The valid field combinations are non-obvious. The following +/// example shows some of them. See also the comments on `LifetimeName`. +/// ``` +/// #[repr(C)] +/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No +/// unsafe extern "C" { +/// fn f1(s: S); // res=Param, name='_, IsAnonInPath::Yes +/// fn f2(s: S<'_>); // res=Param, name='_, IsAnonInPath::No +/// fn f3<'a>(s: S<'a>); // res=Param, name='a, IsAnonInPath::No +/// } +/// +/// struct St<'a> { x: &'a u32 } // res=Param, name='a, IsAnonInPath::No +/// fn f() { +/// _ = St { x: &0 }; // res=Infer, name='_, IsAnonInPath::Yes +/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, IsAnonInPath::No +/// } +/// +/// struct Name<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No +/// const A: Name = Name("a"); // res=Static, name='_, IsAnonInPath::Yes +/// const B: &str = ""; // res=Static, name='_, IsAnonInPath::No +/// static C: &'_ str = ""; // res=Static, name='_, IsAnonInPath::No +/// static D: &'static str = ""; // res=Static, name='static, IsAnonInPath::No +/// +/// trait Tr {} +/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, IsAnonInPath::No +/// +/// // (commented out because these cases trigger errors) +/// // struct S1<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No +/// // struct S2(S1); // res=Error, name='_, IsAnonInPath::Yes +/// // struct S3(S1<'_>); // res=Error, name='_, IsAnonInPath::No +/// // struct S4(S1<'a>); // res=Error, name='a, IsAnonInPath::No +/// ``` #[derive(Debug, Copy, Clone, HashStable_Generic)] pub struct Lifetime { #[stable_hasher(ignore)] pub hir_id: HirId, - /// Either "`'a`", referring to a named lifetime definition, - /// `'_` referring to an anonymous lifetime (either explicitly `'_` or `&type`), - /// or "``" (i.e., `kw::Empty`) when appearing in path. - /// - /// See `Lifetime::suggestion_position` for practical use. + /// Either a named lifetime definition (e.g. `'a`, `'static`) or an + /// anonymous lifetime (`'_`, either explicitly written, or inserted for + /// things like `&type`). pub ident: Ident, /// Semantics of this lifetime. pub res: LifetimeName, + + /// Is the lifetime anonymous and in a path? Used only for error + /// suggestions. See `Lifetime::suggestion` for example use. + pub is_anon_in_path: IsAnonInPath, } #[derive(Debug, Copy, Clone, HashStable_Generic)] @@ -111,11 +151,12 @@ pub enum LifetimeName { /// that was already reported. Error, - /// User wrote an anonymous lifetime, either `'_` or nothing. - /// The semantics of this lifetime should be inferred by typechecking code. + /// User wrote an anonymous lifetime, either `'_` or nothing (which gets + /// converted to `'_`). The semantics of this lifetime should be inferred + /// by typechecking code. Infer, - /// User wrote `'static`. + /// User wrote `'static` or nothing (which gets converted to `'_`). Static, } @@ -135,34 +176,56 @@ impl LifetimeName { impl fmt::Display for Lifetime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.ident.name != kw::Empty { self.ident.name.fmt(f) } else { "'_".fmt(f) } + self.ident.name.fmt(f) } } impl Lifetime { + pub fn new( + hir_id: HirId, + ident: Ident, + res: LifetimeName, + is_anon_in_path: IsAnonInPath, + ) -> Lifetime { + let lifetime = Lifetime { hir_id, ident, res, is_anon_in_path }; + + // Sanity check: elided lifetimes form a strict subset of anonymous lifetimes. + #[cfg(debug_assertions)] + match (lifetime.is_elided(), lifetime.is_anonymous()) { + (false, false) => {} // e.g. `'a` + (false, true) => {} // e.g. explicit `'_` + (true, true) => {} // e.g. `&x` + (true, false) => panic!("bad Lifetime"), + } + + lifetime + } + pub fn is_elided(&self) -> bool { self.res.is_elided() } pub fn is_anonymous(&self) -> bool { - self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime + self.ident.name == kw::UnderscoreLifetime } pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) { debug_assert!(new_lifetime.starts_with('\'')); - match (self.ident.name.is_empty(), self.ident.span.is_empty()) { + match (self.is_anon_in_path, self.ident.span.is_empty()) { // The user wrote `Path`, and omitted the `'_,`. - (true, true) => (self.ident.span, format!("{new_lifetime}, ")), + (IsAnonInPath::Yes, true) => (self.ident.span, format!("{new_lifetime}, ")), // The user wrote `Path` and omitted the `<'_>`. - (true, false) => (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")), + (IsAnonInPath::Yes, false) => { + (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) + } // The user wrote `&type` or `&mut type`. - (false, true) => (self.ident.span, format!("{new_lifetime} ")), + (IsAnonInPath::No, true) => (self.ident.span, format!("{new_lifetime} ")), // The user wrote `'a` or `'_`. - (false, false) => (self.ident.span, format!("{new_lifetime}")), + (IsAnonInPath::No, false) => (self.ident.span, format!("{new_lifetime}")), } } } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index f75b9662132e..62ef02d2f500 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -58,6 +58,7 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) { hir_id: HirId::INVALID, ident: Ident::new(sym::name, DUMMY_SP), res: LifetimeName::Static, + is_anon_in_path: IsAnonInPath::No, } }, syntax, diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7159397c4b1a..b30390a9330e 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -9,7 +9,7 @@ use rustc_errors::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; -use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node}; +use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, Region, Ty, TyCtxt}; @@ -567,10 +567,14 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { impl<'v> Visitor<'v> for ImplicitLifetimeFinder { fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { - let make_suggestion = |ident: Ident| { - if ident.name == kw::Empty && ident.span.is_empty() { + let make_suggestion = |lifetime: &hir::Lifetime| { + if lifetime.is_anon_in_path == IsAnonInPath::Yes + && lifetime.ident.span.is_empty() + { format!("{}, ", self.suggestion_param_name) - } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() { + } else if lifetime.ident.name == kw::UnderscoreLifetime + && lifetime.ident.span.is_empty() + { format!("{} ", self.suggestion_param_name) } else { self.suggestion_param_name.clone() @@ -584,7 +588,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { matches!( arg, hir::GenericArg::Lifetime(lifetime) - if lifetime.ident.name == kw::Empty + if lifetime.is_anon_in_path == IsAnonInPath::Yes ) }) { self.suggestions.push(( @@ -605,7 +609,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { { self.suggestions.push(( lifetime.ident.span, - make_suggestion(lifetime.ident), + make_suggestion(lifetime), )); } } @@ -614,8 +618,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { } } hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { - self.suggestions - .push((lifetime.ident.span, make_suggestion(lifetime.ident))); + self.suggestions.push((lifetime.ident.span, make_suggestion(lifetime))); } _ => {} } diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp index df3aba516b9c..e545b0c8f576 100644 --- a/tests/pretty/hir-lifetimes.pp +++ b/tests/pretty/hir-lifetimes.pp @@ -73,7 +73,7 @@ fn h<'b, F>(f: F, y: Foo<'b>) where F: for<'d> MyTrait<'d, 'b> { } struct S<'a>(&'a u32); extern "C" { - unsafe fn g1(s: S<>); + unsafe fn g1(s: S<'_>); unsafe fn g2(s: S<'_>); unsafe fn g3<'a>(s: S<'a>); } @@ -86,7 +86,7 @@ fn f() { { let _ = St{ x: &0,}; }; { let _ = St{ x: &0,}; }; } struct Name<'a>(&'a str); -const A: Name<> = Name("a"); +const A: Name<'_> = Name("a"); const B: &'_ str = ""; static C: &'_ str = ""; static D: &'static str = ""; diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index dbc9e7d254c8..191daff2137d 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -119,7 +119,7 @@ hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size hir-stats ---------------------------------------------------------------- hir-stats ForeignItemRef 24 ( 0.3%) 1 24 -hir-stats Lifetime 24 ( 0.3%) 1 24 +hir-stats Lifetime 28 ( 0.3%) 1 28 hir-stats Mod 32 ( 0.4%) 1 32 hir-stats ExprField 40 ( 0.4%) 1 40 hir-stats TraitItemRef 56 ( 0.6%) 2 28 @@ -155,7 +155,7 @@ hir-stats Generics 560 ( 6.2%) 10 56 hir-stats Ty 720 ( 8.0%) 15 48 hir-stats - Ptr 48 ( 0.5%) 1 hir-stats - Ref 48 ( 0.5%) 1 -hir-stats - Path 624 ( 7.0%) 13 +hir-stats - Path 624 ( 6.9%) 13 hir-stats Expr 768 ( 8.6%) 12 64 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 @@ -174,5 +174,5 @@ hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.8%) 31 40 hir-stats PathSegment 1_920 (21.4%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_976 180 +hir-stats Total 8_980 180 hir-stats From 3b7d59ad1212a6e6556423b4c383aee99f7d20e0 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Fri, 28 Mar 2025 01:54:35 +0000 Subject: [PATCH 408/546] Update target maintainers for thumb targets to reflect new REWG Arm team name --- src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md | 3 +-- src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md | 3 +-- src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md | 3 +-- src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md | 3 +-- src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md index f4ed6201bbdc..746b84435479 100644 --- a/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md @@ -26,8 +26,7 @@ only option because there is no FPU support in [Armv6-M]. ## Target maintainers -* [Rust Embedded Devices Working Group Cortex-M - Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` +* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md index 11c9486cb76e..12e28265678c 100644 --- a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md @@ -21,8 +21,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -* [Rust Embedded Devices Working Group Cortex-M - Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` +* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md index b258033bb0fa..03324b341d07 100644 --- a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md @@ -22,8 +22,7 @@ only option because there is no FPU support in [Armv7-M]. ## Target maintainers -* [Rust Embedded Devices Working Group Cortex-M - Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` +* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md index 0ae4e3e94bd8..4a92e856466c 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md @@ -22,8 +22,7 @@ only option because there is no FPU support in [Armv8-M] Baseline. ## Target maintainers -* [Rust Embedded Devices Working Group Cortex-M - Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` +* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md index 82fdc5b21cf2..9f85d08fa0ac 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md @@ -25,8 +25,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -* [Rust Embedded Devices Working Group Cortex-M - Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` +* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options From b24083bccc15a55d8488fee8ee629689c5039ded Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 27 Mar 2025 23:10:30 +0530 Subject: [PATCH 409/546] Add new change-id option in bootstrap.example.toml and update the change-id description references --- bootstrap.example.toml | 5 +++-- src/bootstrap/src/bin/main.rs | 4 ++-- src/bootstrap/src/core/config/config.rs | 6 +++++- src/bootstrap/src/utils/change_tracker.rs | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index caffe1a93712..2a98821f2252 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -28,8 +28,9 @@ # - A new option # - A change in the default values # -# If `change-id` does not match the version that is currently running, -# `x.py` will inform you about the changes made on bootstrap. +# If the change-id does not match the version currently in use, x.py will +# display the changes made to the bootstrap. +# To suppress these warnings, you can set change-id = "ignore". #change-id = # ============================================================================= diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 5df9902a9778..7ec3140c0386 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -163,7 +163,7 @@ fn check_version(config: &Config) -> Option { msg.push_str("WARNING: The `change-id` is missing in the `bootstrap.toml`. This means that you will not be able to track the major changes made to the bootstrap configurations.\n"); msg.push_str("NOTE: to silence this warning, "); msg.push_str(&format!( - "add `change-id = {latest_change_id}` at the top of `bootstrap.toml`" + "add `change-id = {latest_change_id}` or change-id = \"ignore\" at the top of `bootstrap.toml`" )); return Some(msg); } @@ -195,7 +195,7 @@ fn check_version(config: &Config) -> Option { msg.push_str("NOTE: to silence this warning, "); msg.push_str(&format!( - "update `bootstrap.toml` to use `change-id = {latest_change_id}` instead" + "update `bootstrap.toml` to use `change-id = {latest_change_id}` or change-id = \"ignore\" instead" )); if io::stdout().is_terminal() { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 96316d4d0fdb..bbb0fbfbb935 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -724,7 +724,11 @@ fn deserialize_change_id<'de, D: Deserializer<'de>>( Ok(match value { toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore), toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)), - _ => return Err(serde::de::Error::custom("expected \"ignore\" or an integer")), + _ => { + return Err(serde::de::Error::custom( + "expected \"ignore\" or an integer for change-id", + )); + } }) } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 78887a42a000..5314141dd1b0 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -393,6 +393,6 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ ChangeInfo { change_id: 138986, severity: ChangeSeverity::Info, - summary: "You can now use `change_id = \"ignore\"` to suppress `change_id` warnings in the console.", + summary: "You can now use `change-id = \"ignore\"` to suppress `change-id ` warnings in the console.", }, ]; From c83504faefcbb7c26426cbc20686b910bd58c8d2 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Fri, 21 Mar 2025 13:30:56 +0100 Subject: [PATCH 410/546] bootstrap: bump cc to 1.2.17 and cmake to 0.1.54 --- src/bootstrap/Cargo.lock | 8 ++++---- src/bootstrap/Cargo.toml | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 890e64e2babb..17ee4d610f95 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -88,9 +88,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.22" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "shlex", ] @@ -150,9 +150,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cmake" -version = "0.1.48" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index d3e2b9e05e99..23aa87a74075 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -32,10 +32,8 @@ test = false # Most of the time updating these dependencies requires modifications to the # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565); # otherwise, some targets will fail. That's why these dependencies are explicitly pinned. -# -# Do not upgrade this crate unless https://github.com/rust-lang/cc-rs/issues/1317 is fixed. -cc = "=1.1.22" -cmake = "=0.1.48" +cc = "=1.2.17" +cmake = "=0.1.54" build_helper = { path = "../build_helper" } clap = { version = "4.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } From 9cf05b893d33a4a83a145396ed76e41ea1da97f2 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 24 Mar 2025 13:08:25 +0100 Subject: [PATCH 411/546] bootstrap: Always set CMAKE_SYSTEM_NAME when cross-compiling To avoid a panic in cmake-rs that was introduced in: https://github.com/rust-lang/cmake-rs/pull/158 --- src/bootstrap/src/core/build_steps/llvm.rs | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 9ae1825fae89..0bc879c7d713 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -645,10 +645,17 @@ fn configure_cmake( if !builder.is_builder_target(target) { cfg.define("CMAKE_CROSSCOMPILING", "True"); + // NOTE: Ideally, we wouldn't have to do this, and `cmake-rs` would just handle it for us. + // But it currently determines this based on the `CARGO_CFG_TARGET_OS` environment variable, + // which isn't set when compiling outside `build.rs` (like bootstrap is). + // + // So for now, we define `CMAKE_SYSTEM_NAME` ourselves, to panicking in `cmake-rs`. if target.contains("netbsd") { cfg.define("CMAKE_SYSTEM_NAME", "NetBSD"); } else if target.contains("dragonfly") { cfg.define("CMAKE_SYSTEM_NAME", "DragonFly"); + } else if target.contains("openbsd") { + cfg.define("CMAKE_SYSTEM_NAME", "OpenBSD"); } else if target.contains("freebsd") { cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD"); } else if target.is_windows() { @@ -659,10 +666,27 @@ fn configure_cmake( cfg.define("CMAKE_SYSTEM_NAME", "SunOS"); } else if target.contains("linux") { cfg.define("CMAKE_SYSTEM_NAME", "Linux"); + } else if target.contains("darwin") { + // macOS + cfg.define("CMAKE_SYSTEM_NAME", "Darwin"); + } else if target.contains("ios") { + cfg.define("CMAKE_SYSTEM_NAME", "iOS"); + } else if target.contains("tvos") { + cfg.define("CMAKE_SYSTEM_NAME", "tvOS"); + } else if target.contains("visionos") { + cfg.define("CMAKE_SYSTEM_NAME", "visionOS"); + } else if target.contains("watchos") { + cfg.define("CMAKE_SYSTEM_NAME", "watchOS"); + } else if target.contains("none") { + // "none" should be the last branch + cfg.define("CMAKE_SYSTEM_NAME", "Generic"); } else { builder.info(&format!( "could not determine CMAKE_SYSTEM_NAME from the target `{target}`, build may fail", )); + // Fallback, set `CMAKE_SYSTEM_NAME` anyhow to avoid the logic `cmake-rs` tries, and + // to avoid CMAKE_SYSTEM_NAME being inferred from the host. + cfg.define("CMAKE_SYSTEM_NAME", "Generic"); } // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in From a9cb15d793495b6b6318c7a60c42d12ddcf1609a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 24 Mar 2025 11:05:41 +0100 Subject: [PATCH 412/546] bootstrap: Fix CMAKE_OSX_ARCHITECTURES on all Apple platforms --- src/bootstrap/src/core/build_steps/llvm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 0bc879c7d713..41d3ca2c4cd4 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -696,7 +696,7 @@ fn configure_cmake( // CMakeFiles (and then only in tests), and so far no issues have been // reported, the system version is currently left unset. - if target.contains("darwin") { + if target.contains("apple") { // Make sure that CMake does not build universal binaries on macOS. // Explicitly specify the one single target architecture. if target.starts_with("aarch64") { From e8704e899cc72e8a04e0235e2ad7c7375d0c0633 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 24 Mar 2025 22:42:23 +0100 Subject: [PATCH 413/546] bootstrap: Set CMAKE_SYSTEM_NAME=Darwin on Apple platforms compiler-rt's CMake setup seems to have special logic for Apple platforms that works poorly when this is not set. --- src/bootstrap/src/core/build_steps/llvm.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 41d3ca2c4cd4..de91b5d1eb5b 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -697,6 +697,14 @@ fn configure_cmake( // reported, the system version is currently left unset. if target.contains("apple") { + if !target.contains("darwin") { + // FIXME(madsmtm): compiler-rt's CMake setup is kinda weird, it seems like they do + // version testing etc. for macOS (i.e. Darwin), even while building for iOS? + // + // So for now we set it to "Darwin" on all Apple platforms. + cfg.define("CMAKE_SYSTEM_NAME", "Darwin"); + } + // Make sure that CMake does not build universal binaries on macOS. // Explicitly specify the one single target architecture. if target.starts_with("aarch64") { From 011eabd6909e7ba2d6b0fd812658e16d17a38961 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 24 Mar 2025 22:58:39 +0100 Subject: [PATCH 414/546] bootstrap: Override CMAKE_OSX_SYSROOT when building compiler-rt Similarly to what was previously done for the `llvm` step. --- src/bootstrap/src/core/build_steps/llvm.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index de91b5d1eb5b..e21804fa3c07 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -385,9 +385,6 @@ impl Step for Llvm { || target.contains("apple-watchos") || target.contains("apple-visionos") { - // These two defines prevent CMake from automatically trying to add a MacOSX sysroot, which leads to a compiler error. - cfg.define("CMAKE_OSX_SYSROOT", "/"); - cfg.define("CMAKE_OSX_DEPLOYMENT_TARGET", ""); // Prevent cmake from adding -bundle to CFLAGS automatically, which leads to a compiler error because "-bitcode_bundle" also gets added. cfg.define("LLVM_ENABLE_PLUGINS", "OFF"); // Zlib fails to link properly, leading to a compiler error. @@ -703,6 +700,10 @@ fn configure_cmake( // // So for now we set it to "Darwin" on all Apple platforms. cfg.define("CMAKE_SYSTEM_NAME", "Darwin"); + + // These two defines prevent CMake from automatically trying to add a MacOSX sysroot, which leads to a compiler error. + cfg.define("CMAKE_OSX_SYSROOT", "/"); + cfg.define("CMAKE_OSX_DEPLOYMENT_TARGET", ""); } // Make sure that CMake does not build universal binaries on macOS. From 7a6a3241ca18147c86926bb388aad54c4e3eadc5 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Tue, 25 Mar 2025 11:03:06 +0100 Subject: [PATCH 415/546] bootstrap: Update download-ci-llvm-stamp This PR makes a fairly large version update to CMake and cc, so it is likely that LLVM is built differently. --- src/bootstrap/download-ci-llvm-stamp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index d2c0d380fb40..e157ff233bbf 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/134740 +Last change is for: https://github.com/rust-lang/rust/pull/138784 From d5f7e71d5c861c513fda67bd35382ac03049e177 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 28 Mar 2025 10:11:45 +0300 Subject: [PATCH 416/546] bootstrap: update `test_find` test `cc::Build::get_archiver` is noisy on the `arm-linux-androideabi` target and constantly printing `llvm-ar --version` output during bootstrap tests on all platforms. Signed-off-by: onur-ozkan --- src/bootstrap/src/utils/cc_detect/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index c97529cbe9eb..b4a1b52dd230 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -264,7 +264,7 @@ fn test_find_target_without_config() { fn test_find() { let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu"); - let target2 = TargetSelection::from_user("arm-linux-androideabi"); + let target2 = TargetSelection::from_user("x86_64-unknown-openbsd"); build.targets.push(target1.clone()); build.hosts.push(target2.clone()); find(&build); From 3a9a5770ef44401315e8c99b13b81b4c595fc82e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 28 Mar 2025 08:15:18 +0100 Subject: [PATCH 417/546] Remove ScopeDepth entirely. The scope depth was tracked, but never actually used for anything. --- .../rustc_hir_analysis/src/check/region.rs | 38 +++++++------------ compiler/rustc_middle/src/middle/region.rs | 8 ++-- compiler/rustc_middle/src/ty/rvalue_scopes.rs | 2 +- 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index ba8124b11fc1..9d99a3ea6739 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -23,18 +23,11 @@ use tracing::debug; #[derive(Debug, Copy, Clone)] struct Context { - /// The scope that contains any new variables declared, plus its depth in - /// the scope tree. + /// The scope that contains any new variables declared. var_parent: Option, - /// Region parent of expressions, etc., plus its depth in the scope tree. - parent: Option<(Scope, ScopeDepth)>, -} - -impl Context { - fn set_var_parent(&mut self) { - self.var_parent = self.parent.map(|(p, _)| p); - } + /// Region parent of expressions, etc. + parent: Option, } struct ScopeResolutionVisitor<'tcx> { @@ -119,7 +112,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi // itself has returned. visitor.enter_node_scope_with_dtor(blk.hir_id.local_id); - visitor.cx.set_var_parent(); + visitor.cx.var_parent = visitor.cx.parent; { // This block should be kept approximately in sync with @@ -138,7 +131,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi local_id: blk.hir_id.local_id, data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); - visitor.cx.set_var_parent(); + visitor.cx.var_parent = visitor.cx.parent; visitor.visit_stmt(statement); // We need to back out temporarily to the last enclosing scope // for the `else` block, so that even the temporaries receiving @@ -163,7 +156,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi local_id: blk.hir_id.local_id, data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); - visitor.cx.set_var_parent(); + visitor.cx.var_parent = visitor.cx.parent; visitor.visit_stmt(statement) } hir::StmtKind::Item(..) => { @@ -213,7 +206,7 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir: visitor.terminating_scopes.insert(arm.hir_id.local_id); visitor.enter_node_scope_with_dtor(arm.hir_id.local_id); - visitor.cx.set_var_parent(); + visitor.cx.var_parent = visitor.cx.parent; if let Some(expr) = arm.guard && !has_let_expr(expr) @@ -490,7 +483,7 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi ScopeData::IfThen }; visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); - visitor.cx.set_var_parent(); + visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); visitor.visit_expr(then); visitor.cx = expr_cx; @@ -505,7 +498,7 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi ScopeData::IfThen }; visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); - visitor.cx.set_var_parent(); + visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); visitor.visit_expr(then); visitor.cx = expr_cx; @@ -545,7 +538,7 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi // Keep traversing up while we can. match visitor.scope_tree.parent_map.get(&scope) { // Don't cross from closure bodies to their parent. - Some(&(superscope, _)) => match superscope.data { + Some(&superscope) => match superscope.data { ScopeData::CallSite => break, _ => scope = superscope, }, @@ -782,19 +775,16 @@ fn resolve_local<'tcx>( impl<'tcx> ScopeResolutionVisitor<'tcx> { /// Records the current parent (if any) as the parent of `child_scope`. /// Returns the depth of `child_scope`. - fn record_child_scope(&mut self, child_scope: Scope) -> ScopeDepth { + fn record_child_scope(&mut self, child_scope: Scope) { let parent = self.cx.parent; self.scope_tree.record_scope_parent(child_scope, parent); - // If `child_scope` has no parent, it must be the root node, and so has - // a depth of 1. Otherwise, its depth is one more than its parent's. - parent.map_or(1, |(_p, d)| d + 1) } /// Records the current parent (if any) as the parent of `child_scope`, /// and sets `child_scope` as the new current parent. fn enter_scope(&mut self, child_scope: Scope) { - let child_depth = self.record_child_scope(child_scope); - self.cx.parent = Some((child_scope, child_depth)); + self.record_child_scope(child_scope); + self.cx.parent = Some(child_scope); } fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) { @@ -855,7 +845,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { self.enter_body(body.value.hir_id, |this| { if this.tcx.hir_body_owner_kind(owner_id).is_fn_or_closure() { // The arguments and `self` are parented to the fn. - this.cx.set_var_parent(); + this.cx.var_parent = this.cx.parent; for param in body.params { this.visit_pat(param.pat); } diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 66ece8f0e52f..ba31f775b651 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -199,8 +199,6 @@ impl Scope { } } -pub type ScopeDepth = u32; - /// The region scope tree encodes information about region relationships. #[derive(Default, Debug, HashStable)] pub struct ScopeTree { @@ -213,7 +211,7 @@ pub struct ScopeTree { /// conditional expression or repeating block. (Note that the /// enclosing scope ID for the block associated with a closure is /// the closure itself.) - pub parent_map: FxIndexMap, + pub parent_map: FxIndexMap, /// Maps from a variable or binding ID to the block in which that /// variable is declared. @@ -328,7 +326,7 @@ pub struct YieldData { } impl ScopeTree { - pub fn record_scope_parent(&mut self, child: Scope, parent: Option<(Scope, ScopeDepth)>) { + pub fn record_scope_parent(&mut self, child: Scope, parent: Option) { debug!("{:?}.parent = {:?}", child, parent); if let Some(p) = parent { @@ -353,7 +351,7 @@ impl ScopeTree { /// Returns the narrowest scope that encloses `id`, if any. pub fn opt_encl_scope(&self, id: Scope) -> Option { - self.parent_map.get(&id).cloned().map(|(p, _)| p) + self.parent_map.get(&id).cloned() } /// Returns the lifetime of the local variable `var_id`, if any. diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index b00c8169a36a..9bf6e3a75900 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -38,7 +38,7 @@ impl RvalueScopes { let mut id = Scope { local_id: expr_id, data: ScopeData::Node }; let mut backwards_incompatible = None; - while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) { + while let Some(&p) = region_scope_tree.parent_map.get(&id) { match p.data { ScopeData::Destruction => { debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]"); From deeac1c588d3487202490280ee64434ad3c45f0c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 28 Mar 2025 08:36:16 +0100 Subject: [PATCH 418/546] Remove outdated comment. --- compiler/rustc_hir_analysis/src/check/region.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 9d99a3ea6739..2528adb937b3 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -774,7 +774,6 @@ fn resolve_local<'tcx>( impl<'tcx> ScopeResolutionVisitor<'tcx> { /// Records the current parent (if any) as the parent of `child_scope`. - /// Returns the depth of `child_scope`. fn record_child_scope(&mut self, child_scope: Scope) { let parent = self.cx.parent; self.scope_tree.record_scope_parent(child_scope, parent); From c41476034d49813d574af3877f6995e14b10729d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 28 Mar 2025 10:16:03 +0100 Subject: [PATCH 419/546] Put pin!() tests in the right file. --- library/coretests/tests/pin.rs | 14 -------------- library/coretests/tests/pin_macro.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs index a866cf12a3bb..b3fb06e710d4 100644 --- a/library/coretests/tests/pin.rs +++ b/library/coretests/tests/pin.rs @@ -34,9 +34,6 @@ fn pin_const() { } pin_mut_const(); - - // Check that we accept a Rust 2024 $expr. - std::pin::pin!(const { 1 }); } #[allow(unused)] @@ -84,14 +81,3 @@ mod pin_coerce_unsized { arg } } - -#[test] -#[cfg(not(bootstrap))] -fn temp_lifetime() { - // Check that temporary lifetimes work as in Rust 2021. - // Regression test for https://github.com/rust-lang/rust/issues/138596 - match std::pin::pin!(foo(&mut 0)) { - _ => {} - } - async fn foo(_: &mut usize) {} -} diff --git a/library/coretests/tests/pin_macro.rs b/library/coretests/tests/pin_macro.rs index 43542397a613..639eab740c0b 100644 --- a/library/coretests/tests/pin_macro.rs +++ b/library/coretests/tests/pin_macro.rs @@ -30,3 +30,20 @@ fn unsize_coercion() { let dyn_obj: Pin<&mut dyn Send> = pin!([PhantomPinned; 2]); stuff(dyn_obj); } + +#[test] +fn rust_2024_expr() { + // Check that we accept a Rust 2024 $expr. + std::pin::pin!(const { 1 }); +} + +#[test] +#[cfg(not(bootstrap))] +fn temp_lifetime() { + // Check that temporary lifetimes work as in Rust 2021. + // Regression test for https://github.com/rust-lang/rust/issues/138596 + match std::pin::pin!(foo(&mut 0)) { + _ => {} + } + async fn foo(_: &mut usize) {} +} From a5fa12b6b908894f59a788641c4b14839e556c5f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 14 Mar 2025 15:56:33 +0000 Subject: [PATCH 420/546] Avoid wrapping constant allocations in packed structs when not necessary This way LLVM will set the string merging flag if the alloc is a nul terminated string, reducing binary sizes. --- compiler/rustc_codegen_gcc/src/consts.rs | 1 + compiler/rustc_codegen_llvm/src/consts.rs | 2 +- tests/codegen/const-array.rs | 4 +-- tests/codegen/debug-vtable.rs | 2 +- tests/codegen/external-no-mangle-statics.rs | 32 ++++++++++----------- tests/codegen/link_section.rs | 2 +- tests/codegen/remap_path_prefix/main.rs | 2 +- tests/codegen/uninit-consts.rs | 6 ++-- 8 files changed, 26 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index c514b7a428bc..474475f311f7 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -364,6 +364,7 @@ pub fn const_alloc_to_gcc<'gcc>( llvals.push(cx.const_bytes(bytes)); } + // FIXME(bjorn3) avoid wrapping in a struct when there is only a single element. cx.const_struct(&llvals, true) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index a4e5749b3acb..a1ab6714d370 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -128,7 +128,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>( append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, range); } - cx.const_struct(&llvals, true) + if let &[data] = &*llvals { data } else { cx.const_struct(&llvals, true) } } fn codegen_static_initializer<'ll, 'tcx>( diff --git a/tests/codegen/const-array.rs b/tests/codegen/const-array.rs index e257d8acc088..b3df76c3d8e0 100644 --- a/tests/codegen/const-array.rs +++ b/tests/codegen/const-array.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -const LUT: [u8; 2] = [1, 1]; +const LUT: [u8; 4] = [1, 1, 1, 1]; // CHECK-LABEL: @decode #[no_mangle] @@ -11,5 +11,5 @@ pub fn decode(i: u8) -> u8 { // CHECK-NEXT: icmp // CHECK-NEXT: select // CHECK-NEXT: ret - if i < 2 { LUT[i as usize] } else { 2 } + if i < 4 { LUT[i as usize] } else { 2 } } diff --git a/tests/codegen/debug-vtable.rs b/tests/codegen/debug-vtable.rs index b9808e4079bc..8a7b1cc3c4bc 100644 --- a/tests/codegen/debug-vtable.rs +++ b/tests/codegen/debug-vtable.rs @@ -15,7 +15,7 @@ // Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled. // This helps debuggers more reliably map from dyn pointer to concrete type. -// CHECK: @vtable.2 = private constant <{ +// CHECK: @vtable.2 = private constant [ // CHECK: @vtable.3 = private constant <{ // CHECK: @vtable.4 = private constant <{ diff --git a/tests/codegen/external-no-mangle-statics.rs b/tests/codegen/external-no-mangle-statics.rs index dc4eca8c7b48..49f42ee977d5 100644 --- a/tests/codegen/external-no-mangle-statics.rs +++ b/tests/codegen/external-no-mangle-statics.rs @@ -6,72 +6,72 @@ // `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their // definitions -// CHECK: @A = {{(dso_local )?}}local_unnamed_addr constant +// CHECK-DAG: @A = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] static A: u8 = 0; -// CHECK: @B = {{(dso_local )?}}local_unnamed_addr global +// CHECK-DAG: @B = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] static mut B: u8 = 0; -// CHECK: @C = {{(dso_local )?}}local_unnamed_addr constant +// CHECK-DAG: @C = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] pub static C: u8 = 0; -// CHECK: @D = {{(dso_local )?}}local_unnamed_addr global +// CHECK-DAG: @D = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] pub static mut D: u8 = 0; mod private { - // CHECK: @E = {{(dso_local )?}}local_unnamed_addr constant + // CHECK-DAG: @E = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] static E: u8 = 0; - // CHECK: @F = {{(dso_local )?}}local_unnamed_addr global + // CHECK-DAG: @F = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] static mut F: u8 = 0; - // CHECK: @G = {{(dso_local )?}}local_unnamed_addr constant + // CHECK-DAG: @G = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] pub static G: u8 = 0; - // CHECK: @H = {{(dso_local )?}}local_unnamed_addr global + // CHECK-DAG: @H = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] pub static mut H: u8 = 0; } const HIDDEN: () = { - // CHECK: @I = {{(dso_local )?}}local_unnamed_addr constant + // CHECK-DAG: @I = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] static I: u8 = 0; - // CHECK: @J = {{(dso_local )?}}local_unnamed_addr global + // CHECK-DAG: @J = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] static mut J: u8 = 0; - // CHECK: @K = {{(dso_local )?}}local_unnamed_addr constant + // CHECK-DAG: @K = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] pub static K: u8 = 0; - // CHECK: @L = {{(dso_local )?}}local_unnamed_addr global + // CHECK-DAG: @L = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] pub static mut L: u8 = 0; }; fn x() { - // CHECK: @M = {{(dso_local )?}}local_unnamed_addr constant + // CHECK-DAG: @M = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] static M: fn() = x; - // CHECK: @N = {{(dso_local )?}}local_unnamed_addr global + // CHECK-DAG: @N = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] static mut N: u8 = 0; - // CHECK: @O = {{(dso_local )?}}local_unnamed_addr constant + // CHECK-DAG: @O = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] pub static O: u8 = 0; - // CHECK: @P = {{(dso_local )?}}local_unnamed_addr global + // CHECK-DAG: @P = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] pub static mut P: u8 = 0; } diff --git a/tests/codegen/link_section.rs b/tests/codegen/link_section.rs index 196f5edb7d63..f62f69480793 100644 --- a/tests/codegen/link_section.rs +++ b/tests/codegen/link_section.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = {{(dso_local )?}}constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" +// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section ".test_one" #[no_mangle] #[link_section = ".test_one"] #[cfg(target_endian = "little")] diff --git a/tests/codegen/remap_path_prefix/main.rs b/tests/codegen/remap_path_prefix/main.rs index bfbccfe0df80..7d17b3b67cfa 100644 --- a/tests/codegen/remap_path_prefix/main.rs +++ b/tests/codegen/remap_path_prefix/main.rs @@ -12,7 +12,7 @@ mod aux_mod; include!("aux_mod.rs"); // Here we check that the expansion of the file!() macro is mapped. -// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }> +// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant [34 x i8] c"/the/src/remap_path_prefix/main.rs" pub static FILE_PATH: &'static str = file!(); fn main() { diff --git a/tests/codegen/uninit-consts.rs b/tests/codegen/uninit-consts.rs index a58008e171e2..bde71a35c47d 100644 --- a/tests/codegen/uninit-consts.rs +++ b/tests/codegen/uninit-consts.rs @@ -11,15 +11,15 @@ pub struct PartiallyUninit { y: MaybeUninit<[u8; 10]>, } -// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant <{ [10 x i8] }> undef +// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant [10 x i8] undef // CHECK: [[PARTIALLY_UNINIT:@.*]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"{{\\EF\\BE\\AD\\DE|\\DE\\AD\\BE\\EF}}", [12 x i8] undef }>, align 4 // This shouldn't contain undef, since it contains more chunks // than the default value of uninit_const_chunk_threshold. -// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant <{ [32768 x i8] }> <{ [32768 x i8] c"{{.+}}" }>, align 4 +// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant [32768 x i8] c"{{.+}}", align 4 -// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant <{ [16384 x i8] }> undef +// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant [16384 x i8] undef // CHECK-LABEL: @fully_uninit #[no_mangle] From 5c82a59bd30815a942b64fa09e22dbe442edf56d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:57:42 +0000 Subject: [PATCH 421/546] Add test and comment --- compiler/rustc_codegen_llvm/src/consts.rs | 5 +++++ tests/assembly/cstring-merging.rs | 27 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/assembly/cstring-merging.rs diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index a1ab6714d370..75b4ff1b6bbf 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -128,6 +128,11 @@ pub(crate) fn const_alloc_to_llvm<'ll>( append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, range); } + // Avoid wrapping in a struct if there is only a single value. This ensures + // that LLVM is able to perform the string merging optimization if the constant + // is a valid C string. LLVM only considers bare arrays for this optimization, + // not arrays wrapped in a struct. LLVM handles this at: + // https://github.com/rust-lang/llvm-project/blob/acaea3d2bb8f351b740db7ebce7d7a40b9e21488/llvm/lib/Target/TargetLoweringObjectFile.cpp#L249-L280 if let &[data] = &*llvals { data } else { cx.const_struct(&llvals, true) } } diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs new file mode 100644 index 000000000000..7436e2418230 --- /dev/null +++ b/tests/assembly/cstring-merging.rs @@ -0,0 +1,27 @@ +//@ only-linux +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 --edition 2024 + +use std::ffi::CStr; + +// CHECK: .section .rodata.str1.1,"aMS" +// CHECK: .Lanon.{{.+}}: +// CHECK-NEXT: .asciz "foo" +#[unsafe(no_mangle)] +static CSTR: &[u8; 4] = b"foo\0"; + +// CHECK-NOT: .section +// CHECK: .Lanon.{{.+}}: +// CHECK-NEXT: .asciz "bar" +#[unsafe(no_mangle)] +pub fn cstr() -> &'static CStr { + c"bar" +} + +// CHECK-NOT: .section +// CHECK: .Lanon.{{.+}}: +// CHECK-NEXT: .asciz "baz" +#[unsafe(no_mangle)] +pub fn manual_cstr() -> &'static str { + "baz\0" +} From 87d524bef68b6a63f965cec81e0ce28e00843907 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Mar 2025 10:35:53 +0100 Subject: [PATCH 422/546] Update `coverage-run-rustdoc` output --- tests/coverage-run-rustdoc/doctest.coverage | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/coverage-run-rustdoc/doctest.coverage b/tests/coverage-run-rustdoc/doctest.coverage index f007eb0cadea..0fa94361c472 100644 --- a/tests/coverage-run-rustdoc/doctest.coverage +++ b/tests/coverage-run-rustdoc/doctest.coverage @@ -58,21 +58,21 @@ $DIR/doctest.rs: LL| |//! LL| |//! doctest with custom main: LL| |//! ``` - LL| 1|//! fn some_func() { - LL| 1|//! println!("called some_func()"); - LL| 1|//! } - LL| |//! - LL| |//! #[derive(Debug)] - LL| |//! struct SomeError; + LL| |//! fn some_func() { + LL| |//! println!("called some_func()"); + LL| |//! } + LL| 1|//! + LL| 1|//! #[derive(Debug)] + LL| 1|//! struct SomeError; LL| |//! LL| |//! extern crate doctest_crate; LL| |//! - LL| 1|//! fn doctest_main() -> Result<(), SomeError> { + LL| |//! fn doctest_main() -> Result<(), SomeError> { LL| 1|//! some_func(); LL| 1|//! doctest_crate::fn_run_in_doctests(2); LL| 1|//! Ok(()) LL| 1|//! } - LL| |//! + LL| 1|//! LL| |//! // this `main` is not shown as covered, as it clashes with all the other LL| |//! // `main` functions that were automatically generated for doctests LL| |//! fn main() -> Result<(), SomeError> { From 827cb1b2a7b4334b38b20c291a95de62894c335c Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Fri, 28 Mar 2025 12:14:09 +0000 Subject: [PATCH 423/546] use `try_fold` instead of `fold` --- compiler/stable_mir/src/mir/body.rs | 3 +-- compiler/stable_mir/src/mir/visit.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index b1bf7bce828c..2a1c163de3c4 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1057,8 +1057,7 @@ impl Place { /// In order to retrieve the correct type, the `locals` argument must match the list of all /// locals from the function body where this place originates from. pub fn ty(&self, locals: &[LocalDecl]) -> Result { - let start_ty = locals[self.local].ty; - self.projection.iter().fold(Ok(start_ty), |place_ty, elem| elem.ty(place_ty?)) + self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty)) } } diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 09447e70dfb1..9d2368ba3320 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -563,7 +563,7 @@ pub struct PlaceRef<'a> { impl PlaceRef<'_> { /// Get the type of this place. pub fn ty(&self, locals: &[LocalDecl]) -> Result { - self.projection.iter().fold(Ok(locals[self.local].ty), |place_ty, elem| elem.ty(place_ty?)) + self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty)) } } From 9ef35ddc0ca236db91d444a31de5fc8ac835ce9b Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Fri, 28 Mar 2025 12:21:21 +0000 Subject: [PATCH 424/546] use `slice::contains` where applicable --- compiler/rustc_builtin_macros/src/edition_panic.rs | 10 +++++----- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- compiler/rustc_mir_build/src/builder/scope.rs | 2 +- compiler/rustc_passes/src/entry.rs | 2 +- compiler/rustc_session/src/utils.rs | 11 ++++++----- compiler/rustc_span/src/lib.rs | 2 +- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index b39c9861fd64..ccfcc3079ebf 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -74,11 +74,11 @@ pub(crate) fn use_panic_2021(mut span: Span) -> bool { // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.) loop { let expn = span.ctxt().outer_expn_data(); - if let Some(features) = expn.allow_internal_unstable { - if features.iter().any(|&f| f == sym::edition_panic) { - span = expn.call_site; - continue; - } + if let Some(features) = expn.allow_internal_unstable + && features.contains(&sym::edition_panic) + { + span = expn.call_site; + continue; } break expn.edition >= Edition::Edition2021; } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 216a18e72edf..ccc0273280fe 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -2186,7 +2186,7 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { // indirectly from ThinLTO. In theory these are not needed as ThinLTO could resolve // these, but it currently does not do so. let can_have_static_objects = - tcx.sess.lto() == Lto::Thin || tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib); + tcx.sess.lto() == Lto::Thin || tcx.crate_types().contains(&CrateType::Rlib); tcx.sess.target.is_like_windows && can_have_static_objects && diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d16d4ed22838..a85d032f36ee 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -604,7 +604,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let Some((name, _)) = lang_items::extract(attrs) && let Some(lang_item) = LangItem::from_name(name) { - if WEAK_LANG_ITEMS.iter().any(|&l| l == lang_item) { + if WEAK_LANG_ITEMS.contains(&lang_item) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } if let Some(link_name) = lang_item.link_name() { diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index e56c0ae92cac..e42336a1dbbc 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1496,7 +1496,7 @@ fn build_scope_drops<'tcx>( // path, then don't generate the drop. (We only take this into // account for non-unwind paths so as not to disturb the // caching mechanism.) - if scope.moved_locals.iter().any(|&o| o == local) { + if scope.moved_locals.contains(&local) { continue; } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index d2729876ebbb..2a435c4b2e05 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -24,7 +24,7 @@ struct EntryContext<'tcx> { } fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { - let any_exe = tcx.crate_types().iter().any(|ty| *ty == CrateType::Executable); + let any_exe = tcx.crate_types().contains(&CrateType::Executable); if !any_exe { // No need to find a main function. return None; diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index fcede379b893..2243e831b66e 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -149,14 +149,15 @@ pub fn extra_compiler_flags() -> Option<(Vec, bool)> { arg[a.len()..].to_string() }; let option = content.split_once('=').map(|s| s.0).unwrap_or(&content); - if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) { + if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&option) { excluded_cargo_defaults = true; } else { result.push(a.to_string()); - match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) { - Some(s) => result.push(format!("{s}=[REDACTED]")), - None => result.push(content), - } + result.push(if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&option) { + format!("{option}=[REDACTED]") + } else { + content + }); } } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f19d4d9f3624..9e6ba2e1b9ce 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -876,7 +876,7 @@ impl Span { self.ctxt() .outer_expn_data() .allow_internal_unstable - .is_some_and(|features| features.iter().any(|&f| f == feature)) + .is_some_and(|features| features.contains(&feature)) } /// Checks if this span arises from a compiler desugaring of kind `kind`. From 0f418520c649f6bd0e731b4315a7c79b40df8e0e Mon Sep 17 00:00:00 2001 From: Rafael Bachmann Date: Fri, 28 Mar 2025 13:22:09 +0100 Subject: [PATCH 425/546] Fix formatting nit in process.rs --- library/std/src/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index f81ce8e1a1a1..3b765a9537bc 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1836,7 +1836,7 @@ impl crate::sealed::Sealed for ExitStatusError {} /// # if cfg!(unix) { /// use std::process::{Command, ExitStatusError}; /// -/// fn run(cmd: &str) -> Result<(),ExitStatusError> { +/// fn run(cmd: &str) -> Result<(), ExitStatusError> { /// Command::new(cmd).status().unwrap().exit_ok()?; /// Ok(()) /// } From 074edbd89c0c116f10918e0bf07a5227b3922a33 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 28 Mar 2025 19:48:40 +0800 Subject: [PATCH 426/546] std: Explain range follows standard half-open range in `offset` Signed-off-by: xizheyin --- library/core/src/ptr/const_ptr.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 7d0839aff3f7..71a84aff2460 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -386,7 +386,8 @@ impl *const T { /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in /// bounds of that allocated object. In particular, this range must not "wrap around" the edge - /// of the address space. + /// of the address space. Note that "range" here refers to a half-open range as usual in Rust, + /// i.e., `self..result` for non-negative offsets and `result..self` for negative offsets. /// /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. From 9055765ce1c89b0bc619df39aa8ba66ad641da9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Fri, 28 Mar 2025 15:58:41 +0100 Subject: [PATCH 427/546] `io::Take`: avoid new `BorrowedBuf` creation in some case --- library/std/src/io/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 6579b6887aaa..314cbb45d49e 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2989,11 +2989,11 @@ impl Read for Take { return Ok(()); } - if self.limit <= buf.capacity() as u64 { - // if we just use an as cast to convert, limit may wrap around on a 32 bit target - let limit = cmp::min(self.limit, usize::MAX as u64) as usize; + if self.limit < buf.capacity() as u64 { + // The condition above guarantees that `self.limit` fits in `usize`. + let limit = self.limit as usize; - let extra_init = cmp::min(limit as usize, buf.init_ref().len()); + let extra_init = cmp::min(limit, buf.init_ref().len()); // SAFETY: no uninit data is written to ibuf let ibuf = unsafe { &mut buf.as_mut()[..limit] }; From 9300fa19b73e569d7c38f51149d9537a6ef0a232 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 28 Mar 2025 16:53:17 +0000 Subject: [PATCH 428/546] Bump to 1.88.0 --- src/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version b/src/version index f6342716723f..59be592144c2 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.87.0 +1.88.0 From dabee5d5635fd9f5093031df19cacf805292528c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 28 Mar 2025 17:01:23 +0000 Subject: [PATCH 429/546] Do not treat lifetimes from parent items as influencing child items --- compiler/rustc_resolve/src/late.rs | 5 ++++- .../static-default-lifetime/static-trait-impl.rs | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 533e216ddb29..0d23ae501f04 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1833,7 +1833,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } LifetimeRibKind::StaticIfNoLifetimeInScope { lint_id: node_id, emit_lint } => { let mut lifetimes_in_scope = vec![]; - for rib in &self.lifetime_ribs[..i] { + for rib in self.lifetime_ribs[..i].iter().rev() { lifetimes_in_scope.extend(rib.bindings.iter().map(|(ident, _)| ident.span)); // Consider any anonymous lifetimes, too if let LifetimeRibKind::AnonymousCreateParameter { binder, .. } = rib.kind @@ -1841,6 +1841,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { { lifetimes_in_scope.extend(extra.iter().map(|(ident, _, _)| ident.span)); } + if let LifetimeRibKind::Item = rib.kind { + break; + } } if lifetimes_in_scope.is_empty() { self.record_lifetime_res( diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.rs b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs index b50bf01453dc..1e12259e4833 100644 --- a/tests/ui/consts/static-default-lifetime/static-trait-impl.rs +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs @@ -17,4 +17,17 @@ impl Bar<'static> for B { const STATIC: &str = ""; } +struct C; +impl Bar<'_> for C { + // make ^^ not cause + const STATIC: &'static str = { + struct B; + impl Bar<'static> for B { + const STATIC: &str = ""; + // ^ to emit a future incompat warning + } + "" + }; +} + fn main() {} From 7a295d1be07d191527dfcdf4613ced7ab6fa9676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 28 Mar 2025 15:14:35 +0100 Subject: [PATCH 430/546] Fix TAIT & ATPIT feature gating in the presence of anon consts --- compiler/rustc_ast_passes/src/feature_gate.rs | 7 ++ .../feature-gate-impl_trait_in_assoc_type.rs | 9 ++ ...ature-gate-impl_trait_in_assoc_type.stderr | 20 +++- .../feature-gate-type_alias_impl_trait.rs | 26 ++-- .../feature-gate-type_alias_impl_trait.stderr | 111 ++++++++++++++++++ tests/ui/impl-trait/impl_trait_projections.rs | 5 + .../impl-trait/impl_trait_projections.stderr | 10 +- .../inside-item-nested-in-anon-const.rs | 25 ++++ 8 files changed, 200 insertions(+), 13 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr create mode 100644 tests/ui/impl-trait/inside-item-nested-in-anon-const.rs diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 31ff102c127a..a3fcc110a166 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -99,6 +99,13 @@ impl<'a> PostExpansionVisitor<'a> { } visit::walk_ty(self, ty); } + + fn visit_anon_const(&mut self, _: &ast::AnonConst) -> Self::Result { + // We don't walk the anon const because it crosses a conceptual boundary: We're no + // longer "inside" the original type. + // Brittle: We assume that the callers of `check_impl_trait` will later recurse into + // the items found in the AnonConst to look for nested TyAliases. + } } ImplTraitVisitor { vis: self, in_associated_ty }.visit_ty(ty); } diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs index 2c130664e9a1..f9b5176d78ac 100644 --- a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs @@ -17,4 +17,13 @@ impl Mop { //~| ERROR: unconstrained opaque type } +fn funky(_: [(); { + impl Foo for fn() { + type Bar = impl Sized; + //~^ ERROR: `impl Trait` in associated types is unstable + //~| ERROR: unconstrained opaque type + } + 0 +}]) {} + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr index 7dfd79c72864..01d25c162281 100644 --- a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr @@ -18,6 +18,16 @@ LL | type Bop = impl std::fmt::Debug; = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: `impl Trait` in associated types is unstable + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:22:20 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: inherent associated types are unstable --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:5 | @@ -44,6 +54,14 @@ LL | type Bop = impl std::fmt::Debug; | = note: `Bop` must be used in combination with a concrete type within the same impl -error: aborting due to 5 previous errors +error: unconstrained opaque type + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:22:20 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + | + = note: `Bar` must be used in combination with a concrete type within the same impl + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs b/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs index ec70a20844a5..d332fba0623c 100644 --- a/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs +++ b/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs @@ -1,38 +1,42 @@ -//@ check-pass -#![feature(type_alias_impl_trait)] use std::fmt::Debug; -type Foo = impl Debug; +type Foo = impl Debug; //~ ERROR `impl Trait` in type aliases is unstable struct Bar(Foo); -#[define_opaque(Foo)] +#[define_opaque(Foo)] //~ ERROR use of unstable library feature `type_alias_impl_trait` fn define() -> Bar { Bar(42) } -type Foo2 = impl Debug; +type Foo2 = impl Debug; //~ ERROR `impl Trait` in type aliases is unstable -#[define_opaque(Foo2)] +#[define_opaque(Foo2)] //~ ERROR use of unstable library feature `type_alias_impl_trait` fn define2() { let x = || -> Foo2 { 42 }; } -type Foo3 = impl Debug; +type Foo3 = impl Debug; //~ ERROR `impl Trait` in type aliases is unstable -#[define_opaque(Foo3)] +#[define_opaque(Foo3)] //~ ERROR use of unstable library feature `type_alias_impl_trait` fn define3(x: Foo3) { let y: i32 = x; } -#[define_opaque(Foo3)] +#[define_opaque(Foo3)] //~ ERROR use of unstable library feature `type_alias_impl_trait` fn define3_1() { define3(42) } -type Foo4 = impl Debug; +type Foo4 = impl Debug; //~ ERROR `impl Trait` in type aliases is unstable -#[define_opaque(Foo4)] +#[define_opaque(Foo4)] //~ ERROR use of unstable library feature `type_alias_impl_trait` fn define4(_: Foo4) { let y: Foo4 = 42; } +type Foo5 = [(); { + type Foo = impl Debug; //~ ERROR `impl Trait` in type aliases is unstable + //~^ ERROR unconstrained opaque type + 0 +}]; + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr b/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr new file mode 100644 index 000000000000..bab60eb42930 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr @@ -0,0 +1,111 @@ +error[E0658]: use of unstable library feature `type_alias_impl_trait`: `type_alias_impl_trait` has open design concerns + --> $DIR/feature-gate-type_alias_impl_trait.rs:6:3 + | +LL | #[define_opaque(Foo)] + | ^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `type_alias_impl_trait`: `type_alias_impl_trait` has open design concerns + --> $DIR/feature-gate-type_alias_impl_trait.rs:13:3 + | +LL | #[define_opaque(Foo2)] + | ^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `type_alias_impl_trait`: `type_alias_impl_trait` has open design concerns + --> $DIR/feature-gate-type_alias_impl_trait.rs:20:3 + | +LL | #[define_opaque(Foo3)] + | ^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `type_alias_impl_trait`: `type_alias_impl_trait` has open design concerns + --> $DIR/feature-gate-type_alias_impl_trait.rs:24:3 + | +LL | #[define_opaque(Foo3)] + | ^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `type_alias_impl_trait`: `type_alias_impl_trait` has open design concerns + --> $DIR/feature-gate-type_alias_impl_trait.rs:31:3 + | +LL | #[define_opaque(Foo4)] + | ^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/feature-gate-type_alias_impl_trait.rs:3:12 + | +LL | type Foo = impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/feature-gate-type_alias_impl_trait.rs:11:13 + | +LL | type Foo2 = impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/feature-gate-type_alias_impl_trait.rs:18:13 + | +LL | type Foo3 = impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/feature-gate-type_alias_impl_trait.rs:29:13 + | +LL | type Foo4 = impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/feature-gate-type_alias_impl_trait.rs:37:16 + | +LL | type Foo = impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: unconstrained opaque type + --> $DIR/feature-gate-type_alias_impl_trait.rs:37:16 + | +LL | type Foo = impl Debug; + | ^^^^^^^^^^ + | + = note: `Foo` must be used in combination with a concrete type within the same crate + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs index 2c277aee06da..89fe3c1509cc 100644 --- a/tests/ui/impl-trait/impl_trait_projections.rs +++ b/tests/ui/impl-trait/impl_trait_projections.rs @@ -35,4 +35,9 @@ fn projection_from_impl_trait_inside_dyn_trait_is_disallowed() panic!() } +fn parametrized_value_in_anon_const_is_disallowed() -> [(); None::] { + //~^ ERROR `impl Trait` is not allowed in paths + loop {} +} + fn main() {} diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr index 5e0b80fcd592..21f45613938f 100644 --- a/tests/ui/impl-trait/impl_trait_projections.stderr +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -30,6 +30,14 @@ LL | -> as Iterator>::Item | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error: aborting due to 4 previous errors +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:38:68 + | +LL | fn parametrized_value_in_anon_const_is_disallowed() -> [(); None::] { + | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/inside-item-nested-in-anon-const.rs b/tests/ui/impl-trait/inside-item-nested-in-anon-const.rs new file mode 100644 index 000000000000..ab54d5f87bae --- /dev/null +++ b/tests/ui/impl-trait/inside-item-nested-in-anon-const.rs @@ -0,0 +1,25 @@ +// Ensure we don't misclassify `impl Trait` as TAIT/ATPIT if located inside an anon const in a +// type alias/assoc type. +// issue: +//@ check-pass +#![forbid(unstable_features)] + +struct Girder; + +type Alias = Girder<{ + fn pass(input: impl Sized) -> impl Sized { input } + 0 +}>; + +trait Trait { + type Assoc; +} + +impl Trait for () { + type Assoc = [(); { + fn pass(input: impl Sized) -> impl Sized { input } + 0 + }]; +} + +fn main() {} From e6a2c29bc4e935e6abda1f5348cf726590d302aa Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Fri, 28 Mar 2025 14:15:08 -0400 Subject: [PATCH 431/546] tracking autodiff files via triagebot.toml --- triagebot.toml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index ebbcfa4516b9..d7ec803d1cf1 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -254,6 +254,16 @@ trigger_files = [ "compiler/rustc_attr_data_structures", ] +[autolabel."F-autodiff"] +trigger_files = [ + "src/tools/enzyme", + "src/doc/unstable-book/src/compiler-flags/autodiff.md", + "compiler/rustc_ast/src/expand/autodiff_attrs.rs", + "compiler/rustc_monomorphize/src/partitioning/autodiff.rs", + "compiler/rustc_codegen_llvm/src/builder/autodiff.rs", + "compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs", +] + [autolabel."T-rustdoc-frontend"] trigger_labels = [ "A-rustdoc-search", @@ -1092,6 +1102,23 @@ cc = ["@jdonszelmann"] [mentions."compiler/rustc_attr_data_structures"] cc = ["@jdonszelmann"] +[mentions."src/tools/enzyme"] +cc = ["@ZuseZ4"] +[mentions."src/doc/unstable-book/src/compiler-flags/autodiff.md"] +cc = ["@ZuseZ4"] +[mentions."compiler/rustc_ast/src/expand/autodiff_attrs.rs"] +cc = ["@ZuseZ4"] +[mentions."compiler/rustc_ast/src/expand/typetree.rs"] +cc = ["@ZuseZ4"] +[mentions."compiler/rustc_builtin_macros/src/autodiff.rs"] +cc = ["@ZuseZ4"] +[mentions."compiler/rustc_monomorphize/src/partitioning/autodiff.rs"] +cc = ["@ZuseZ4"] +[mentions."compiler/rustc_codegen_llvm/src/builder/autodiff.rs"] +cc = ["@ZuseZ4"] +[mentions."compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs"] +cc = ["@ZuseZ4"] + [assign] warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" From dd4f616423219d81ffd34786d6a589b3ad7ba803 Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 28 Mar 2025 19:32:36 +0100 Subject: [PATCH 432/546] std: deduplicate `errno` accesses By marking `__errno_location` as `#[ffi_const]` and `std::sys::os::errno` as `#[inline]`, this PR allows merging multiple calls to `io::Error::last_os_error()` into one. --- library/std/src/lib.rs | 1 + library/std/src/sys/pal/unix/os.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ad005833ad53..9dcedaa13f66 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -297,6 +297,7 @@ #![feature(extended_varargs_abi_support)] #![feature(f128)] #![feature(f16)] +#![feature(ffi_const)] #![feature(formatting_options)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 30282fbf6554..f47421c67051 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -59,11 +59,14 @@ unsafe extern "C" { #[cfg_attr(any(target_os = "freebsd", target_vendor = "apple"), link_name = "__error")] #[cfg_attr(target_os = "haiku", link_name = "_errnop")] #[cfg_attr(target_os = "aix", link_name = "_Errno")] + // SAFETY: this will always return the same pointer on a given thread. + #[unsafe(ffi_const)] fn errno_location() -> *mut c_int; } /// Returns the platform-specific value of errno #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] +#[inline] pub fn errno() -> i32 { unsafe { (*errno_location()) as i32 } } @@ -72,16 +75,19 @@ pub fn errno() -> i32 { // needed for readdir and syscall! #[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))] #[allow(dead_code)] // but not all target cfgs actually end up using it +#[inline] pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } } #[cfg(target_os = "vxworks")] +#[inline] pub fn errno() -> i32 { unsafe { libc::errnoGet() } } #[cfg(target_os = "rtems")] +#[inline] pub fn errno() -> i32 { unsafe extern "C" { #[thread_local] @@ -92,6 +98,7 @@ pub fn errno() -> i32 { } #[cfg(target_os = "dragonfly")] +#[inline] pub fn errno() -> i32 { unsafe extern "C" { #[thread_local] @@ -103,6 +110,7 @@ pub fn errno() -> i32 { #[cfg(target_os = "dragonfly")] #[allow(dead_code)] +#[inline] pub fn set_errno(e: i32) { unsafe extern "C" { #[thread_local] From 7c74474d8d9fb2a714d86bae7a5099d27899e150 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 28 Mar 2025 16:32:28 +0300 Subject: [PATCH 433/546] hygiene: Rewrite `apply_mark_internal` to be more understandable --- compiler/rustc_span/src/hygiene.rs | 119 +++++++++--------- .../nonterminal-token-hygiene.stdout | 20 +-- 2 files changed, 70 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 4390085cd049..e7a8dee27f56 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -75,6 +75,21 @@ pub struct SyntaxContextData { } impl SyntaxContextData { + fn new( + (parent, outer_expn, outer_transparency): SyntaxContextKey, + opaque: SyntaxContext, + opaque_and_semitransparent: SyntaxContext, + ) -> SyntaxContextData { + SyntaxContextData { + outer_expn, + outer_transparency, + parent, + opaque, + opaque_and_semitransparent, + dollar_crate_name: kw::DollarCrate, + } + } + fn root() -> SyntaxContextData { SyntaxContextData { outer_expn: ExpnId::root(), @@ -543,7 +558,7 @@ impl HygieneData { ) -> SyntaxContext { assert_ne!(expn_id, ExpnId::root()); if transparency == Transparency::Opaque { - return self.apply_mark_internal(ctxt, expn_id, transparency); + return self.alloc_ctxt(ctxt, expn_id, transparency); } let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt(); @@ -554,7 +569,7 @@ impl HygieneData { }; if call_site_ctxt.is_root() { - return self.apply_mark_internal(ctxt, expn_id, transparency); + return self.alloc_ctxt(ctxt, expn_id, transparency); } // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a @@ -567,74 +582,60 @@ impl HygieneData { // // See the example at `test/ui/hygiene/legacy_interaction.rs`. for (expn_id, transparency) in self.marks(ctxt) { - call_site_ctxt = self.apply_mark_internal(call_site_ctxt, expn_id, transparency); + call_site_ctxt = self.alloc_ctxt(call_site_ctxt, expn_id, transparency); } - self.apply_mark_internal(call_site_ctxt, expn_id, transparency) + self.alloc_ctxt(call_site_ctxt, expn_id, transparency) } - fn apply_mark_internal( + /// Allocate a new context with the given key, or retrieve it from cache if the given key + /// already exists. The auxiliary fields are calculated from the key. + fn alloc_ctxt( &mut self, - ctxt: SyntaxContext, + parent: SyntaxContext, expn_id: ExpnId, transparency: Transparency, ) -> SyntaxContext { - let syntax_context_data = &mut self.syntax_context_data; - debug_assert!(!syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - let mut opaque = syntax_context_data[ctxt.0 as usize].opaque; - let mut opaque_and_semitransparent = - syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent; + debug_assert!(!self.syntax_context_data[parent.0 as usize].is_decode_placeholder()); - if transparency >= Transparency::Opaque { - let parent = opaque; - opaque = *self - .syntax_context_map - .entry((parent, expn_id, transparency)) - .or_insert_with(|| { - let new_opaque = SyntaxContext::from_usize(syntax_context_data.len()); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque: new_opaque, - opaque_and_semitransparent: new_opaque, - dollar_crate_name: kw::DollarCrate, - }); - new_opaque - }); + // Look into the cache first. + let key = (parent, expn_id, transparency); + if let Some(ctxt) = self.syntax_context_map.get(&key) { + return *ctxt; } - if transparency >= Transparency::SemiTransparent { - let parent = opaque_and_semitransparent; - opaque_and_semitransparent = *self - .syntax_context_map - .entry((parent, expn_id, transparency)) - .or_insert_with(|| { - let new_opaque_and_semitransparent = - SyntaxContext::from_usize(syntax_context_data.len()); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque, - opaque_and_semitransparent: new_opaque_and_semitransparent, - dollar_crate_name: kw::DollarCrate, - }); - new_opaque_and_semitransparent - }); - } + // Reserve a new syntax context. + let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len()); + self.syntax_context_data.push(SyntaxContextData::decode_placeholder()); + self.syntax_context_map.insert(key, ctxt); - let parent = ctxt; - *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| { - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque, - opaque_and_semitransparent, - dollar_crate_name: kw::DollarCrate, - }); - SyntaxContext::from_usize(syntax_context_data.len() - 1) - }) + // Opaque and semi-transparent versions of the parent. Note that they may be equal to the + // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques, + // and `parent_opaque_and_semitransparent` == `parent` if the expn contains only opaques + // and semi-transparents. + let parent_opaque = self.syntax_context_data[parent.0 as usize].opaque; + let parent_opaque_and_semitransparent = + self.syntax_context_data[parent.0 as usize].opaque_and_semitransparent; + + // Evaluate opaque and semi-transparent versions of the new syntax context. + let (opaque, opaque_and_semitransparent) = match transparency { + Transparency::Transparent => (parent_opaque, parent_opaque_and_semitransparent), + Transparency::SemiTransparent => ( + parent_opaque, + // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. + self.alloc_ctxt(parent_opaque_and_semitransparent, expn_id, transparency), + ), + Transparency::Opaque => ( + // Will be the same as `ctxt` if the expn chain contains only opaques. + self.alloc_ctxt(parent_opaque, expn_id, transparency), + // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. + self.alloc_ctxt(parent_opaque_and_semitransparent, expn_id, transparency), + ), + }; + + // Fill the full data, now that we have it. + self.syntax_context_data[ctxt.as_u32() as usize] = + SyntaxContextData::new(key, opaque, opaque_and_semitransparent); + ctxt } } diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index c80a33206fb4..6fd6cb474693 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -5,19 +5,19 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "struct", - span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#5), }, Ident { ident: "S", - span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#5), }, Punct { ch: ';', spacing: Alone, - span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#5), }, ], - span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#5), + span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#4), }, ] #![feature /* 0#0 */(prelude_import)] @@ -59,7 +59,7 @@ macro_rules! outer struct S /* 0#0 */; macro inner /* 0#3 */ { () => { print_bang! { struct S; } } } -struct S /* 0#4 */; +struct S /* 0#5 */; // OK, not a duplicate definition of `S` fn main /* 0#0 */() {} @@ -70,7 +70,7 @@ crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") -crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") @@ -83,9 +83,9 @@ SyntaxContexts: #1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) #2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) #3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) -#4: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) -#5: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) +#4: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) +#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) #6: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) -#7: parent: #5, outer_mark: (crate0::{{expn4}}, Transparent) -#8: parent: #4, outer_mark: (crate0::{{expn4}}, SemiTransparent) +#7: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent) +#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) */ From fbe5e555214c079d82985c40b44a3b992d695fab Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Thu, 27 Mar 2025 22:43:23 -0700 Subject: [PATCH 434/546] bootstrap: Avoid cloning change-id list --- src/bootstrap/src/bin/main.rs | 2 +- src/bootstrap/src/core/config/config.rs | 2 +- src/bootstrap/src/utils/change_tracker.rs | 22 +++++++++------------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 7ec3140c0386..cbfe00a757ce 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -191,7 +191,7 @@ fn check_version(config: &Config) -> Option { } msg.push_str("There have been changes to x.py since you last updated:\n"); - msg.push_str(&human_readable_changes(&changes)); + msg.push_str(&human_readable_changes(changes)); msg.push_str("NOTE: to silence this warning, "); msg.push_str(&format!( diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index bbb0fbfbb935..1712be7f947f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1381,7 +1381,7 @@ impl Config { if !changes.is_empty() { println!( "WARNING: There have been changes to x.py since you last updated:\n{}", - crate::human_readable_changes(&changes) + crate::human_readable_changes(changes) ); } } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 5314141dd1b0..244391739f38 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -35,29 +35,25 @@ impl Display for ChangeSeverity { } } -pub fn find_recent_config_change_ids(current_id: usize) -> Vec { - if !CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == current_id) { +pub fn find_recent_config_change_ids(current_id: usize) -> &'static [ChangeInfo] { + if let Some(index) = + CONFIG_CHANGE_HISTORY.iter().position(|config| config.change_id == current_id) + { + // Skip the current_id and IDs before it + &CONFIG_CHANGE_HISTORY[index + 1..] + } else { // If the current change-id is greater than the most recent one, return // an empty list (it may be due to switching from a recent branch to an // older one); otherwise, return the full list (assuming the user provided // the incorrect change-id by accident). if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id) { if current_id > config.change_id { - return Vec::new(); + return &[]; } } - return CONFIG_CHANGE_HISTORY.to_vec(); + CONFIG_CHANGE_HISTORY } - - let index = - CONFIG_CHANGE_HISTORY.iter().position(|config| config.change_id == current_id).unwrap(); - - CONFIG_CHANGE_HISTORY - .iter() - .skip(index + 1) // Skip the current_id and IDs before it - .cloned() - .collect() } pub fn human_readable_changes(changes: &[ChangeInfo]) -> String { From 122d7e1dcd921eafabd5c76d050d997876110e08 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 28 Mar 2025 15:24:49 +0100 Subject: [PATCH 435/546] Remove `terminating_scopes` hash set. --- .../rustc_hir_analysis/src/check/region.rs | 259 +++++++----------- 1 file changed, 95 insertions(+), 164 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 2528adb937b3..cf66ab708bb9 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -8,7 +8,6 @@ use std::mem; -use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -45,28 +44,6 @@ struct ScopeResolutionVisitor<'tcx> { scope_tree: ScopeTree, cx: Context, - - /// `terminating_scopes` is a set containing the ids of each - /// statement, or conditional/repeating expression. These scopes - /// are calling "terminating scopes" because, when attempting to - /// find the scope of a temporary, by default we search up the - /// enclosing scopes until we encounter the terminating scope. A - /// conditional/repeating expression is one which is not - /// guaranteed to execute exactly once upon entering the parent - /// scope. This could be because the expression only executes - /// conditionally, such as the expression `b` in `a && b`, or - /// because the expression may execute many times, such as a loop - /// body. The reason that we distinguish such expressions is that, - /// upon exiting the parent scope, we cannot statically know how - /// many times the expression executed, and thus if the expression - /// creates temporaries we cannot know statically how many such - /// temporaries we would have to cleanup. Therefore, we ensure that - /// the temporaries never outlast the conditional/repeating - /// expression, preventing the need for dynamic checks and/or - /// arbitrary amounts of stack space. Terminating scopes end - /// up being contained in a DestructionScope that contains the - /// destructor's execution. - terminating_scopes: FxHashSet, } /// Records the lifetime of a local variable as `cx.var_parent` @@ -81,7 +58,11 @@ fn record_var_lifetime(visitor: &mut ScopeResolutionVisitor<'_>, var_id: hir::It } } -fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hir::Block<'tcx>) { +fn resolve_block<'tcx>( + visitor: &mut ScopeResolutionVisitor<'tcx>, + blk: &'tcx hir::Block<'tcx>, + terminating: bool, +) { debug!("resolve_block(blk.hir_id={:?})", blk.hir_id); let prev_cx = visitor.cx; @@ -111,7 +92,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi // `other_argument()` has run and also the call to `quux(..)` // itself has returned. - visitor.enter_node_scope_with_dtor(blk.hir_id.local_id); + visitor.enter_node_scope_with_dtor(blk.hir_id.local_id, terminating); visitor.cx.var_parent = visitor.cx.parent; { @@ -140,8 +121,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi // the sequence of visits agree with the order in the default // `hir::intravisit` visitor. mem::swap(&mut prev_cx, &mut visitor.cx); - visitor.terminating_scopes.insert(els.hir_id.local_id); - visitor.visit_block(els); + resolve_block(visitor, els, true); // From now on, we continue normally. visitor.cx = prev_cx; } @@ -169,12 +149,12 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi if let Some(tail_expr) = blk.expr { let local_id = tail_expr.hir_id.local_id; let edition = blk.span.edition(); - if edition.at_least_rust_2024() { - visitor.terminating_scopes.insert(local_id); - } else if !visitor - .tcx - .lints_that_dont_need_to_run(()) - .contains(&lint::LintId::of(lint::builtin::TAIL_EXPR_DROP_ORDER)) + let terminating = edition.at_least_rust_2024(); + if !terminating + && !visitor + .tcx + .lints_that_dont_need_to_run(()) + .contains(&lint::LintId::of(lint::builtin::TAIL_EXPR_DROP_ORDER)) { // If this temporary scope will be changing once the codebase adopts Rust 2024, // and we are linting about possible semantic changes that would result, @@ -185,7 +165,7 @@ fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hi .backwards_incompatible_scope .insert(local_id, Scope { local_id, data: ScopeData::Node }); } - visitor.visit_expr(tail_expr); + resolve_expr(visitor, tail_expr, terminating); } } @@ -203,18 +183,14 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir: let prev_cx = visitor.cx; - visitor.terminating_scopes.insert(arm.hir_id.local_id); - - visitor.enter_node_scope_with_dtor(arm.hir_id.local_id); + visitor.enter_node_scope_with_dtor(arm.hir_id.local_id, true); visitor.cx.var_parent = visitor.cx.parent; - if let Some(expr) = arm.guard - && !has_let_expr(expr) - { - visitor.terminating_scopes.insert(expr.hir_id.local_id); + resolve_pat(visitor, arm.pat); + if let Some(guard) = arm.guard { + resolve_expr(visitor, guard, !has_let_expr(guard)); } - - intravisit::walk_arm(visitor, arm); + resolve_expr(visitor, arm.body, false); visitor.cx = prev_cx; } @@ -243,126 +219,24 @@ fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hi // associated destruction scope that represents the scope of the // statement plus its destructors, and thus the scope for which // regions referenced by the destructors need to survive. - visitor.terminating_scopes.insert(stmt_id); let prev_parent = visitor.cx.parent; - visitor.enter_node_scope_with_dtor(stmt_id); + visitor.enter_node_scope_with_dtor(stmt_id, true); intravisit::walk_stmt(visitor, stmt); visitor.cx.parent = prev_parent; } -fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) { +fn resolve_expr<'tcx>( + visitor: &mut ScopeResolutionVisitor<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + terminating: bool, +) { debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr); let prev_cx = visitor.cx; - visitor.enter_node_scope_with_dtor(expr.hir_id.local_id); - - { - let terminating_scopes = &mut visitor.terminating_scopes; - let mut terminating = |id: hir::ItemLocalId| { - terminating_scopes.insert(id); - }; - match expr.kind { - // Conditional or repeating scopes are always terminating - // scopes, meaning that temporaries cannot outlive them. - // This ensures fixed size stacks. - hir::ExprKind::Binary( - source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, - l, - r, - ) => { - // expr is a short circuiting operator (|| or &&). As its - // functionality can't be overridden by traits, it always - // processes bool sub-expressions. bools are Copy and thus we - // can drop any temporaries in evaluation (read) order - // (with the exception of potentially failing let expressions). - // We achieve this by enclosing the operands in a terminating - // scope, both the LHS and the RHS. - - // We optimize this a little in the presence of chains. - // Chains like a && b && c get lowered to AND(AND(a, b), c). - // In here, b and c are RHS, while a is the only LHS operand in - // that chain. This holds true for longer chains as well: the - // leading operand is always the only LHS operand that is not a - // binop itself. Putting a binop like AND(a, b) into a - // terminating scope is not useful, thus we only put the LHS - // into a terminating scope if it is not a binop. - - let terminate_lhs = match l.kind { - // let expressions can create temporaries that live on - hir::ExprKind::Let(_) => false, - // binops already drop their temporaries, so there is no - // need to put them into a terminating scope. - // This is purely an optimization to reduce the number of - // terminating scopes. - hir::ExprKind::Binary( - source_map::Spanned { - node: hir::BinOpKind::And | hir::BinOpKind::Or, .. - }, - .., - ) => false, - // otherwise: mark it as terminating - _ => true, - }; - if terminate_lhs { - terminating(l.hir_id.local_id); - } - - // `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries - // should live beyond the immediate expression - if !matches!(r.kind, hir::ExprKind::Let(_)) { - terminating(r.hir_id.local_id); - } - } - hir::ExprKind::If(_, then, Some(otherwise)) => { - terminating(then.hir_id.local_id); - terminating(otherwise.hir_id.local_id); - } - - hir::ExprKind::If(_, then, None) => { - terminating(then.hir_id.local_id); - } - - hir::ExprKind::Loop(body, _, _, _) => { - terminating(body.hir_id.local_id); - } - - hir::ExprKind::DropTemps(expr) => { - // `DropTemps(expr)` does not denote a conditional scope. - // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`. - terminating(expr.hir_id.local_id); - } - - hir::ExprKind::AssignOp(..) - | hir::ExprKind::Index(..) - | hir::ExprKind::Unary(..) - | hir::ExprKind::Call(..) - | hir::ExprKind::MethodCall(..) => { - // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls - // - // The lifetimes for a call or method call look as follows: - // - // call.id - // - arg0.id - // - ... - // - argN.id - // - call.callee_id - // - // The idea is that call.callee_id represents *the time when - // the invoked function is actually running* and call.id - // represents *the time to prepare the arguments and make the - // call*. See the section "Borrows in Calls" borrowck/README.md - // for an extended explanation of why this distinction is - // important. - // - // record_superlifetime(new_cx, expr.callee_id); - } - - _ => {} - } - } + visitor.enter_node_scope_with_dtor(expr.hir_id.local_id, terminating); let prev_pessimistic = visitor.pessimistic_yield; @@ -417,6 +291,53 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi // properly, we can't miss any types. match expr.kind { + // Conditional or repeating scopes are always terminating + // scopes, meaning that temporaries cannot outlive them. + // This ensures fixed size stacks. + hir::ExprKind::Binary( + source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, + left, + right, + ) => { + // expr is a short circuiting operator (|| or &&). As its + // functionality can't be overridden by traits, it always + // processes bool sub-expressions. bools are Copy and thus we + // can drop any temporaries in evaluation (read) order + // (with the exception of potentially failing let expressions). + // We achieve this by enclosing the operands in a terminating + // scope, both the LHS and the RHS. + + // We optimize this a little in the presence of chains. + // Chains like a && b && c get lowered to AND(AND(a, b), c). + // In here, b and c are RHS, while a is the only LHS operand in + // that chain. This holds true for longer chains as well: the + // leading operand is always the only LHS operand that is not a + // binop itself. Putting a binop like AND(a, b) into a + // terminating scope is not useful, thus we only put the LHS + // into a terminating scope if it is not a binop. + + let terminate_lhs = match left.kind { + // let expressions can create temporaries that live on + hir::ExprKind::Let(_) => false, + // binops already drop their temporaries, so there is no + // need to put them into a terminating scope. + // This is purely an optimization to reduce the number of + // terminating scopes. + hir::ExprKind::Binary( + source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, + .., + ) => false, + // otherwise: mark it as terminating + _ => true, + }; + + // `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries + // should live beyond the immediate expression + let terminate_rhs = !matches!(right.kind, hir::ExprKind::Let(_)); + + resolve_expr(visitor, left, terminate_lhs); + resolve_expr(visitor, right, terminate_rhs); + } // Manually recurse over closures, because they are nested bodies // that share the parent environment. We handle const blocks in // `visit_inline_const`. @@ -485,9 +406,9 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); - visitor.visit_expr(then); + resolve_expr(visitor, then, true); visitor.cx = expr_cx; - visitor.visit_expr(otherwise); + resolve_expr(visitor, otherwise, true); } hir::ExprKind::If(cond, then, None) => { @@ -500,10 +421,20 @@ fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hi visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); - visitor.visit_expr(then); + resolve_expr(visitor, then, true); visitor.cx = expr_cx; } + hir::ExprKind::Loop(body, _, _, _) => { + resolve_block(visitor, body, true); + } + + hir::ExprKind::DropTemps(expr) => { + // `DropTemps(expr)` does not denote a conditional scope. + // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`. + resolve_expr(visitor, expr, true); + } + _ => intravisit::walk_expr(visitor, expr), } @@ -786,12 +717,12 @@ impl<'tcx> ScopeResolutionVisitor<'tcx> { self.cx.parent = Some(child_scope); } - fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) { + fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId, terminating: bool) { // If node was previously marked as a terminating scope during the // recursive visit of its parent node in the HIR, then we need to // account for the destruction scope representing the scope of // the destructors that run immediately after it completes. - if self.terminating_scopes.contains(&id) { + if terminating { self.enter_scope(Scope { local_id: id, data: ScopeData::Destruction }); } self.enter_scope(Scope { local_id: id, data: ScopeData::Node }); @@ -803,13 +734,11 @@ impl<'tcx> ScopeResolutionVisitor<'tcx> { // visited the body. let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0); let outer_cx = self.cx; - let outer_ts = mem::take(&mut self.terminating_scopes); // The 'pessimistic yield' flag is set to true when we are // processing a `+=` statement and have to make pessimistic // control flow assumptions. This doesn't apply to nested // bodies within the `+=` statements. See #69307. let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false); - self.terminating_scopes.insert(hir_id.local_id); self.enter_scope(Scope { local_id: hir_id.local_id, data: ScopeData::CallSite }); self.enter_scope(Scope { local_id: hir_id.local_id, data: ScopeData::Arguments }); @@ -819,14 +748,13 @@ impl<'tcx> ScopeResolutionVisitor<'tcx> { // Restore context we had at the start. self.expr_and_pat_count = outer_ec; self.cx = outer_cx; - self.terminating_scopes = outer_ts; self.pessimistic_yield = outer_pessimistic_yield; } } impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { fn visit_block(&mut self, b: &'tcx Block<'tcx>) { - resolve_block(self, b); + resolve_block(self, b, false); } fn visit_body(&mut self, body: &hir::Body<'tcx>) { @@ -850,7 +778,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { } // The body of the every fn is a root scope. - this.visit_expr(body.value) + resolve_expr(this, body.value, true); } else { // Only functions have an outer terminating (drop) scope, while // temporaries in constant initializers may be 'static, but only @@ -871,6 +799,10 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { // (i.e., `'static`), which means that after `g` returns, it drops, // and all the associated destruction scope rules apply. this.cx.var_parent = None; + this.enter_scope(Scope { + local_id: body.value.hir_id.local_id, + data: ScopeData::Destruction, + }); resolve_local(this, None, Some(body.value)); } }) @@ -886,7 +818,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { resolve_stmt(self, s); } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - resolve_expr(self, ex); + resolve_expr(self, ex, false); } fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) { resolve_local(self, Some(l.pat), l.init) @@ -916,7 +848,6 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { scope_tree: ScopeTree::default(), expr_and_pat_count: 0, cx: Context { parent: None, var_parent: None }, - terminating_scopes: Default::default(), pessimistic_yield: false, fixup_scopes: vec![], }; From 5004e10ceb5c02a7170d81adb551a25f6f9e3565 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sat, 29 Mar 2025 12:13:38 +0800 Subject: [PATCH 436/546] Add a test for `Weak` created from `UniqueArc::downgrade` --- library/alloctests/tests/arc.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/library/alloctests/tests/arc.rs b/library/alloctests/tests/arc.rs index 45a145c6271a..00bdf527133f 100644 --- a/library/alloctests/tests/arc.rs +++ b/library/alloctests/tests/arc.rs @@ -1,7 +1,7 @@ use std::any::Any; use std::cell::{Cell, RefCell}; use std::iter::TrustedLen; -use std::sync::{Arc, Weak}; +use std::sync::{Arc, UniqueArc, Weak}; #[test] fn uninhabited() { @@ -263,6 +263,27 @@ fn make_mut_unsized() { assert_eq!(*other_data, [110, 20, 30]); } +#[test] +fn test_unique_arc_weak() { + let data = UniqueArc::new(32); + + // Test that `Weak` downgraded from `UniqueArc` cannot be upgraded. + let weak = UniqueArc::downgrade(&data); + assert_eq!(weak.strong_count(), 0); + assert_eq!(weak.weak_count(), 0); + assert!(weak.upgrade().is_none()); + + // Test that `Weak` can now be upgraded after the `UniqueArc` being converted to `Arc`. + let strong = UniqueArc::into_arc(data); + assert_eq!(*strong, 32); + assert_eq!(weak.strong_count(), 1); + assert_eq!(weak.weak_count(), 1); + let upgraded = weak.upgrade().unwrap(); + assert_eq!(*upgraded, 32); + assert_eq!(weak.strong_count(), 2); + assert_eq!(weak.weak_count(), 1); +} + #[allow(unused)] mod pin_coerce_unsized { use alloc::sync::{Arc, UniqueArc}; From 163ea4acd0e93d5a45ea44b42a999abe39d0a93f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 28 Mar 2025 10:38:44 +0100 Subject: [PATCH 437/546] Add more tests for pin!(). Co-authored-by: Daniel Henry-Mantilla --- library/coretests/tests/pin_macro.rs | 11 ++++++++ tests/ui/pin-macro/pin_move.rs | 26 +++++++++++++++++++ tests/ui/pin-macro/pin_move.stderr | 38 ++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 tests/ui/pin-macro/pin_move.rs create mode 100644 tests/ui/pin-macro/pin_move.stderr diff --git a/library/coretests/tests/pin_macro.rs b/library/coretests/tests/pin_macro.rs index 639eab740c0b..3174c91a6498 100644 --- a/library/coretests/tests/pin_macro.rs +++ b/library/coretests/tests/pin_macro.rs @@ -47,3 +47,14 @@ fn temp_lifetime() { } async fn foo(_: &mut usize) {} } + +#[test] +fn transitive_extension() { + async fn temporary() {} + + // `pin!` witnessed in the wild being used like this, even if it yields + // a `Pin<&mut &mut impl Unpin>`; it does work because `pin!` + // happens to transitively extend the lifespan of `temporary()`. + let p = pin!(&mut temporary()); + let _use = p; +} diff --git a/tests/ui/pin-macro/pin_move.rs b/tests/ui/pin-macro/pin_move.rs new file mode 100644 index 000000000000..0f6d34fad951 --- /dev/null +++ b/tests/ui/pin-macro/pin_move.rs @@ -0,0 +1,26 @@ +//@ edition:2024 + +use core::marker::PhantomPinned; +use core::pin::pin; + +fn a() { + struct NotCopy(T); + #[allow(unused_mut)] + let mut pointee = NotCopy(PhantomPinned); + pin!(pointee); + let _moved = pointee; + //~^ ERROR use of moved value +} + +fn b() { + struct NotCopy(T); + let mut pointee = NotCopy(PhantomPinned); + pin!(*&mut pointee); + //~^ ERROR cannot move + let _moved = pointee; +} + +fn main() { + a(); + b(); +} diff --git a/tests/ui/pin-macro/pin_move.stderr b/tests/ui/pin-macro/pin_move.stderr new file mode 100644 index 000000000000..c9b8ad9b2021 --- /dev/null +++ b/tests/ui/pin-macro/pin_move.stderr @@ -0,0 +1,38 @@ +error[E0382]: use of moved value: `pointee` + --> $DIR/pin_move.rs:11:18 + | +LL | let mut pointee = NotCopy(PhantomPinned); + | ----------- move occurs because `pointee` has type `a::NotCopy`, which does not implement the `Copy` trait +LL | pin!(pointee); + | ------- value moved here +LL | let _moved = pointee; + | ^^^^^^^ value used here after move + | +note: if `a::NotCopy` implemented `Clone`, you could clone the value + --> $DIR/pin_move.rs:7:5 + | +LL | struct NotCopy(T); + | ^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | pin!(pointee); + | ------- you could clone this value + +error[E0507]: cannot move out of a mutable reference + --> $DIR/pin_move.rs:18:10 + | +LL | pin!(*&mut pointee); + | ^^^^^^^^^^^^^ move occurs because value has type `b::NotCopy`, which does not implement the `Copy` trait + | +note: if `b::NotCopy` implemented `Clone`, you could clone the value + --> $DIR/pin_move.rs:16:5 + | +LL | struct NotCopy(T); + | ^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +LL | let mut pointee = NotCopy(PhantomPinned); +LL | pin!(*&mut pointee); + | ------------- you could clone this value + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0382, E0507. +For more information about an error, try `rustc --explain E0382`. From 366095d6c738821ab6745bf3b224e8643e0eb464 Mon Sep 17 00:00:00 2001 From: bohan Date: Sat, 29 Mar 2025 17:37:01 +0800 Subject: [PATCH 438/546] less decoding if it has the same syntax context --- compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- .../rustc_middle/src/query/on_disk_cache.rs | 10 +- compiler/rustc_middle/src/ty/parameterized.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 201 ++++++------------ .../nonterminal-token-hygiene.stdout | 20 +- 5 files changed, 80 insertions(+), 157 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index dc453b1e747c..34e4f2f26022 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -36,7 +36,7 @@ use rustc_serialize::opaque::FileEncoder; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData}; +use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; @@ -193,7 +193,7 @@ enum LazyState { Previous(NonZero), } -type SyntaxContextTable = LazyTable>>; +type SyntaxContextTable = LazyTable>>; type ExpnDataTable = LazyTable>>; type ExpnHashTable = LazyTable>>; diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 14e3ce8bef6b..ce6219c207fd 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -16,7 +16,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixed use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::Session; use rustc_span::hygiene::{ - ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, + ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextKey, }; use rustc_span::source_map::Spanned; use rustc_span::{ @@ -75,9 +75,9 @@ pub struct OnDiskCache { alloc_decoding_state: AllocDecodingState, // A map from syntax context ids to the position of their associated - // `SyntaxContextData`. We use a `u32` instead of a `SyntaxContext` + // `SyntaxContextKey`. We use a `u32` instead of a `SyntaxContext` // to represent the fact that we are storing *encoded* ids. When we decode - // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`, + // a `SyntaxContextKey`, a new id will be allocated from the global `HygieneData`, // which will almost certainly be different than the serialized id. syntax_contexts: FxHashMap, // A map from the `DefPathHash` of an `ExpnId` to the position @@ -305,7 +305,7 @@ impl OnDiskCache { let mut expn_data = UnhashMap::default(); let mut foreign_expn_data = UnhashMap::default(); - // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current + // Encode all hygiene data (`SyntaxContextKey` and `ExpnData`) from the current // session. hygiene_encode_context.encode( @@ -566,7 +566,7 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { // We look up the position of the associated `SyntaxData` and decode it. let pos = syntax_contexts.get(&id).unwrap(); this.with_position(pos.to_usize(), |decoder| { - let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); + let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); data }) }) diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 19e2b5745632..134f76d7248d 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -111,7 +111,7 @@ trivially_parameterized_over_tcx! { rustc_span::Span, rustc_span::Symbol, rustc_span::def_id::DefPathHash, - rustc_span::hygiene::SyntaxContextData, + rustc_span::hygiene::SyntaxContextKey, rustc_span::Ident, rustc_type_ir::Variance, rustc_hir::Attribute, diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 4390085cd049..f94858856729 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -24,9 +24,6 @@ // because getting it wrong can lead to nested `HygieneData::with` calls that // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) -use std::cell::RefCell; -use std::collections::hash_map::Entry; -use std::collections::hash_set::Entry as SetEntry; use std::hash::Hash; use std::sync::Arc; use std::{fmt, iter, mem}; @@ -34,7 +31,7 @@ use std::{fmt, iter, mem}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; -use rustc_data_structures::sync::{Lock, WorkerLocal}; +use rustc_data_structures::sync::Lock; use rustc_data_structures::unhash::UnhashMap; use rustc_hashes::Hash64; use rustc_index::IndexVec; @@ -59,10 +56,10 @@ impl !PartialOrd for SyntaxContext {} /// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal. /// The other fields are only for caching. -type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); +pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); #[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable)] -pub struct SyntaxContextData { +struct SyntaxContextData { outer_expn: ExpnId, outer_transparency: Transparency, parent: SyntaxContext, @@ -94,6 +91,21 @@ impl SyntaxContextData { self.dollar_crate_name == kw::Empty } + fn new( + (parent, outer_expn, outer_transparency): SyntaxContextKey, + opaque: SyntaxContext, + opaque_and_semitransparent: SyntaxContext, + ) -> Self { + SyntaxContextData { + parent, + outer_expn, + outer_transparency, + opaque, + opaque_and_semitransparent, + dollar_crate_name: kw::DollarCrate, + } + } + fn key(&self) -> SyntaxContextKey { (self.parent, self.outer_expn, self.outer_transparency) } @@ -574,67 +586,49 @@ impl HygieneData { fn apply_mark_internal( &mut self, - ctxt: SyntaxContext, + parent: SyntaxContext, expn_id: ExpnId, transparency: Transparency, ) -> SyntaxContext { - let syntax_context_data = &mut self.syntax_context_data; - debug_assert!(!syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - let mut opaque = syntax_context_data[ctxt.0 as usize].opaque; - let mut opaque_and_semitransparent = - syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent; - - if transparency >= Transparency::Opaque { - let parent = opaque; - opaque = *self - .syntax_context_map - .entry((parent, expn_id, transparency)) - .or_insert_with(|| { - let new_opaque = SyntaxContext::from_usize(syntax_context_data.len()); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque: new_opaque, - opaque_and_semitransparent: new_opaque, - dollar_crate_name: kw::DollarCrate, - }); - new_opaque - }); + debug_assert!(!self.syntax_context_data[parent.0 as usize].is_decode_placeholder()); + // Look into the cache first. + let key = (parent, expn_id, transparency); + if let Some(ctxt) = self.syntax_context_map.get(&key) { + return *ctxt; } + // Reserve a new syntax context. + let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len()); + self.syntax_context_data.push(SyntaxContextData::decode_placeholder()); + self.syntax_context_map.insert(key, ctxt); - if transparency >= Transparency::SemiTransparent { - let parent = opaque_and_semitransparent; - opaque_and_semitransparent = *self - .syntax_context_map - .entry((parent, expn_id, transparency)) - .or_insert_with(|| { - let new_opaque_and_semitransparent = - SyntaxContext::from_usize(syntax_context_data.len()); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque, - opaque_and_semitransparent: new_opaque_and_semitransparent, - dollar_crate_name: kw::DollarCrate, - }); - new_opaque_and_semitransparent - }); - } + // Opaque and semi-transparent versions of the parent. Note that they may be equal to the + // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques, + // and `parent_opaque_and_semitransparent` == `parent` if the expn contains only opaques + // and semi-transparents. + let parent_opaque = self.syntax_context_data[parent.0 as usize].opaque; + let parent_opaque_and_semitransparent = + self.syntax_context_data[parent.0 as usize].opaque_and_semitransparent; - let parent = ctxt; - *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| { - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque, - opaque_and_semitransparent, - dollar_crate_name: kw::DollarCrate, - }); - SyntaxContext::from_usize(syntax_context_data.len() - 1) - }) + // Evaluate opaque and semi-transparent versions of the new syntax context. + let (opaque, opaque_and_semitransparent) = match transparency { + Transparency::Transparent => (parent_opaque, parent_opaque_and_semitransparent), + Transparency::SemiTransparent => ( + parent_opaque, + // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. + self.apply_mark_internal(parent_opaque_and_semitransparent, expn_id, transparency), + ), + Transparency::Opaque => ( + // Will be the same as `ctxt` if the expn chain contains only opaques. + self.apply_mark_internal(parent_opaque, expn_id, transparency), + // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. + self.apply_mark_internal(parent_opaque_and_semitransparent, expn_id, transparency), + ), + }; + + // Fill the full data, now that we have it. + self.syntax_context_data[ctxt.as_u32() as usize] = + SyntaxContextData::new(key, opaque, opaque_and_semitransparent); + ctxt } } @@ -1265,7 +1259,7 @@ impl HygieneEncodeContext { pub fn encode( &self, encoder: &mut T, - mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData), + mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey), mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash), ) { // When we serialize a `SyntaxContextData`, we may end up serializing @@ -1323,9 +1317,6 @@ struct HygieneDecodeContextInner { /// Additional information used to assist in decoding hygiene data pub struct HygieneDecodeContext { inner: Lock, - - /// A set of serialized `SyntaxContext` ids that are currently being decoded on each thread. - local_in_progress: WorkerLocal>>, } /// Register an expansion which has been decoded from the on-disk-cache for the local crate. @@ -1396,10 +1387,10 @@ pub fn decode_expn_id( // to track which `SyntaxContext`s we have already decoded. // The provided closure will be invoked to deserialize a `SyntaxContextData` // if we haven't already seen the id of the `SyntaxContext` we are deserializing. -pub fn decode_syntax_context SyntaxContextData>( +pub fn decode_syntax_context SyntaxContextKey>( d: &mut D, context: &HygieneDecodeContext, - decode_data: F, + decode_ctxt_key: F, ) -> SyntaxContext { let raw_id: u32 = Decodable::decode(d); if raw_id == 0 { @@ -1408,58 +1399,9 @@ pub fn decode_syntax_context SyntaxContext return SyntaxContext::root(); } - let pending_ctxt = { - let mut inner = context.inner.lock(); - - // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between - // raw ids from different crate metadatas. - if let Some(ctxt) = inner.remapped_ctxts.get(raw_id as usize).copied().flatten() { - // This has already been decoded. - return ctxt; - } - - match inner.decoding.entry(raw_id) { - Entry::Occupied(ctxt_entry) => { - let pending_ctxt = *ctxt_entry.get(); - match context.local_in_progress.borrow_mut().entry(raw_id) { - // We're decoding this already on the current thread. Return here and let the - // function higher up the stack finish decoding to handle recursive cases. - // Hopefully having a `SyntaxContext` that refers to an incorrect data is ok - // during reminder of the decoding process, it's certainly not ok after the - // top level decoding function returns. - SetEntry::Occupied(..) => return pending_ctxt, - // Some other thread is currently decoding this. - // Race with it (alternatively we could wait here). - // We cannot return this value, unlike in the recursive case above, because it - // may expose a `SyntaxContext` pointing to incorrect data to arbitrary code. - SetEntry::Vacant(entry) => { - entry.insert(); - pending_ctxt - } - } - } - Entry::Vacant(entry) => { - // We are the first thread to start decoding. Mark the current thread as being progress. - context.local_in_progress.borrow_mut().insert(raw_id); - - // Allocate and store SyntaxContext id *before* calling the decoder function, - // as the SyntaxContextData may reference itself. - let new_ctxt = HygieneData::with(|hygiene_data| { - // Push a dummy SyntaxContextData to ensure that nobody else can get the - // same ID as us. This will be overwritten after call `decode_data`. - hygiene_data.syntax_context_data.push(SyntaxContextData::decode_placeholder()); - SyntaxContext::from_usize(hygiene_data.syntax_context_data.len() - 1) - }); - entry.insert(new_ctxt); - new_ctxt - } - } - }; - // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let ctxt_data = decode_data(d, raw_id); - let ctxt_key = ctxt_data.key(); + let ctxt_key = decode_ctxt_key(d, raw_id); let ctxt = HygieneData::with(|hygiene_data| { match hygiene_data.syntax_context_map.get(&ctxt_key) { @@ -1473,29 +1415,10 @@ pub fn decode_syntax_context SyntaxContext Some(&ctxt) => ctxt, // This is a completely new context. // Overwrite its placeholder data with our decoded data. - None => { - let ctxt_data_ref = - &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize]; - let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data); - // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`. - // We don't care what the encoding crate set this to - we want to resolve it - // from the perspective of the current compilation session. - ctxt_data_ref.dollar_crate_name = kw::DollarCrate; - // Make sure nothing weird happened while `decode_data` was running. - if !prev_ctxt_data.is_decode_placeholder() { - // Another thread may have already inserted the decoded data, - // but the decoded data should match. - assert_eq!(prev_ctxt_data, *ctxt_data_ref); - } - hygiene_data.syntax_context_map.insert(ctxt_key, pending_ctxt); - pending_ctxt - } + None => hygiene_data.apply_mark_internal(ctxt_key.0, ctxt_key.1, ctxt_key.2), } }); - // Mark the context as completed - context.local_in_progress.borrow_mut().remove(&raw_id); - let mut inner = context.inner.lock(); let new_len = raw_id as usize + 1; if inner.remapped_ctxts.len() < new_len { @@ -1507,7 +1430,7 @@ pub fn decode_syntax_context SyntaxContext ctxt } -fn for_all_ctxts_in( +fn for_all_ctxts_in( ctxts: impl Iterator, mut f: F, ) { @@ -1515,7 +1438,7 @@ fn for_all_ctxts_in( ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect() }); for (ctxt, data) in all_data.into_iter() { - f(ctxt.0, ctxt, &data); + f(ctxt.0, ctxt, &data.key()); } } diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index c80a33206fb4..6fd6cb474693 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -5,19 +5,19 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "struct", - span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#5), }, Ident { ident: "S", - span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#5), }, Punct { ch: ';', spacing: Alone, - span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#5), }, ], - span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#5), + span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#4), }, ] #![feature /* 0#0 */(prelude_import)] @@ -59,7 +59,7 @@ macro_rules! outer struct S /* 0#0 */; macro inner /* 0#3 */ { () => { print_bang! { struct S; } } } -struct S /* 0#4 */; +struct S /* 0#5 */; // OK, not a duplicate definition of `S` fn main /* 0#0 */() {} @@ -70,7 +70,7 @@ crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") -crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") @@ -83,9 +83,9 @@ SyntaxContexts: #1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) #2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) #3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) -#4: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) -#5: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) +#4: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) +#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) #6: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) -#7: parent: #5, outer_mark: (crate0::{{expn4}}, Transparent) -#8: parent: #4, outer_mark: (crate0::{{expn4}}, SemiTransparent) +#7: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent) +#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) */ From cf451f08307168f32ffc74b478026e5e3ebc5ca9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 29 Mar 2025 12:52:10 +0300 Subject: [PATCH 439/546] compiletest: Support matching diagnostics on lines below --- src/doc/rustc-dev-guide/src/tests/ui.md | 15 +++++++++++++++ src/tools/compiletest/src/errors.rs | 8 +++++++- tests/ui/parser/issues/issue-103451.rs | 2 +- tests/ui/parser/issues/issue-10636-2.rs | 2 +- .../issue-58094-missing-right-square-bracket.rs | 3 +-- ...ssue-58094-missing-right-square-bracket.stderr | 2 +- tests/ui/parser/issues/issue-62524.rs | 3 ++- tests/ui/parser/issues/issue-62524.stderr | 2 +- tests/ui/parser/issues/issue-62554.rs | 3 +-- tests/ui/parser/issues/issue-62554.stderr | 2 +- tests/ui/parser/issues/issue-62894.rs | 2 +- tests/ui/parser/issues/issue-62973.rs | 4 +++- tests/ui/parser/issues/issue-62973.stderr | 6 +++--- tests/ui/parser/issues/issue-63116.rs | 3 ++- tests/ui/parser/issues/issue-63116.stderr | 4 ++-- tests/ui/parser/issues/issue-63135.rs | 3 +-- tests/ui/parser/issues/issue-63135.stderr | 2 +- tests/ui/parser/issues/issue-81804.rs | 5 ++--- tests/ui/parser/issues/issue-81804.stderr | 4 ++-- tests/ui/parser/issues/issue-81827.rs | 7 ++----- tests/ui/parser/issues/issue-81827.stderr | 4 ++-- tests/ui/parser/issues/issue-84104.rs | 2 +- tests/ui/parser/issues/issue-84148-2.rs | 2 +- tests/ui/parser/issues/issue-88770.rs | 3 +-- tests/ui/parser/issues/issue-88770.stderr | 2 +- tests/ui/parser/mbe_missing_right_paren.rs | 2 +- tests/ui/parser/missing_right_paren.rs | 3 +-- tests/ui/parser/missing_right_paren.stderr | 2 +- tests/ui/parser/unbalanced-doublequote.rs | 4 +--- tests/ui/parser/unbalanced-doublequote.stderr | 2 +- tests/ui/parser/use-unclosed-brace.rs | 2 +- 31 files changed, 62 insertions(+), 48 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 98bb9dee76c5..1190c2646af1 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -202,6 +202,9 @@ several ways to match the message with the line (see the examples below): * `~|`: Associates the error level and message with the *same* line as the *previous comment*. This is more convenient than using multiple carets when there are multiple messages associated with the same line. +* `~v`: Associates the error level and message with the *next* error + annotation line. Each symbol (`v`) that you add adds a line to this, so `~vvv` + is three lines below the error annotation line. * `~?`: Used to match error levels and messages with errors not having line information. These can be placed on any line in the test file, but are conventionally placed at the end. @@ -273,6 +276,18 @@ fn main() { //~| ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields [E0023] ``` +#### Positioned above error line + +Use the `//~v` idiom with number of v's in the string to indicate the number +of lines below. This is typically used in lexer or parser tests matching on errors like unclosed +delimiter or unclosed literal happening at the end of file. + +```rust,ignore +// ignore-tidy-trailing-newlines +//~v ERROR this file contains an unclosed delimiter +fn main((ؼ +``` + #### Error without line information Use `//~?` to match an error without line information. diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index c0566ef93b92..b68f817146fd 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -122,13 +122,17 @@ fn parse_expected( // //~| // //~^ // //~^^^^^ + // //~v + // //~vvvvv // //~? // //[rev1]~ // //[rev1,rev2]~^^ static RE: OnceLock = OnceLock::new(); let captures = RE - .get_or_init(|| Regex::new(r"//(?:\[(?P[\w\-,]+)])?~(?P\?|\||\^*)").unwrap()) + .get_or_init(|| { + Regex::new(r"//(?:\[(?P[\w\-,]+)])?~(?P\?|\||[v\^]*)").unwrap() + }) .captures(line)?; match (test_revision, captures.name("revs")) { @@ -164,6 +168,8 @@ fn parse_expected( (true, Some(last_nonfollow_error.expect("encountered //~| without preceding //~^ line"))) } else if line_num_adjust == "?" { (false, None) + } else if line_num_adjust.starts_with('v') { + (false, Some(line_num + line_num_adjust.len())) } else { (false, Some(line_num - line_num_adjust.len())) }; diff --git a/tests/ui/parser/issues/issue-103451.rs b/tests/ui/parser/issues/issue-103451.rs index 6b0928229e91..687dbc632d67 100644 --- a/tests/ui/parser/issues/issue-103451.rs +++ b/tests/ui/parser/issues/issue-103451.rs @@ -1,4 +1,4 @@ -//@ error-pattern: this file contains an unclosed delimiter struct R { } +//~vv ERROR this file contains an unclosed delimiter struct S { x: [u8; R diff --git a/tests/ui/parser/issues/issue-10636-2.rs b/tests/ui/parser/issues/issue-10636-2.rs index 7200ea1f1dd1..dcc03fec545c 100644 --- a/tests/ui/parser/issues/issue-10636-2.rs +++ b/tests/ui/parser/issues/issue-10636-2.rs @@ -1,7 +1,7 @@ -//@ error-pattern: mismatched closing delimiter: `}` // FIXME(31528) we emit a bunch of silly errors here due to continuing past the // first one. This would be easy-ish to address by better recovery in tokenisation. +//~vvvvv ERROR mismatched closing delimiter: `}` pub fn trace_option(option: Option) { option.map(|some| 42; diff --git a/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.rs b/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.rs index 7952d29c2602..0c0fbd7d5929 100644 --- a/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.rs +++ b/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.rs @@ -1,5 +1,4 @@ // Fixed in #66054. // ignore-tidy-trailing-newlines -//@ error-pattern: this file contains an unclosed delimiter -//@ error-pattern: aborting due to 1 previous error +//~v ERROR this file contains an unclosed delimiter #[Ѕ \ No newline at end of file diff --git a/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.stderr b/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.stderr index 14f5469f6af9..28fd78d660dd 100644 --- a/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.stderr +++ b/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-58094-missing-right-square-bracket.rs:5:4 + --> $DIR/issue-58094-missing-right-square-bracket.rs:4:4 | LL | #[Ѕ | - ^ diff --git a/tests/ui/parser/issues/issue-62524.rs b/tests/ui/parser/issues/issue-62524.rs index a219f662cf78..a8c7d6eb9fdd 100644 --- a/tests/ui/parser/issues/issue-62524.rs +++ b/tests/ui/parser/issues/issue-62524.rs @@ -1,6 +1,7 @@ // ignore-tidy-trailing-newlines -//@ error-pattern: aborting due to 1 previous error + #![allow(uncommon_codepoints)] +//~vv ERROR this file contains an unclosed delimiter y![ Ϥ, \ No newline at end of file diff --git a/tests/ui/parser/issues/issue-62524.stderr b/tests/ui/parser/issues/issue-62524.stderr index d83a49aedd6e..c1ff6e7e7158 100644 --- a/tests/ui/parser/issues/issue-62524.stderr +++ b/tests/ui/parser/issues/issue-62524.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-62524.rs:6:3 + --> $DIR/issue-62524.rs:7:3 | LL | y![ | - unclosed delimiter diff --git a/tests/ui/parser/issues/issue-62554.rs b/tests/ui/parser/issues/issue-62554.rs index 9f196e4b0d61..4a8a1684a412 100644 --- a/tests/ui/parser/issues/issue-62554.rs +++ b/tests/ui/parser/issues/issue-62554.rs @@ -1,5 +1,4 @@ -//@ error-pattern:this file contains an unclosed delimiter - fn main() {} +//~v ERROR this file contains an unclosed delimiter fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { diff --git a/tests/ui/parser/issues/issue-62554.stderr b/tests/ui/parser/issues/issue-62554.stderr index d4aaef161813..50515c4c574a 100644 --- a/tests/ui/parser/issues/issue-62554.stderr +++ b/tests/ui/parser/issues/issue-62554.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-62554.rs:5:89 + --> $DIR/issue-62554.rs:4:89 | LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { | - - - - -^ diff --git a/tests/ui/parser/issues/issue-62894.rs b/tests/ui/parser/issues/issue-62894.rs index 5b1627a25537..c49cbe4b934d 100644 --- a/tests/ui/parser/issues/issue-62894.rs +++ b/tests/ui/parser/issues/issue-62894.rs @@ -1,6 +1,6 @@ // Regression test for #62894, shouldn't crash. -//@ error-pattern: this file contains an unclosed delimiter +//~vvv ERROR this file contains an unclosed delimiter fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! fn main() {} diff --git a/tests/ui/parser/issues/issue-62973.rs b/tests/ui/parser/issues/issue-62973.rs index 5c666d802fe4..a091e4eec1d9 100644 --- a/tests/ui/parser/issues/issue-62973.rs +++ b/tests/ui/parser/issues/issue-62973.rs @@ -1,8 +1,10 @@ // ignore-tidy-trailing-newlines -//@ error-pattern: aborting due to 3 previous errors fn main() {} +//~vvv ERROR mismatched closing delimiter: `)` +//~vv ERROR mismatched closing delimiter: `)` +//~vvv ERROR this file contains an unclosed delimiter fn p() { match s { v, E { [) {) } diff --git a/tests/ui/parser/issues/issue-62973.stderr b/tests/ui/parser/issues/issue-62973.stderr index 493183988e18..ea3e2bebee40 100644 --- a/tests/ui/parser/issues/issue-62973.stderr +++ b/tests/ui/parser/issues/issue-62973.stderr @@ -1,5 +1,5 @@ error: mismatched closing delimiter: `)` - --> $DIR/issue-62973.rs:6:27 + --> $DIR/issue-62973.rs:8:27 | LL | fn p() { match s { v, E { [) {) } | ^^ mismatched closing delimiter @@ -7,7 +7,7 @@ LL | fn p() { match s { v, E { [) {) } | unclosed delimiter error: mismatched closing delimiter: `)` - --> $DIR/issue-62973.rs:6:30 + --> $DIR/issue-62973.rs:8:30 | LL | fn p() { match s { v, E { [) {) } | ^^ mismatched closing delimiter @@ -15,7 +15,7 @@ LL | fn p() { match s { v, E { [) {) } | unclosed delimiter error: this file contains an unclosed delimiter - --> $DIR/issue-62973.rs:8:2 + --> $DIR/issue-62973.rs:10:2 | LL | fn p() { match s { v, E { [) {) } | - - - - missing open `(` for this delimiter diff --git a/tests/ui/parser/issues/issue-63116.rs b/tests/ui/parser/issues/issue-63116.rs index 3be9606b4edb..48abe639e8d9 100644 --- a/tests/ui/parser/issues/issue-63116.rs +++ b/tests/ui/parser/issues/issue-63116.rs @@ -1,3 +1,4 @@ // fixed by #66361 -//@ error-pattern: aborting due to 2 previous errors +//~vv ERROR mismatched closing delimiter: `]` +//~v ERROR this file contains an unclosed delimiter impl W $DIR/issue-63116.rs:3:14 + --> $DIR/issue-63116.rs:4:14 | LL | impl W $DIR/issue-63116.rs:3:18 + --> $DIR/issue-63116.rs:4:18 | LL | impl W $DIR/issue-63135.rs:3:16 + --> $DIR/issue-63135.rs:2:16 | LL | fn i(n{...,f # | - - ^ diff --git a/tests/ui/parser/issues/issue-81804.rs b/tests/ui/parser/issues/issue-81804.rs index 7c9e6e905825..57951ca5c4bc 100644 --- a/tests/ui/parser/issues/issue-81804.rs +++ b/tests/ui/parser/issues/issue-81804.rs @@ -1,6 +1,5 @@ -//@ error-pattern: this file contains an unclosed delimiter -//@ error-pattern: this file contains an unclosed delimiter - fn main() {} +//~vv ERROR mismatched closing delimiter: `}` +//~v ERROR this file contains an unclosed delimiter fn p([=(} diff --git a/tests/ui/parser/issues/issue-81804.stderr b/tests/ui/parser/issues/issue-81804.stderr index 6caaaa792b19..f12c6a61ce5e 100644 --- a/tests/ui/parser/issues/issue-81804.stderr +++ b/tests/ui/parser/issues/issue-81804.stderr @@ -1,5 +1,5 @@ error: mismatched closing delimiter: `}` - --> $DIR/issue-81804.rs:6:8 + --> $DIR/issue-81804.rs:5:8 | LL | fn p([=(} | ^^ mismatched closing delimiter @@ -7,7 +7,7 @@ LL | fn p([=(} | unclosed delimiter error: this file contains an unclosed delimiter - --> $DIR/issue-81804.rs:6:11 + --> $DIR/issue-81804.rs:5:11 | LL | fn p([=(} | -- ^ diff --git a/tests/ui/parser/issues/issue-81827.rs b/tests/ui/parser/issues/issue-81827.rs index a2bd345fc050..7dfeec13022a 100644 --- a/tests/ui/parser/issues/issue-81827.rs +++ b/tests/ui/parser/issues/issue-81827.rs @@ -1,10 +1,7 @@ -//@ error-pattern: this file contains an unclosed delimiter -//@ error-pattern: mismatched closing delimiter: `]` - #![crate_name="0"] - - fn main() {} +//~vv ERROR mismatched closing delimiter: `]` +//~v ERROR this file contains an unclosed delimiter fn r()->i{0|{#[cfg(r(0{]0 diff --git a/tests/ui/parser/issues/issue-81827.stderr b/tests/ui/parser/issues/issue-81827.stderr index d12c74b4a342..986ed6b7e70f 100644 --- a/tests/ui/parser/issues/issue-81827.stderr +++ b/tests/ui/parser/issues/issue-81827.stderr @@ -1,5 +1,5 @@ error: mismatched closing delimiter: `]` - --> $DIR/issue-81827.rs:10:23 + --> $DIR/issue-81827.rs:7:23 | LL | fn r()->i{0|{#[cfg(r(0{]0 | - ^^ mismatched closing delimiter @@ -8,7 +8,7 @@ LL | fn r()->i{0|{#[cfg(r(0{]0 | closing delimiter possibly meant for this error: this file contains an unclosed delimiter - --> $DIR/issue-81827.rs:10:27 + --> $DIR/issue-81827.rs:7:27 | LL | fn r()->i{0|{#[cfg(r(0{]0 | - - - ^ diff --git a/tests/ui/parser/issues/issue-84104.rs b/tests/ui/parser/issues/issue-84104.rs index bced05e684a7..6baf882701d3 100644 --- a/tests/ui/parser/issues/issue-84104.rs +++ b/tests/ui/parser/issues/issue-84104.rs @@ -1,2 +1,2 @@ -//@ error-pattern: this file contains an unclosed delimiter +//~v ERROR this file contains an unclosed delimiter #[i=i::<ښܖ< diff --git a/tests/ui/parser/issues/issue-84148-2.rs b/tests/ui/parser/issues/issue-84148-2.rs index 560475bd32c3..452279021ab9 100644 --- a/tests/ui/parser/issues/issue-84148-2.rs +++ b/tests/ui/parser/issues/issue-84148-2.rs @@ -1,2 +1,2 @@ -//@ error-pattern: this file contains an unclosed delimiter +//~v ERROR this file contains an unclosed delimiter fn f(t:for<>t? diff --git a/tests/ui/parser/issues/issue-88770.rs b/tests/ui/parser/issues/issue-88770.rs index ecc50481f65d..0dd18435ce3f 100644 --- a/tests/ui/parser/issues/issue-88770.rs +++ b/tests/ui/parser/issues/issue-88770.rs @@ -1,7 +1,6 @@ // Regression test for the ICE described in #88770. -//@ error-pattern:this file contains an unclosed delimiter - +//~vvvv ERROR this file contains an unclosed delimiter fn m(){print!("",(c for&g u e diff --git a/tests/ui/parser/issues/issue-88770.stderr b/tests/ui/parser/issues/issue-88770.stderr index 5b54072d009f..137cfea7e1d0 100644 --- a/tests/ui/parser/issues/issue-88770.stderr +++ b/tests/ui/parser/issues/issue-88770.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-88770.rs:8:3 + --> $DIR/issue-88770.rs:7:3 | LL | fn m(){print!("",(c for&g | - - - unclosed delimiter diff --git a/tests/ui/parser/mbe_missing_right_paren.rs b/tests/ui/parser/mbe_missing_right_paren.rs index 9c57b0ebcfc3..851919316647 100644 --- a/tests/ui/parser/mbe_missing_right_paren.rs +++ b/tests/ui/parser/mbe_missing_right_paren.rs @@ -1,3 +1,3 @@ // ignore-tidy-trailing-newlines -//@ error-pattern: this file contains an unclosed delimiter +//~v ERROR this file contains an unclosed delimiter macro_rules! abc(ؼ \ No newline at end of file diff --git a/tests/ui/parser/missing_right_paren.rs b/tests/ui/parser/missing_right_paren.rs index bbf4519a713e..311a16c214c3 100644 --- a/tests/ui/parser/missing_right_paren.rs +++ b/tests/ui/parser/missing_right_paren.rs @@ -1,4 +1,3 @@ // ignore-tidy-trailing-newlines -//@ error-pattern: this file contains an unclosed delimiter -//@ error-pattern: aborting due to 1 previous error +//~v ERROR this file contains an unclosed delimiter fn main((ؼ \ No newline at end of file diff --git a/tests/ui/parser/missing_right_paren.stderr b/tests/ui/parser/missing_right_paren.stderr index 4815f04fbce0..97ccb40a5a2a 100644 --- a/tests/ui/parser/missing_right_paren.stderr +++ b/tests/ui/parser/missing_right_paren.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/missing_right_paren.rs:4:11 + --> $DIR/missing_right_paren.rs:3:11 | LL | fn main((ؼ | -- ^ diff --git a/tests/ui/parser/unbalanced-doublequote.rs b/tests/ui/parser/unbalanced-doublequote.rs index d9c936186ea0..43e23a70271b 100644 --- a/tests/ui/parser/unbalanced-doublequote.rs +++ b/tests/ui/parser/unbalanced-doublequote.rs @@ -1,6 +1,4 @@ -//@ error-pattern: unterminated double quote string - - +//~vv ERROR unterminated double quote string fn main() { " } diff --git a/tests/ui/parser/unbalanced-doublequote.stderr b/tests/ui/parser/unbalanced-doublequote.stderr index d40b982da7c3..60057eddbb42 100644 --- a/tests/ui/parser/unbalanced-doublequote.stderr +++ b/tests/ui/parser/unbalanced-doublequote.stderr @@ -1,5 +1,5 @@ error[E0765]: unterminated double quote string - --> $DIR/unbalanced-doublequote.rs:5:5 + --> $DIR/unbalanced-doublequote.rs:3:5 | LL | / " LL | | } diff --git a/tests/ui/parser/use-unclosed-brace.rs b/tests/ui/parser/use-unclosed-brace.rs index 6679651fe47e..aa52fe92ac1b 100644 --- a/tests/ui/parser/use-unclosed-brace.rs +++ b/tests/ui/parser/use-unclosed-brace.rs @@ -1,4 +1,3 @@ -//@ error-pattern: this file contains an unclosed delimiter use foo::{bar, baz; use std::fmt::Display; @@ -7,4 +6,5 @@ mod bar { } mod baz { } +//~v ERROR this file contains an unclosed delimiter fn main() {} From 439048e074e1a4293e1839875e799329d92e4f81 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sat, 29 Mar 2025 12:21:51 +0100 Subject: [PATCH 440/546] `BackendRepr::is_signed`: comment why this may panics --- compiler/rustc_abi/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 3f28dc7a1efa..843d5ca61ddd 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1462,7 +1462,8 @@ impl BackendRepr { !self.is_unsized() } - /// Returns `true` if this is a single signed integer scalar + /// Returns `true` if this is a single signed integer scalar. + /// Sanity check: panics if this is not a scalar type (see PR #70189). #[inline] pub fn is_signed(&self) -> bool { match self { From daeb449640b189069f76a13a4a208b1a6d6a32b6 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sat, 29 Mar 2025 12:39:06 +0100 Subject: [PATCH 441/546] Mark .pp files as Rust --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index d29c15fe712f..8700d5d6dcff 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,6 +5,7 @@ *.h rust *.rs rust diff=rust *.fixed linguist-language=Rust +*.pp linguist-language=Rust *.mir linguist-language=Rust src/etc/installer/gfx/* binary src/vendor/** -text From 89c9c21b06c8661242b0545f690ac3e716327ac6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 22 Mar 2025 11:24:33 +0000 Subject: [PATCH 442/546] Start using with_native_path in std::sys::fs --- library/std/src/fs.rs | 16 +-- library/std/src/sys/fs/mod.rs | 101 +++++++++++++++-- library/std/src/sys/fs/unix.rs | 199 +++++++++++++++------------------ 3 files changed, 191 insertions(+), 125 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index f9a360585e85..01fbd27e3991 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2362,7 +2362,7 @@ impl AsInner for DirEntry { #[doc(alias = "rm", alias = "unlink", alias = "DeleteFile")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_file>(path: P) -> io::Result<()> { - fs_imp::unlink(path.as_ref()) + fs_imp::remove_file(path.as_ref()) } /// Given a path, queries the file system to get information about a file, @@ -2401,7 +2401,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { #[doc(alias = "stat")] #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata>(path: P) -> io::Result { - fs_imp::stat(path.as_ref()).map(Metadata) + fs_imp::metadata(path.as_ref()).map(Metadata) } /// Queries the metadata about a file without following symlinks. @@ -2436,7 +2436,7 @@ pub fn metadata>(path: P) -> io::Result { #[doc(alias = "lstat")] #[stable(feature = "symlink_metadata", since = "1.1.0")] pub fn symlink_metadata>(path: P) -> io::Result { - fs_imp::lstat(path.as_ref()).map(Metadata) + fs_imp::symlink_metadata(path.as_ref()).map(Metadata) } /// Renames a file or directory to a new name, replacing the original file if @@ -2590,7 +2590,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { #[doc(alias = "CreateHardLink", alias = "linkat")] #[stable(feature = "rust1", since = "1.0.0")] pub fn hard_link, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - fs_imp::link(original.as_ref(), link.as_ref()) + fs_imp::hard_link(original.as_ref(), link.as_ref()) } /// Creates a new symbolic link on the filesystem. @@ -2656,7 +2656,7 @@ pub fn soft_link, Q: AsRef>(original: P, link: Q) -> io::Re /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn read_link>(path: P) -> io::Result { - fs_imp::readlink(path.as_ref()) + fs_imp::read_link(path.as_ref()) } /// Returns the canonical, absolute form of a path with all intermediate @@ -2832,7 +2832,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { #[doc(alias = "rmdir", alias = "RemoveDirectory")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir>(path: P) -> io::Result<()> { - fs_imp::rmdir(path.as_ref()) + fs_imp::remove_dir(path.as_ref()) } /// Removes a directory at this path, after removing all its contents. Use @@ -2959,7 +2959,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { #[doc(alias = "ls", alias = "opendir", alias = "FindFirstFile", alias = "FindNextFile")] #[stable(feature = "rust1", since = "1.0.0")] pub fn read_dir>(path: P) -> io::Result { - fs_imp::readdir(path.as_ref()).map(ReadDir) + fs_imp::read_dir(path.as_ref()).map(ReadDir) } /// Changes the permissions found on a file or a directory. @@ -2995,7 +2995,7 @@ pub fn read_dir>(path: P) -> io::Result { #[doc(alias = "chmod", alias = "SetFileAttributes")] #[stable(feature = "set_permissions", since = "1.1.0")] pub fn set_permissions>(path: P, perm: Permissions) -> io::Result<()> { - fs_imp::set_perm(path.as_ref(), perm.0) + fs_imp::set_permissions(path.as_ref(), perm.0) } impl DirBuilder { diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index c2e19eb393a1..3b176d0d16c4 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -1,28 +1,115 @@ #![deny(unsafe_op_in_unsafe_fn)] +use crate::io; +use crate::path::{Path, PathBuf}; + pub mod common; cfg_if::cfg_if! { if #[cfg(target_family = "unix")] { mod unix; - pub use unix::*; + use unix as imp; + pub use unix::{chown, fchown, lchown}; + #[cfg(not(target_os = "fuchsia"))] + pub use unix::chroot; + pub(crate) use unix::debug_assert_fd_is_open; + #[cfg(any(target_os = "linux", target_os = "android"))] + pub(crate) use unix::CachedFileMetadata; + use crate::sys::common::small_c_string::run_path_with_cstr as with_native_path; } else if #[cfg(target_os = "windows")] { mod windows; - pub use windows::*; + use windows as imp; + pub use windows::{symlink_inner, junction_point}; } else if #[cfg(target_os = "hermit")] { mod hermit; - pub use hermit::*; + use hermit as imp; } else if #[cfg(target_os = "solid_asp3")] { mod solid; - pub use solid::*; + use solid as imp; } else if #[cfg(target_os = "uefi")] { mod uefi; - pub use uefi::*; + use uefi as imp; } else if #[cfg(target_os = "wasi")] { mod wasi; - pub use wasi::*; + use wasi as imp; } else { mod unsupported; - pub use unsupported::*; + use unsupported as imp; } } + +// FIXME: Replace this with platform-specific path conversion functions. +#[cfg(not(target_family = "unix"))] +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { + f(path) +} + +pub use imp::{ + DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, + ReadDir, +}; + +pub fn read_dir(path: &Path) -> io::Result { + // FIXME: use with_native_path + imp::readdir(path) +} + +pub fn remove_file(path: &Path) -> io::Result<()> { + with_native_path(path, &imp::unlink) +} + +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + with_native_path(old, &|old| with_native_path(new, &|new| imp::rename(old, new))) +} + +pub fn remove_dir(path: &Path) -> io::Result<()> { + with_native_path(path, &imp::rmdir) +} + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + // FIXME: use with_native_path + imp::remove_dir_all(path) +} + +pub fn read_link(path: &Path) -> io::Result { + with_native_path(path, &imp::readlink) +} + +pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { + with_native_path(original, &|original| { + with_native_path(link, &|link| imp::symlink(original, link)) + }) +} + +pub fn hard_link(original: &Path, link: &Path) -> io::Result<()> { + with_native_path(original, &|original| { + with_native_path(link, &|link| imp::link(original, link)) + }) +} + +pub fn metadata(path: &Path) -> io::Result { + with_native_path(path, &imp::stat) +} + +pub fn symlink_metadata(path: &Path) -> io::Result { + with_native_path(path, &imp::lstat) +} + +pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { + with_native_path(path, &|path| imp::set_perm(path, perm.clone())) +} + +pub fn canonicalize(path: &Path) -> io::Result { + with_native_path(path, &imp::canonicalize) +} + +pub fn copy(from: &Path, to: &Path) -> io::Result { + // FIXME: use with_native_path + imp::copy(from, to) +} + +pub fn exists(path: &Path) -> io::Result { + // FIXME: use with_native_path + imp::exists(path) +} diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 7c3ed8029f7d..e32392ca94eb 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -926,7 +926,7 @@ impl DirEntry { miri ))] pub fn metadata(&self) -> io::Result { - lstat(&self.path()) + run_path_with_cstr(&self.path(), &lstat) } #[cfg(any( @@ -1653,7 +1653,7 @@ impl fmt::Debug for File { fn get_path(fd: c_int) -> Option { let mut p = PathBuf::from("/proc/self/fd"); p.push(&fd.to_string()); - readlink(&p).ok() + run_path_with_cstr(&p, &readlink).ok() } #[cfg(any(target_vendor = "apple", target_os = "netbsd"))] @@ -1671,7 +1671,7 @@ impl fmt::Debug for File { // fallback to procfs as last resort let mut p = PathBuf::from("/proc/self/fd"); p.push(&fd.to_string()); - return readlink(&p).ok(); + return run_path_with_cstr(&p, &readlink).ok() } else { return None; } @@ -1826,127 +1826,106 @@ pub fn readdir(path: &Path) -> io::Result { } } -pub fn unlink(p: &Path) -> io::Result<()> { - run_path_with_cstr(p, &|p| cvt(unsafe { libc::unlink(p.as_ptr()) }).map(|_| ())) +pub fn unlink(p: &CStr) -> io::Result<()> { + cvt(unsafe { libc::unlink(p.as_ptr()) }).map(|_| ()) } -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - run_path_with_cstr(old, &|old| { - run_path_with_cstr(new, &|new| { - cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }).map(|_| ()) - }) - }) +pub fn rename(old: &CStr, new: &CStr) -> io::Result<()> { + cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }).map(|_| ()) } -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - run_path_with_cstr(p, &|p| cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ())) +pub fn set_perm(p: &CStr, perm: FilePermissions) -> io::Result<()> { + cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ()) } -pub fn rmdir(p: &Path) -> io::Result<()> { - run_path_with_cstr(p, &|p| cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ())) +pub fn rmdir(p: &CStr) -> io::Result<()> { + cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ()) } -pub fn readlink(p: &Path) -> io::Result { - run_path_with_cstr(p, &|c_path| { - let p = c_path.as_ptr(); +pub fn readlink(c_path: &CStr) -> io::Result { + let p = c_path.as_ptr(); - let mut buf = Vec::with_capacity(256); + let mut buf = Vec::with_capacity(256); - loop { - let buf_read = - cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? - as usize; + loop { + let buf_read = + cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize; - unsafe { - buf.set_len(buf_read); - } - - if buf_read != buf.capacity() { - buf.shrink_to_fit(); - - return Ok(PathBuf::from(OsString::from_vec(buf))); - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. The length is guaranteed to be - // the same as the capacity due to the if statement above. - buf.reserve(1); - } - }) -} - -pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { - run_path_with_cstr(original, &|original| { - run_path_with_cstr(link, &|link| { - cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) }).map(|_| ()) - }) - }) -} - -pub fn link(original: &Path, link: &Path) -> io::Result<()> { - run_path_with_cstr(original, &|original| { - run_path_with_cstr(link, &|link| { - cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] { - // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves - // it implementation-defined whether `link` follows symlinks, so rely on the - // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. - // Android has `linkat` on newer versions, but we happen to know `link` - // always has the correct behavior, so it's here as well. - cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; - } else { - // Where we can, use `linkat` instead of `link`; see the comment above - // this one for details on why. - cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; - } - } - Ok(()) - }) - }) -} - -pub fn stat(p: &Path) -> io::Result { - run_path_with_cstr(p, &|p| { - cfg_has_statx! { - if let Some(ret) = unsafe { try_statx( - libc::AT_FDCWD, - p.as_ptr(), - libc::AT_STATX_SYNC_AS_STAT, - libc::STATX_BASIC_STATS | libc::STATX_BTIME, - ) } { - return ret; - } + unsafe { + buf.set_len(buf_read); } - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr::from_stat64(stat)) - }) -} + if buf_read != buf.capacity() { + buf.shrink_to_fit(); -pub fn lstat(p: &Path) -> io::Result { - run_path_with_cstr(p, &|p| { - cfg_has_statx! { - if let Some(ret) = unsafe { try_statx( - libc::AT_FDCWD, - p.as_ptr(), - libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, - libc::STATX_BASIC_STATS | libc::STATX_BTIME, - ) } { - return ret; - } + return Ok(PathBuf::from(OsString::from_vec(buf))); } - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr::from_stat64(stat)) - }) + // Trigger the internal buffer resizing logic of `Vec` by requiring + // more space than the current capacity. The length is guaranteed to be + // the same as the capacity due to the if statement above. + buf.reserve(1); + } } -pub fn canonicalize(p: &Path) -> io::Result { - let r = run_path_with_cstr(p, &|path| unsafe { - Ok(libc::realpath(path.as_ptr(), ptr::null_mut())) - })?; +pub fn symlink(original: &CStr, link: &CStr) -> io::Result<()> { + cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) }).map(|_| ()) +} + +pub fn link(original: &CStr, link: &CStr) -> io::Result<()> { + cfg_if::cfg_if! { + if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] { + // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves + // it implementation-defined whether `link` follows symlinks, so rely on the + // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. + // Android has `linkat` on newer versions, but we happen to know `link` + // always has the correct behavior, so it's here as well. + cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; + } else { + // Where we can, use `linkat` instead of `link`; see the comment above + // this one for details on why. + cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; + } + } + Ok(()) +} + +pub fn stat(p: &CStr) -> io::Result { + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_BASIC_STATS | libc::STATX_BTIME, + ) } { + return ret; + } + } + + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?; + Ok(FileAttr::from_stat64(stat)) +} + +pub fn lstat(p: &CStr) -> io::Result { + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_BASIC_STATS | libc::STATX_BTIME, + ) } { + return ret; + } + } + + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?; + Ok(FileAttr::from_stat64(stat)) +} + +pub fn canonicalize(path: &CStr) -> io::Result { + let r = unsafe { libc::realpath(path.as_ptr(), ptr::null_mut()) }; if r.is_null() { return Err(io::Error::last_os_error()); } @@ -2324,19 +2303,19 @@ mod remove_dir_impl { Ok(()) } - fn remove_dir_all_modern(p: &Path) -> io::Result<()> { + fn remove_dir_all_modern(p: &CStr) -> io::Result<()> { // We cannot just call remove_dir_all_recursive() here because that would not delete a passed // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse // into symlinks. let attr = lstat(p)?; if attr.file_type().is_symlink() { - crate::fs::remove_file(p) + super::unlink(p) } else { - run_path_with_cstr(p, &|p| remove_dir_all_recursive(None, &p)) + remove_dir_all_recursive(None, &p) } } pub fn remove_dir_all(p: &Path) -> io::Result<()> { - remove_dir_all_modern(p) + run_path_with_cstr(p, &remove_dir_all_modern) } } From 02899f86f5b6d3aa87e9809fa3ee0d91fa3df574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Sat, 29 Mar 2025 17:27:33 +0100 Subject: [PATCH 443/546] Properly document FakeReads --- compiler/rustc_middle/src/mir/syntax.rs | 112 ++++++++++++++++++------ 1 file changed, 84 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 4f86703e9537..6d6e6a1f185b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -334,14 +334,19 @@ pub enum StatementKind<'tcx> { /// See [`Rvalue`] documentation for details on each of those. Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), - /// This represents all the reading that a pattern match may do (e.g., inspecting constants and - /// discriminant values), and the kind of pattern it comes from. This is in order to adapt - /// potential error messages to these specific patterns. + /// When executed at runtime, this is a nop. /// - /// Note that this also is emitted for regular `let` bindings to ensure that locals that are - /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` + /// During static analysis, a fake read: + /// - requires that the value being read is initialized (or, in the case + /// of closures, that it was fully initialized at some point in the past) + /// - constitutes a use of a value for the purposes of NLL (i.e. if the + /// value being fake-read is a reference, the lifetime of that reference + /// will be extended to cover the `FakeRead`) + /// - but, unlike an actual read, does *not* invalidate any exclusive + /// borrows. /// - /// When executed at runtime this is a nop. + /// See [`FakeReadCause`] for more details on the situations in which a + /// `FakeRead` is emitted. /// /// Disallowed after drop elaboration. FakeRead(Box<(FakeReadCause, Place<'tcx>)>), @@ -518,28 +523,59 @@ pub enum RetagKind { /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] pub enum FakeReadCause { - /// Inject a fake read of the borrowed input at the end of each guards - /// code. + /// A fake read injected into a match guard to ensure that the discriminants + /// that are being matched on aren't modified while the match guard is being + /// evaluated. + /// + /// At the beginning of each match guard, a [fake borrow][FakeBorrowKind] is + /// inserted for each discriminant accessed in the entire `match` statement. + /// + /// Then, at the end of the match guard, a `FakeRead(ForMatchGuard)` is + /// inserted to keep the fake borrows alive until that point. /// /// This should ensure that you cannot change the variant for an enum while /// you are in the midst of matching on it. ForMatchGuard, - /// `let x: !; match x {}` doesn't generate any read of x so we need to - /// generate a read of x to check that it is initialized and safe. + /// Fake read of the scrutinee of a `match` or destructuring `let` + /// (i.e. `let` with non-trivial pattern). /// - /// If a closure pattern matches a Place starting with an Upvar, then we introduce a - /// FakeRead for that Place outside the closure, in such a case this option would be - /// Some(closure_def_id). - /// Otherwise, the value of the optional LocalDefId will be None. + /// In `match x { ... }`, we generate a `FakeRead(ForMatchedPlace, x)` + /// and insert it into the `otherwise_block` (which is supposed to be + /// unreachable for irrefutable pattern-matches like `match` or `let`). + /// + /// This is necessary because `let x: !; match x {}` doesn't generate any + /// actual read of x, so we need to generate a `FakeRead` to check that it + /// is initialized. + /// + /// If the `FakeRead(ForMatchedPlace)` is being performed with a closure + /// that doesn't capture the required upvars, the `FakeRead` within the + /// closure is omitted entirely. + /// + /// To make sure that this is still sound, if a closure matches against + /// a Place starting with an Upvar, we hoist the `FakeRead` to the + /// definition point of the closure. + /// + /// If the `FakeRead` comes from being hoisted out of a closure like this, + /// we record the `LocalDefId` of the closure. Otherwise, the `Option` will be `None`. // // We can use LocalDefId here since fake read statements are removed // before codegen in the `CleanupNonCodegenStatements` pass. ForMatchedPlace(Option), - /// A fake read of the RefWithinGuard version of a bind-by-value variable - /// in a match guard to ensure that its value hasn't change by the time - /// we create the OutsideGuard version. + /// A fake read injected into a match guard to ensure that the places + /// bound by the pattern are immutable for the duration of the match guard. + /// + /// Within a match guard, references are created for each place that the + /// pattern creates a binding for — this is known as the `RefWithinGuard` + /// version of the variables. To make sure that the references stay + /// alive until the end of the match guard, and properly prevent the + /// places in question from being modified, a `FakeRead(ForGuardBinding)` + /// is inserted at the end of the match guard. + /// + /// For details on how these references are created, see the extensive + /// documentation on `bind_matched_candidate_for_guard` in + /// `rustc_mir_build`. ForGuardBinding, /// Officially, the semantics of @@ -552,22 +588,42 @@ pub enum FakeReadCause { /// However, if we see the simple pattern `let var = `, we optimize this to /// evaluate `` directly into the variable `var`. This is mostly unobservable, /// but in some cases it can affect the borrow checker, as in #53695. - /// Therefore, we insert a "fake read" here to ensure that we get - /// appropriate errors. /// - /// If a closure pattern matches a Place starting with an Upvar, then we introduce a - /// FakeRead for that Place outside the closure, in such a case this option would be - /// Some(closure_def_id). - /// Otherwise, the value of the optional DefId will be None. + /// Therefore, we insert a `FakeRead(ForLet)` immediately after each `let` + /// with a trivial pattern. + /// + /// FIXME: `ExprUseVisitor` has an entirely different opinion on what `FakeRead(ForLet)` + /// is supposed to mean. If it was accurate to what MIR lowering does, + /// would it even make sense to hoist these out of closures like + /// `ForMatchedPlace`? ForLet(Option), - /// If we have an index expression like + /// Currently, index expressions overloaded through the `Index` trait + /// get lowered differently than index expressions with builtin semantics + /// for arrays and slices — the latter will emit code to perform + /// bound checks, and then return a MIR place that will only perform the + /// indexing "for real" when it gets incorporated into an instruction. /// - /// (*x)[1][{ x = y; 4}] + /// This is observable in the fact that the following compiles: /// - /// then the first bounds check is invalidated when we evaluate the second - /// index expression. Thus we create a fake borrow of `x` across the second - /// indexer, which will cause a borrow check error. + /// ``` + /// fn f(x: &mut [&mut [u32]], i: usize) { + /// x[i][x[i].len() - 1] += 1; + /// } + /// ``` + /// + /// However, we need to be careful to not let the user invalidate the + /// bound check with an expression like + /// + /// `(*x)[1][{ x = y; 4}]` + /// + /// Here, the first bounds check would be invalidated when we evaluate the + /// second index expression. To make sure that this doesn't happen, we + /// create a fake borrow of `x` and hold it while we evaluate the second + /// index. + /// + /// This borrow is kept alive by a `FakeRead(ForIndex)` at the end of its + /// scope. ForIndex, } From 2dfd2a2a242e920b7378328b87f901652d9d81be Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Mar 2025 00:39:55 +0300 Subject: [PATCH 444/546] Remove attribute `#[rustc_error]` --- compiler/rustc_feature/src/builtin_attrs.rs | 6 +-- compiler/rustc_interface/messages.ftl | 6 --- compiler/rustc_interface/src/errors.rs | 14 ------- compiler/rustc_interface/src/passes.rs | 42 +++---------------- compiler/rustc_middle/src/util/bug.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- .../crates/hir-expand/src/inert_attr_macro.rs | 4 -- tests/incremental/delayed_span_bug.rs | 4 +- .../bound-lifetime-constrained.ok.stderr | 8 ---- .../bound-lifetime-constrained.rs | 5 +-- .../bound-lifetime-in-binding-only.ok.stderr | 8 ---- .../bound-lifetime-in-binding-only.rs | 5 +-- .../bound-lifetime-in-return-only.ok.stderr | 8 ---- .../bound-lifetime-in-return-only.rs | 5 +-- .../borrowck-report-with-custom-diagnostic.rs | 3 +- ...rowck-report-with-custom-diagnostic.stderr | 6 +-- tests/ui/borrowck/mut-borrow-outside-loop.rs | 4 +- tests/ui/codemap_tests/issue-11715.rs | 3 +- tests/ui/codemap_tests/issue-11715.stderr | 2 +- tests/ui/consts/async-block.rs | 5 +-- .../ui/consts/async-block.with_feature.stderr | 8 ---- .../allow-non-lint-warnings.rs | 10 +++-- ...llow-non-lint-warnings.without_flag.stderr | 10 +++-- .../feature-gate-rustc-attrs-1.rs | 1 - .../feature-gate-rustc-attrs-1.stderr | 13 +----- tests/ui/mir/issue-75053.rs | 5 +-- tests/ui/mir/issue-75053.stderr | 8 ---- tests/ui/proc-macro/no-macro-use-attr.rs | 5 +-- tests/ui/proc-macro/no-macro-use-attr.stderr | 8 +--- .../feature-gate.no_gate.stderr | 2 +- .../feature-gate.rs | 6 +-- .../feature-gate.with_gate.stderr | 8 ---- tests/ui/rustc-error.rs | 6 --- tests/ui/rustc-error.stderr | 8 ---- tests/ui/span/range-2.rs | 4 +- .../regionck-unboxed-closure-lifetimes.rs | 3 +- .../regionck-unboxed-closure-lifetimes.stderr | 2 +- tests/ui/suggestions/attribute-typos.rs | 4 +- tests/ui/suggestions/attribute-typos.stderr | 10 ++--- .../const-traits/feature-gate.gated.stderr | 8 ---- tests/ui/traits/const-traits/feature-gate.rs | 5 +-- tests/ui/treat-err-as-bug/span_delayed_bug.rs | 2 +- .../treat-err-as-bug/span_delayed_bug.stderr | 2 +- tests/ui/type-alias-impl-trait/issue-53096.rs | 6 +-- .../type-alias-impl-trait/issue-53096.stderr | 8 ---- tests/ui/type-alias-impl-trait/issue-60407.rs | 6 +-- .../type-alias-impl-trait/issue-60407.stderr | 8 ---- 47 files changed, 72 insertions(+), 236 deletions(-) delete mode 100644 tests/ui/associated-types/bound-lifetime-constrained.ok.stderr delete mode 100644 tests/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr delete mode 100644 tests/ui/associated-types/bound-lifetime-in-return-only.ok.stderr delete mode 100644 tests/ui/consts/async-block.with_feature.stderr delete mode 100644 tests/ui/mir/issue-75053.stderr delete mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr delete mode 100644 tests/ui/rustc-error.rs delete mode 100644 tests/ui/rustc-error.stderr delete mode 100644 tests/ui/traits/const-traits/feature-gate.gated.stderr delete mode 100644 tests/ui/type-alias-impl-trait/issue-53096.stderr delete mode 100644 tests/ui/type-alias-impl-trait/issue-60407.stderr diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 6fe65c88f712..1e33e2e9393f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1087,9 +1087,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( - TEST, rustc_error, Normal, - template!(Word, List: "delayed_bug_from_inside_query"), - WarnFollowingWordOnly, EncodeCrossCrate::Yes + TEST, rustc_delayed_bug_from_inside_query, Normal, + template!(Word), + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_dump_user_args, Normal, template!(Word), diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index ffbe708ba8da..4b9c71d71725 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -50,11 +50,5 @@ interface_out_dir_error = interface_proc_macro_crate_panic_abort = building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic -interface_rustc_error_fatal = - fatal error triggered by #[rustc_error] - -interface_rustc_error_unexpected_annotation = - unexpected annotation used with `#[rustc_error(...)]`! - interface_temps_dir_error = failed to find or create the directory specified by `--temps-dir` diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index ef0235b5577f..6b39b4f18911 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -73,20 +73,6 @@ pub struct TempsDirError; #[diag(interface_out_dir_error)] pub struct OutDirError; -#[derive(Diagnostic)] -#[diag(interface_rustc_error_fatal)] -pub struct RustcErrorFatal { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(interface_rustc_error_unexpected_annotation)] -pub struct RustcErrorUnexpectedAnnotation { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(interface_failed_writing_file)] pub struct FailedWritingFile<'a> { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 2440f0639c8a..93013c8b3f61 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1067,48 +1067,18 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { }); } -/// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used -/// to write UI tests that actually test that compilation succeeds without reporting -/// an error. -fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { - let Some((def_id, _)) = tcx.entry_fn(()) else { return }; - for attr in tcx.get_attrs(def_id, sym::rustc_error) { - match attr.meta_item_list() { - // Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`. - Some(list) - if list.iter().any(|list_item| { - matches!( - list_item.ident().map(|i| i.name), - Some(sym::delayed_bug_from_inside_query) - ) - }) => - { - tcx.ensure_ok().trigger_delayed_bug(def_id); - } - - // Bare `#[rustc_error]`. - None => { - tcx.dcx().emit_fatal(errors::RustcErrorFatal { span: tcx.def_span(def_id) }); - } - - // Some other attribute. - Some(_) => { - tcx.dcx().emit_warn(errors::RustcErrorUnexpectedAnnotation { - span: tcx.def_span(def_id), - }); - } - } - } -} - /// Runs the codegen backend, after which the AST and analysis can /// be discarded. pub(crate) fn start_codegen<'tcx>( codegen_backend: &dyn CodegenBackend, tcx: TyCtxt<'tcx>, ) -> Box { - // Hook for UI tests. - check_for_rustc_errors_attr(tcx); + // Hook for tests. + if let Some((def_id, _)) = tcx.entry_fn(()) + && tcx.has_attr(def_id, sym::rustc_delayed_bug_from_inside_query) + { + tcx.ensure_ok().trigger_delayed_bug(def_id); + } // Don't run this test assertions when not doing codegen. Compiletest tries to build // build-fail tests in check mode first and expects it to not give an error in that case. diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index 7dda68b8393a..c4357fae1046 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -49,7 +49,7 @@ fn opt_span_bug_fmt>( pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { tcx.dcx().span_delayed_bug( tcx.def_span(key), - "delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]", + "delayed bug triggered by #[rustc_delayed_bug_from_inside_query]", ); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6807f96e712c..409497c169e2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1771,6 +1771,7 @@ symbols! { rustc_deallocator, rustc_def_path, rustc_default_body_unstable, + rustc_delayed_bug_from_inside_query, rustc_deny_explicit_impl, rustc_deprecated_safe_2024, rustc_diagnostic_item, @@ -1787,7 +1788,6 @@ symbols! { rustc_dump_user_args, rustc_dump_vtable, rustc_effective_visibility, - rustc_error, rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, rustc_force_inline, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index 9a7a1a01a09c..4c4174e2680f 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -665,10 +665,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), - rustc_attr!( - TEST, rustc_error, Normal, - template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly - ), rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing), rustc_attr!( diff --git a/tests/incremental/delayed_span_bug.rs b/tests/incremental/delayed_span_bug.rs index 958e9dd07e2d..1534aca5dddf 100644 --- a/tests/incremental/delayed_span_bug.rs +++ b/tests/incremental/delayed_span_bug.rs @@ -1,8 +1,8 @@ //@ revisions: cfail1 cfail2 //@ should-ice -//@ error-pattern: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)] +//@ error-pattern: delayed bug triggered by #[rustc_delayed_bug_from_inside_query] #![feature(rustc_attrs)] -#[rustc_error(delayed_bug_from_inside_query)] +#[rustc_delayed_bug_from_inside_query] fn main() {} diff --git a/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr b/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr deleted file mode 100644 index 9082044fe068..000000000000 --- a/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/bound-lifetime-constrained.rs:48:1 - | -LL | fn main() { } - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/associated-types/bound-lifetime-constrained.rs b/tests/ui/associated-types/bound-lifetime-constrained.rs index 1dc3b2f5c2b7..3a5a77f57f23 100644 --- a/tests/ui/associated-types/bound-lifetime-constrained.rs +++ b/tests/ui/associated-types/bound-lifetime-constrained.rs @@ -1,7 +1,7 @@ //@ revisions: func object clause ok +//@[ok] check-pass #![allow(dead_code)] -#![feature(rustc_attrs)] trait Foo<'a> { type Item; @@ -44,5 +44,4 @@ fn clause2() where T: for<'a> Fn() -> <() as Foo<'a>>::Item { //[clause]~^ ERROR `Output` references lifetime `'a` } -#[rustc_error] -fn main() { } //[ok]~ ERROR fatal error triggered by #[rustc_error] +fn main() { } diff --git a/tests/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr b/tests/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr deleted file mode 100644 index 435e224bd892..000000000000 --- a/tests/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/bound-lifetime-in-binding-only.rs:71:1 - | -LL | fn main() { } - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/associated-types/bound-lifetime-in-binding-only.rs b/tests/ui/associated-types/bound-lifetime-in-binding-only.rs index e973e58b629f..2401fe0ef1f7 100644 --- a/tests/ui/associated-types/bound-lifetime-in-binding-only.rs +++ b/tests/ui/associated-types/bound-lifetime-in-binding-only.rs @@ -1,7 +1,7 @@ //@ revisions: angle paren ok elision +//@[ok] check-pass #![allow(dead_code)] -#![feature(rustc_attrs)] #![feature(unboxed_closures)] trait Foo { @@ -67,5 +67,4 @@ fn ok2 Fn<(&'b Parameterized<'a>,), Output=&'a i32>>() { fn ok3() where for<'a> Parameterized<'a>: Foo { } -#[rustc_error] -fn main() { } //[ok]~ ERROR fatal error triggered by #[rustc_error] +fn main() { } diff --git a/tests/ui/associated-types/bound-lifetime-in-return-only.ok.stderr b/tests/ui/associated-types/bound-lifetime-in-return-only.ok.stderr deleted file mode 100644 index 1815a7be7ee8..000000000000 --- a/tests/ui/associated-types/bound-lifetime-in-return-only.ok.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/bound-lifetime-in-return-only.rs:49:1 - | -LL | fn main() { } - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/associated-types/bound-lifetime-in-return-only.rs b/tests/ui/associated-types/bound-lifetime-in-return-only.rs index bf3aa6149cce..8a28f5b77861 100644 --- a/tests/ui/associated-types/bound-lifetime-in-return-only.rs +++ b/tests/ui/associated-types/bound-lifetime-in-return-only.rs @@ -1,7 +1,7 @@ //@ revisions: sig local structure ok elision +//@[ok] check-pass #![allow(dead_code)] -#![feature(rustc_attrs)] #![feature(unboxed_closures)] trait Foo { @@ -45,5 +45,4 @@ fn ok1(_: &dyn for<'a> Fn(&Parameterized<'a>) -> &'a i32) { fn ok2(_: &dyn for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>) { } -#[rustc_error] -fn main() { } //[ok]~ ERROR fatal error triggered by #[rustc_error] +fn main() { } diff --git a/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs index 6f323d912275..9d323bf0324e 100644 --- a/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs +++ b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs @@ -1,6 +1,5 @@ -#![feature(rustc_attrs)] #![allow(dead_code)] -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { // Original borrow ends at end of function let mut x = 1; let y = &mut x; diff --git a/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr index db73d4c04acc..444a74cbfcf5 100644 --- a/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr +++ b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-report-with-custom-diagnostic.rs:8:13 + --> $DIR/borrowck-report-with-custom-diagnostic.rs:7:13 | LL | let y = &mut x; | ------ mutable borrow occurs here @@ -11,7 +11,7 @@ LL | y.use_mut(); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-report-with-custom-diagnostic.rs:21:21 + --> $DIR/borrowck-report-with-custom-diagnostic.rs:20:21 | LL | let y = &x; | -- immutable borrow occurs here @@ -23,7 +23,7 @@ LL | y.use_ref(); | - immutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-report-with-custom-diagnostic.rs:36:17 + --> $DIR/borrowck-report-with-custom-diagnostic.rs:35:17 | LL | let y = &mut x; | ------ first mutable borrow occurs here diff --git a/tests/ui/borrowck/mut-borrow-outside-loop.rs b/tests/ui/borrowck/mut-borrow-outside-loop.rs index c02bfbf87390..3cc362def38f 100644 --- a/tests/ui/borrowck/mut-borrow-outside-loop.rs +++ b/tests/ui/borrowck/mut-borrow-outside-loop.rs @@ -1,6 +1,6 @@ // ensure borrowck messages are correct outside special case -#![feature(rustc_attrs)] -fn main() { #![rustc_error] // rust-lang/rust#49855 + +fn main() { let mut void = (); let first = &mut void; diff --git a/tests/ui/codemap_tests/issue-11715.rs b/tests/ui/codemap_tests/issue-11715.rs index 617d57ff75a4..d0daaf444b34 100644 --- a/tests/ui/codemap_tests/issue-11715.rs +++ b/tests/ui/codemap_tests/issue-11715.rs @@ -1,5 +1,4 @@ -#![feature(rustc_attrs)] -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { let mut x = "foo"; let y = &mut x; let z = &mut x; //~ ERROR cannot borrow diff --git a/tests/ui/codemap_tests/issue-11715.stderr b/tests/ui/codemap_tests/issue-11715.stderr index 5d0cf718761c..6b330560adb9 100644 --- a/tests/ui/codemap_tests/issue-11715.stderr +++ b/tests/ui/codemap_tests/issue-11715.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/issue-11715.rs:5:13 + --> $DIR/issue-11715.rs:4:13 | LL | let y = &mut x; | ------ first mutable borrow occurs here diff --git a/tests/ui/consts/async-block.rs b/tests/ui/consts/async-block.rs index 40be4d195d4b..1211a150f7d5 100644 --- a/tests/ui/consts/async-block.rs +++ b/tests/ui/consts/async-block.rs @@ -2,8 +2,8 @@ //@ edition:2018 //@ revisions: with_feature without_feature +//@[with_feature] check-pass -#![feature(rustc_attrs)] #![cfg_attr(with_feature, feature(const_async_blocks))] use std::future::Future; @@ -15,5 +15,4 @@ const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; static _FUT: &(dyn Future + Sync) = &async {}; //[without_feature]~^ `async` block -#[rustc_error] -fn main() {} //[with_feature]~ fatal error triggered by #[rustc_error] +fn main() {} diff --git a/tests/ui/consts/async-block.with_feature.stderr b/tests/ui/consts/async-block.with_feature.stderr deleted file mode 100644 index 8228fa29edf1..000000000000 --- a/tests/ui/consts/async-block.with_feature.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/async-block.rs:19:1 - | -LL | fn main() {} - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs b/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs index 8980ef9c4220..f928e1122894 100644 --- a/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs +++ b/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs @@ -13,14 +13,16 @@ //! - Original impl PR: . //! - RFC 507 "Release channels": //! . -#![feature(rustc_attrs)] //@ revisions: without_flag with_flag +//@ check-pass +//@ compile-flags: -Zunleash-the-miri-inside-of-you //@[with_flag] compile-flags: -Awarnings -//@ check-pass +fn non_constant() {} +const fn constant() { non_constant() } -#[rustc_error(warn)] fn main() {} -//[without_flag]~^ WARN unexpected annotation used with `#[rustc_error(...)]`! + +//[without_flag]~? WARN skipping const checks diff --git a/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr b/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr index 3f33ccbd1c9f..08ae11fc18a9 100644 --- a/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr +++ b/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr @@ -1,8 +1,10 @@ -warning: unexpected annotation used with `#[rustc_error(...)]`! - --> $DIR/allow-non-lint-warnings.rs:25:1 +warning: skipping const checks | -LL | fn main() {} - | ^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/allow-non-lint-warnings.rs:24:23 + | +LL | const fn constant() { non_constant() } + | ^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs index 7ae4a8d911ba..025b4b52f12f 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs @@ -1,7 +1,6 @@ // Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate. #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable -#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable #[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 8c3a8eb2df87..0f760e0602d2 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -7,18 +7,9 @@ LL | #[rustc_variance] = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable - --> $DIR/feature-gate-rustc-attrs-1.rs:4:1 - | -LL | #[rustc_error] - | ^^^^^^^^^^^^^^ - | - = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable (note that the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized) - --> $DIR/feature-gate-rustc-attrs-1.rs:5:1 + --> $DIR/feature-gate-rustc-attrs-1.rs:4:1 | LL | #[rustc_nonnull_optimization_guaranteed] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,6 +17,6 @@ LL | #[rustc_nonnull_optimization_guaranteed] = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/mir/issue-75053.rs b/tests/ui/mir/issue-75053.rs index 9b247fa54349..4bc481b82e53 100644 --- a/tests/ui/mir/issue-75053.rs +++ b/tests/ui/mir/issue-75053.rs @@ -1,6 +1,7 @@ +//@ check-pass //@ compile-flags: -Z mir-opt-level=3 -#![feature(type_alias_impl_trait, rustc_attrs)] +#![feature(type_alias_impl_trait)] use std::marker::PhantomData; @@ -43,8 +44,6 @@ impl>>, U> MyIndex> for Scope { } } -#[rustc_error] fn main() { - //~^ ERROR let _pos: Phantom1> = Scope::new().my_index(); } diff --git a/tests/ui/mir/issue-75053.stderr b/tests/ui/mir/issue-75053.stderr deleted file mode 100644 index 91032bc3797e..000000000000 --- a/tests/ui/mir/issue-75053.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/issue-75053.rs:47:1 - | -LL | fn main() { - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/proc-macro/no-macro-use-attr.rs b/tests/ui/proc-macro/no-macro-use-attr.rs index d44f51bfd8d4..252003781311 100644 --- a/tests/ui/proc-macro/no-macro-use-attr.rs +++ b/tests/ui/proc-macro/no-macro-use-attr.rs @@ -1,10 +1,9 @@ +//@ check-pass //@ proc-macro: test-macros.rs -#![feature(rustc_attrs)] #![warn(unused_extern_crates)] extern crate test_macros; //~^ WARN unused extern crate -#[rustc_error] -fn main() {} //~ ERROR fatal error triggered by #[rustc_error] +fn main() {} diff --git a/tests/ui/proc-macro/no-macro-use-attr.stderr b/tests/ui/proc-macro/no-macro-use-attr.stderr index 3dda3cc7d5a5..4913672450ab 100644 --- a/tests/ui/proc-macro/no-macro-use-attr.stderr +++ b/tests/ui/proc-macro/no-macro-use-attr.stderr @@ -10,11 +10,5 @@ note: the lint level is defined here LL | #![warn(unused_extern_crates)] | ^^^^^^^^^^^^^^^^^^^^ -error: fatal error triggered by #[rustc_error] - --> $DIR/no-macro-use-attr.rs:10:1 - | -LL | fn main() {} - | ^^^^^^^^^ - -error: aborting due to 1 previous error; 1 warning emitted +warning: 1 warning emitted diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr index 085843496266..c5756269def6 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `structural_match` - --> $DIR/feature-gate.rs:29:6 + --> $DIR/feature-gate.rs:27:6 | LL | impl std::marker::StructuralPartialEq for Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs index 711b07fee3b6..694081654d58 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs @@ -3,11 +3,10 @@ // used in a match. //@ revisions: with_gate no_gate - +//@[with_gate] check-pass // gate-test-structural_match #![allow(unused)] -#![feature(rustc_attrs)] #![cfg_attr(with_gate, feature(structural_match))] @@ -17,8 +16,7 @@ struct Foo { const FOO: Foo = Foo { x: 0 }; -#[rustc_error] -fn main() { //[with_gate]~ ERROR fatal error triggered by #[rustc_error] +fn main() { let y = Foo { x: 1 }; match y { FOO => { } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr deleted file mode 100644 index 505b7d79cadb..000000000000 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/feature-gate.rs:21:1 - | -LL | fn main() { - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/rustc-error.rs b/tests/ui/rustc-error.rs deleted file mode 100644 index 69d57948fb5e..000000000000 --- a/tests/ui/rustc-error.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_error] -fn main() { - //~^ ERROR fatal error triggered by #[rustc_error] -} diff --git a/tests/ui/rustc-error.stderr b/tests/ui/rustc-error.stderr deleted file mode 100644 index 67451195b64f..000000000000 --- a/tests/ui/rustc-error.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/rustc-error.rs:4:1 - | -LL | fn main() { - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/span/range-2.rs b/tests/ui/span/range-2.rs index c4bb16f44bd1..2e8252169b7e 100644 --- a/tests/ui/span/range-2.rs +++ b/tests/ui/span/range-2.rs @@ -1,6 +1,6 @@ // Test range syntax - borrow errors. -#![feature(rustc_attrs)] -pub fn main() { #![rustc_error] // rust-lang/rust#49855 + +pub fn main() { let r = { let a = 42; let b = 42; diff --git a/tests/ui/span/regionck-unboxed-closure-lifetimes.rs b/tests/ui/span/regionck-unboxed-closure-lifetimes.rs index 60ccaa872e73..fe6c353e8f8e 100644 --- a/tests/ui/span/regionck-unboxed-closure-lifetimes.rs +++ b/tests/ui/span/regionck-unboxed-closure-lifetimes.rs @@ -1,7 +1,6 @@ -#![feature(rustc_attrs)] use std::ops::FnMut; -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { let mut f; { let c = 1; diff --git a/tests/ui/span/regionck-unboxed-closure-lifetimes.stderr b/tests/ui/span/regionck-unboxed-closure-lifetimes.stderr index 225f83b6e666..bb6298211bc1 100644 --- a/tests/ui/span/regionck-unboxed-closure-lifetimes.stderr +++ b/tests/ui/span/regionck-unboxed-closure-lifetimes.stderr @@ -1,5 +1,5 @@ error[E0597]: `c` does not live long enough - --> $DIR/regionck-unboxed-closure-lifetimes.rs:8:21 + --> $DIR/regionck-unboxed-closure-lifetimes.rs:7:21 | LL | let c = 1; | - binding `c` declared here diff --git a/tests/ui/suggestions/attribute-typos.rs b/tests/ui/suggestions/attribute-typos.rs index 7c8231bbb24f..4c2336e105e2 100644 --- a/tests/ui/suggestions/attribute-typos.rs +++ b/tests/ui/suggestions/attribute-typos.rs @@ -4,8 +4,8 @@ fn foo() {} #[tests] //~ ERROR cannot find attribute `tests` in this scope fn bar() {} -#[rustc_err] -//~^ ERROR cannot find attribute `rustc_err` in this scope +#[rustc_dumm] +//~^ ERROR cannot find attribute `rustc_dumm` in this scope //~| ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler fn main() {} diff --git a/tests/ui/suggestions/attribute-typos.stderr b/tests/ui/suggestions/attribute-typos.stderr index b871c9b45a56..a1a01c0abd63 100644 --- a/tests/ui/suggestions/attribute-typos.stderr +++ b/tests/ui/suggestions/attribute-typos.stderr @@ -1,14 +1,14 @@ error: attributes starting with `rustc` are reserved for use by the `rustc` compiler --> $DIR/attribute-typos.rs:7:3 | -LL | #[rustc_err] - | ^^^^^^^^^ +LL | #[rustc_dumm] + | ^^^^^^^^^^ -error: cannot find attribute `rustc_err` in this scope +error: cannot find attribute `rustc_dumm` in this scope --> $DIR/attribute-typos.rs:7:3 | -LL | #[rustc_err] - | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `rustc_error` +LL | #[rustc_dumm] + | ^^^^^^^^^^ help: a built-in attribute with a similar name exists: `rustc_dummy` error: cannot find attribute `tests` in this scope --> $DIR/attribute-typos.rs:4:3 diff --git a/tests/ui/traits/const-traits/feature-gate.gated.stderr b/tests/ui/traits/const-traits/feature-gate.gated.stderr deleted file mode 100644 index 12f9355e41d4..000000000000 --- a/tests/ui/traits/const-traits/feature-gate.gated.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/feature-gate.rs:22:1 - | -LL | fn main() {} - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/traits/const-traits/feature-gate.rs b/tests/ui/traits/const-traits/feature-gate.rs index c36ec3538c36..921dfb054e30 100644 --- a/tests/ui/traits/const-traits/feature-gate.rs +++ b/tests/ui/traits/const-traits/feature-gate.rs @@ -1,8 +1,8 @@ //@ revisions: stock gated +//@[gated] check-pass // gate-test-const_trait_impl #![cfg_attr(gated, feature(const_trait_impl))] -#![feature(rustc_attrs)] struct S; #[const_trait] //[stock]~ ERROR `const_trait` is a temporary placeholder @@ -18,5 +18,4 @@ macro_rules! discard { ($ty:ty) => {} } discard! { impl ~const T } //[stock]~ ERROR const trait impls are experimental discard! { impl const T } //[stock]~ ERROR const trait impls are experimental -#[rustc_error] -fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error] +fn main() {} diff --git a/tests/ui/treat-err-as-bug/span_delayed_bug.rs b/tests/ui/treat-err-as-bug/span_delayed_bug.rs index 296bdd7a12d9..88a9d07c94cf 100644 --- a/tests/ui/treat-err-as-bug/span_delayed_bug.rs +++ b/tests/ui/treat-err-as-bug/span_delayed_bug.rs @@ -8,5 +8,5 @@ #![feature(rustc_attrs)] -#[rustc_error(delayed_bug_from_inside_query)] +#[rustc_delayed_bug_from_inside_query] fn main() {} diff --git a/tests/ui/treat-err-as-bug/span_delayed_bug.stderr b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr index aec1b89c7666..1c8d279c14c4 100644 --- a/tests/ui/treat-err-as-bug/span_delayed_bug.stderr +++ b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr @@ -1,4 +1,4 @@ -error: internal compiler error: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)] +error: internal compiler error: delayed bug triggered by #[rustc_delayed_bug_from_inside_query] --> $DIR/span_delayed_bug.rs:12:1 | LL | fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-53096.rs b/tests/ui/type-alias-impl-trait/issue-53096.rs index c24f1bf44fab..60e455a6a07d 100644 --- a/tests/ui/type-alias-impl-trait/issue-53096.rs +++ b/tests/ui/type-alias-impl-trait/issue-53096.rs @@ -1,4 +1,5 @@ -#![feature(rustc_attrs)] +//@ check-pass + #![feature(type_alias_impl_trait)] pub type Foo = impl Fn() -> usize; @@ -8,5 +9,4 @@ pub const fn bar() -> Foo { } const BAZR: Foo = bar(); -#[rustc_error] -fn main() {} //~ ERROR +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-53096.stderr b/tests/ui/type-alias-impl-trait/issue-53096.stderr deleted file mode 100644 index 53490896af79..000000000000 --- a/tests/ui/type-alias-impl-trait/issue-53096.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/issue-53096.rs:12:1 - | -LL | fn main() {} - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/type-alias-impl-trait/issue-60407.rs b/tests/ui/type-alias-impl-trait/issue-60407.rs index 5b8ff6b74de5..53280c28ecb1 100644 --- a/tests/ui/type-alias-impl-trait/issue-60407.rs +++ b/tests/ui/type-alias-impl-trait/issue-60407.rs @@ -1,4 +1,6 @@ -#![feature(type_alias_impl_trait, rustc_attrs)] +//@ check-pass + +#![feature(type_alias_impl_trait)] pub type Debuggable = impl core::fmt::Debug; @@ -9,8 +11,6 @@ pub fn foo() -> Debuggable { static mut TEST: Option = None; -#[rustc_error] fn main() { - //~^ ERROR unsafe { TEST = Some(foo()) } } diff --git a/tests/ui/type-alias-impl-trait/issue-60407.stderr b/tests/ui/type-alias-impl-trait/issue-60407.stderr deleted file mode 100644 index f517d5b65fa2..000000000000 --- a/tests/ui/type-alias-impl-trait/issue-60407.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/issue-60407.rs:13:1 - | -LL | fn main() { - | ^^^^^^^^^ - -error: aborting due to 1 previous error - From 41fdd280ff1089d1618487d59ed49f83160d2513 Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 22 Mar 2025 16:09:37 -0400 Subject: [PATCH 445/546] rustc_resolve: Test the order that preludes are resolved --- tests/ui/resolve/auxiliary/macro_helpers.rs | 16 ++++ tests/ui/resolve/prelude-order.rs | 89 +++++++++++++++++++++ tests/ui/resolve/prelude-order.stderr | 47 +++++++++++ 3 files changed, 152 insertions(+) create mode 100644 tests/ui/resolve/auxiliary/macro_helpers.rs create mode 100644 tests/ui/resolve/prelude-order.rs create mode 100644 tests/ui/resolve/prelude-order.stderr diff --git a/tests/ui/resolve/auxiliary/macro_helpers.rs b/tests/ui/resolve/auxiliary/macro_helpers.rs new file mode 100644 index 000000000000..43aa336457de --- /dev/null +++ b/tests/ui/resolve/auxiliary/macro_helpers.rs @@ -0,0 +1,16 @@ +/* macro namespace. */ + +extern crate proc_macro; +use proc_macro::*; +use std::str::FromStr; + +const ERROR: &str = "fn helper() { \"helper\" }"; +// https://doc.rust-lang.org/nightly/std/prelude/v1/index.html#attributes +// NOTE: all the bang macros in std are currently unstable. +#[proc_macro_attribute] pub fn test // lang. + (_: TokenStream, _: TokenStream) -> TokenStream { + TokenStream::from_str("fn test_macro() { \"\" }").unwrap() } +// https://doc.rust-lang.org/nightly/reference/attributes.html#built-in-attributes-index +#[proc_macro_attribute] pub fn global_allocator // lang. + (_: TokenStream, _: TokenStream) -> TokenStream { + TokenStream::from_str("fn global_allocator_macro() { \"\" }").unwrap() } diff --git a/tests/ui/resolve/prelude-order.rs b/tests/ui/resolve/prelude-order.rs new file mode 100644 index 000000000000..a3f194270d48 --- /dev/null +++ b/tests/ui/resolve/prelude-order.rs @@ -0,0 +1,89 @@ +//@ proc-macro:macro_helpers.rs +//@ compile-flags: --crate-type=lib + +/* There are 5 preludes and 3 namespaces. Test the order in which they are resolved. + * See https://doc.rust-lang.org/nightly/reference/names/preludes.html. + * + * Macros cannot be in the type or value namespace. + * Tools and extern crates cannot be in the macro or value namespace. + * + * Test the following truth tables: + +Type: +| ...... | tool | extern | macro | lang | libs | +| tool | N/A | mirror +| extern | extern | N/A | universe +| macro | N/A | N/A | N/A | +| lang | tool | extern | N/A | N/A | +| libs | tool | extern | N/A | X | N/A | + +Macro: +| ...... | tool | extern | macro | lang | libs | +| tool | N/A | mirror +| extern | N/A | N/A | universe +| macro | N/A | N/A | N/A | +| lang | N/A | N/A | macro | N/A | +| libs | N/A | N/A | macro | X | N/A | + +Value: N/A. Only libs has items in the value namespace. + +† ambiguous +X don't care (controlled namespace with no overlap) + +* Types are tested with `#[name::inner]`. Macros are tested with `#[name]`. +* WARNING: I have found in testing that attribute macros give ambiguity errors in some contexts +* instead of choosing a prelude. Have not been able to replicate. +* +* There should be 7 total tests. +* See `rustc_resolve::ident::visit_scopes` for more information, +* and for a definition of "controlled namespace". +*/ + +#![feature(register_tool)] + +/* tool prelude */ +#![register_tool(type_ns)] // extern prelude. type. +#![register_tool(i8)] // lang prelude. type. +#![register_tool(Sync)] // libs prelude. type. + +/* extern prelude */ +extern crate macro_helpers as type_ns; // tool prelude. type. +extern crate macro_helpers as usize; // lang prelude. type. +extern crate macro_helpers as Option; // libs prelude. type. + +/* macro_use prelude */ +#[macro_use] +extern crate macro_helpers as _; + +/* lang and libs implicitly in scope */ + +// tool/extern -> extern +#[type_ns::inner] //~ ERROR could not find `inner` in `type_ns` +fn t1() {} + +// tool/lang -> tool +#[i8::inner] // ok +fn t2() {} + +// tool/libs -> tool +#[Sync::not_real] // ok +fn t3() {} + +// extern/lang -> extern +#[usize::inner] //~ ERROR could not find `inner` in `usize` +fn e1() {} // NOTE: testing with `-> usize` isn't valid, crates aren't considered in that scope + // (unless they have generic arguments, for some reason.) + +// extern/libs -> extern +// https://github.com/rust-lang/rust/issues/139095 +fn e2() -> Option { None } //~ ERROR: expected type, found crate + +// macro/libs -> macro +#[test] //~ ERROR mismatched types +fn m1() {} + +// macro/lang -> macro +#[global_allocator] //~ ERROR mismatched types +fn m2() {} + +// lang/libs: no items that currently overlap, in either macro or type ns. diff --git a/tests/ui/resolve/prelude-order.stderr b/tests/ui/resolve/prelude-order.stderr new file mode 100644 index 000000000000..1b9cc94285aa --- /dev/null +++ b/tests/ui/resolve/prelude-order.stderr @@ -0,0 +1,47 @@ +error[E0433]: failed to resolve: could not find `inner` in `type_ns` + --> $DIR/prelude-order.rs:61:12 + | +LL | #[type_ns::inner] + | ^^^^^ could not find `inner` in `type_ns` + +error[E0433]: failed to resolve: could not find `inner` in `usize` + --> $DIR/prelude-order.rs:73:10 + | +LL | #[usize::inner] + | ^^^^^ could not find `inner` in `usize` + +error[E0573]: expected type, found crate `Option` + --> $DIR/prelude-order.rs:79:12 + | +LL | fn e2() -> Option { None } + | ^^^^^^^^^^^ not a type + | +help: consider importing this enum instead + | +LL + use std::option::Option; + | + +error[E0308]: mismatched types + --> $DIR/prelude-order.rs:82:1 + | +LL | #[test] + | ^^^^^^^- help: try adding a return type: `-> &'static str` + | | + | expected `()`, found `&str` + | + = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/prelude-order.rs:86:1 + | +LL | #[global_allocator] + | ^^^^^^^^^^^^^^^^^^^- help: try adding a return type: `-> &'static str` + | | + | expected `()`, found `&str` + | + = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0308, E0433, E0573. +For more information about an error, try `rustc --explain E0308`. From 4f2baaa9c6b75d4267eea9e1096339d56d380615 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 25 Mar 2025 18:57:04 +0000 Subject: [PATCH 446/546] Do not mix normalized and unnormalized caller bounds when constructing param-env for receiver_is_dispatchable --- .../src/traits/dyn_compatibility.rs | 35 ++++++++++++------- tests/ui/associated-types/issue-59324.stderr | 30 ++++++++-------- ...-do-not-mix-normalized-and-unnormalized.rs | 26 ++++++++++++++ 3 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 tests/ui/self/dyn-dispatch-do-not-mix-normalized-and-unnormalized.rs diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 78a452439836..fa6bbf1d6e57 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -583,27 +583,36 @@ fn receiver_is_dispatchable<'tcx>( // create a modified param env, with `Self: Unsize` and `U: Trait` (and all of // its supertraits) added to caller bounds. `U: ?Sized` is already implied here. let param_env = { - let param_env = tcx.param_env(method.def_id); + // N.B. We generally want to emulate the construction of the `unnormalized_param_env` + // in the param-env query here. The fact that we don't just start with the clauses + // in the param-env of the method is because those are already normalized, and mixing + // normalized and unnormalized copies of predicates in `normalize_param_env_or_error` + // will cause ambiguity that the user can't really avoid. + // + // We leave out certain complexities of the param-env query here. Specifically, we: + // 1. Do not add `~const` bounds since there are no `dyn const Trait`s. + // 2. Do not add RPITIT self projection bounds for defaulted methods, since we + // are not constructing a param-env for "inside" of the body of the defaulted + // method, so we don't really care about projecting to a specific RPIT type, + // and because RPITITs are not dyn compatible (yet). + let mut predicates = tcx.predicates_of(method.def_id).instantiate_identity(tcx).predicates; // Self: Unsize let unsize_predicate = - ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]).upcast(tcx); + ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]); + predicates.push(unsize_predicate.upcast(tcx)); // U: Trait - let trait_predicate = { - let trait_def_id = method.trait_container(tcx).unwrap(); - let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| { - if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) } - }); - - ty::TraitRef::new_from_args(tcx, trait_def_id, args).upcast(tcx) - }; + let trait_def_id = method.trait_container(tcx).unwrap(); + let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| { + if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) } + }); + let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args); + predicates.push(trait_predicate.upcast(tcx)); normalize_param_env_or_error( tcx, - ty::ParamEnv::new(tcx.mk_clauses_from_iter( - param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]), - )), + ty::ParamEnv::new(tcx.mk_clauses(&predicates)), ObligationCause::dummy_with_span(tcx.def_span(method.def_id)), ) }; diff --git a/tests/ui/associated-types/issue-59324.stderr b/tests/ui/associated-types/issue-59324.stderr index f5e696b7ac1c..f79afc89d10f 100644 --- a/tests/ui/associated-types/issue-59324.stderr +++ b/tests/ui/associated-types/issue-59324.stderr @@ -27,21 +27,6 @@ help: consider further restricting type parameter `Bug` with trait `Foo` LL | pub trait ThriftService: | +++++ -error[E0277]: the trait bound `Bug: Foo` is not satisfied - --> $DIR/issue-59324.rs:16:5 - | -LL | / fn get_service( -LL | | -LL | | -LL | | &self, -LL | | ) -> Self::AssocType; - | |_________________________^ the trait `Foo` is not implemented for `Bug` - | -help: consider further restricting type parameter `Bug` with trait `Foo` - | -LL | pub trait ThriftService: - | +++++ - error[E0277]: the trait bound `Bug: Foo` is not satisfied --> $DIR/issue-59324.rs:16:5 | @@ -64,6 +49,21 @@ help: this trait has no implementations, consider adding one LL | pub trait Foo: NotFoo { | ^^^^^^^^^^^^^^^^^^^^^ +error[E0277]: the trait bound `Bug: Foo` is not satisfied + --> $DIR/issue-59324.rs:16:5 + | +LL | / fn get_service( +LL | | +LL | | +LL | | &self, +LL | | ) -> Self::AssocType; + | |_________________________^ the trait `Foo` is not implemented for `Bug` + | +help: consider further restricting type parameter `Bug` with trait `Foo` + | +LL | pub trait ThriftService: + | +++++ + error[E0277]: the trait bound `Bug: Foo` is not satisfied --> $DIR/issue-59324.rs:20:10 | diff --git a/tests/ui/self/dyn-dispatch-do-not-mix-normalized-and-unnormalized.rs b/tests/ui/self/dyn-dispatch-do-not-mix-normalized-and-unnormalized.rs new file mode 100644 index 000000000000..2bc70de2a340 --- /dev/null +++ b/tests/ui/self/dyn-dispatch-do-not-mix-normalized-and-unnormalized.rs @@ -0,0 +1,26 @@ +//@ check-pass + +// Regression test for . + +// Previously, we'd take the normalized param env's clauses which included +// `::Value = i32`, which comes from the supertraits of `TraitD` +// after normalizing `::Value = ::Scalar`. Since +// `normalize_param_env_or_error` ends up re-elaborating `PF: TraitD`, we'd +// end up with both versions of this predicate (normalized and unnormalized). +// Since these projections preds are not equal, we'd fail with ambiguity. + +trait TraitB {} + +trait TraitC: TraitB { + type Value; +} + +trait TraitD: TraitC { + type Scalar; +} + +trait TraitE { + fn apply>(&self); +} + +fn main() {} From cc5ee70b1a51bf30e85d261cc6e485eb3431bcac Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 30 Mar 2025 10:35:59 +0200 Subject: [PATCH 447/546] Simplify expansion for format_args!(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of calling new(), we can just use a struct expression directly. Before: Placeholder::new(…, …, …, …) After: Placeholder { position: …, flags: …, width: …, precision: …, } --- compiler/rustc_ast_lowering/src/format.rs | 28 +++++++++++------------ compiler/rustc_span/src/symbol.rs | 4 ++++ library/core/src/fmt/rt.rs | 8 +------ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 343895984ca4..0de0319c6676 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -323,14 +323,12 @@ fn make_count<'hir>( /// Generates /// /// ```text -/// ::…, // alignment -/// …u32, // flags -/// , // width -/// , // precision -/// ) +/// , +/// width: , +/// } /// ``` fn make_format_spec<'hir>( ctx: &mut LoweringContext<'_, 'hir>, @@ -384,13 +382,13 @@ fn make_format_spec<'hir>( let flags = ctx.expr_u32(sp, flags); let precision = make_count(ctx, sp, precision, argmap); let width = make_count(ctx, sp, width, argmap); - let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - sp, - hir::LangItem::FormatPlaceholder, - sym::new, - )); - let args = ctx.arena.alloc_from_iter([position, flags, precision, width]); - ctx.expr_call_mut(sp, format_placeholder_new, args) + let position = ctx.expr_field(Ident::new(sym::position, sp), ctx.arena.alloc(position), sp); + let flags = ctx.expr_field(Ident::new(sym::flags, sp), ctx.arena.alloc(flags), sp); + let precision = ctx.expr_field(Ident::new(sym::precision, sp), ctx.arena.alloc(precision), sp); + let width = ctx.expr_field(Ident::new(sym::width, sp), ctx.arena.alloc(width), sp); + let placeholder = ctx.arena.alloc(hir::QPath::LangItem(hir::LangItem::FormatPlaceholder, sp)); + let fields = ctx.arena.alloc_from_iter([position, flags, precision, width]); + ctx.expr(sp, hir::ExprKind::Struct(placeholder, fields, hir::StructTailExpr::None)) } fn expand_format_args<'hir>( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6807f96e712c..cc4c9860bc27 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -986,6 +986,7 @@ symbols! { field_init_shorthand, file, file_options, + flags, float, float_to_int_unchecked, floorf128, @@ -1570,6 +1571,7 @@ symbols! { pointer_like, poll, poll_next, + position, post_dash_lto: "post-lto", postfix_match, powerpc_target_feature, @@ -1585,6 +1587,7 @@ symbols! { precise_capturing, precise_capturing_in_traits, precise_pointer_size_matching, + precision, pref_align_of, prefetch_read_data, prefetch_read_instruction, @@ -2274,6 +2277,7 @@ symbols! { wasm_target_feature, where_clause_attrs, while_let, + width, windows, windows_subsystem, with_negative_coherence, diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index d27f7e6e0d8e..0b04ebccae2b 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -20,8 +20,8 @@ pub struct Placeholder { pub width: Count, } +#[cfg(bootstrap)] impl Placeholder { - #[cfg(bootstrap)] #[inline] pub const fn new( position: usize, @@ -33,12 +33,6 @@ impl Placeholder { ) -> Self { Self { position, fill, align, flags, precision, width } } - - #[cfg(not(bootstrap))] - #[inline] - pub const fn new(position: usize, flags: u32, precision: Count, width: Count) -> Self { - Self { position, flags, precision, width } - } } #[cfg(bootstrap)] From 31face9f6087c2914ea995af969bb995629a5e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 30 Mar 2025 11:14:33 +0200 Subject: [PATCH 448/546] Revert "Auto merge of #129827 - bvanjoi:less-decoding, r=petrochenkov" Reverting because of a performance regression. This reverts commit d4812c8638173ec163825d56a72a33589483ec4c, reversing changes made to 5cc60728e7ee10eb2ae5f61f7d412d9805b22f0c. --- compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- .../rustc_middle/src/query/on_disk_cache.rs | 10 +- compiler/rustc_middle/src/ty/parameterized.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 201 ++++++++++++------ .../nonterminal-token-hygiene.stdout | 20 +- 5 files changed, 157 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 34e4f2f26022..dc453b1e747c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -36,7 +36,7 @@ use rustc_serialize::opaque::FileEncoder; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey}; +use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; @@ -193,7 +193,7 @@ enum LazyState { Previous(NonZero), } -type SyntaxContextTable = LazyTable>>; +type SyntaxContextTable = LazyTable>>; type ExpnDataTable = LazyTable>>; type ExpnHashTable = LazyTable>>; diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index ce6219c207fd..14e3ce8bef6b 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -16,7 +16,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixed use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::Session; use rustc_span::hygiene::{ - ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextKey, + ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, }; use rustc_span::source_map::Spanned; use rustc_span::{ @@ -75,9 +75,9 @@ pub struct OnDiskCache { alloc_decoding_state: AllocDecodingState, // A map from syntax context ids to the position of their associated - // `SyntaxContextKey`. We use a `u32` instead of a `SyntaxContext` + // `SyntaxContextData`. We use a `u32` instead of a `SyntaxContext` // to represent the fact that we are storing *encoded* ids. When we decode - // a `SyntaxContextKey`, a new id will be allocated from the global `HygieneData`, + // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`, // which will almost certainly be different than the serialized id. syntax_contexts: FxHashMap, // A map from the `DefPathHash` of an `ExpnId` to the position @@ -305,7 +305,7 @@ impl OnDiskCache { let mut expn_data = UnhashMap::default(); let mut foreign_expn_data = UnhashMap::default(); - // Encode all hygiene data (`SyntaxContextKey` and `ExpnData`) from the current + // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current // session. hygiene_encode_context.encode( @@ -566,7 +566,7 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { // We look up the position of the associated `SyntaxData` and decode it. let pos = syntax_contexts.get(&id).unwrap(); this.with_position(pos.to_usize(), |decoder| { - let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); + let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); data }) }) diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 134f76d7248d..19e2b5745632 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -111,7 +111,7 @@ trivially_parameterized_over_tcx! { rustc_span::Span, rustc_span::Symbol, rustc_span::def_id::DefPathHash, - rustc_span::hygiene::SyntaxContextKey, + rustc_span::hygiene::SyntaxContextData, rustc_span::Ident, rustc_type_ir::Variance, rustc_hir::Attribute, diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index f94858856729..4390085cd049 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -24,6 +24,9 @@ // because getting it wrong can lead to nested `HygieneData::with` calls that // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) +use std::cell::RefCell; +use std::collections::hash_map::Entry; +use std::collections::hash_set::Entry as SetEntry; use std::hash::Hash; use std::sync::Arc; use std::{fmt, iter, mem}; @@ -31,7 +34,7 @@ use std::{fmt, iter, mem}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sync::{Lock, WorkerLocal}; use rustc_data_structures::unhash::UnhashMap; use rustc_hashes::Hash64; use rustc_index::IndexVec; @@ -56,10 +59,10 @@ impl !PartialOrd for SyntaxContext {} /// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal. /// The other fields are only for caching. -pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); +type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); #[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable)] -struct SyntaxContextData { +pub struct SyntaxContextData { outer_expn: ExpnId, outer_transparency: Transparency, parent: SyntaxContext, @@ -91,21 +94,6 @@ impl SyntaxContextData { self.dollar_crate_name == kw::Empty } - fn new( - (parent, outer_expn, outer_transparency): SyntaxContextKey, - opaque: SyntaxContext, - opaque_and_semitransparent: SyntaxContext, - ) -> Self { - SyntaxContextData { - parent, - outer_expn, - outer_transparency, - opaque, - opaque_and_semitransparent, - dollar_crate_name: kw::DollarCrate, - } - } - fn key(&self) -> SyntaxContextKey { (self.parent, self.outer_expn, self.outer_transparency) } @@ -586,49 +574,67 @@ impl HygieneData { fn apply_mark_internal( &mut self, - parent: SyntaxContext, + ctxt: SyntaxContext, expn_id: ExpnId, transparency: Transparency, ) -> SyntaxContext { - debug_assert!(!self.syntax_context_data[parent.0 as usize].is_decode_placeholder()); - // Look into the cache first. - let key = (parent, expn_id, transparency); - if let Some(ctxt) = self.syntax_context_map.get(&key) { - return *ctxt; + let syntax_context_data = &mut self.syntax_context_data; + debug_assert!(!syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); + let mut opaque = syntax_context_data[ctxt.0 as usize].opaque; + let mut opaque_and_semitransparent = + syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent; + + if transparency >= Transparency::Opaque { + let parent = opaque; + opaque = *self + .syntax_context_map + .entry((parent, expn_id, transparency)) + .or_insert_with(|| { + let new_opaque = SyntaxContext::from_usize(syntax_context_data.len()); + syntax_context_data.push(SyntaxContextData { + outer_expn: expn_id, + outer_transparency: transparency, + parent, + opaque: new_opaque, + opaque_and_semitransparent: new_opaque, + dollar_crate_name: kw::DollarCrate, + }); + new_opaque + }); } - // Reserve a new syntax context. - let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len()); - self.syntax_context_data.push(SyntaxContextData::decode_placeholder()); - self.syntax_context_map.insert(key, ctxt); - // Opaque and semi-transparent versions of the parent. Note that they may be equal to the - // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques, - // and `parent_opaque_and_semitransparent` == `parent` if the expn contains only opaques - // and semi-transparents. - let parent_opaque = self.syntax_context_data[parent.0 as usize].opaque; - let parent_opaque_and_semitransparent = - self.syntax_context_data[parent.0 as usize].opaque_and_semitransparent; + if transparency >= Transparency::SemiTransparent { + let parent = opaque_and_semitransparent; + opaque_and_semitransparent = *self + .syntax_context_map + .entry((parent, expn_id, transparency)) + .or_insert_with(|| { + let new_opaque_and_semitransparent = + SyntaxContext::from_usize(syntax_context_data.len()); + syntax_context_data.push(SyntaxContextData { + outer_expn: expn_id, + outer_transparency: transparency, + parent, + opaque, + opaque_and_semitransparent: new_opaque_and_semitransparent, + dollar_crate_name: kw::DollarCrate, + }); + new_opaque_and_semitransparent + }); + } - // Evaluate opaque and semi-transparent versions of the new syntax context. - let (opaque, opaque_and_semitransparent) = match transparency { - Transparency::Transparent => (parent_opaque, parent_opaque_and_semitransparent), - Transparency::SemiTransparent => ( - parent_opaque, - // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. - self.apply_mark_internal(parent_opaque_and_semitransparent, expn_id, transparency), - ), - Transparency::Opaque => ( - // Will be the same as `ctxt` if the expn chain contains only opaques. - self.apply_mark_internal(parent_opaque, expn_id, transparency), - // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. - self.apply_mark_internal(parent_opaque_and_semitransparent, expn_id, transparency), - ), - }; - - // Fill the full data, now that we have it. - self.syntax_context_data[ctxt.as_u32() as usize] = - SyntaxContextData::new(key, opaque, opaque_and_semitransparent); - ctxt + let parent = ctxt; + *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| { + syntax_context_data.push(SyntaxContextData { + outer_expn: expn_id, + outer_transparency: transparency, + parent, + opaque, + opaque_and_semitransparent, + dollar_crate_name: kw::DollarCrate, + }); + SyntaxContext::from_usize(syntax_context_data.len() - 1) + }) } } @@ -1259,7 +1265,7 @@ impl HygieneEncodeContext { pub fn encode( &self, encoder: &mut T, - mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey), + mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData), mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash), ) { // When we serialize a `SyntaxContextData`, we may end up serializing @@ -1317,6 +1323,9 @@ struct HygieneDecodeContextInner { /// Additional information used to assist in decoding hygiene data pub struct HygieneDecodeContext { inner: Lock, + + /// A set of serialized `SyntaxContext` ids that are currently being decoded on each thread. + local_in_progress: WorkerLocal>>, } /// Register an expansion which has been decoded from the on-disk-cache for the local crate. @@ -1387,10 +1396,10 @@ pub fn decode_expn_id( // to track which `SyntaxContext`s we have already decoded. // The provided closure will be invoked to deserialize a `SyntaxContextData` // if we haven't already seen the id of the `SyntaxContext` we are deserializing. -pub fn decode_syntax_context SyntaxContextKey>( +pub fn decode_syntax_context SyntaxContextData>( d: &mut D, context: &HygieneDecodeContext, - decode_ctxt_key: F, + decode_data: F, ) -> SyntaxContext { let raw_id: u32 = Decodable::decode(d); if raw_id == 0 { @@ -1399,9 +1408,58 @@ pub fn decode_syntax_context SyntaxContext return SyntaxContext::root(); } + let pending_ctxt = { + let mut inner = context.inner.lock(); + + // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between + // raw ids from different crate metadatas. + if let Some(ctxt) = inner.remapped_ctxts.get(raw_id as usize).copied().flatten() { + // This has already been decoded. + return ctxt; + } + + match inner.decoding.entry(raw_id) { + Entry::Occupied(ctxt_entry) => { + let pending_ctxt = *ctxt_entry.get(); + match context.local_in_progress.borrow_mut().entry(raw_id) { + // We're decoding this already on the current thread. Return here and let the + // function higher up the stack finish decoding to handle recursive cases. + // Hopefully having a `SyntaxContext` that refers to an incorrect data is ok + // during reminder of the decoding process, it's certainly not ok after the + // top level decoding function returns. + SetEntry::Occupied(..) => return pending_ctxt, + // Some other thread is currently decoding this. + // Race with it (alternatively we could wait here). + // We cannot return this value, unlike in the recursive case above, because it + // may expose a `SyntaxContext` pointing to incorrect data to arbitrary code. + SetEntry::Vacant(entry) => { + entry.insert(); + pending_ctxt + } + } + } + Entry::Vacant(entry) => { + // We are the first thread to start decoding. Mark the current thread as being progress. + context.local_in_progress.borrow_mut().insert(raw_id); + + // Allocate and store SyntaxContext id *before* calling the decoder function, + // as the SyntaxContextData may reference itself. + let new_ctxt = HygieneData::with(|hygiene_data| { + // Push a dummy SyntaxContextData to ensure that nobody else can get the + // same ID as us. This will be overwritten after call `decode_data`. + hygiene_data.syntax_context_data.push(SyntaxContextData::decode_placeholder()); + SyntaxContext::from_usize(hygiene_data.syntax_context_data.len() - 1) + }); + entry.insert(new_ctxt); + new_ctxt + } + } + }; + // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let ctxt_key = decode_ctxt_key(d, raw_id); + let ctxt_data = decode_data(d, raw_id); + let ctxt_key = ctxt_data.key(); let ctxt = HygieneData::with(|hygiene_data| { match hygiene_data.syntax_context_map.get(&ctxt_key) { @@ -1415,10 +1473,29 @@ pub fn decode_syntax_context SyntaxContext Some(&ctxt) => ctxt, // This is a completely new context. // Overwrite its placeholder data with our decoded data. - None => hygiene_data.apply_mark_internal(ctxt_key.0, ctxt_key.1, ctxt_key.2), + None => { + let ctxt_data_ref = + &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize]; + let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data); + // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`. + // We don't care what the encoding crate set this to - we want to resolve it + // from the perspective of the current compilation session. + ctxt_data_ref.dollar_crate_name = kw::DollarCrate; + // Make sure nothing weird happened while `decode_data` was running. + if !prev_ctxt_data.is_decode_placeholder() { + // Another thread may have already inserted the decoded data, + // but the decoded data should match. + assert_eq!(prev_ctxt_data, *ctxt_data_ref); + } + hygiene_data.syntax_context_map.insert(ctxt_key, pending_ctxt); + pending_ctxt + } } }); + // Mark the context as completed + context.local_in_progress.borrow_mut().remove(&raw_id); + let mut inner = context.inner.lock(); let new_len = raw_id as usize + 1; if inner.remapped_ctxts.len() < new_len { @@ -1430,7 +1507,7 @@ pub fn decode_syntax_context SyntaxContext ctxt } -fn for_all_ctxts_in( +fn for_all_ctxts_in( ctxts: impl Iterator, mut f: F, ) { @@ -1438,7 +1515,7 @@ fn for_all_ctxts_in( ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect() }); for (ctxt, data) in all_data.into_iter() { - f(ctxt.0, ctxt, &data.key()); + f(ctxt.0, ctxt, &data); } } diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 6fd6cb474693..c80a33206fb4 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -5,19 +5,19 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "struct", - span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#5), + span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#4), }, Ident { ident: "S", - span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#5), + span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#5), + span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#4), }, ], - span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#4), + span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#5), }, ] #![feature /* 0#0 */(prelude_import)] @@ -59,7 +59,7 @@ macro_rules! outer struct S /* 0#0 */; macro inner /* 0#3 */ { () => { print_bang! { struct S; } } } -struct S /* 0#5 */; +struct S /* 0#4 */; // OK, not a duplicate definition of `S` fn main /* 0#0 */() {} @@ -70,7 +70,7 @@ crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") -crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") @@ -83,9 +83,9 @@ SyntaxContexts: #1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) #2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) #3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) -#4: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) -#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) +#4: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) +#5: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) #6: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) -#7: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent) -#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) +#7: parent: #5, outer_mark: (crate0::{{expn4}}, Transparent) +#8: parent: #4, outer_mark: (crate0::{{expn4}}, SemiTransparent) */ From d035ca7db384e125d1a5110cefb3872386fa692f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 30 Mar 2025 11:19:07 +0200 Subject: [PATCH 449/546] Improve hir_pretty for struct expressions. Before: let a = StructWithSomeFields{ field_1: 1, field_2: 2, field_3: 3, field_4: 4, field_5: 5, field_6: 6,}; let a = StructWithSomeFields{ field_1: 1, field_2: 2, ..a}; After: let a = StructWithSomeFields { field_1: 1, field_2: 2, field_3: 3, field_4: 4, field_5: 5, field_6: 6 }; let a = StructWithSomeFields { field_1: 1, field_2: 2, ..a }; --- compiler/rustc_hir_pretty/src/lib.rs | 14 ++++---------- tests/pretty/hir-lifetimes.pp | 6 +++--- tests/pretty/hir-struct-expr.pp | 28 ++++++++++++++++++++++++++++ tests/pretty/hir-struct-expr.rs | 24 ++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 tests/pretty/hir-struct-expr.pp create mode 100644 tests/pretty/hir-struct-expr.rs diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ddaca89ccf82..1c23761b2e5b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1193,7 +1193,8 @@ impl<'a> State<'a> { wth: hir::StructTailExpr<'_>, ) { self.print_qpath(qpath, true); - self.word("{"); + self.nbsp(); + self.word_space("{"); self.commasep_cmnt(Consistent, fields, |s, field| s.print_expr_field(field), |f| f.span); match wth { hir::StructTailExpr::Base(expr) => { @@ -1215,20 +1216,13 @@ impl<'a> State<'a> { self.word(".."); self.end(); } - hir::StructTailExpr::None => { - if !fields.is_empty() { - self.word(","); - } - } + hir::StructTailExpr::None => {} } - + self.space(); self.word("}"); } fn print_expr_field(&mut self, field: &hir::ExprField<'_>) { - if self.attrs(field.hir_id).is_empty() { - self.space(); - } self.cbox(INDENT_UNIT); self.print_attrs_as_outer(self.attrs(field.hir_id)); if !field.is_shorthand { diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp index e545b0c8f576..4d1ab9d383bf 100644 --- a/tests/pretty/hir-lifetimes.pp +++ b/tests/pretty/hir-lifetimes.pp @@ -30,10 +30,10 @@ impl Foo<'_> { // FIXME: impl Traits printed as just `/*impl Trait*/`, ugh fn iter1<'a>(&self) - -> /*impl Trait*/ { #[lang = "Range"]{ start: 0, end: 1,} } + -> /*impl Trait*/ { #[lang = "Range"] { start: 0, end: 1 } } fn iter2(&self) - -> /*impl Trait*/ { #[lang = "Range"]{ start: 0, end: 1,} } + -> /*impl Trait*/ { #[lang = "Range"] { start: 0, end: 1 } } } fn a(x: Foo<'_>) { } @@ -82,7 +82,7 @@ struct St<'a> { x: &'a u32, } -fn f() { { let _ = St{ x: &0,}; }; { let _ = St{ x: &0,}; }; } +fn f() { { let _ = St { x: &0 }; }; { let _ = St { x: &0 }; }; } struct Name<'a>(&'a str); diff --git a/tests/pretty/hir-struct-expr.pp b/tests/pretty/hir-struct-expr.pp new file mode 100644 index 000000000000..f85d17542dff --- /dev/null +++ b/tests/pretty/hir-struct-expr.pp @@ -0,0 +1,28 @@ +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-struct-expr.pp + +struct StructWithSomeFields { + field_1: i32, + field_2: i32, + field_3: i32, + field_4: i32, + field_5: i32, + field_6: i32, +} + +fn main() { + let a = + StructWithSomeFields { + field_1: 1, + field_2: 2, + field_3: 3, + field_4: 4, + field_5: 5, + field_6: 6 }; + let a = StructWithSomeFields { field_1: 1, field_2: 2, ..a }; +} diff --git a/tests/pretty/hir-struct-expr.rs b/tests/pretty/hir-struct-expr.rs new file mode 100644 index 000000000000..9580f5d557d3 --- /dev/null +++ b/tests/pretty/hir-struct-expr.rs @@ -0,0 +1,24 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-struct-expr.pp + +struct StructWithSomeFields { + field_1: i32, + field_2: i32, + field_3: i32, + field_4: i32, + field_5: i32, + field_6: i32, +} + +fn main() { + let a = StructWithSomeFields { + field_1: 1, + field_2: 2, + field_3: 3, + field_4: 4, + field_5: 5, + field_6: 6, + }; + let a = StructWithSomeFields { field_1: 1, field_2: 2, ..a }; +} From db576c13607401e686181d428de61136011f4551 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 9 Mar 2025 13:52:03 +0100 Subject: [PATCH 450/546] Expose `peel_casts` method as an util method inside `rustc_lint` --- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/reference_casting.rs | 44 +--------------- compiler/rustc_lint/src/utils.rs | 55 ++++++++++++++++++++ 3 files changed, 57 insertions(+), 43 deletions(-) create mode 100644 compiler/rustc_lint/src/utils.rs diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c38a75400181..f6e624554567 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -80,6 +80,7 @@ mod types; mod unit_bindings; mod unqualified_local_imports; mod unused; +mod utils; use async_closures::AsyncClosureUsage; use async_fn_in_trait::AsyncFnInTrait; diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 7c6656f91c99..1d4d380cb685 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -6,6 +6,7 @@ use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; use crate::lints::InvalidReferenceCastingDiag; +use crate::utils::peel_casts; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { @@ -235,46 +236,3 @@ fn is_cast_to_bigger_memory_layout<'tcx>( None } } - -fn peel_casts<'tcx>(cx: &LateContext<'tcx>, mut e: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, bool) { - let mut gone_trough_unsafe_cell_raw_get = false; - - loop { - e = e.peel_blocks(); - // as ... - e = if let ExprKind::Cast(expr, _) = e.kind { - expr - // .cast(), .cast_mut() or .cast_const() - } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind - && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) - && matches!( - cx.tcx.get_diagnostic_name(def_id), - Some(sym::ptr_cast | sym::const_ptr_cast | sym::ptr_cast_mut | sym::ptr_cast_const) - ) - { - expr - // ptr::from_ref(), UnsafeCell::raw_get() or mem::transmute<_, _>() - } else if let ExprKind::Call(path, [arg]) = e.kind - && let ExprKind::Path(ref qpath) = path.kind - && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() - && matches!( - cx.tcx.get_diagnostic_name(def_id), - Some(sym::ptr_from_ref | sym::unsafe_cell_raw_get | sym::transmute) - ) - { - if cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) { - gone_trough_unsafe_cell_raw_get = true; - } - arg - } else { - let init = cx.expr_or_init(e); - if init.hir_id != e.hir_id { - init - } else { - break; - } - }; - } - - (e, gone_trough_unsafe_cell_raw_get) -} diff --git a/compiler/rustc_lint/src/utils.rs b/compiler/rustc_lint/src/utils.rs new file mode 100644 index 000000000000..64bfa428ae43 --- /dev/null +++ b/compiler/rustc_lint/src/utils.rs @@ -0,0 +1,55 @@ +use rustc_hir::{Expr, ExprKind}; +use rustc_span::sym; + +use crate::LateContext; + +/// Given an expression, peel all of casts (` as ...`, `.cast{,_mut,_const}()`, +/// `ptr::from_ref()`, ...) and init expressions. +/// +/// Returns the outermost expression and a boolean representing if one of the casts was +/// `UnsafeCell::raw_get()` +pub(crate) fn peel_casts<'tcx>( + cx: &LateContext<'tcx>, + mut e: &'tcx Expr<'tcx>, +) -> (&'tcx Expr<'tcx>, bool) { + let mut gone_trough_unsafe_cell_raw_get = false; + + loop { + e = e.peel_blocks(); + // as ... + e = if let ExprKind::Cast(expr, _) = e.kind { + expr + // .cast(), .cast_mut() or .cast_const() + } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind + && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_cast | sym::const_ptr_cast | sym::ptr_cast_mut | sym::ptr_cast_const) + ) + { + expr + // ptr::from_ref(), UnsafeCell::raw_get() or mem::transmute<_, _>() + } else if let ExprKind::Call(path, [arg]) = e.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_from_ref | sym::unsafe_cell_raw_get | sym::transmute) + ) + { + if cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) { + gone_trough_unsafe_cell_raw_get = true; + } + arg + } else { + let init = cx.expr_or_init(e); + if init.hir_id != e.hir_id { + init + } else { + break; + } + }; + } + + (e, gone_trough_unsafe_cell_raw_get) +} From a20d2ef0d9f10d65080216e7e7a1ace57ee210e8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 9 Mar 2025 13:40:03 +0100 Subject: [PATCH 451/546] Improve explicitness of the impl of the `useless_ptr_null_checks` lint --- compiler/rustc_lint/messages.ftl | 18 +++++++++--------- compiler/rustc_lint/src/lints.rs | 10 +++++----- compiler/rustc_lint/src/ptr_nulls.rs | 24 ++++++++++++------------ 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d51865810b9a..01e6a819cf38 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -680,15 +680,6 @@ lint_private_extern_crate_reexport = extern crate `{$ident}` is private and cann lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope .label = names from parent modules are not accessible without an explicit import -lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false - .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value - .label = expression has type `{$orig_ty}` - -lint_ptr_null_checks_fn_ret = returned pointer of `{$fn_name}` call is never null, so checking it for null will always return false - -lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false - .label = expression has type `{$orig_ty}` - lint_query_instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale @@ -978,6 +969,15 @@ lint_unused_result = unused result of type `{$ty}` lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result +lint_useless_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false + .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value + .label = expression has type `{$orig_ty}` + +lint_useless_ptr_null_checks_fn_ret = returned pointer of `{$fn_name}` call is never null, so checking it for null will always return false + +lint_useless_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false + .label = expression has type `{$orig_ty}` + lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type lint_variant_size_differences = diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 005863095729..774665e93c42 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -591,21 +591,21 @@ pub(crate) struct ExpectationNote { // ptr_nulls.rs #[derive(LintDiagnostic)] -pub(crate) enum PtrNullChecksDiag<'a> { - #[diag(lint_ptr_null_checks_fn_ptr)] - #[help(lint_help)] +pub(crate) enum UselessPtrNullChecksDiag<'a> { + #[diag(lint_useless_ptr_null_checks_fn_ptr)] + #[help] FnPtr { orig_ty: Ty<'a>, #[label] label: Span, }, - #[diag(lint_ptr_null_checks_ref)] + #[diag(lint_useless_ptr_null_checks_ref)] Ref { orig_ty: Ty<'a>, #[label] label: Span, }, - #[diag(lint_ptr_null_checks_fn_ret)] + #[diag(lint_useless_ptr_null_checks_fn_ret)] FnRet { fn_name: Ident }, } diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 1489f9de8199..9ace3a689ad9 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -3,7 +3,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; -use crate::lints::PtrNullChecksDiag; +use crate::lints::UselessPtrNullChecksDiag; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { @@ -38,10 +38,10 @@ declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]); /// a fn ptr, a reference, or a function call whose definition is /// annotated with `#![rustc_never_returns_null_ptr]`. /// If this situation is present, the function returns the appropriate diagnostic. -fn incorrect_check<'a, 'tcx: 'a>( +fn useless_check<'a, 'tcx: 'a>( cx: &'a LateContext<'tcx>, mut e: &'a Expr<'a>, -) -> Option> { +) -> Option> { let mut had_at_least_one_cast = false; loop { e = e.peel_blocks(); @@ -50,14 +50,14 @@ fn incorrect_check<'a, 'tcx: 'a>( && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { - return Some(PtrNullChecksDiag::FnRet { fn_name }); + return Some(UselessPtrNullChecksDiag::FnRet { fn_name }); } else if let ExprKind::Call(path, _args) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { - return Some(PtrNullChecksDiag::FnRet { fn_name }); + return Some(UselessPtrNullChecksDiag::FnRet { fn_name }); } e = if let ExprKind::Cast(expr, t) = e.kind && let TyKind::Ptr(_) = t.kind @@ -73,9 +73,9 @@ fn incorrect_check<'a, 'tcx: 'a>( } else if had_at_least_one_cast { let orig_ty = cx.typeck_results().expr_ty(e); return if orig_ty.is_fn() { - Some(PtrNullChecksDiag::FnPtr { orig_ty, label: e.span }) + Some(UselessPtrNullChecksDiag::FnPtr { orig_ty, label: e.span }) } else if orig_ty.is_ref() { - Some(PtrNullChecksDiag::Ref { orig_ty, label: e.span }) + Some(UselessPtrNullChecksDiag::Ref { orig_ty, label: e.span }) } else { None }; @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_const_is_null | sym::ptr_is_null) ) - && let Some(diag) = incorrect_check(cx, arg) => + && let Some(diag) = useless_check(cx, arg) => { cx.emit_span_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } @@ -110,18 +110,18 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_const_is_null | sym::ptr_is_null) ) - && let Some(diag) = incorrect_check(cx, receiver) => + && let Some(diag) = useless_check(cx, receiver) => { cx.emit_span_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => { let to_check: &Expr<'_>; - let diag: PtrNullChecksDiag<'_>; - if let Some(ddiag) = incorrect_check(cx, left) { + let diag: UselessPtrNullChecksDiag<'_>; + if let Some(ddiag) = useless_check(cx, left) { to_check = right; diag = ddiag; - } else if let Some(ddiag) = incorrect_check(cx, right) { + } else if let Some(ddiag) = useless_check(cx, right) { to_check = left; diag = ddiag; } else { From b1bc7255bb16f2500d5bdcbc17c06c2acd91c7f0 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 30 Mar 2025 15:25:27 +0200 Subject: [PATCH 452/546] Delete unreacheable `#[rustc_on_unimplemented]` --- library/alloc/src/vec/mod.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 3782f9e95194..633ef717e04d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3360,10 +3360,6 @@ impl Hash for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( - message = "vector indices are of type `usize` or ranges of `usize`", - label = "vector indices are of type `usize` or ranges of `usize`" -)] impl, A: Allocator> Index for Vec { type Output = I::Output; @@ -3374,10 +3370,6 @@ impl, A: Allocator> Index for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( - message = "vector indices are of type `usize` or ranges of `usize`", - label = "vector indices are of type `usize` or ranges of `usize`" -)] impl, A: Allocator> IndexMut for Vec { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { From 41bee761bb81888c09c0567377abdcacf564f6b9 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 30 Mar 2025 15:25:47 +0200 Subject: [PATCH 453/546] use `diagnostic::on_unimplemented` instead --- library/core/src/iter/traits/accum.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 5b7d95c2f65e..12e2b8b393a8 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -10,7 +10,7 @@ use crate::num::Wrapping; /// [`sum()`]: Iterator::sum /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "a value of type `{Self}` cannot be made by summing an iterator over elements of type `{A}`", label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator`" )] @@ -31,7 +31,7 @@ pub trait Sum: Sized { /// [`product()`]: Iterator::product /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "a value of type `{Self}` cannot be made by multiplying all elements of type `{A}` from an iterator", label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator`" )] From 66b1f3ba0c9bbd40e671078a320c6d99f415a055 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Mar 2025 14:42:17 +0000 Subject: [PATCH 454/546] Rustup to rustc 1.88.0-nightly (1799887bb 2025-03-29) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index ab650c05d357..ceff15b1180a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-25" +channel = "nightly-2025-03-30" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From ba315abda789c9f59f2100102232bddb30b0d3d3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Mar 2025 15:01:39 +0000 Subject: [PATCH 455/546] Fix rustc test suite --- scripts/test_rustc_tests.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 5e96210d8589..95a4302b5e47 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -27,7 +27,6 @@ done git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed git checkout -- tests/ui/proc-macro/pretty-print-hack/ git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs -rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR # missing features # ================ @@ -136,7 +135,6 @@ rm -r tests/run-make/incr-add-rust-src-component # ============ rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort -rm tests/ui/deprecation/deprecated_inline_threshold.rs # missing deprecation warning for -Cinline-threshold # bugs in the test suite # ====================== From 08f6747ac7428dcbc1e35732eac120d2659669b0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Mar 2025 15:48:52 +0000 Subject: [PATCH 456/546] Update tidy exceptions --- src/tools/tidy/src/deps.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 1a6550691ee3..603653847e31 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -181,6 +181,8 @@ const EXCEPTIONS_RUSTBOOK: ExceptionList = &[ const EXCEPTIONS_CRANELIFT: ExceptionList = &[ // tidy-alphabetical-start + ("cranelift-assembler-x64", "Apache-2.0 WITH LLVM-exception"), + ("cranelift-assembler-x64-meta", "Apache-2.0 WITH LLVM-exception"), ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"), ("cranelift-bitset", "Apache-2.0 WITH LLVM-exception"), ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"), @@ -512,6 +514,8 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "bitflags", "bumpalo", "cfg-if", + "cranelift-assembler-x64", + "cranelift-assembler-x64-meta", "cranelift-bforest", "cranelift-bitset", "cranelift-codegen", From 96a2f698444144efe2cb359102ca15a48d66ad6b Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 9 Mar 2025 14:38:16 +0100 Subject: [PATCH 457/546] Uplift `clippy::invalid_null_ptr_usage` as `invalid_null_arguments` --- compiler/rustc_lint/messages.ftl | 4 + compiler/rustc_lint/src/lints.rs | 16 ++ compiler/rustc_lint/src/ptr_nulls.rs | 106 +++++++- compiler/rustc_lint/src/utils.rs | 2 +- tests/ui/lint/invalid_null_args.rs | 136 ++++++++++ tests/ui/lint/invalid_null_args.stderr | 330 +++++++++++++++++++++++++ 6 files changed, 590 insertions(+), 4 deletions(-) create mode 100644 tests/ui/lint/invalid_null_args.rs create mode 100644 tests/ui/lint/invalid_null_args.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 01e6a819cf38..f45caf96f9b6 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -456,6 +456,10 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable +lint_invalid_null_arguments = calling this function with a null pointer is undefined behavior, even if the result of the function is unused + .origin = null pointer originates from here + .doc = for more information, visit and + lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell` .label = casting happened here diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 774665e93c42..4de998c08747 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -609,6 +609,22 @@ pub(crate) enum UselessPtrNullChecksDiag<'a> { FnRet { fn_name: Ident }, } +#[derive(LintDiagnostic)] +pub(crate) enum InvalidNullArgumentsDiag { + #[diag(lint_invalid_null_arguments)] + #[help(lint_doc)] + NullPtrInline { + #[label(lint_origin)] + null_span: Span, + }, + #[diag(lint_invalid_null_arguments)] + #[help(lint_doc)] + NullPtrThroughBinding { + #[note(lint_origin)] + null_span: Span, + }, +} + // for_loops_over_fallibles.rs #[derive(LintDiagnostic)] #[diag(lint_for_loops_over_fallibles)] diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 9ace3a689ad9..826bce2c3150 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -1,9 +1,11 @@ use rustc_ast::LitKind; use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind}; +use rustc_middle::ty::RawPtr; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::sym; +use rustc_span::{Span, sym}; -use crate::lints::UselessPtrNullChecksDiag; +use crate::lints::{InvalidNullArgumentsDiag, UselessPtrNullChecksDiag}; +use crate::utils::peel_casts; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { @@ -31,7 +33,30 @@ declare_lint! { "useless checking of non-null-typed pointer" } -declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]); +declare_lint! { + /// The `invalid_null_arguments` lint checks for invalid usage of null pointers in arguments. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # use std::{slice, ptr}; + /// // Undefined behavior + /// # let _slice: &[u8] = + /// unsafe { slice::from_raw_parts(ptr::null(), 0) }; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling methods whos safety invariants requires non-null ptr with a null pointer + /// is [Undefined Behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)! + INVALID_NULL_ARGUMENTS, + Deny, + "invalid null pointer in arguments" +} + +declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS, INVALID_NULL_ARGUMENTS]); /// This function checks if the expression is from a series of consecutive casts, /// ie. `(my_fn as *const _ as *mut _).cast_mut()` and whether the original expression is either @@ -85,6 +110,25 @@ fn useless_check<'a, 'tcx: 'a>( } } +/// Checks if the given expression is a null pointer (modulo casting) +fn is_null_ptr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { + let (expr, _) = peel_casts(cx, expr); + + if let ExprKind::Call(path, []) = expr.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) + { + (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut).then_some(expr.span) + } else if let ExprKind::Lit(spanned) = expr.kind + && let LitKind::Int(v, _) = spanned.node + { + (v == 0).then_some(expr.span) + } else { + None + } +} + impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { match expr.kind { @@ -102,6 +146,62 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { cx.emit_span_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) } + // Catching: + // (arg...) where `arg` is null-ptr and `path` is a fn that expect non-null-ptr + ExprKind::Call(path, args) + if let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(diag_name) = cx.tcx.get_diagnostic_name(def_id) => + { + // `arg` positions where null would cause U.B and whenever ZST are allowed. + // + // We should probably have a `rustc` attribute, but checking them is costly, + // maybe if we checked for null ptr first, it would be acceptable? + let (arg_indices, are_zsts_allowed): (&[_], _) = match diag_name { + sym::ptr_read + | sym::ptr_read_unaligned + | sym::ptr_read_volatile + | sym::ptr_replace + | sym::ptr_write + | sym::ptr_write_bytes + | sym::ptr_write_unaligned + | sym::ptr_write_volatile => (&[0], true), + sym::slice_from_raw_parts | sym::slice_from_raw_parts_mut => (&[0], false), + sym::ptr_copy + | sym::ptr_copy_nonoverlapping + | sym::ptr_swap + | sym::ptr_swap_nonoverlapping => (&[0, 1], true), + _ => return, + }; + + for &arg_idx in arg_indices { + if let Some(arg) = args.get(arg_idx) + && let Some(null_span) = is_null_ptr(cx, arg) + && let Some(ty) = cx.typeck_results().expr_ty_opt(arg) + && let RawPtr(ty, _mutbl) = ty.kind() + { + // If ZST are fine, don't lint on them + let typing_env = cx.typing_env(); + if are_zsts_allowed + && cx + .tcx + .layout_of(typing_env.as_query_input(*ty)) + .is_ok_and(|layout| layout.is_1zst()) + { + break; + } + + let diag = if arg.span.contains(null_span) { + InvalidNullArgumentsDiag::NullPtrInline { null_span } + } else { + InvalidNullArgumentsDiag::NullPtrThroughBinding { null_span } + }; + + cx.emit_span_lint(INVALID_NULL_ARGUMENTS, expr.span, diag) + } + } + } + // Catching: // (fn_ptr as * ).is_null() ExprKind::MethodCall(_, receiver, _, _) diff --git a/compiler/rustc_lint/src/utils.rs b/compiler/rustc_lint/src/utils.rs index 64bfa428ae43..a7295d9c5326 100644 --- a/compiler/rustc_lint/src/utils.rs +++ b/compiler/rustc_lint/src/utils.rs @@ -6,7 +6,7 @@ use crate::LateContext; /// Given an expression, peel all of casts (` as ...`, `.cast{,_mut,_const}()`, /// `ptr::from_ref()`, ...) and init expressions. /// -/// Returns the outermost expression and a boolean representing if one of the casts was +/// Returns the innermost expression and a boolean representing if one of the casts was /// `UnsafeCell::raw_get()` pub(crate) fn peel_casts<'tcx>( cx: &LateContext<'tcx>, diff --git a/tests/ui/lint/invalid_null_args.rs b/tests/ui/lint/invalid_null_args.rs new file mode 100644 index 000000000000..7948f0d86d09 --- /dev/null +++ b/tests/ui/lint/invalid_null_args.rs @@ -0,0 +1,136 @@ +// check-fail +// run-rustfix + +use std::ptr; +use std::mem; + +unsafe fn null_ptr() { + ptr::write( + //~^ ERROR calling this function with a null pointer is undefined behavior + ptr::null_mut() as *mut u32, + mem::transmute::<[u8; 4], _>([0, 0, 0, 255]), + ); + + let null_ptr = ptr::null_mut(); + ptr::write( + //~^ ERROR calling this function with a null pointer is undefined behavior + null_ptr as *mut u32, + mem::transmute::<[u8; 4], _>([0, 0, 0, 255]), + ); + + let _: &[usize] = std::slice::from_raw_parts(ptr::null(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + let _: &[usize] = std::slice::from_raw_parts(ptr::null_mut(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + let _: &[usize] = std::slice::from_raw_parts(0 as *mut _, 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + let _: &[usize] = std::slice::from_raw_parts(mem::transmute(0usize), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + + let _: &[usize] = std::slice::from_raw_parts_mut(ptr::null_mut(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::copy::(ptr::null(), ptr::NonNull::dangling().as_ptr(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + ptr::copy::(ptr::NonNull::dangling().as_ptr(), ptr::null_mut(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::copy_nonoverlapping::(ptr::null(), ptr::NonNull::dangling().as_ptr(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + ptr::copy_nonoverlapping::( + //~^ ERROR calling this function with a null pointer is undefined behavior + ptr::NonNull::dangling().as_ptr(), + ptr::null_mut(), + 0 + ); + + #[derive(Copy, Clone)] + struct A(usize); + let mut v = A(200); + + let _a: A = ptr::read(ptr::null()); + //~^ ERROR calling this function with a null pointer is undefined behavior + let _a: A = ptr::read(ptr::null_mut()); + //~^ ERROR calling this function with a null pointer is undefined behavior + + let _a: A = ptr::read_unaligned(ptr::null()); + //~^ ERROR calling this function with a null pointer is undefined behavior + let _a: A = ptr::read_unaligned(ptr::null_mut()); + //~^ ERROR calling this function with a null pointer is undefined behavior + + let _a: A = ptr::read_volatile(ptr::null()); + //~^ ERROR calling this function with a null pointer is undefined behavior + let _a: A = ptr::read_volatile(ptr::null_mut()); + //~^ ERROR calling this function with a null pointer is undefined behavior + + let _a: A = ptr::replace(ptr::null_mut(), v); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::swap::(ptr::null_mut(), &mut v); + //~^ ERROR calling this function with a null pointer is undefined behavior + ptr::swap::(&mut v, ptr::null_mut()); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::swap_nonoverlapping::(ptr::null_mut(), &mut v, 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + ptr::swap_nonoverlapping::(&mut v, ptr::null_mut(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::write(ptr::null_mut(), v); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::write_unaligned(ptr::null_mut(), v); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::write_volatile(ptr::null_mut(), v); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::write_bytes::(ptr::null_mut(), 42, 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + + // with indirections + let const_ptr = null_ptr as *const u8; + let _a: u8 = ptr::read(const_ptr); + //~^ ERROR calling this function with a null pointer is undefined behavior +} + +unsafe fn zst() { + struct Zst; // zero-sized type + + std::slice::from_raw_parts::<()>(ptr::null(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + std::slice::from_raw_parts::(ptr::null(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + std::slice::from_raw_parts_mut::<()>(ptr::null_mut(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + std::slice::from_raw_parts_mut::(ptr::null_mut(), 0); + //~^ ERROR calling this function with a null pointer is undefined behavior + + ptr::read::<()>(ptr::null()); + ptr::read::(ptr::null()); + + ptr::write(ptr::null_mut(), ()); + ptr::write(ptr::null_mut(), Zst); + + ptr::copy(ptr::null::<()>(), ptr::null_mut::<()>(), 1); + ptr::copy(ptr::null::(), ptr::null_mut::(), 1); +} + +unsafe fn not_invalid() { + // Simplified false-positive from std quicksort implementation + + let mut a = ptr::null_mut(); + let mut b = (); + + loop { + if false { + break; + } + + a = &raw mut b; + } + + ptr::write(a, ()); +} + +fn main() {} diff --git a/tests/ui/lint/invalid_null_args.stderr b/tests/ui/lint/invalid_null_args.stderr new file mode 100644 index 000000000000..f95bc2afa829 --- /dev/null +++ b/tests/ui/lint/invalid_null_args.stderr @@ -0,0 +1,330 @@ +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:8:5 + | +LL | / ptr::write( +LL | | +LL | | ptr::null_mut() as *mut u32, + | | --------------- null pointer originates from here +LL | | mem::transmute::<[u8; 4], _>([0, 0, 0, 255]), +LL | | ); + | |_____^ + | + = help: for more information, visit and + = note: `#[deny(invalid_null_arguments)]` on by default + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:15:5 + | +LL | / ptr::write( +LL | | +LL | | null_ptr as *mut u32, +LL | | mem::transmute::<[u8; 4], _>([0, 0, 0, 255]), +LL | | ); + | |_____^ + | + = help: for more information, visit and +note: null pointer originates from here + --> $DIR/invalid_null_args.rs:14:20 + | +LL | let null_ptr = ptr::null_mut(); + | ^^^^^^^^^^^^^^^ + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:21:23 + | +LL | let _: &[usize] = std::slice::from_raw_parts(ptr::null(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:23:23 + | +LL | let _: &[usize] = std::slice::from_raw_parts(ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:25:23 + | +LL | let _: &[usize] = std::slice::from_raw_parts(0 as *mut _, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:27:23 + | +LL | let _: &[usize] = std::slice::from_raw_parts(mem::transmute(0usize), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:30:23 + | +LL | let _: &[usize] = std::slice::from_raw_parts_mut(ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:33:5 + | +LL | ptr::copy::(ptr::null(), ptr::NonNull::dangling().as_ptr(), 0); + | ^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:35:5 + | +LL | ptr::copy::(ptr::NonNull::dangling().as_ptr(), ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:38:5 + | +LL | ptr::copy_nonoverlapping::(ptr::null(), ptr::NonNull::dangling().as_ptr(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:40:5 + | +LL | / ptr::copy_nonoverlapping::( +LL | | +LL | | ptr::NonNull::dangling().as_ptr(), +LL | | ptr::null_mut(), + | | --------------- null pointer originates from here +LL | | 0 +LL | | ); + | |_____^ + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:51:17 + | +LL | let _a: A = ptr::read(ptr::null()); + | ^^^^^^^^^^-----------^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:53:17 + | +LL | let _a: A = ptr::read(ptr::null_mut()); + | ^^^^^^^^^^---------------^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:56:17 + | +LL | let _a: A = ptr::read_unaligned(ptr::null()); + | ^^^^^^^^^^^^^^^^^^^^-----------^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:58:17 + | +LL | let _a: A = ptr::read_unaligned(ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^---------------^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:61:17 + | +LL | let _a: A = ptr::read_volatile(ptr::null()); + | ^^^^^^^^^^^^^^^^^^^-----------^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:63:17 + | +LL | let _a: A = ptr::read_volatile(ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^---------------^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:66:17 + | +LL | let _a: A = ptr::replace(ptr::null_mut(), v); + | ^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:69:5 + | +LL | ptr::swap::(ptr::null_mut(), &mut v); + | ^^^^^^^^^^^^^^^---------------^^^^^^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:71:5 + | +LL | ptr::swap::(&mut v, ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:74:5 + | +LL | ptr::swap_nonoverlapping::(ptr::null_mut(), &mut v, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^^^^^^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:76:5 + | +LL | ptr::swap_nonoverlapping::(&mut v, ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:79:5 + | +LL | ptr::write(ptr::null_mut(), v); + | ^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:82:5 + | +LL | ptr::write_unaligned(ptr::null_mut(), v); + | ^^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:85:5 + | +LL | ptr::write_volatile(ptr::null_mut(), v); + | ^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:88:5 + | +LL | ptr::write_bytes::(ptr::null_mut(), 42, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:93:18 + | +LL | let _a: u8 = ptr::read(const_ptr); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: for more information, visit and +note: null pointer originates from here + --> $DIR/invalid_null_args.rs:14:20 + | +LL | let null_ptr = ptr::null_mut(); + | ^^^^^^^^^^^^^^^ + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:100:5 + | +LL | std::slice::from_raw_parts::<()>(ptr::null(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:102:5 + | +LL | std::slice::from_raw_parts::(ptr::null(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:104:5 + | +LL | std::slice::from_raw_parts_mut::<()>(ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused + --> $DIR/invalid_null_args.rs:106:5 + | +LL | std::slice::from_raw_parts_mut::(ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | null pointer originates from here + | + = help: for more information, visit and + +error: aborting due to 31 previous errors + From b738343a54bdaf009d928737e7c682c72aec475c Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 9 Mar 2025 14:55:46 +0100 Subject: [PATCH 458/546] Drop `clippy::invalid_null_ptr_usage` --- .../clippy/clippy_lints/src/declared_lints.rs | 1 - .../clippy_lints/src/deprecated_lints.rs | 2 + src/tools/clippy/clippy_lints/src/ptr.rs | 73 +--------- src/tools/clippy/tests/ui/crashes/ice-1782.rs | 2 +- .../tests/ui/invalid_null_ptr_usage.fixed | 66 --------- .../clippy/tests/ui/invalid_null_ptr_usage.rs | 66 --------- .../tests/ui/invalid_null_ptr_usage.stderr | 136 ------------------ .../ui/invalid_null_ptr_usage_no_std.fixed | 79 ---------- .../tests/ui/invalid_null_ptr_usage_no_std.rs | 79 ---------- .../ui/invalid_null_ptr_usage_no_std.stderr | 136 ------------------ src/tools/clippy/tests/ui/rename.fixed | 1 + src/tools/clippy/tests/ui/rename.rs | 1 + src/tools/clippy/tests/ui/rename.stderr | 30 ++-- 13 files changed, 24 insertions(+), 648 deletions(-) delete mode 100644 src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed delete mode 100644 src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs delete mode 100644 src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr delete mode 100644 src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.fixed delete mode 100644 src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.rs delete mode 100644 src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.stderr diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 7fa23dad6981..39e451637070 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -638,7 +638,6 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::precedence::PRECEDENCE_INFO, crate::precedence::PRECEDENCE_BITS_INFO, crate::ptr::CMP_NULL_INFO, - crate::ptr::INVALID_NULL_PTR_USAGE_INFO, crate::ptr::MUT_FROM_REF_INFO, crate::ptr::PTR_ARG_INFO, crate::ptr::PTR_EQ_INFO, diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 0031da406f17..de66ead4f420 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -131,6 +131,8 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[ ("clippy::clone_double_ref", "suspicious_double_ref_op"), #[clippy::version = ""] ("clippy::cmp_nan", "invalid_nan_comparisons"), + #[clippy::version = "CURRENT_RUSTC_VERSION"] + ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"), #[clippy::version = "1.86.0"] ("clippy::double_neg", "double_negations"), #[clippy::version = ""] diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 55f1ece05593..50ef56db167c 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -125,29 +125,6 @@ declare_clippy_lint! { "fns that create mutable refs from immutable ref args" } -declare_clippy_lint! { - /// ### What it does - /// This lint checks for invalid usages of `ptr::null`. - /// - /// ### Why is this bad? - /// This causes undefined behavior. - /// - /// ### Example - /// ```ignore - /// // Undefined behavior - /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); } - /// ``` - /// - /// Use instead: - /// ```ignore - /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); } - /// ``` - #[clippy::version = "1.53.0"] - pub INVALID_NULL_PTR_USAGE, - correctness, - "invalid usage of a null pointer, suggesting `NonNull::dangling()` instead" -} - declare_clippy_lint! { /// ### What it does /// Use `std::ptr::eq` when applicable @@ -177,7 +154,7 @@ declare_clippy_lint! { "use `std::ptr::eq` when comparing raw pointers" } -declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USAGE, PTR_EQ]); +declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, PTR_EQ]); impl<'tcx> LateLintPass<'tcx> for Ptr { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { @@ -301,54 +278,6 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { format!("{non_null_path_snippet}.is_null()"), Applicability::MachineApplicable, ); - } else { - check_invalid_ptr_usage(cx, expr); - } - } -} - -fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Call(fun, args) = expr.kind - && let ExprKind::Path(ref qpath) = fun.kind - && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() - && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id) - { - // TODO: `ptr_slice_from_raw_parts` and its mutable variant should probably still be linted - // conditionally based on how the return value is used, but not universally like the other - // functions since there are valid uses for null slice pointers. - // - // See: https://github.com/rust-lang/rust-clippy/pull/13452/files#r1773772034 - - // `arg` positions where null would cause U.B. - let arg_indices: &[_] = match name { - sym::ptr_read - | sym::ptr_read_unaligned - | sym::ptr_read_volatile - | sym::ptr_replace - | sym::ptr_write - | sym::ptr_write_bytes - | sym::ptr_write_unaligned - | sym::ptr_write_volatile - | sym::slice_from_raw_parts - | sym::slice_from_raw_parts_mut => &[0], - sym::ptr_copy | sym::ptr_copy_nonoverlapping | sym::ptr_swap | sym::ptr_swap_nonoverlapping => &[0, 1], - _ => return, - }; - - for &arg_idx in arg_indices { - if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) - && let Some(std_or_core) = std_or_core(cx) - { - span_lint_and_sugg( - cx, - INVALID_NULL_PTR_USAGE, - arg.span, - "pointer must be non-null", - "change this to", - format!("{std_or_core}::ptr::NonNull::dangling().as_ptr()"), - Applicability::MachineApplicable, - ); - } } } } diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs index fefdc405cce2..4a1886c08af6 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-1782.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs @@ -1,6 +1,6 @@ //@ check-pass -#![allow(dead_code, unused_variables)] +#![allow(dead_code, unused_variables, invalid_null_arguments)] #![allow(clippy::unnecessary_cast, clippy::missing_transmute_annotations)] /// Should not trigger an ICE in `SpanlessEq` / `consts::constant` diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed deleted file mode 100644 index ce78e89ee829..000000000000 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed +++ /dev/null @@ -1,66 +0,0 @@ -fn main() { - unsafe { - let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - let _slice: &[usize] = std::slice::from_raw_parts_mut(std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - struct A; // zero sized struct - assert_eq!(std::mem::size_of::(), 0); - - let _a: A = std::ptr::read(std::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - let _a: A = std::ptr::read(std::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - - let _a: A = std::ptr::read_unaligned(std::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - let _a: A = std::ptr::read_unaligned(std::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - - let _a: A = std::ptr::read_volatile(std::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - let _a: A = std::ptr::read_volatile(std::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - - let _a: A = std::ptr::replace(std::ptr::NonNull::dangling().as_ptr(), A); - //~^ invalid_null_ptr_usage - let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint - let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); - - std::ptr::swap::(std::ptr::NonNull::dangling().as_ptr(), &mut A); - //~^ invalid_null_ptr_usage - std::ptr::swap::(&mut A, std::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - - std::ptr::swap_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), &mut A, 0); - //~^ invalid_null_ptr_usage - std::ptr::swap_nonoverlapping::(&mut A, std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - std::ptr::write(std::ptr::NonNull::dangling().as_ptr(), A); - //~^ invalid_null_ptr_usage - - std::ptr::write_unaligned(std::ptr::NonNull::dangling().as_ptr(), A); - //~^ invalid_null_ptr_usage - - std::ptr::write_volatile(std::ptr::NonNull::dangling().as_ptr(), A); - //~^ invalid_null_ptr_usage - - std::ptr::write_bytes::(std::ptr::NonNull::dangling().as_ptr(), 42, 0); - //~^ invalid_null_ptr_usage - } -} diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs deleted file mode 100644 index 361865fbd960..000000000000 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs +++ /dev/null @@ -1,66 +0,0 @@ -fn main() { - unsafe { - let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null(), 0); - //~^ invalid_null_ptr_usage - let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - let _slice: &[usize] = std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - std::ptr::copy::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - std::ptr::copy_nonoverlapping::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - struct A; // zero sized struct - assert_eq!(std::mem::size_of::(), 0); - - let _a: A = std::ptr::read(std::ptr::null()); - //~^ invalid_null_ptr_usage - let _a: A = std::ptr::read(std::ptr::null_mut()); - //~^ invalid_null_ptr_usage - - let _a: A = std::ptr::read_unaligned(std::ptr::null()); - //~^ invalid_null_ptr_usage - let _a: A = std::ptr::read_unaligned(std::ptr::null_mut()); - //~^ invalid_null_ptr_usage - - let _a: A = std::ptr::read_volatile(std::ptr::null()); - //~^ invalid_null_ptr_usage - let _a: A = std::ptr::read_volatile(std::ptr::null_mut()); - //~^ invalid_null_ptr_usage - - let _a: A = std::ptr::replace(std::ptr::null_mut(), A); - //~^ invalid_null_ptr_usage - let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint - let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); - - std::ptr::swap::(std::ptr::null_mut(), &mut A); - //~^ invalid_null_ptr_usage - std::ptr::swap::(&mut A, std::ptr::null_mut()); - //~^ invalid_null_ptr_usage - - std::ptr::swap_nonoverlapping::(std::ptr::null_mut(), &mut A, 0); - //~^ invalid_null_ptr_usage - std::ptr::swap_nonoverlapping::(&mut A, std::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - std::ptr::write(std::ptr::null_mut(), A); - //~^ invalid_null_ptr_usage - - std::ptr::write_unaligned(std::ptr::null_mut(), A); - //~^ invalid_null_ptr_usage - - std::ptr::write_volatile(std::ptr::null_mut(), A); - //~^ invalid_null_ptr_usage - - std::ptr::write_bytes::(std::ptr::null_mut(), 42, 0); - //~^ invalid_null_ptr_usage - } -} diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr deleted file mode 100644 index 3f9d15b90401..000000000000 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr +++ /dev/null @@ -1,136 +0,0 @@ -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:3:59 - | -LL | let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null(), 0); - | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - | - = note: `#[deny(clippy::invalid_null_ptr_usage)]` on by default - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:5:59 - | -LL | let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:8:63 - | -LL | let _slice: &[usize] = std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:11:33 - | -LL | std::ptr::copy::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); - | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:13:73 - | -LL | std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:16:48 - | -LL | std::ptr::copy_nonoverlapping::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); - | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:18:88 - | -LL | std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:24:36 - | -LL | let _a: A = std::ptr::read(std::ptr::null()); - | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:26:36 - | -LL | let _a: A = std::ptr::read(std::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:29:46 - | -LL | let _a: A = std::ptr::read_unaligned(std::ptr::null()); - | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:31:46 - | -LL | let _a: A = std::ptr::read_unaligned(std::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:34:45 - | -LL | let _a: A = std::ptr::read_volatile(std::ptr::null()); - | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:36:45 - | -LL | let _a: A = std::ptr::read_volatile(std::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:39:39 - | -LL | let _a: A = std::ptr::replace(std::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:44:29 - | -LL | std::ptr::swap::(std::ptr::null_mut(), &mut A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:46:37 - | -LL | std::ptr::swap::(&mut A, std::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:49:44 - | -LL | std::ptr::swap_nonoverlapping::(std::ptr::null_mut(), &mut A, 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:51:52 - | -LL | std::ptr::swap_nonoverlapping::(&mut A, std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:54:25 - | -LL | std::ptr::write(std::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:57:35 - | -LL | std::ptr::write_unaligned(std::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:60:34 - | -LL | std::ptr::write_volatile(std::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:63:40 - | -LL | std::ptr::write_bytes::(std::ptr::null_mut(), 42, 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` - -error: aborting due to 22 previous errors - diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.fixed b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.fixed deleted file mode 100644 index df7ab166187d..000000000000 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.fixed +++ /dev/null @@ -1,79 +0,0 @@ -#![no_std] -#![feature(lang_items)] - -use core::panic::PanicInfo; - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - loop {} -} - -fn main() { - unsafe { - let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - struct A; // zero sized struct - assert_eq!(core::mem::size_of::(), 0); - - let _a: A = core::ptr::read(core::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - let _a: A = core::ptr::read(core::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - - let _a: A = core::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - let _a: A = core::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - - let _a: A = core::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - let _a: A = core::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - - let _a: A = core::ptr::replace(core::ptr::NonNull::dangling().as_ptr(), A); - //~^ invalid_null_ptr_usage - let _slice: *const [usize] = core::ptr::slice_from_raw_parts(core::ptr::null_mut(), 0); // shouldn't lint - let _slice: *const [usize] = core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut(), 0); - - core::ptr::swap::(core::ptr::NonNull::dangling().as_ptr(), &mut A); - //~^ invalid_null_ptr_usage - core::ptr::swap::(&mut A, core::ptr::NonNull::dangling().as_ptr()); - //~^ invalid_null_ptr_usage - - core::ptr::swap_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), &mut A, 0); - //~^ invalid_null_ptr_usage - core::ptr::swap_nonoverlapping::(&mut A, core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - - core::ptr::write(core::ptr::NonNull::dangling().as_ptr(), A); - //~^ invalid_null_ptr_usage - - core::ptr::write_unaligned(core::ptr::NonNull::dangling().as_ptr(), A); - //~^ invalid_null_ptr_usage - - core::ptr::write_volatile(core::ptr::NonNull::dangling().as_ptr(), A); - //~^ invalid_null_ptr_usage - - core::ptr::write_bytes::(core::ptr::NonNull::dangling().as_ptr(), 42, 0); - //~^ invalid_null_ptr_usage - } -} diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.rs b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.rs deleted file mode 100644 index 38ddfff05535..000000000000 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.rs +++ /dev/null @@ -1,79 +0,0 @@ -#![no_std] -#![feature(lang_items)] - -use core::panic::PanicInfo; - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - loop {} -} - -fn main() { - unsafe { - let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null(), 0); - //~^ invalid_null_ptr_usage - let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - core::ptr::copy::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - core::ptr::copy_nonoverlapping::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); - //~^ invalid_null_ptr_usage - core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - struct A; // zero sized struct - assert_eq!(core::mem::size_of::(), 0); - - let _a: A = core::ptr::read(core::ptr::null()); - //~^ invalid_null_ptr_usage - let _a: A = core::ptr::read(core::ptr::null_mut()); - //~^ invalid_null_ptr_usage - - let _a: A = core::ptr::read_unaligned(core::ptr::null()); - //~^ invalid_null_ptr_usage - let _a: A = core::ptr::read_unaligned(core::ptr::null_mut()); - //~^ invalid_null_ptr_usage - - let _a: A = core::ptr::read_volatile(core::ptr::null()); - //~^ invalid_null_ptr_usage - let _a: A = core::ptr::read_volatile(core::ptr::null_mut()); - //~^ invalid_null_ptr_usage - - let _a: A = core::ptr::replace(core::ptr::null_mut(), A); - //~^ invalid_null_ptr_usage - let _slice: *const [usize] = core::ptr::slice_from_raw_parts(core::ptr::null_mut(), 0); // shouldn't lint - let _slice: *const [usize] = core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut(), 0); - - core::ptr::swap::(core::ptr::null_mut(), &mut A); - //~^ invalid_null_ptr_usage - core::ptr::swap::(&mut A, core::ptr::null_mut()); - //~^ invalid_null_ptr_usage - - core::ptr::swap_nonoverlapping::(core::ptr::null_mut(), &mut A, 0); - //~^ invalid_null_ptr_usage - core::ptr::swap_nonoverlapping::(&mut A, core::ptr::null_mut(), 0); - //~^ invalid_null_ptr_usage - - core::ptr::write(core::ptr::null_mut(), A); - //~^ invalid_null_ptr_usage - - core::ptr::write_unaligned(core::ptr::null_mut(), A); - //~^ invalid_null_ptr_usage - - core::ptr::write_volatile(core::ptr::null_mut(), A); - //~^ invalid_null_ptr_usage - - core::ptr::write_bytes::(core::ptr::null_mut(), 42, 0); - //~^ invalid_null_ptr_usage - } -} diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.stderr b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.stderr deleted file mode 100644 index b5dd21ce6248..000000000000 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.stderr +++ /dev/null @@ -1,136 +0,0 @@ -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:16:60 - | -LL | let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null(), 0); - | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - | - = note: `#[deny(clippy::invalid_null_ptr_usage)]` on by default - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:18:60 - | -LL | let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:21:64 - | -LL | let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:24:34 - | -LL | core::ptr::copy::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); - | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:26:75 - | -LL | core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:29:49 - | -LL | core::ptr::copy_nonoverlapping::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); - | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:31:90 - | -LL | core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:37:37 - | -LL | let _a: A = core::ptr::read(core::ptr::null()); - | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:39:37 - | -LL | let _a: A = core::ptr::read(core::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:42:47 - | -LL | let _a: A = core::ptr::read_unaligned(core::ptr::null()); - | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:44:47 - | -LL | let _a: A = core::ptr::read_unaligned(core::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:47:46 - | -LL | let _a: A = core::ptr::read_volatile(core::ptr::null()); - | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:49:46 - | -LL | let _a: A = core::ptr::read_volatile(core::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:52:40 - | -LL | let _a: A = core::ptr::replace(core::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:57:30 - | -LL | core::ptr::swap::(core::ptr::null_mut(), &mut A); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:59:38 - | -LL | core::ptr::swap::(&mut A, core::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:62:45 - | -LL | core::ptr::swap_nonoverlapping::(core::ptr::null_mut(), &mut A, 0); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:64:53 - | -LL | core::ptr::swap_nonoverlapping::(&mut A, core::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:67:26 - | -LL | core::ptr::write(core::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:70:36 - | -LL | core::ptr::write_unaligned(core::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:73:35 - | -LL | core::ptr::write_volatile(core::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:76:41 - | -LL | core::ptr::write_bytes::(core::ptr::null_mut(), 42, 0); - | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: aborting due to 22 previous errors - diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 501811fa491b..796404706968 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -119,6 +119,7 @@ #![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` #![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref` #![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` +#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` #![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` #![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg` #![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 7f4b8062e1b4..aa7b905b4b81 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -119,6 +119,7 @@ #![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` #![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref` #![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` +#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` #![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` #![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg` #![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index f24eaec3917a..b3c88167c111 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -343,71 +343,77 @@ error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_fro LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` -error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` +error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments` --> tests/ui/rename.rs:122:9 | +LL | #![warn(clippy::invalid_null_ptr_usage)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments` + +error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` + --> tests/ui/rename.rs:123:9 + | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs` - --> tests/ui/rename.rs:123:9 + --> tests/ui/rename.rs:124:9 | LL | #![warn(clippy::maybe_misused_cfg)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> tests/ui/rename.rs:124:9 + --> tests/ui/rename.rs:125:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs` - --> tests/ui/rename.rs:125:9 + --> tests/ui/rename.rs:126:9 | LL | #![warn(clippy::mismatched_target_os)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> tests/ui/rename.rs:126:9 + --> tests/ui/rename.rs:127:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> tests/ui/rename.rs:127:9 + --> tests/ui/rename.rs:128:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` - --> tests/ui/rename.rs:128:9 + --> tests/ui/rename.rs:129:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> tests/ui/rename.rs:129:9 + --> tests/ui/rename.rs:130:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> tests/ui/rename.rs:130:9 + --> tests/ui/rename.rs:131:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> tests/ui/rename.rs:131:9 + --> tests/ui/rename.rs:132:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> tests/ui/rename.rs:132:9 + --> tests/ui/rename.rs:133:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` -error: aborting due to 68 previous errors +error: aborting due to 69 previous errors From aa8848040a160842d47a5a143e04da8ad9f27613 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 9 Mar 2025 22:23:31 +0100 Subject: [PATCH 459/546] Allow `invalid_null_arguments` in some tests --- tests/ui/precondition-checks/copy-nonoverlapping.rs | 2 ++ tests/ui/precondition-checks/copy.rs | 2 ++ tests/ui/precondition-checks/read_volatile.rs | 2 ++ tests/ui/precondition-checks/replace.rs | 2 ++ tests/ui/precondition-checks/slice-from-raw-parts-mut.rs | 2 ++ tests/ui/precondition-checks/slice-from-raw-parts.rs | 2 ++ tests/ui/precondition-checks/swap-nonoverlapping.rs | 2 ++ tests/ui/precondition-checks/write_volatile.rs | 2 ++ tests/ui/precondition-checks/zero-size-null.rs | 2 ++ 9 files changed, 18 insertions(+) diff --git a/tests/ui/precondition-checks/copy-nonoverlapping.rs b/tests/ui/precondition-checks/copy-nonoverlapping.rs index 81018e4bff3e..eacaa63e543a 100644 --- a/tests/ui/precondition-checks/copy-nonoverlapping.rs +++ b/tests/ui/precondition-checks/copy-nonoverlapping.rs @@ -3,6 +3,8 @@ //@ error-pattern: unsafe precondition(s) violated: ptr::copy_nonoverlapping requires //@ revisions: null_src null_dst misaligned_src misaligned_dst overlapping +#![allow(invalid_null_arguments)] + use std::ptr; fn main() { diff --git a/tests/ui/precondition-checks/copy.rs b/tests/ui/precondition-checks/copy.rs index 694853f950ab..1fadd90bf70b 100644 --- a/tests/ui/precondition-checks/copy.rs +++ b/tests/ui/precondition-checks/copy.rs @@ -3,6 +3,8 @@ //@ error-pattern: unsafe precondition(s) violated: ptr::copy requires //@ revisions: null_src null_dst misaligned_src misaligned_dst +#![allow(invalid_null_arguments)] + use std::ptr; fn main() { diff --git a/tests/ui/precondition-checks/read_volatile.rs b/tests/ui/precondition-checks/read_volatile.rs index e14881d02903..ada8932c398c 100644 --- a/tests/ui/precondition-checks/read_volatile.rs +++ b/tests/ui/precondition-checks/read_volatile.rs @@ -3,6 +3,8 @@ //@ error-pattern: unsafe precondition(s) violated: ptr::read_volatile requires //@ revisions: null misaligned +#![allow(invalid_null_arguments)] + use std::ptr; fn main() { diff --git a/tests/ui/precondition-checks/replace.rs b/tests/ui/precondition-checks/replace.rs index 2808cee7b64b..44afbd8174c0 100644 --- a/tests/ui/precondition-checks/replace.rs +++ b/tests/ui/precondition-checks/replace.rs @@ -3,6 +3,8 @@ //@ error-pattern: unsafe precondition(s) violated: ptr::replace requires //@ revisions: null misaligned +#![allow(invalid_null_arguments)] + use std::ptr; fn main() { diff --git a/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs b/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs index 3801639e2551..9b9ded69a83b 100644 --- a/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs +++ b/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs @@ -3,6 +3,8 @@ //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts_mut requires //@ revisions: null misaligned toolarge +#![allow(invalid_null_arguments)] + fn main() { unsafe { #[cfg(null)] diff --git a/tests/ui/precondition-checks/slice-from-raw-parts.rs b/tests/ui/precondition-checks/slice-from-raw-parts.rs index a3690fa045eb..96578c1eae58 100644 --- a/tests/ui/precondition-checks/slice-from-raw-parts.rs +++ b/tests/ui/precondition-checks/slice-from-raw-parts.rs @@ -3,6 +3,8 @@ //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts requires //@ revisions: null misaligned toolarge +#![allow(invalid_null_arguments)] + fn main() { unsafe { #[cfg(null)] diff --git a/tests/ui/precondition-checks/swap-nonoverlapping.rs b/tests/ui/precondition-checks/swap-nonoverlapping.rs index 52e4a3c870be..ea1f6f36ad78 100644 --- a/tests/ui/precondition-checks/swap-nonoverlapping.rs +++ b/tests/ui/precondition-checks/swap-nonoverlapping.rs @@ -3,6 +3,8 @@ //@ error-pattern: unsafe precondition(s) violated: ptr::swap_nonoverlapping requires //@ revisions: null_src null_dst misaligned_src misaligned_dst overlapping +#![allow(invalid_null_arguments)] + use std::ptr; fn main() { diff --git a/tests/ui/precondition-checks/write_volatile.rs b/tests/ui/precondition-checks/write_volatile.rs index ac0b89b5ecf2..0d5ecb014b3d 100644 --- a/tests/ui/precondition-checks/write_volatile.rs +++ b/tests/ui/precondition-checks/write_volatile.rs @@ -3,6 +3,8 @@ //@ error-pattern: unsafe precondition(s) violated: ptr::write_volatile requires //@ revisions: null misaligned +#![allow(invalid_null_arguments)] + use std::ptr; fn main() { diff --git a/tests/ui/precondition-checks/zero-size-null.rs b/tests/ui/precondition-checks/zero-size-null.rs index 43a81175f944..55d768fc9e58 100644 --- a/tests/ui/precondition-checks/zero-size-null.rs +++ b/tests/ui/precondition-checks/zero-size-null.rs @@ -7,8 +7,10 @@ use std::ptr; fn main() { unsafe { + #[expect(invalid_null_arguments)] // false-positive, copy of 0 ptr::copy_nonoverlapping::(ptr::null(), ptr::null_mut(), 0); ptr::copy_nonoverlapping::<()>(ptr::null(), ptr::null_mut(), 123); + #[expect(invalid_null_arguments)] // false-positive, copy of 0 ptr::copy::(ptr::null(), ptr::null_mut(), 0); ptr::copy::<()>(ptr::null(), ptr::null_mut(), 123); ptr::swap::<()>(ptr::null_mut(), ptr::null_mut()); From f3cbc3992e1428e92c608410614c3e7b7a64b815 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 30 Mar 2025 22:13:47 +0200 Subject: [PATCH 460/546] Remove duplicate c-variadic.md --- .../src/library-features/c-variadic.md | 26 ------------------- src/tools/tidy/src/unstable_book.rs | 12 ++++----- 2 files changed, 5 insertions(+), 33 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/c-variadic.md diff --git a/src/doc/unstable-book/src/library-features/c-variadic.md b/src/doc/unstable-book/src/library-features/c-variadic.md deleted file mode 100644 index 77762116e6b1..000000000000 --- a/src/doc/unstable-book/src/library-features/c-variadic.md +++ /dev/null @@ -1,26 +0,0 @@ -# `c_variadic` - -The tracking issue for this feature is: [#44930] - -[#44930]: https://github.com/rust-lang/rust/issues/44930 - ------------------------- - -The `c_variadic` library feature exposes the `VaList` structure, -Rust's analogue of C's `va_list` type. - -## Examples - -```rust -#![feature(c_variadic)] - -use std::ffi::VaList; - -pub unsafe extern "C" fn vadd(n: usize, mut args: VaList) -> usize { - let mut sum = 0; - for _ in 0..n { - sum += args.arg::(); - } - sum -} -``` diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index 8be25b98df0d..d19de081807d 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -93,14 +93,12 @@ pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) { // Check for Unstable Book sections that don't have a corresponding unstable feature for feature_name in &unstable_book_lib_features_section_file_names - &unstable_lib_feature_names { - if !unstable_lang_feature_names.contains(&feature_name) { - tidy_error!( - bad, - "The Unstable Book has a 'library feature' section '{}' which doesn't \ + tidy_error!( + bad, + "The Unstable Book has a 'library feature' section '{}' which doesn't \ correspond to an unstable library feature", - feature_name - ); - } + feature_name + ); } // Check for Unstable Book sections that don't have a corresponding unstable feature. From 14e4f9f245c615cd379397908abc52c795b65d04 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 30 Mar 2025 22:19:18 +0200 Subject: [PATCH 461/546] Suggest switching underscores for dashes --- src/tools/tidy/src/unstable_book.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index d19de081807d..a2453a6c9605 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -72,6 +72,19 @@ fn collect_unstable_book_lib_features_section_file_names(base_src_path: &Path) - collect_unstable_book_section_file_names(&unstable_book_lib_features_path(base_src_path)) } +/// Would switching underscores for dashes work? +fn maybe_suggest_dashes(names: &BTreeSet, feature_name: &str, bad: &mut bool) { + let with_dashes = feature_name.replace('_', "-"); + if names.contains(&with_dashes) { + tidy_error!( + bad, + "the file `{}.md` contains underscores; use dashes instead: `{}.md`", + feature_name, + with_dashes, + ); + } +} + pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) { let lang_features = features.lang; let lib_features = features @@ -99,6 +112,7 @@ pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) { correspond to an unstable library feature", feature_name ); + maybe_suggest_dashes(&unstable_lib_feature_names, &feature_name, bad); } // Check for Unstable Book sections that don't have a corresponding unstable feature. @@ -110,7 +124,8 @@ pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) { "The Unstable Book has a 'language feature' section '{}' which doesn't \ correspond to an unstable language feature", feature_name - ) + ); + maybe_suggest_dashes(&unstable_lang_feature_names, &feature_name, bad); } // List unstable features that don't have Unstable Book sections. From 8a3ee9755245eccae6327c3f4cc658fe12615b18 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sun, 30 Mar 2025 15:45:44 -0700 Subject: [PATCH 462/546] Apply suggestions from code review Co-authored-by: Mark Rousskov Co-authored-by: alexey semenyuk --- RELEASES.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 3047a0c366a4..0948eb85192e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -5,7 +5,7 @@ Version 1.86.0 (2025-04-03) Language -------- -- [Stabilize the ability to upcast a trait object to one of its supertraits.](https://github.com/rust-lang/rust/pull/134367) +- [Stabilize upcasting trait objects to supertraits.](https://github.com/rust-lang/rust/pull/134367) - [Allow safe functions to be marked with the `#[target_feature]` attribute.](https://github.com/rust-lang/rust/pull/134090) - [The `missing_abi` lint now warns-by-default.](https://github.com/rust-lang/rust/pull/132397) - Rust now lints about double negations, to catch cases that might have intended to be a prefix decrement operator (`--x`) as written in other languages. This was previously a clippy lint, `clippy::double_neg`, and is [now available directly in Rust as `double_negations`.](https://github.com/rust-lang/rust/pull/126604) @@ -104,8 +104,9 @@ Compatibility Notes - [The `wasm_c_abi` future compatibility warning is now a hard error.](https://github.com/rust-lang/rust/pull/133951) Users of `wasm-bindgen` should upgrade to at least version 0.2.89, otherwise compilation will fail. - [Remove long-deprecated no-op attributes `#![no_start]` and `#![crate_id]`.](https://github.com/rust-lang/rust/pull/134300) -- The future incompatibility lint `cenum_impl_drop_cast` [has been made into a hard error.](https://github.com/rust-lang/rust/pull/135964) This means it is now an error to cast a field-less enum to an integer if the enum implements `Drop`. +- [The future incompatibility lint `cenum_impl_drop_cast` has been made into a hard error.](https://github.com/rust-lang/rust/pull/135964) This means it is now an error to cast a field-less enum to an integer if the enum implements `Drop`. - [SSE2 is now required for "i686" 32-bit x86 hard-float targets; disabling it causes a warning that will become a hard error eventually.](https://github.com/rust-lang/rust/pull/137037) + To compile for pre-SSE2 32-bit x86, use a "i586" target instead. @@ -117,7 +118,7 @@ significant improvements to the performance or internals of rustc and related tools. - [Build the rustc on AArch64 Linux with ThinLTO + PGO.](https://github.com/rust-lang/rust/pull/133807) -The ARM 64-bit compiler (AArch64) on Linux is now optimized with ThinLTO and PGO, similar to the optimizations we have already performed for the x86-64 compiler on Linux. This should make it up to 30% faster. + The ARM 64-bit compiler (AArch64) on Linux is now optimized with ThinLTO and PGO, similar to the optimizations we have already performed for the x86-64 compiler on Linux. This should make it up to 30% faster. Version 1.85.1 (2025-03-18) From 897acc3e5d3622927118924fa920c8be0ef6f154 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 30 Mar 2025 21:39:12 +0000 Subject: [PATCH 463/546] Encode synthetic by-move coroutine body with a different DefPathData --- compiler/rustc_hir/src/def.rs | 2 +- compiler/rustc_hir/src/definitions.rs | 15 +++++++++++++-- compiler/rustc_middle/src/ty/context.rs | 6 +++--- compiler/rustc_middle/src/ty/print/mod.rs | 7 +++++-- .../rustc_query_system/src/dep_graph/graph.rs | 7 ++++--- .../src/cfi/typeid/itanium_cxx_abi/encode.rs | 1 + compiler/rustc_symbol_mangling/src/legacy.rs | 5 ++++- compiler/rustc_symbol_mangling/src/v0.rs | 1 + tests/coverage/async_closure.cov-map | 18 +++++++++--------- tests/coverage/async_closure.coverage | 2 +- ...itten-closure-synthetic-closure-conflict.rs | 15 +++++++++++++++ ...-{closure#0}-{synthetic#0}.built.after.mir} | 4 ++-- .../async_closure_fake_read_for_by_move.rs | 2 +- ...-{closure#0}-{synthetic#0}.built.after.mir} | 4 ++-- ...-{closure#1}-{synthetic#0}.built.after.mir} | 4 ++-- tests/mir-opt/async_closure_shims.rs | 4 ++-- tests/ui/stable-mir-print/async-closure.stdout | 2 +- 17 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 tests/incremental/user-written-closure-synthetic-closure-conflict.rs rename tests/mir-opt/{async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir => async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir} (85%) rename tests/mir-opt/{async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.mir => async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir} (80%) rename tests/mir-opt/{async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.mir => async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir} (80%) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 5f8941d4754e..dc00b52a5936 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -294,7 +294,7 @@ impl DefKind { DefKind::GlobalAsm => DefPathData::GlobalAsm, DefKind::Impl { .. } => DefPathData::Impl, DefKind::Closure => DefPathData::Closure, - DefKind::SyntheticCoroutineBody => DefPathData::Closure, + DefKind::SyntheticCoroutineBody => DefPathData::SyntheticCoroutineBody, } } diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 61f5efd9978c..c52954aa96fc 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -291,6 +291,8 @@ pub enum DefPathData { /// An existential `impl Trait` type node. /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. OpaqueTy, + /// A synthetic body for a coroutine's by-move body. + SyntheticCoroutineBody, } impl Definitions { @@ -415,8 +417,16 @@ impl DefPathData { ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), - Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst - | OpaqueTy => None, + Impl + | ForeignMod + | CrateRoot + | Use + | GlobalAsm + | Closure + | Ctor + | AnonConst + | OpaqueTy + | SyntheticCoroutineBody => None, } } @@ -441,6 +451,7 @@ impl DefPathData { Ctor => DefPathDataName::Anon { namespace: sym::constructor }, AnonConst => DefPathDataName::Anon { namespace: sym::constant }, OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, + SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic }, } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 08d4c1f9cf2f..618a65a01864 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1930,10 +1930,10 @@ impl<'tcx> TyCtxt<'tcx> { // As a consequence, this LocalDefId is always re-created before it is needed by the incr. // comp. engine itself. // - // This call also writes to the value of `source_span` and `expn_that_defined` queries. + // This call also writes to the value of the `source_span` query. // This is fine because: - // - those queries are `eval_always` so we won't miss their result changing; - // - this write will have happened before these queries are called. + // - that query is `eval_always` so we won't miss its result changing; + // - this write will have happened before that query is called. let def_id = self.untracked.definitions.write().create_def(parent, data); // This function modifies `self.definitions` using a side-effect. diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index dc2040aa5cf8..5904deaaaad8 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -139,8 +139,7 @@ pub trait Printer<'tcx>: Sized { match key.disambiguated_data.data { DefPathData::Closure => { - // FIXME(async_closures): This is somewhat ugly. - // We need to additionally print the `kind` field of a closure if + // We need to additionally print the `kind` field of a coroutine if // it is desugared from a coroutine-closure. if let Some(hir::CoroutineKind::Desugared( _, @@ -156,6 +155,10 @@ pub trait Printer<'tcx>: Sized { // Closures' own generics are only captures, don't print them. } } + DefPathData::SyntheticCoroutineBody => { + // Synthetic coroutine bodies have no distinct generics, since like + // closures they're all just internal state of the coroutine. + } // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`. // Anon consts doesn't have their own generics, and inline consts' own // generics are their inferred types, so don't print them. diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 495f34733f70..127dcd825da5 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -66,6 +66,7 @@ pub struct MarkFrame<'a> { parent: Option<&'a MarkFrame<'a>>, } +#[derive(Debug)] pub(super) enum DepNodeColor { Red, Green(DepNodeIndex), @@ -909,7 +910,7 @@ impl DepGraphData { self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node, frame); if node_index.is_some() { - debug!("managed to MARK dependency {dep_dep_node:?} as green",); + debug!("managed to MARK dependency {dep_dep_node:?} as green"); return Some(()); } } @@ -930,7 +931,7 @@ impl DepGraphData { return Some(()); } Some(DepNodeColor::Red) => { - debug!("dependency {dep_dep_node:?} was red after forcing",); + debug!("dependency {dep_dep_node:?} was red after forcing"); return None; } None => {} @@ -950,7 +951,7 @@ impl DepGraphData { // invalid state will not be persisted to the // incremental compilation cache because of // compilation errors being present. - debug!("dependency {dep_dep_node:?} resulted in compilation error",); + debug!("dependency {dep_dep_node:?} resulted in compilation error"); return None; } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index e088417d72e3..d56ca9c24538 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -716,6 +716,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { hir::definitions::DefPathData::Ctor => "c", hir::definitions::DefPathData::AnonConst => "k", hir::definitions::DefPathData::OpaqueTy => "i", + hir::definitions::DefPathData::SyntheticCoroutineBody => "s", hir::definitions::DefPathData::CrateRoot | hir::definitions::DefPathData::Use | hir::definitions::DefPathData::GlobalAsm diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 88754f1f15b4..2802e8918073 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -28,7 +28,10 @@ pub(super) fn mangle<'tcx>( loop { let key = tcx.def_key(ty_def_id); match key.disambiguated_data.data { - DefPathData::TypeNs(_) | DefPathData::ValueNs(_) | DefPathData::Closure => { + DefPathData::TypeNs(_) + | DefPathData::ValueNs(_) + | DefPathData::Closure + | DefPathData::SyntheticCoroutineBody => { instance_ty = tcx.type_of(ty_def_id).instantiate_identity(); debug!(?instance_ty); break; diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index d824a23279b1..99d44bcd7eb8 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -850,6 +850,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { DefPathData::Ctor => 'c', DefPathData::AnonConst => 'k', DefPathData::OpaqueTy => 'i', + DefPathData::SyntheticCoroutineBody => 's', // These should never show up as `path_append` arguments. DefPathData::CrateRoot diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map index 9144a938a9e2..0e1d98778307 100644 --- a/tests/coverage/async_closure.cov-map +++ b/tests/coverage/async_closure.cov-map @@ -38,6 +38,15 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36) Highest counter ID seen: c0 +Function name: async_closure::main::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 23, 00, 24] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36) +Highest counter ID seen: c0 + Function name: async_closure::main::{closure#0}::{closure#0}:: Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24] Number of files: 1 @@ -47,12 +56,3 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36) Highest counter ID seen: c0 -Function name: async_closure::main::{closure#0}::{closure#1}:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 23, 00, 24] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36) -Highest counter ID seen: c0 - diff --git a/tests/coverage/async_closure.coverage b/tests/coverage/async_closure.coverage index 7fbea2658125..10a8ea14504b 100644 --- a/tests/coverage/async_closure.coverage +++ b/tests/coverage/async_closure.coverage @@ -14,7 +14,7 @@ | async_closure::main::{closure#0}: | LL| 1| let async_closure = async || {}; ------------------ - | async_closure::main::{closure#0}::{closure#1}::: + | async_closure::main::{closure#0}: | LL| 1| let async_closure = async || {}; ------------------ LL| 1| executor::block_on(async_closure()); diff --git a/tests/incremental/user-written-closure-synthetic-closure-conflict.rs b/tests/incremental/user-written-closure-synthetic-closure-conflict.rs new file mode 100644 index 000000000000..618604d06b17 --- /dev/null +++ b/tests/incremental/user-written-closure-synthetic-closure-conflict.rs @@ -0,0 +1,15 @@ +//@ revisions: rpass1 rpass2 +//@ edition: 2024 + +#![allow(unused)] + +fn main() { + #[cfg(rpass1)] + async || {}; + + #[cfg(rpass2)] + || { + || (); + || (); + }; +} diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir similarity index 85% rename from tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir rename to tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir index bd0baddb1f89..9070c95bca4d 100644 --- a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir @@ -1,6 +1,6 @@ -// MIR for `foo::{closure#0}::{closure#1}` after built +// MIR for `foo::{closure#0}::{synthetic#0}` after built -fn foo::{closure#0}::{closure#1}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: ResumeTy) -> () +fn foo::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.rs b/tests/mir-opt/async_closure_fake_read_for_by_move.rs index 3c5aec94bbfe..e78671f5e9d5 100644 --- a/tests/mir-opt/async_closure_fake_read_for_by_move.rs +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.rs @@ -7,7 +7,7 @@ enum Foo { } // EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir -// EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir +// EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir fn foo(f: &Foo) { let x = async move || match f { Foo::Bar if true => {} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir similarity index 80% rename from tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.mir rename to tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir index a9e08d2e8f60..c5f538e5ecd8 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir @@ -1,6 +1,6 @@ -// MIR for `main::{closure#0}::{closure#0}::{closure#1}` after built +// MIR for `main::{closure#0}::{closure#0}::{synthetic#0}` after built -fn main::{closure#0}::{closure#0}::{closure#1}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir similarity index 80% rename from tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.mir rename to tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir index 4452ae7812e3..e295f9b3cf12 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir @@ -1,6 +1,6 @@ -// MIR for `main::{closure#0}::{closure#1}::{closure#1}` after built +// MIR for `main::{closure#0}::{closure#1}::{synthetic#0}` after built -fn main::{closure#0}::{closure#1}::{closure#1}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#1}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs index cd2e83e939ab..93cc7834a643 100644 --- a/tests/mir-opt/async_closure_shims.rs +++ b/tests/mir-opt/async_closure_shims.rs @@ -42,11 +42,11 @@ async fn call_normal_mut>(f: &mut impl FnMut(i32) -> F) { // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.mir -// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.mir -// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir pub fn main() { block_on(async { let b = 2i32; diff --git a/tests/ui/stable-mir-print/async-closure.stdout b/tests/ui/stable-mir-print/async-closure.stdout index 21df1fd39540..12e7a5530ace 100644 --- a/tests/ui/stable-mir-print/async-closure.stdout +++ b/tests/ui/stable-mir-print/async-closure.stdout @@ -56,7 +56,7 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo unreachable; } } -fn foo::{closure#0}::{closure#1}(_1: Pin<&mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}>, _2: &mut Context<'_>) -> Poll<()> { +fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}>, _2: &mut Context<'_>) -> Poll<()> { let mut _0: Poll<()>; let _3: i32; let mut _4: &i32; From 73d33ed1bafdf3c0b32e936492eb6a9cdd9b080c Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Mon, 31 Mar 2025 01:26:55 +0200 Subject: [PATCH 464/546] Remove mention of `exhaustive_patterns` from `never` docs --- library/core/src/primitive_docs.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 89c856fe1074..ba4c849837e7 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -127,15 +127,13 @@ mod prim_bool {} /// [`Result`] which we can unpack like this: /// /// ``` -/// #![feature(exhaustive_patterns)] /// use std::str::FromStr; /// let Ok(s) = String::from_str("hello"); /// ``` /// -/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` -/// feature is present this means we can exhaustively match on [`Result`] by just taking the -/// [`Ok`] variant. This illustrates another behavior of `!` - it can be used to "delete" certain -/// enum variants from generic types like `Result`. +/// Since the [`Err`] variant contains a `!`, it can never occur. This means we can exhaustively +/// match on [`Result`] by just taking the [`Ok`] variant. This illustrates another behavior +/// of `!` - it can be used to "delete" certain enum variants from generic types like `Result`. /// /// ## Infinite loops /// From 0666b740e5fd06f682a9a8d539b6ea3bb1d56538 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:49:58 +0000 Subject: [PATCH 465/546] Simplify find_commandline_library --- compiler/rustc_metadata/src/locator.rs | 44 ++++++++++---------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index d5dd5059aacc..038236827489 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -728,37 +728,25 @@ impl<'a> CrateLocator<'a> { let Some(file) = loc_orig.file_name().and_then(|s| s.to_str()) else { return Err(CrateError::ExternLocationNotFile(self.crate_name, loc_orig.clone())); }; - // FnMut cannot return reference to captured value, so references - // must be taken outside the closure. - let rlibs = &mut rlibs; - let rmetas = &mut rmetas; - let dylibs = &mut dylibs; - let type_via_filename = (|| { - if file.starts_with("lib") { - if file.ends_with(".rlib") { - return Some(rlibs); - } - if file.ends_with(".rmeta") { - return Some(rmetas); - } + if file.starts_with("lib") { + if file.ends_with(".rlib") { + rlibs.insert(loc_canon.clone(), PathKind::ExternFlag); + continue; } - let dll_prefix = self.target.dll_prefix.as_ref(); - let dll_suffix = self.target.dll_suffix.as_ref(); - if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) { - return Some(dylibs); - } - None - })(); - match type_via_filename { - Some(type_via_filename) => { - type_via_filename.insert(loc_canon.clone(), PathKind::ExternFlag); - } - None => { - self.crate_rejections - .via_filename - .push(CrateMismatch { path: loc_orig.clone(), got: String::new() }); + if file.ends_with(".rmeta") { + rmetas.insert(loc_canon.clone(), PathKind::ExternFlag); + continue; } } + let dll_prefix = self.target.dll_prefix.as_ref(); + let dll_suffix = self.target.dll_suffix.as_ref(); + if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) { + dylibs.insert(loc_canon.clone(), PathKind::ExternFlag); + continue; + } + self.crate_rejections + .via_filename + .push(CrateMismatch { path: loc_orig.clone(), got: String::new() }); } // Extract the dylib/rlib/rmeta triple. From 9800eb2cabd962ff1899e94841b15ca9dc874528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 20 Feb 2025 21:23:10 +0100 Subject: [PATCH 466/546] Add `-Zembed-metadata` CLI option --- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index b44be1710edf..4592e0144388 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -787,6 +787,7 @@ fn test_unstable_options_tracking_hash() { tracked!(direct_access_external_data, Some(true)); tracked!(dual_proc_macros, true); tracked!(dwarf_version, Some(5)); + tracked!(embed_metadata, false); tracked!(embed_source, true); tracked!(emit_thin_lto, false); tracked!(emscripten_wasm_eh, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4cc666b3e37d..cd5e2c4173e7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2175,6 +2175,8 @@ options! { them only if an error has not been emitted"), ehcont_guard: bool = (false, parse_bool, [TRACKED], "generate Windows EHCont Guard tables"), + embed_metadata: bool = (true, parse_bool, [TRACKED], + "embed metadata in rlibs and dylibs (default: yes)"), embed_source: bool = (false, parse_bool, [TRACKED], "embed source text in DWARF debug sections (default: no)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], From a5057b786b1f6fd04c4b590ea7eb160e36c281db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 20 Feb 2025 21:34:11 +0100 Subject: [PATCH 467/546] Add documentation of the option into the unstable book --- src/doc/unstable-book/src/compiler-flags/embed-metadata.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/embed-metadata.md diff --git a/src/doc/unstable-book/src/compiler-flags/embed-metadata.md b/src/doc/unstable-book/src/compiler-flags/embed-metadata.md new file mode 100644 index 000000000000..a2a790ee76af --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/embed-metadata.md @@ -0,0 +1,3 @@ +## `embed-metadata` + +This option instructs `rustc` to include the full metadata in `rlib` and `dylib` crate types. The default value is `yes` (enabled). If disabled (`no`), only stub metadata will be stored in these files, to reduce their size on disk. When using `-Zembed-metadata=no`, you will probably want to use `--emit=metadata` to produce the full metadata into a separate `.rmeta` file. From 4dca28cfa27661e0d87f9de23761445cac62d2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 28 Mar 2025 17:58:23 +0100 Subject: [PATCH 468/546] Store only a metadata stub into `rlibs` and `dylibs` with `-Zembed-metadata=no` --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- .../rustc_codegen_ssa/src/back/metadata.rs | 4 +- compiler/rustc_metadata/src/fs.rs | 26 ++++-- compiler/rustc_metadata/src/rmeta/encoder.rs | 91 +++++++++++++++---- compiler/rustc_metadata/src/rmeta/mod.rs | 6 ++ 5 files changed, 101 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b59d73a9aae0..7d4110872417 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -294,7 +294,7 @@ fn link_rlib<'a>( let (metadata, metadata_position) = create_wrapper_file( sess, ".rmeta".to_string(), - codegen_results.metadata.raw_data(), + codegen_results.metadata.stub_or_full(), ); let metadata = emit_wrapper_file(sess, &metadata, tmpdir, METADATA_FILENAME); match metadata_position { diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 68b453ff4242..ac9ac9bbb31f 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -540,8 +540,8 @@ pub fn create_compressed_metadata_file( symbol_name: &str, ) -> Vec { let mut packed_metadata = rustc_metadata::METADATA_HEADER.to_vec(); - packed_metadata.write_all(&(metadata.raw_data().len() as u64).to_le_bytes()).unwrap(); - packed_metadata.extend(metadata.raw_data()); + packed_metadata.write_all(&(metadata.stub_or_full().len() as u64).to_le_bytes()).unwrap(); + packed_metadata.extend(metadata.stub_or_full()); let Some(mut file) = create_object_file(sess) else { if sess.target.is_like_wasm { diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index 4450d050c8e1..c4e1e0f1d1a9 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -3,7 +3,7 @@ use std::{fs, io}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{OutFileName, OutputType}; +use rustc_session::config::{CrateType, OutFileName, OutputType}; use rustc_session::output::filename_for_metadata; use rustc_session::{MetadataKind, Session}; use tempfile::Builder as TempFileBuilder; @@ -50,7 +50,14 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new(""))) .unwrap_or_else(|err| tcx.dcx().emit_fatal(FailedCreateTempdir { err })); let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); - let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME); + let metadata_filename = metadata_tmpdir.as_ref().join("full.rmeta"); + let metadata_stub_filename = if !tcx.sess.opts.unstable_opts.embed_metadata + && !tcx.crate_types().contains(&CrateType::ProcMacro) + { + Some(metadata_tmpdir.as_ref().join("stub.rmeta")) + } else { + None + }; // Always create a file at `metadata_filename`, even if we have nothing to write to it. // This simplifies the creation of the output `out_filename` when requested. @@ -60,9 +67,15 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { std::fs::File::create(&metadata_filename).unwrap_or_else(|err| { tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_filename, err }); }); + if let Some(metadata_stub_filename) = &metadata_stub_filename { + std::fs::File::create(metadata_stub_filename).unwrap_or_else(|err| { + tcx.dcx() + .emit_fatal(FailedCreateFile { filename: &metadata_stub_filename, err }); + }); + } } MetadataKind::Uncompressed | MetadataKind::Compressed => { - encode_metadata(tcx, &metadata_filename); + encode_metadata(tcx, &metadata_filename, metadata_stub_filename.as_deref()) } }; @@ -100,9 +113,10 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { // Load metadata back to memory: codegen may need to include it in object files. let metadata = - EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|err| { - tcx.dcx().emit_fatal(FailedCreateEncodedMetadata { err }); - }); + EncodedMetadata::from_path(metadata_filename, metadata_stub_filename, metadata_tmpdir) + .unwrap_or_else(|err| { + tcx.dcx().emit_fatal(FailedCreateEncodedMetadata { err }); + }); let need_metadata_module = metadata_kind == MetadataKind::Compressed; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7ab3d432bdf8..386d3d3156a1 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -701,6 +701,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { triple: tcx.sess.opts.target_triple.clone(), hash: tcx.crate_hash(LOCAL_CRATE), is_proc_macro_crate: proc_macro_data.is_some(), + is_stub: false, }, extra_filename: tcx.sess.opts.cg.extra_filename.clone(), stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), @@ -2231,8 +2232,12 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { // generated regardless of trailing bytes that end up in it. pub struct EncodedMetadata { - // The declaration order matters because `mmap` should be dropped before `_temp_dir`. - mmap: Option, + // The declaration order matters because `full_metadata` should be dropped + // before `_temp_dir`. + full_metadata: Option, + // This is an optional stub metadata containing only the crate header. + // The header should be very small, so we load it directly into memory. + stub_metadata: Option>, // We need to carry MaybeTempDir to avoid deleting the temporary // directory while accessing the Mmap. _temp_dir: Option, @@ -2240,33 +2245,50 @@ pub struct EncodedMetadata { impl EncodedMetadata { #[inline] - pub fn from_path(path: PathBuf, temp_dir: Option) -> std::io::Result { + pub fn from_path( + path: PathBuf, + stub_path: Option, + temp_dir: Option, + ) -> std::io::Result { let file = std::fs::File::open(&path)?; let file_metadata = file.metadata()?; if file_metadata.len() == 0 { - return Ok(Self { mmap: None, _temp_dir: None }); + return Ok(Self { full_metadata: None, stub_metadata: None, _temp_dir: None }); } - let mmap = unsafe { Some(Mmap::map(file)?) }; - Ok(Self { mmap, _temp_dir: temp_dir }) + let full_mmap = unsafe { Some(Mmap::map(file)?) }; + + let stub = + if let Some(stub_path) = stub_path { Some(std::fs::read(stub_path)?) } else { None }; + + Ok(Self { full_metadata: full_mmap, stub_metadata: stub, _temp_dir: temp_dir }) } #[inline] - pub fn raw_data(&self) -> &[u8] { - self.mmap.as_deref().unwrap_or_default() + pub fn full(&self) -> &[u8] { + &self.full_metadata.as_deref().unwrap_or_default() + } + + #[inline] + pub fn stub_or_full(&self) -> &[u8] { + self.stub_metadata.as_deref().unwrap_or(self.full()) } } impl Encodable for EncodedMetadata { fn encode(&self, s: &mut S) { - let slice = self.raw_data(); + self.stub_metadata.encode(s); + + let slice = self.full(); slice.encode(s) } } impl Decodable for EncodedMetadata { fn decode(d: &mut D) -> Self { + let stub = >>::decode(d); + let len = d.read_usize(); - let mmap = if len > 0 { + let full_metadata = if len > 0 { let mut mmap = MmapMut::map_anon(len).unwrap(); mmap.copy_from_slice(d.read_raw_bytes(len)); Some(mmap.make_read_only().unwrap()) @@ -2274,11 +2296,11 @@ impl Decodable for EncodedMetadata { None }; - Self { mmap, _temp_dir: None } + Self { full_metadata, stub_metadata: stub, _temp_dir: None } } } -pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { +pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path, ref_path: Option<&Path>) { let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata"); // Since encoding metadata is not in a query, and nothing is cached, @@ -2292,6 +2314,42 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE)); } + with_encode_metadata_header(tcx, path, |ecx| { + // Encode all the entries and extra information in the crate, + // culminating in the `CrateRoot` which points to all of it. + let root = ecx.encode_crate_root(); + + // Flush buffer to ensure backing file has the correct size. + ecx.opaque.flush(); + // Record metadata size for self-profiling + tcx.prof.artifact_size( + "crate_metadata", + "crate_metadata", + ecx.opaque.file().metadata().unwrap().len(), + ); + + root.position.get() + }); + + if let Some(ref_path) = ref_path { + with_encode_metadata_header(tcx, ref_path, |ecx| { + let header: LazyValue = ecx.lazy(CrateHeader { + name: tcx.crate_name(LOCAL_CRATE), + triple: tcx.sess.opts.target_triple.clone(), + hash: tcx.crate_hash(LOCAL_CRATE), + is_proc_macro_crate: false, + is_stub: true, + }); + header.position.get() + }); + } +} + +fn with_encode_metadata_header( + tcx: TyCtxt<'_>, + path: &Path, + f: impl FnOnce(&mut EncodeContext<'_, '_>) -> usize, +) { let mut encoder = opaque::FileEncoder::new(path) .unwrap_or_else(|err| tcx.dcx().emit_fatal(FailCreateFileEncoder { err })); encoder.emit_raw_bytes(METADATA_HEADER); @@ -2326,9 +2384,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { // Encode the rustc version string in a predictable location. rustc_version(tcx.sess.cfg_version).encode(&mut ecx); - // Encode all the entries and extra information in the crate, - // culminating in the `CrateRoot` which points to all of it. - let root = ecx.encode_crate_root(); + let root_position = f(&mut ecx); // Make sure we report any errors from writing to the file. // If we forget this, compilation can succeed with an incomplete rmeta file, @@ -2338,12 +2394,9 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { } let file = ecx.opaque.file(); - if let Err(err) = encode_root_position(file, root.position.get()) { + if let Err(err) = encode_root_position(file, root_position) { tcx.dcx().emit_fatal(FailWriteFile { path: ecx.opaque.path(), err }); } - - // Record metadata size for self-profiling - tcx.prof.artifact_size("crate_metadata", "crate_metadata", file.metadata().unwrap().len()); } fn encode_root_position(mut file: &File, pos: usize) -> Result<(), std::io::Error> { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index dc453b1e747c..bbdc986ef7a2 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -221,6 +221,12 @@ pub(crate) struct CrateHeader { /// This is separate from [`ProcMacroData`] to avoid having to update [`METADATA_VERSION`] every /// time ProcMacroData changes. pub(crate) is_proc_macro_crate: bool, + /// Whether this crate metadata section is just a stub. + /// Stubs do not contain the full metadata (it will be typically stored + /// in a separate rmeta file). + /// + /// This is used inside rlibs and dylibs when using `-Zembed-metadata=no`. + pub(crate) is_stub: bool, } /// Serialized `.rmeta` data for a crate. From 674a7adf9bd765354f58c50f3632f3410a6ac9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 14 Mar 2025 11:45:22 +0100 Subject: [PATCH 469/546] Add an error when full metadata was not found --- compiler/rustc_metadata/messages.ftl | 4 ++++ compiler/rustc_metadata/src/errors.rs | 9 +++++++++ compiler/rustc_metadata/src/locator.rs | 23 ++++++++++++++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 9adbcabcf450..d997ba198aca 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -97,6 +97,10 @@ metadata_found_staticlib = found staticlib `{$crate_name}` instead of rlib or dylib{$add_info} .help = please recompile that crate using --crate-type lib +metadata_full_metadata_not_found = + only metadata stub found for `{$flavor}` dependency `{$crate_name}` + please provide path to the corresponding .rmeta file with full metadata + metadata_global_alloc_required = no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 0c54628598c4..c45daeda85db 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -525,6 +525,15 @@ impl Diagnostic<'_, G> for MultipleCandidates { } } +#[derive(Diagnostic)] +#[diag(metadata_full_metadata_not_found)] +pub(crate) struct FullMetadataNotFound { + #[primary_span] + pub span: Span, + pub flavor: CrateFlavor, + pub crate_name: Symbol, +} + #[derive(Diagnostic)] #[diag(metadata_symbol_conflicts_current, code = E0519)] pub struct SymbolConflictsCurrent { diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 038236827489..112954eca0df 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -654,7 +654,24 @@ impl<'a> CrateLocator<'a> { continue; } } - *slot = Some((hash, metadata, lib.clone())); + + // We error eagerly here. If we're locating a rlib, then in theory the full metadata + // could still be in a (later resolved) dylib. In practice, if the rlib and dylib + // were produced in a way where one has full metadata and the other hasn't, it would + // mean that they were compiled using different compiler flags and probably also have + // a different SVH value. + if metadata.get_header().is_stub { + // `is_stub` should never be true for .rmeta files. + assert_ne!(flavor, CrateFlavor::Rmeta); + + // Because rmeta files are resolved before rlib/dylib files, if this is a stub and + // we haven't found a slot already, it means that the full metadata is missing. + if slot.is_none() { + return Err(CrateError::FullMetadataNotFound(self.crate_name, flavor)); + } + } else { + *slot = Some((hash, metadata, lib.clone())); + } ret = Some((lib, kind)); } @@ -916,6 +933,7 @@ pub(crate) enum CrateError { ExternLocationNotExist(Symbol, PathBuf), ExternLocationNotFile(Symbol, PathBuf), MultipleCandidates(Symbol, CrateFlavor, Vec), + FullMetadataNotFound(Symbol, CrateFlavor), SymbolConflictsCurrent(Symbol), StableCrateIdCollision(Symbol, Symbol), DlOpen(String, String), @@ -966,6 +984,9 @@ impl CrateError { CrateError::MultipleCandidates(crate_name, flavor, candidates) => { dcx.emit_err(errors::MultipleCandidates { span, crate_name, flavor, candidates }); } + CrateError::FullMetadataNotFound(crate_name, flavor) => { + dcx.emit_err(errors::FullMetadataNotFound { span, crate_name, flavor }); + } CrateError::SymbolConflictsCurrent(root_name) => { dcx.emit_err(errors::SymbolConflictsCurrent { span, crate_name: root_name }); } From 5a71da56d88b52a89b24dd64dad4421994a7a39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 14 Mar 2025 11:45:25 +0100 Subject: [PATCH 470/546] Add tests --- tests/run-make/embed-metadata/dep1.rs | 1 + tests/run-make/embed-metadata/foo.rs | 5 ++ tests/run-make/embed-metadata/rmake.rs | 86 ++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 tests/run-make/embed-metadata/dep1.rs create mode 100644 tests/run-make/embed-metadata/foo.rs create mode 100644 tests/run-make/embed-metadata/rmake.rs diff --git a/tests/run-make/embed-metadata/dep1.rs b/tests/run-make/embed-metadata/dep1.rs new file mode 100644 index 000000000000..be70c3933e09 --- /dev/null +++ b/tests/run-make/embed-metadata/dep1.rs @@ -0,0 +1 @@ +pub fn func_dep1() {} diff --git a/tests/run-make/embed-metadata/foo.rs b/tests/run-make/embed-metadata/foo.rs new file mode 100644 index 000000000000..0cc9cede8608 --- /dev/null +++ b/tests/run-make/embed-metadata/foo.rs @@ -0,0 +1,5 @@ +extern crate dep1; + +fn main() { + dep1::func_dep1(); +} diff --git a/tests/run-make/embed-metadata/rmake.rs b/tests/run-make/embed-metadata/rmake.rs new file mode 100644 index 000000000000..acefb1864844 --- /dev/null +++ b/tests/run-make/embed-metadata/rmake.rs @@ -0,0 +1,86 @@ +// Tests the -Zembed-metadata compiler flag. +// Tracking issue: https://github.com/rust-lang/rust/issues/139165 + +use run_make_support::rfs::{create_dir, remove_file, rename}; +use run_make_support::{Rustc, dynamic_lib_name, path, run_in_tmpdir, rust_lib_name, rustc}; + +#[derive(Debug, Copy, Clone)] +enum LibraryKind { + Rlib, + Dylib, +} + +impl LibraryKind { + fn crate_type(&self) -> &str { + match self { + LibraryKind::Rlib => "rlib", + LibraryKind::Dylib => "dylib", + } + } + + fn add_extern(&self, rustc: &mut Rustc, dep_name: &str, dep_path: &str) { + let dep_path = match self { + LibraryKind::Dylib => format!("{dep_path}/{}", dynamic_lib_name(dep_name)), + LibraryKind::Rlib => format!("{dep_path}/{}", rust_lib_name(dep_name)), + }; + rustc.extern_(dep_name, dep_path); + } +} + +fn main() { + // The compiler takes different paths based on if --extern is passed or not, so we test all + // combinations (`rlib`/`dylib` x `--extern`/`no --extern`). + for kind in [LibraryKind::Rlib, LibraryKind::Dylib] { + eprintln!("Testing library kind {kind:?}"); + lookup_rmeta_in_lib_dir(kind); + lookup_rmeta_through_extern(kind); + lookup_rmeta_missing(kind); + } +} + +// Lookup .rmeta file in the same directory as a rlib/dylib with stub metadata. +fn lookup_rmeta_in_lib_dir(kind: LibraryKind) { + run_in_tmpdir(|| { + build_dep_rustc(kind).run(); + rustc().input("foo.rs").run(); + }); +} + +// Lookup .rmeta file when specifying the dependency using --extern. +fn lookup_rmeta_through_extern(kind: LibraryKind) { + run_in_tmpdir(|| { + // Generate libdep1.rlib and libdep1.rmeta in deps + create_dir("deps"); + build_dep_rustc(kind).out_dir("deps").run(); + + let mut rustc = rustc(); + kind.add_extern(&mut rustc, "dep1", "deps"); + rustc.extern_("dep1", path("deps").join("libdep1.rmeta")); + rustc.input("foo.rs").run(); + }); +} + +// Check the error message when the .rmeta file is missing. +fn lookup_rmeta_missing(kind: LibraryKind) { + run_in_tmpdir(|| { + create_dir("deps"); + build_dep_rustc(kind).out_dir("deps").run(); + + let mut rustc = rustc(); + kind.add_extern(&mut rustc, "dep1", "deps"); + rustc.input("foo.rs").run_fail().assert_stderr_contains("only metadata stub found"); + }); +} + +fn build_dep_rustc(kind: LibraryKind) -> Rustc { + let mut dep_rustc = rustc(); + dep_rustc + .arg("-Zembed-metadata=no") + .crate_type(kind.crate_type()) + .input("dep1.rs") + .emit("metadata,link"); + if matches!(kind, LibraryKind::Dylib) { + dep_rustc.arg("-Cprefer-dynamic"); + } + dep_rustc +} From 53f4397bd9c6b83936725fcf8d640be231c6facd Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 31 Mar 2025 11:01:46 +0100 Subject: [PATCH 471/546] Remove Amanieu from the libs review rotation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 217da9935383..3e7a441c4532 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1161,7 +1161,6 @@ compiler = [ ] libs = [ "@Mark-Simulacrum", - "@Amanieu", "@Noratrieb", "@workingjubilee", "@joboet", From 4e99dca8c35b37fcf097e7bd3c2b00abb7a64dfb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 31 Mar 2025 15:37:16 +0200 Subject: [PATCH 472/546] Remove fragile equal-pointers-unequal/*/print3.rs tests. --- .../equal-pointers-unequal/as-cast/print3.rs | 23 ----------------- .../exposed-provenance/print3.rs | 25 ------------------- .../strict-provenance/print3.rs | 25 ------------------- 3 files changed, 73 deletions(-) delete mode 100644 tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs delete mode 100644 tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs deleted file mode 100644 index eda83e999a52..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -fn main() { - let a = { - let v = 0; - &v as *const _ as usize - }; - let b = { - let v = 0; - &v as *const _ as usize - }; - - assert_ne!(a, b); - assert_ne!(a, b); - let c = a; - assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "false true false"); - println!("{a} {b}"); - assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "true true true"); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs deleted file mode 100644 index c7f46318aaef..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0; - ptr::from_ref(&v).expose_provenance() - }; - let b: usize = { - let v = 0; - ptr::from_ref(&v).expose_provenance() - }; - - assert_ne!(a, b); - assert_ne!(a, b); - let c = a; - assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "false true false"); - println!("{a} {b}"); - assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "true true true"); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs deleted file mode 100644 index a02ff30918da..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0; - ptr::from_ref(&v).addr() - }; - let b: usize = { - let v = 0; - ptr::from_ref(&v).addr() - }; - - assert_ne!(a, b); - assert_ne!(a, b); - let c = a; - assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "false true false"); - println!("{a} {b}"); - assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "true true true"); -} From dea947212795fb4fcdef2b2351008d08be3fb854 Mon Sep 17 00:00:00 2001 From: reez12g Date: Sun, 30 Mar 2025 17:53:19 +0900 Subject: [PATCH 473/546] Add tests for LLVM 20 slice bounds check optimization --- .../slice-last-elements-optimization.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/codegen/slice-last-elements-optimization.rs diff --git a/tests/codegen/slice-last-elements-optimization.rs b/tests/codegen/slice-last-elements-optimization.rs new file mode 100644 index 000000000000..b90f91d7b17b --- /dev/null +++ b/tests/codegen/slice-last-elements-optimization.rs @@ -0,0 +1,37 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 +//@ min-llvm-version: 20 +#![crate_type = "lib"] + +// This test verifies that LLVM 20 properly optimizes the bounds check +// when accessing the last few elements of a slice with proper conditions. +// Previously, this would generate an unreachable branch to +// slice_start_index_len_fail even when the bounds check was provably safe. + +// CHECK-LABEL: @last_four_initial( +#[no_mangle] +pub fn last_four_initial(s: &[u8]) -> &[u8] { + // Previously this would generate a branch to slice_start_index_len_fail + // that is unreachable. The LLVM 20 fix should eliminate this branch. + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: unreachable + let start = if s.len() <= 4 { 0 } else { s.len() - 4 }; + &s[start..] +} + +// CHECK-LABEL: @last_four_optimized( +#[no_mangle] +pub fn last_four_optimized(s: &[u8]) -> &[u8] { + // This version was already correctly optimized before the fix in LLVM 20. + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: unreachable + if s.len() <= 4 { &s[0..] } else { &s[s.len() - 4..] } +} + +// Just to verify we're correctly checking for the right thing +// CHECK-LABEL: @test_bounds_check_happens( +#[no_mangle] +pub fn test_bounds_check_happens(s: &[u8], i: usize) -> &[u8] { + // CHECK: slice_start_index_len_fail + &s[i..] +} From 1238a20d38d976ccd4ccecf1b9e2cab039ab6d63 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 31 Mar 2025 17:58:05 +0200 Subject: [PATCH 474/546] Expose `LintLevelsBuilder` with crate root builder --- compiler/rustc_lint/src/levels.rs | 13 +++++++++++++ compiler/rustc_lint/src/lib.rs | 1 + 2 files changed, 14 insertions(+) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 8718fb807ecf..313d8f6ba8ff 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -450,6 +450,19 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { builder } + pub fn crate_root( + sess: &'s Session, + features: &'s Features, + lint_added_lints: bool, + store: &'s LintStore, + registered_tools: &'s RegisteredTools, + crate_attrs: &[ast::Attribute], + ) -> Self { + let mut builder = Self::new(sess, features, lint_added_lints, store, registered_tools); + builder.add(crate_attrs, true, None); + builder + } + fn process_command_line(&mut self) { self.provider.cur = self .provider diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c38a75400181..0c875a4b1bc0 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -129,6 +129,7 @@ pub use context::{ }; pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; +pub use levels::LintLevelsBuilder; pub use passes::{EarlyLintPass, LateLintPass}; pub use rustc_session::lint::Level::{self, *}; pub use rustc_session::lint::{ From 69cb0a9e15393bf9dea483725a2cfdba74dff47d Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 31 Mar 2025 18:00:28 +0200 Subject: [PATCH 475/546] Expose `registered_tools` directly without `TyCtxt`-query --- compiler/rustc_resolve/src/lib.rs | 2 ++ compiler/rustc_resolve/src/macros.rs | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 78153fd41740..6ef26d7d53a6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -88,6 +88,8 @@ mod late; mod macros; pub mod rustdoc; +pub use macros::registered_tools_ast; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[derive(Debug)] diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 3637854f1204..49156f2d856c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -10,7 +10,7 @@ use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::{AttributeKind, StabilityLevel, find_attr}; use rustc_data_structures::intern::Interned; -use rustc_errors::{Applicability, StashKey}; +use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, }; @@ -124,14 +124,21 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { - let mut registered_tools = RegisteredTools::default(); let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); + registered_tools_ast(tcx.dcx(), pre_configured_attrs) +} + +pub fn registered_tools_ast( + dcx: DiagCtxtHandle<'_>, + pre_configured_attrs: &[ast::Attribute], +) -> RegisteredTools { + let mut registered_tools = RegisteredTools::default(); for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) { for meta_item_inner in attr.meta_item_list().unwrap_or_default() { match meta_item_inner.ident() { Some(ident) => { if let Some(old_ident) = registered_tools.replace(ident) { - tcx.dcx().emit_err(errors::ToolWasAlreadyRegistered { + dcx.emit_err(errors::ToolWasAlreadyRegistered { span: ident.span, tool: ident, old_ident_span: old_ident.span, @@ -139,7 +146,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { } } None => { - tcx.dcx().emit_err(errors::ToolOnlyAcceptsIdentifiers { + dcx.emit_err(errors::ToolOnlyAcceptsIdentifiers { span: meta_item_inner.span(), tool: sym::register_tool, }); From 3ef1a3f1c5775357c6192584a42bb6469c1f51b8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 31 Mar 2025 16:10:02 +0000 Subject: [PATCH 476/546] Remove ChrisDenton from on vacation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 217da9935383..47a8c588ad9e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1124,7 +1124,6 @@ warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "jyn514", - "ChrisDenton", "saethlin", ] From 753968162a423d5a63ca86ef509d4aaf18ac1f9a Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 31 Mar 2025 16:42:01 +0000 Subject: [PATCH 477/546] Fix invalid link --- compiler/rustc_middle/src/ty/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ac98cbc8d6cb..0ffaef82f1c8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -953,7 +953,7 @@ impl<'tcx> rustc_type_ir::Flags for Clauses<'tcx> { /// environment. `ParamEnv` is the type that represents this information. See the /// [dev guide chapter][param_env_guide] for more information. /// -/// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html +/// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/typing_parameter_envs.html #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] #[derive(HashStable, TypeVisitable, TypeFoldable)] pub struct ParamEnv<'tcx> { @@ -977,7 +977,7 @@ impl<'tcx> ParamEnv<'tcx> { /// to use an empty environment. See the [dev guide section][param_env_guide] /// for information on what a `ParamEnv` is and how to acquire one. /// - /// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html + /// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/typing_parameter_envs.html #[inline] pub fn empty() -> Self { Self::new(ListWithCachedTypeInfo::empty()) From ebca98fa2ff11cf1fc4d753a12db4b1c0bddeda9 Mon Sep 17 00:00:00 2001 From: apiraino Date: Mon, 31 Mar 2025 16:39:25 +0200 Subject: [PATCH 478/546] Remove cjgillot from automated review assignment --- triagebot.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index ebbcfa4516b9..865429cf5fa0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1115,7 +1115,6 @@ compiler_leads = [ ] compiler = [ "@BoxyUwU", - "@cjgillot", "@compiler-errors", "@davidtwco", "@estebank", @@ -1171,7 +1170,7 @@ codegen = [ "@workingjubilee", ] query-system = [ - "@cjgillot", + "@oli-obk", ] incremental = [ "@wesleywiser", From b14a0ce7f6b9b72d3495fc9b0d632fd14400dcec Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Mon, 31 Mar 2025 14:34:14 -0400 Subject: [PATCH 479/546] PassWrapper: adapt for llvm/llvm-project@94122d58fc77079a291a3d008914006cb509d9db We also have to remove the LLVM argument in cast-target-abi.rs for LLVM 21. I'm not really sure what the best approach here is since that test already uses revisions. We could also fork the test into a copy for LLVM 19-20 and another for LLVM 21, but what I did for now was drop the lint-abort-on-error flag to LLVM figuring that some coverage was better than none, but I'm happy to change this if that was a bad direction. The above also applies for ffi-out-of-bounds-loads.rs. r? dianqk @rustbot label llvm-main --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 13 +++++++++---- tests/codegen/cast-target-abi.rs | 2 +- tests/codegen/cffi/ffi-out-of-bounds-loads.rs | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 86f1bcc46eea..257bdc01993f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -855,10 +855,15 @@ extern "C" LLVMRustResult LLVMRustOptimize( } if (LintIR) { - PipelineStartEPCallbacks.push_back( - [](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(createModuleToFunctionPassAdaptor(LintPass())); - }); + PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM, + OptimizationLevel Level) { +#if LLVM_VERSION_GE(21, 0) + MPM.addPass( + createModuleToFunctionPassAdaptor(LintPass(/*AbortOnError=*/true))); +#else + MPM.addPass(createModuleToFunctionPassAdaptor(LintPass())); +#endif + }); } if (InstrumentCoverage) { diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs index 186198bc631e..e1a7ad718a06 100644 --- a/tests/codegen/cast-target-abi.rs +++ b/tests/codegen/cast-target-abi.rs @@ -2,7 +2,7 @@ //@ add-core-stubs //@ revisions:aarch64 loongarch64 powerpc64 sparc64 x86_64 //@ min-llvm-version: 19 -//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Zlint-llvm-ir -Cllvm-args=-lint-abort-on-error +//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Zlint-llvm-ir //@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu //@[aarch64] needs-llvm-components: arm diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs index 404f6237849e..73bc7ef6b77d 100644 --- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs +++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs @@ -1,7 +1,7 @@ //@ add-core-stubs //@ revisions: linux apple //@ min-llvm-version: 19 -//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -Zlint-llvm-ir -Cllvm-args=-lint-abort-on-error +//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -Zlint-llvm-ir //@[linux] compile-flags: --target x86_64-unknown-linux-gnu //@[linux] needs-llvm-components: x86 From a6a6d01bbc93da72474983d355e7442abbd162e8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 26 Mar 2025 09:47:46 +1100 Subject: [PATCH 480/546] Use `sym::dummy` in one more place. It makes it clearer that the symbol is unused and doesn't matter. --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 63ea8c4ced13..f7343b93281f 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1091,7 +1091,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { )); } Scope::BuiltinAttrs => { - let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(kw::Empty)); + let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(sym::dummy)); if filter_fn(res) { suggestions.extend( BUILTIN_ATTRIBUTES diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e7a8dee27f56..9959e98e3dd7 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1440,7 +1440,8 @@ pub fn decode_syntax_context SyntaxContext } } Entry::Vacant(entry) => { - // We are the first thread to start decoding. Mark the current thread as being progress. + // We are the first thread to start decoding. Mark the current thread as being + // progress. context.local_in_progress.borrow_mut().insert(raw_id); // Allocate and store SyntaxContext id *before* calling the decoder function, From 9fb0defa520c82ccf79af7961ee926dba77b4e96 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 26 Mar 2025 13:23:13 +1100 Subject: [PATCH 481/546] Tweak `check_doc_keyword`. To use one `kw::Empty` instead of two. It's a little more direct this way, and avoids `kw::Empty` being used for both "no string" and "empty string". --- compiler/rustc_passes/src/check_attr.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ada3151c3b8c..3019c5c0dae8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1041,11 +1041,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { s <= kw::Union || s == sym::SelfTy } - let doc_keyword = meta.value_str().unwrap_or(kw::Empty); - if doc_keyword == kw::Empty { - self.doc_attr_str_error(meta, "keyword"); - return; - } + let doc_keyword = match meta.value_str() { + Some(value) if value != kw::Empty => value, + _ => return self.doc_attr_str_error(meta, "keyword"), + }; + let item_kind = match self.tcx.hir_node(hir_id) { hir::Node::Item(item) => Some(&item.kind), _ => None, From 929749d8018b3a5afde968cff6da11b8460dd52d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 26 Mar 2025 13:33:38 +1100 Subject: [PATCH 482/546] Improve `is_doc_keyword`. This is part of the implementation of `#[doc(keyword = "match")]` attributes used by `std` to provide documentation for keywords. `is_doc_keyword` currently does a crude keyword range test that's intended to catch all keywords but misses `kw::Yeet`. This commit changes it to use `Symbol` methods, including the new `is_weak` method (required for `union`). `Symbol` methods are much less prone to falling out of date if new keywords are added. --- compiler/rustc_passes/src/check_attr.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3019c5c0dae8..cfc0369c5989 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, kw, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; @@ -1038,7 +1038,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the // `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`. - s <= kw::Union || s == sym::SelfTy + s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy } let doc_keyword = match meta.value_str() { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 47dd80c432ea..c6e570e524f5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -131,7 +131,7 @@ symbols! { // tidy-alphabetical-end // Weak keywords, have special meaning only in specific contexts. - // Matching predicates: none + // Matching predicates: `is_weak` // tidy-alphabetical-start Auto: "auto", Builtin: "builtin", @@ -2725,6 +2725,10 @@ impl Symbol { || self.is_unused_keyword_conditional(edition) } + pub fn is_weak(self) -> bool { + self >= kw::Auto && self <= kw::Yeet + } + /// A keyword or reserved identifier that can be used as a path segment. pub fn is_path_segment_keyword(self) -> bool { self == kw::Super From 27850631638e74bd017d963a35c53e7f81f42e4d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Mar 2025 22:56:13 +1100 Subject: [PATCH 483/546] Avoid `kw::Empty` use for `AuxParamsAttr`. By changing two of the fields to use `Option` instead of `Ident`. As a result, `None` now means "no identifier", which is much clearer than using an empty identifier. --- .../src/significant_drop_tightening.rs | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index e9db7c9d031a..76874cc34206 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -79,10 +79,11 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { if apa.counter <= 1 || !apa.has_expensive_expr_after_last_attr { continue; } + let first_bind_ident = apa.first_bind_ident.unwrap(); span_lint_and_then( cx, SIGNIFICANT_DROP_TIGHTENING, - apa.first_bind_ident.span, + first_bind_ident.span, "temporary with significant `Drop` can be early dropped", |diag| { match apa.counter { @@ -91,13 +92,13 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { let indent = " ".repeat(indent_of(cx, apa.last_stmt_span).unwrap_or(0)); let init_method = snippet(cx, apa.first_method_span, ".."); let usage_method = snippet(cx, apa.last_method_span, ".."); - let stmt = if apa.last_bind_ident == Ident::empty() { - format!("\n{indent}{init_method}.{usage_method};") - } else { + let stmt = if let Some(last_bind_ident) = apa.last_bind_ident { format!( "\n{indent}let {} = {init_method}.{usage_method};", - snippet(cx, apa.last_bind_ident.span, ".."), + snippet(cx, last_bind_ident.span, ".."), ) + } else { + format!("\n{indent}{init_method}.{usage_method};") }; diag.multipart_suggestion_verbose( @@ -113,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { format!( "\n{}drop({});", " ".repeat(indent_of(cx, apa.last_stmt_span).unwrap_or(0)), - apa.first_bind_ident + first_bind_ident ), Applicability::MaybeIncorrect, ); @@ -124,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { apa.first_block_span, format!( "temporary `{}` is currently being dropped at the end of its contained scope", - apa.first_bind_ident + first_bind_ident ), ); }, @@ -283,7 +284,7 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { let mut apa = AuxParamsAttr { first_block_hir_id: self.ap.curr_block_hir_id, first_block_span: self.ap.curr_block_span, - first_bind_ident: ident, + first_bind_ident: Some(ident), first_method_span: { let expr_or_init = expr_or_init(self.cx, expr); if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind { @@ -307,7 +308,7 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { match self.ap.curr_stmt.kind { hir::StmtKind::Let(local) => { if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { - apa.last_bind_ident = ident; + apa.last_bind_ident = Some(ident); } if let Some(local_init) = local.init && let hir::ExprKind::MethodCall(_, _, _, span) = local_init.kind @@ -373,7 +374,7 @@ struct AuxParamsAttr { first_block_span: Span, /// The binding or variable that references the initial construction of the type marked with /// `#[has_significant_drop]`. - first_bind_ident: Ident, + first_bind_ident: Option, /// Similar to `init_bind_ident` but encompasses the right-hand method call. first_method_span: Span, /// Similar to `init_bind_ident` but encompasses the whole contained statement. @@ -381,7 +382,7 @@ struct AuxParamsAttr { /// The last visited binding or variable span within a block that had any referenced inner type /// marked with `#[has_significant_drop]`. - last_bind_ident: Ident, + last_bind_ident: Option, /// Similar to `last_bind_span` but encompasses the right-hand method call. last_method_span: Span, /// Similar to `last_bind_span` but encompasses the whole contained statement. @@ -395,10 +396,10 @@ impl Default for AuxParamsAttr { has_expensive_expr_after_last_attr: false, first_block_hir_id: HirId::INVALID, first_block_span: DUMMY_SP, - first_bind_ident: Ident::empty(), + first_bind_ident: None, first_method_span: DUMMY_SP, first_stmt_span: DUMMY_SP, - last_bind_ident: Ident::empty(), + last_bind_ident: None, last_method_span: DUMMY_SP, last_stmt_span: DUMMY_SP, } @@ -413,7 +414,7 @@ fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> { } } -fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_>) -> bool { +fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Option, lcx: &LateContext<'_>) -> bool { if let hir::ExprKind::Call(fun, [first_arg]) = expr.kind && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind && let Res::Def(DefKind::Fn, did) = fun_path.res @@ -422,6 +423,7 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_ let has_ident = |local_expr: &hir::Expr<'_>| { if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind && let [first_arg_ps, ..] = arg_path.segments + && let Some(first_bind_ident) = first_bind_ident && &first_arg_ps.ident == first_bind_ident { true From 7feac15ca7f601b7ef0dd63e9113103f720f5405 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 16 Apr 2023 11:50:15 +0000 Subject: [PATCH 484/546] rustdoc-json: Add test for #[automatically_derived] attribute --- tests/rustdoc-json/attrs/automatically_derived.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/rustdoc-json/attrs/automatically_derived.rs diff --git a/tests/rustdoc-json/attrs/automatically_derived.rs b/tests/rustdoc-json/attrs/automatically_derived.rs new file mode 100644 index 000000000000..4e1ab3d145e5 --- /dev/null +++ b/tests/rustdoc-json/attrs/automatically_derived.rs @@ -0,0 +1,13 @@ +#[derive(Default)] +pub struct Derive; + +pub struct Manual; + +impl Default for Manual { + fn default() -> Self { + Self + } +} + +//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]' +//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]' From e2d5033bce2085fb2baaf5e887d11959928def74 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 31 Mar 2025 20:46:48 +0000 Subject: [PATCH 485/546] Feed HIR for by-move coroutine body def, since the inliner tries to read its attrs --- .../src/coroutine/by_move_body.rs | 2 ++ tests/crashes/134335.rs | 12 -------- .../by-move-body-inlined-attrs.rs | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+), 12 deletions(-) delete mode 100644 tests/crashes/134335.rs create mode 100644 tests/ui/async-await/async-closures/by-move-body-inlined-attrs.rs diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 89a306c61047..dd0e07f2218e 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -219,6 +219,8 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); + // Feed HIR because we try to access this body's attrs in the inliner. + body_def.feed_hir(); // Inherited from the by-ref coroutine. body_def.codegen_fn_attrs(tcx.codegen_fn_attrs(coroutine_def_id).clone()); body_def.coverage_attr_on(tcx.coverage_attr_on(coroutine_def_id)); diff --git a/tests/crashes/134335.rs b/tests/crashes/134335.rs deleted file mode 100644 index bee6686ff3fa..000000000000 --- a/tests/crashes/134335.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #134335 -//@compile-flags: -Zunstable-options --edition=2024 --crate-type=lib -pub async fn async_closure(x: &mut i32) { - let c = async move || { - *x += 1; - }; - call_once(c).await; -} - -fn call_once(f: impl FnOnce() -> T) -> T { - f() -} diff --git a/tests/ui/async-await/async-closures/by-move-body-inlined-attrs.rs b/tests/ui/async-await/async-closures/by-move-body-inlined-attrs.rs new file mode 100644 index 000000000000..ecfc06d2bad0 --- /dev/null +++ b/tests/ui/async-await/async-closures/by-move-body-inlined-attrs.rs @@ -0,0 +1,28 @@ +//@ check-pass +//@ compile-flags: -Zinline-mir -Zvalidate-mir +//@ edition: 2024 + +// See comment below. + +use std::future::Future; +use std::pin::pin; +use std::task::{Context, Waker}; + +fn call_once(f: impl FnOnce() -> T) -> T { f() } + +fn main() { + let x = async || {}; + // We first inline `call_once<{async closure}>`. + // + // This gives us a future whose type is the "FnOnce" flavor of the async closure's + // child coroutine. The body of this coroutine is synthetic, which we synthesize in + // the by-move body query. + let fut = pin!(call_once(x)); + // We then try to inline that body in this poll call. + // + // The inliner does some inlinability checks; one of these checks involves checking + // the body for the `#[rustc_no_mir_inline]` attribute. Since the synthetic body had + // no HIR synthesized, but it's still a local def id, we end up ICEing in the + // `local_def_id_to_hir_id` call when trying to read its attrs. + fut.poll(&mut Context::from_waker(Waker::noop())); +} From 654b7b541300c2d3d497031728b637ab4e457916 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 27 Mar 2025 16:12:00 +0100 Subject: [PATCH 486/546] increment depth of nested obligations --- .../src/traits/effects.rs | 8 --- .../src/traits/fulfill.rs | 56 ++++++++++++------- .../src/traits/select/confirmation.rs | 12 +--- tests/ui/infinite/infinite-autoderef.stderr | 4 +- tests/ui/occurs-check-2.rs | 2 +- tests/ui/occurs-check-2.stderr | 6 +- tests/ui/occurs-check-3.stderr | 4 +- tests/ui/occurs-check.stderr | 4 +- .../mutual-recursion-issue-75860.stderr | 2 +- ...ype-alias-impl-trait-with-cycle-error-1.rs | 3 +- ...alias-impl-trait-with-cycle-error-1.stderr | 11 ++-- ...ype-alias-impl-trait-with-cycle-error-2.rs | 4 +- ...alias-impl-trait-with-cycle-error-2.stderr | 11 ++-- ...ype-alias-impl-trait-with-cycle-error-3.rs | 4 +- ...alias-impl-trait-with-cycle-error-3.stderr | 11 ++-- 15 files changed, 70 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 3c127416cbf7..b8e15088853c 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -106,10 +106,6 @@ fn match_candidate<'tcx>( more_nested(selcx, &mut nested); - for nested in &mut nested { - nested.set_depth_from_parent(obligation.recursion_depth); - } - Ok(nested) } @@ -378,10 +374,6 @@ fn evaluate_host_effect_from_selection_candiate<'tcx>( }), ); - for nested in &mut nested { - nested.set_depth_from_parent(obligation.recursion_depth); - } - Ok(nested) } _ => Err(EvaluationFailure::NoSolution), diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e39f8e673dba..e98a240a53f5 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -225,9 +225,15 @@ struct FulfillProcessor<'a, 'tcx> { selcx: SelectionContext<'a, 'tcx>, } -fn mk_pending<'tcx>(os: PredicateObligations<'tcx>) -> PendingPredicateObligations<'tcx> { +fn mk_pending<'tcx>( + parent: &PredicateObligation<'tcx>, + os: PredicateObligations<'tcx>, +) -> PendingPredicateObligations<'tcx> { os.into_iter() - .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }) + .map(|mut o| { + o.set_depth_from_parent(parent.recursion_depth); + PendingPredicateObligation { obligation: o, stalled_on: vec![] } + }) .collect() } @@ -341,7 +347,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ); if predicate != obligation.predicate { obligations.push(obligation.with(infcx.tcx, predicate)); - return ProcessResult::Changed(mk_pending(obligations)); + return ProcessResult::Changed(mk_pending(obligation, obligations)); } } let binder = obligation.predicate.kind(); @@ -385,7 +391,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let mut obligations = PredicateObligations::with_capacity(1); obligations.push(obligation.with(infcx.tcx, pred)); - ProcessResult::Changed(mk_pending(obligations)) + ProcessResult::Changed(mk_pending(obligation, obligations)) } ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, ty::PredicateKind::NormalizesTo(..) => { @@ -410,6 +416,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let host_obligation = obligation.with(infcx.tcx, data); self.process_host_obligation( + obligation, host_obligation, &mut pending_obligation.stalled_on, ) @@ -486,7 +493,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { // `>::Output` when this is an `Expr` representing // `lhs + rhs`. ty::ConstKind::Expr(_) => { - return ProcessResult::Changed(mk_pending(PredicateObligations::new())); + return ProcessResult::Changed(mk_pending( + obligation, + PredicateObligations::new(), + )); } ty::ConstKind::Placeholder(_) => { bug!("placeholder const {:?} in old solver", ct) @@ -503,7 +513,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ct_ty, ty, ) { - Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), + Ok(inf_ok) => ProcessResult::Changed(mk_pending( + obligation, + inf_ok.into_obligations(), + )), Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select( SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty: ty }, )), @@ -537,7 +550,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()]; ProcessResult::Unchanged } - Some(os) => ProcessResult::Changed(mk_pending(os)), + Some(os) => ProcessResult::Changed(mk_pending(obligation, os)), } } @@ -553,11 +566,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)]; ProcessResult::Unchanged } - Ok(Ok(mut ok)) => { - for subobligation in &mut ok.obligations { - subobligation.set_depth_from_parent(obligation.recursion_depth); - } - ProcessResult::Changed(mk_pending(ok.obligations)) + Ok(Ok(ok)) => { + ProcessResult::Changed(mk_pending(obligation, ok.obligations)) } Ok(Err(err)) => { let expected_found = if subtype.a_is_expected { @@ -582,7 +592,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)]; ProcessResult::Unchanged } - Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Ok(Ok(ok)) => { + ProcessResult::Changed(mk_pending(obligation, ok.obligations)) + } Ok(Err(err)) => { let expected_found = ExpectedFound::new(coerce.b, coerce.a); ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err)) @@ -645,6 +657,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) { return ProcessResult::Changed(mk_pending( + obligation, new_obligations.into_obligations(), )); } @@ -659,6 +672,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { .eq(DefineOpaqueTypes::Yes, c1, c2) { return ProcessResult::Changed(mk_pending( + obligation, new_obligations.into_obligations(), )); } @@ -704,9 +718,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { c1, c2, ) { - Ok(inf_ok) => { - ProcessResult::Changed(mk_pending(inf_ok.into_obligations())) - } + Ok(inf_ok) => ProcessResult::Changed(mk_pending( + obligation, + inf_ok.into_obligations(), + )), Err(err) => { ProcessResult::Error(FulfillmentErrorCode::ConstEquate( ExpectedFound::new(c1, c2), @@ -790,7 +805,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { match self.selcx.poly_select(&trait_obligation) { Ok(Some(impl_source)) => { debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth); - ProcessResult::Changed(mk_pending(impl_source.nested_obligations())) + ProcessResult::Changed(mk_pending(obligation, impl_source.nested_obligations())) } Ok(None) => { debug!("selecting trait at depth {} yielded Ok(None)", obligation.recursion_depth); @@ -854,7 +869,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } match project::poly_project_and_unify_term(&mut self.selcx, &project_obligation) { - ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)), + ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(obligation, os)), ProjectAndUnifyResult::FailedNormalization => { stalled_on.clear(); stalled_on.extend(args_infer_vars( @@ -868,7 +883,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { let mut obligations = PredicateObligations::with_capacity(1); obligations.push(project_obligation.with(tcx, project_obligation.predicate)); - ProcessResult::Changed(mk_pending(obligations)) + ProcessResult::Changed(mk_pending(obligation, obligations)) } ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { ProcessResult::Error(FulfillmentErrorCode::Project(e)) @@ -878,11 +893,12 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { fn process_host_obligation( &mut self, + obligation: &PredicateObligation<'tcx>, host_obligation: HostEffectObligation<'tcx>, stalled_on: &mut Vec, ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) { - Ok(nested) => ProcessResult::Changed(mk_pending(nested)), + Ok(nested) => ProcessResult::Changed(mk_pending(obligation, nested)), Err(effects::EvaluationFailure::Ambiguous) => { stalled_on.clear(); stalled_on.extend(args_infer_vars( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 630241725fdb..2cb7d2d89313 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -39,7 +39,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidate: SelectionCandidate<'tcx>, ) -> Result, SelectionError<'tcx>> { - let mut impl_src = match candidate { + Ok(match candidate { SizedCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); ImplSource::Builtin(BuiltinImplSource::Misc, data) @@ -139,15 +139,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BikeshedGuaranteedNoDropCandidate => { self.confirm_bikeshed_guaranteed_no_drop_candidate(obligation) } - }; - - // The obligations returned by confirmation are recursively evaluated - // so we need to make sure they have the correct depth. - for subobligation in impl_src.borrow_nested_obligations_mut() { - subobligation.set_depth_from_parent(obligation.recursion_depth); - } - - Ok(impl_src) + }) } fn confirm_projection_candidate( diff --git a/tests/ui/infinite/infinite-autoderef.stderr b/tests/ui/infinite/infinite-autoderef.stderr index 7d09af9a7d4a..7770cc8a7204 100644 --- a/tests/ui/infinite/infinite-autoderef.stderr +++ b/tests/ui/infinite/infinite-autoderef.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow assigning `Box<_>` to `_` - --> $DIR/infinite-autoderef.rs:16:13 + --> $DIR/infinite-autoderef.rs:16:22 | LL | x = Box::new(x); - | ^^^^^^^^^^^ + | ^ error: aborting due to 1 previous error diff --git a/tests/ui/occurs-check-2.rs b/tests/ui/occurs-check-2.rs index 1ec460a87352..9289a8e870a1 100644 --- a/tests/ui/occurs-check-2.rs +++ b/tests/ui/occurs-check-2.rs @@ -4,6 +4,6 @@ fn main() { let g; g = f; - f = Box::new(g); //~^ ERROR overflow assigning `Box<_>` to `_` + f = Box::new(g); } diff --git a/tests/ui/occurs-check-2.stderr b/tests/ui/occurs-check-2.stderr index 54307a6c5474..5f296967f30d 100644 --- a/tests/ui/occurs-check-2.stderr +++ b/tests/ui/occurs-check-2.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow assigning `Box<_>` to `_` - --> $DIR/occurs-check-2.rs:7:9 + --> $DIR/occurs-check-2.rs:6:9 | -LL | f = Box::new(g); - | ^^^^^^^^^^^ +LL | g = f; + | ^ error: aborting due to 1 previous error diff --git a/tests/ui/occurs-check-3.stderr b/tests/ui/occurs-check-3.stderr index 77b67ec1a62c..eb05c94957c9 100644 --- a/tests/ui/occurs-check-3.stderr +++ b/tests/ui/occurs-check-3.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow assigning `Clam<_>` to `_` - --> $DIR/occurs-check-3.rs:6:9 + --> $DIR/occurs-check-3.rs:6:17 | LL | c = Clam::A(c); - | ^^^^^^^^^^ + | ^ error: aborting due to 1 previous error diff --git a/tests/ui/occurs-check.stderr b/tests/ui/occurs-check.stderr index 30468d68cbd0..ea7c541abc13 100644 --- a/tests/ui/occurs-check.stderr +++ b/tests/ui/occurs-check.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow assigning `Box<_>` to `_` - --> $DIR/occurs-check.rs:3:9 + --> $DIR/occurs-check.rs:3:18 | LL | f = Box::new(f); - | ^^^^^^^^^^^ + | ^ error: aborting due to 1 previous error diff --git a/tests/ui/traits/mutual-recursion-issue-75860.stderr b/tests/ui/traits/mutual-recursion-issue-75860.stderr index 272c56301bc8..9e8eb1adb111 100644 --- a/tests/ui/traits/mutual-recursion-issue-75860.stderr +++ b/tests/ui/traits/mutual-recursion-issue-75860.stderr @@ -2,7 +2,7 @@ error[E0275]: overflow assigning `_` to `Option<_>` --> $DIR/mutual-recursion-issue-75860.rs:9:33 | LL | let left = |o_a: Option<_>| o_a.unwrap(); - | ^^^ + | ^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs index 19986247d40d..53b7667aa9f1 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs @@ -1,9 +1,10 @@ #![feature(type_alias_impl_trait)] -//@ known-bug: #109268 type Foo = impl Fn() -> Foo; +#[define_opaque(Foo)] fn crash(x: Foo) -> Foo { + //~^ ERROR overflow evaluating the requirement `>::Output == Foo` x } diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr index ad96a0eeb87d..ee8922b673e2 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr @@ -1,10 +1,9 @@ -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-with-cycle-error-1.rs:4:12 +error[E0275]: overflow evaluating the requirement `>::Output == Foo` + --> $DIR/type-alias-impl-trait-with-cycle-error-1.rs:6:21 | -LL | type Foo = impl Fn() -> Foo; - | ^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same crate +LL | fn crash(x: Foo) -> Foo { + | ^^^ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs index 761cc83af510..d0c62d290698 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs @@ -1,13 +1,13 @@ #![feature(type_alias_impl_trait)] -//@ known-bug: #109268 pub trait Bar { type Item; } type Foo = impl Bar; - +#[define_opaque(Foo)] fn crash(x: Foo) -> Foo { + //~^ ERROR overflow evaluating the requirement `>::Item == Foo` x } diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr index e5bb8163a811..40bd6517c06d 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr @@ -1,10 +1,9 @@ -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-with-cycle-error-2.rs:8:12 +error[E0275]: overflow evaluating the requirement `>::Item == Foo` + --> $DIR/type-alias-impl-trait-with-cycle-error-2.rs:9:21 | -LL | type Foo = impl Bar; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same crate +LL | fn crash(x: Foo) -> Foo { + | ^^^ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs index 52942afd6392..de3d23b83a29 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs @@ -1,9 +1,9 @@ #![feature(type_alias_impl_trait)] -//@ known-bug: #109268 type Foo<'a> = impl Fn() -> Foo<'a>; - +#[define_opaque(Foo)] fn crash<'a>(_: &'a (), x: Foo<'a>) -> Foo<'a> { + //~^ ERROR overflow evaluating the requirement ` as FnOnce<()>>::Output == Foo<'a>` x } diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr index 157310bf6236..f9e26fde1bda 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr @@ -1,10 +1,9 @@ -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-with-cycle-error-3.rs:4:16 +error[E0275]: overflow evaluating the requirement ` as FnOnce<()>>::Output == Foo<'a>` + --> $DIR/type-alias-impl-trait-with-cycle-error-3.rs:5:40 | -LL | type Foo<'a> = impl Fn() -> Foo<'a>; - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same crate +LL | fn crash<'a>(_: &'a (), x: Foo<'a>) -> Foo<'a> { + | ^^^^^^^ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0275`. From e80a3e22328641b43a5ea66bfafdfe5950686779 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 29 Mar 2025 18:34:44 +1100 Subject: [PATCH 487/546] coverage: Tweak tests/coverage/assert-ne.rs This test is intended to demonstrate that a particular macro-argument span doesn't get lost during span-refinement, but it turns out that span-extraction currently doesn't yield any MIR spans for this position. This patch therefore tweaks the test to add a function call in that position, so that it still remains relevant to span refinement. --- tests/coverage/assert-ne.coverage | 2 +- tests/coverage/assert-ne.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/coverage/assert-ne.coverage b/tests/coverage/assert-ne.coverage index 236a8fd13858..fc43d4a8e06a 100644 --- a/tests/coverage/assert-ne.coverage +++ b/tests/coverage/assert-ne.coverage @@ -7,7 +7,7 @@ LL| | LL| 1|fn main() { LL| 1| assert_ne!( - LL| 1| Foo(5), // Make sure this expression's span isn't lost. + LL| 1| black_box(Foo(5)), // Make sure this expression's span isn't lost. LL| 1| if black_box(false) { LL| 0| Foo(0) // LL| | } else { diff --git a/tests/coverage/assert-ne.rs b/tests/coverage/assert-ne.rs index 8a8fe0898048..9d9fcb71ba7f 100644 --- a/tests/coverage/assert-ne.rs +++ b/tests/coverage/assert-ne.rs @@ -7,7 +7,7 @@ struct Foo(u32); fn main() { assert_ne!( - Foo(5), // Make sure this expression's span isn't lost. + black_box(Foo(5)), // Make sure this expression's span isn't lost. if black_box(false) { Foo(0) // } else { From 577272eedeaace00aa695135b3b8fee3768536a5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 29 Mar 2025 21:33:01 +1100 Subject: [PATCH 488/546] coverage: Shrink call spans to just the function name This is a way to shrink call spans that doesn't involve mixing different spans, and avoids overlap with argument spans. This patch also removes some low-value comments that were causing rustfmt to ignore the match arms. --- .../src/coverage/spans/from_mir.rs | 18 ++++----- tests/coverage/assert-ne.cov-map | 4 +- tests/coverage/attr/off-on-sandwich.cov-map | 12 +++--- tests/coverage/branch/if.cov-map | 4 +- tests/coverage/branch/lazy-boolean.cov-map | 8 ++-- tests/coverage/branch/let-else.cov-map | 4 +- tests/coverage/branch/match-arms.cov-map | 28 ++++++------- tests/coverage/condition/conditions.cov-map | 10 +++-- tests/coverage/coroutine.cov-map | 4 +- tests/coverage/holes.cov-map | 18 ++++----- tests/coverage/inline-dead.cov-map | 4 +- tests/coverage/loop-break.cov-map | 4 +- tests/coverage/mcdc/non_control_flow.cov-map | 10 +++-- tests/coverage/no_cov_crate.cov-map | 8 ++-- tests/coverage/sort_groups.cov-map | 4 +- tests/coverage/try_error_result.cov-map | 40 +++++++++---------- tests/coverage/try_error_result.coverage | 2 +- tests/coverage/unicode.cov-map | 6 +-- tests/coverage/unicode.coverage | 2 +- tests/coverage/unreachable.cov-map | 12 +++--- ...ch_match_arms.main.InstrumentCoverage.diff | 8 ++-- ...ment_coverage.main.InstrumentCoverage.diff | 2 +- 22 files changed, 106 insertions(+), 106 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 1faa2171c0b0..804cd8ab3f7d 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -120,22 +120,20 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option { // an `if condition { block }` has a span that includes the executed block, if true, // but for coverage, the code region executed, up to *and* through the SwitchInt, // actually stops before the if's block.) - TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG + TerminatorKind::Unreachable | TerminatorKind::Assert { .. } | TerminatorKind::Drop { .. } | TerminatorKind::SwitchInt { .. } - // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. | TerminatorKind::FalseEdge { .. } | TerminatorKind::Goto { .. } => None, // Call `func` operand can have a more specific span when part of a chain of calls - TerminatorKind::Call { ref func, .. } - | TerminatorKind::TailCall { ref func, .. } => { + TerminatorKind::Call { ref func, .. } | TerminatorKind::TailCall { ref func, .. } => { let mut span = terminator.source_info.span; - if let mir::Operand::Constant(box constant) = func { - if constant.span.lo() > span.lo() { - span = span.with_lo(constant.span.lo()); - } + if let mir::Operand::Constant(constant) = func + && span.contains(constant.span) + { + span = constant.span; } Some(span) } @@ -147,9 +145,7 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option { | TerminatorKind::Yield { .. } | TerminatorKind::CoroutineDrop | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => { - Some(terminator.source_info.span) - } + | TerminatorKind::InlineAsm { .. } => Some(terminator.source_info.span), } } diff --git a/tests/coverage/assert-ne.cov-map b/tests/coverage/assert-ne.cov-map index b432e63c168c..27d4b0382dec 100644 --- a/tests/coverage/assert-ne.cov-map +++ b/tests/coverage/assert-ne.cov-map @@ -1,12 +1,12 @@ Function name: assert_ne::main -Raw bytes (28): 0x[01, 01, 02, 01, 05, 01, 09, 04, 01, 08, 01, 03, 1c, 05, 04, 0d, 00, 13, 02, 02, 0d, 00, 13, 06, 03, 05, 01, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 01, 09, 04, 01, 08, 01, 03, 15, 05, 04, 0d, 00, 13, 02, 02, 0d, 00, 13, 06, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28) +- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 21) - Code(Counter(1)) at (prev + 4, 13) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c0 - c1) diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map index ef6f5a9dc428..c55c5897d8ba 100644 --- a/tests/coverage/attr/off-on-sandwich.cov-map +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -1,30 +1,30 @@ Function name: off_on_sandwich::dense_a::dense_b -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 05, 02, 12, 01, 07, 05, 00, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 05, 02, 10, 01, 07, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 5) to (start + 2, 18) +- Code(Counter(0)) at (prev + 16, 5) to (start + 2, 16) - Code(Counter(0)) at (prev + 7, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c -Raw bytes (14): 0x[01, 01, 00, 02, 01, 22, 09, 02, 17, 01, 0b, 09, 00, 0a] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 22, 09, 02, 15, 01, 0b, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 34, 9) to (start + 2, 23) +- Code(Counter(0)) at (prev + 34, 9) to (start + 2, 21) - Code(Counter(0)) at (prev + 11, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d -Raw bytes (14): 0x[01, 01, 00, 02, 01, 25, 0d, 02, 1b, 01, 07, 0d, 00, 0e] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 25, 0d, 02, 19, 01, 07, 0d, 00, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 37, 13) to (start + 2, 27) +- Code(Counter(0)) at (prev + 37, 13) to (start + 2, 25) - Code(Counter(0)) at (prev + 7, 13) to (start + 0, 14) Highest counter ID seen: c0 diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index a6b865318c66..392ace1683a7 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -23,7 +23,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::branch_not -Raw bytes (116): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 12, 01, 0c, 01, 01, 10, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (116): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 12, 01, 0c, 01, 01, 10, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 10, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -40,7 +40,7 @@ Number of file 0 mappings: 18 - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) -- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 8) to (start + 0, 10) diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map index 622f30e2b56f..ff285a038fb8 100644 --- a/tests/coverage/branch/lazy-boolean.cov-map +++ b/tests/coverage/branch/lazy-boolean.cov-map @@ -34,7 +34,7 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: lazy_boolean::chain -Raw bytes (141): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 13, 01, 24, 01, 01, 10, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 11, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 01, 02] +Raw bytes (141): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 13, 01, 24, 01, 01, 10, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 15 @@ -69,7 +69,7 @@ Number of file 0 mappings: 19 true = c3 false = (c2 - c3) - Code(Counter(3)) at (prev + 0, 40) to (start + 0, 45) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 18) - Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 18) @@ -91,7 +91,7 @@ Number of file 0 mappings: 19 Highest counter ID seen: c6 Function name: lazy_boolean::nested_mixed -Raw bytes (137): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 13, 01, 31, 01, 01, 10, 01, 04, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 11, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 01, 02] +Raw bytes (137): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 13, 01, 31, 01, 01, 10, 01, 04, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 13 @@ -127,7 +127,7 @@ Number of file 0 mappings: 19 false = ((c1 + c2) - c3) - Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 51) = ((c1 + c2) - c3) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 19) - Branch { true: Counter(4), false: Expression(8, Sub) } at (prev + 0, 14) to (start + 0, 19) diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map index 215d71599e4c..811b9838e3f5 100644 --- a/tests/coverage/branch/let-else.cov-map +++ b/tests/coverage/branch/let-else.cov-map @@ -1,5 +1,5 @@ Function name: let_else::let_else -Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 10, 20, 02, 05, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 10, 20, 02, 05, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 01, 0f, 02, 04, 05, 00, 0a, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -13,7 +13,7 @@ Number of file 0 mappings: 7 = (c0 - c1) - Code(Counter(0)) at (prev + 0, 19) to (start + 0, 24) - Code(Counter(1)) at (prev + 1, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 11) +- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index d5b4d04d4019..caa18820cf8e 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -1,5 +1,5 @@ Function name: match_arms::guards -Raw bytes (88): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 0c, 01, 30, 01, 01, 10, 21, 03, 0b, 00, 10, 05, 01, 11, 00, 29, 20, 05, 02, 00, 17, 00, 1b, 09, 01, 11, 00, 29, 20, 09, 06, 00, 17, 00, 1b, 0d, 01, 11, 00, 29, 20, 0d, 0a, 00, 17, 00, 1b, 11, 01, 11, 00, 29, 20, 11, 0e, 00, 17, 00, 1b, 12, 01, 0e, 00, 18, 01, 03, 05, 01, 02] +Raw bytes (88): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 0c, 01, 30, 01, 01, 10, 21, 03, 0b, 00, 10, 05, 01, 11, 00, 28, 20, 05, 02, 00, 17, 00, 1b, 09, 01, 11, 00, 28, 20, 09, 06, 00, 17, 00, 1b, 0d, 01, 11, 00, 28, 20, 0d, 0a, 00, 17, 00, 1b, 11, 01, 11, 00, 28, 20, 11, 0e, 00, 17, 00, 1b, 12, 01, 0e, 00, 15, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -14,29 +14,29 @@ Number of expressions: 8 Number of file 0 mappings: 12 - Code(Counter(0)) at (prev + 48, 1) to (start + 1, 16) - Code(Counter(8)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 41) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 40) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c1 false = (c5 - c1) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 41) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 40) - Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c2 false = (c6 - c2) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 41) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 40) - Branch { true: Counter(3), false: Expression(2, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c3 false = (c7 - c3) -- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 41) +- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 40) - Branch { true: Counter(4), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c4 false = (c8 - c4) -- Code(Expression(4, Sub)) at (prev + 1, 14) to (start + 0, 24) +- Code(Expression(4, Sub)) at (prev + 1, 14) to (start + 0, 21) = (c0 - (((c1 + c2) + c3) + c4)) - Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) Highest counter ID seen: c8 Function name: match_arms::match_arms -Raw bytes (45): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 07, 01, 18, 01, 01, 10, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 21, 09, 01, 11, 00, 21, 0d, 01, 11, 00, 21, 02, 01, 11, 00, 21, 01, 03, 05, 01, 02] +Raw bytes (45): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 07, 01, 18, 01, 01, 10, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 20, 09, 01, 11, 00, 20, 0d, 01, 11, 00, 20, 02, 01, 11, 00, 20, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -46,16 +46,16 @@ Number of expressions: 3 Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 24, 1) to (start + 1, 16) - Code(Counter(0)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 33) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 33) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 33) -- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 32) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 32) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 32) +- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 32) = (c0 - ((c1 + c2) + c3)) - Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) Highest counter ID seen: c3 Function name: match_arms::or_patterns -Raw bytes (57): 0x[01, 01, 04, 05, 09, 01, 0b, 03, 0d, 01, 03, 09, 01, 25, 01, 01, 10, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2e, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 0e, 00, 24, 00, 2e, 01, 03, 05, 01, 02] +Raw bytes (57): 0x[01, 01, 04, 05, 09, 01, 0b, 03, 0d, 01, 03, 09, 01, 25, 01, 01, 10, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2d, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 0e, 00, 24, 00, 2d, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -68,12 +68,12 @@ Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 3, 11) to (start + 0, 16) - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 18) - Code(Counter(2)) at (prev + 0, 30) to (start + 0, 31) -- Code(Expression(0, Add)) at (prev + 0, 36) to (start + 0, 46) +- Code(Expression(0, Add)) at (prev + 0, 36) to (start + 0, 45) = (c1 + c2) - Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) - Code(Expression(1, Sub)) at (prev + 0, 30) to (start + 0, 31) = (c0 - ((c1 + c2) + c3)) -- Code(Expression(3, Sub)) at (prev + 0, 36) to (start + 0, 46) +- Code(Expression(3, Sub)) at (prev + 0, 36) to (start + 0, 45) = (c0 - (c1 + c2)) - Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) Highest counter ID seen: c3 diff --git a/tests/coverage/condition/conditions.cov-map b/tests/coverage/condition/conditions.cov-map index 417637f2d2e3..c34075a0bcfc 100644 --- a/tests/coverage/condition/conditions.cov-map +++ b/tests/coverage/condition/conditions.cov-map @@ -109,15 +109,17 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: conditions::func_call -Raw bytes (37): 0x[01, 01, 02, 01, 05, 05, 09, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] +Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 25, 01, 00, 20, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 20, 05, 02, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 37, 1) to (start + 1, 10) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 9) to (start + 0, 10) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 9) to (start + 0, 10) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15) diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index c6f2d415056d..297dde3b2b0f 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -13,7 +13,7 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: coroutine::main -Raw bytes (53): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 35, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 35, 09, 02, 01, 00, 02] +Raw bytes (53): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2d, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 35, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 35, 09, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -21,7 +21,7 @@ Number of expressions: 2 - expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22) -- Code(Counter(0)) at (prev + 8, 11) to (start + 0, 46) +- Code(Counter(0)) at (prev + 8, 11) to (start + 0, 45) - Code(Counter(1)) at (prev + 1, 43) to (start + 0, 45) - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 53) = (c0 - c1) diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map index 3deacbc8e128..8ff291d2d7d3 100644 --- a/tests/coverage/holes.cov-map +++ b/tests/coverage/holes.cov-map @@ -8,20 +8,20 @@ Number of file 0 mappings: 1 Highest counter ID seen: (none) Function name: holes::main -Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 12, 01, 05, 05, 00, 12, 01, 07, 09, 00, 11, 01, 09, 05, 00, 12, 01, 04, 05, 00, 12, 01, 07, 05, 00, 12, 01, 06, 05, 00, 12, 01, 04, 05, 00, 12, 01, 04, 05, 00, 12, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 0c, 0d, 01, 0f, 0e, 05, 02] +Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 11, 01, 05, 05, 00, 11, 01, 07, 09, 00, 11, 01, 09, 05, 00, 11, 01, 04, 05, 00, 11, 01, 07, 05, 00, 11, 01, 06, 05, 00, 11, 01, 04, 05, 00, 11, 01, 04, 05, 00, 11, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 0c, 0d, 01, 0f, 0e, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 18) -- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 17) +- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 17) - Code(Counter(0)) at (prev + 7, 9) to (start + 0, 17) -- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 18) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) -- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 18) -- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 18) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) - Code(Counter(0)) at (prev + 6, 5) to (start + 3, 15) - Code(Counter(0)) at (prev + 10, 5) to (start + 3, 15) - Code(Counter(0)) at (prev + 10, 5) to (start + 12, 13) diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map index 49cdc514fedb..65cefe76c29a 100644 --- a/tests/coverage/inline-dead.cov-map +++ b/tests/coverage/inline-dead.cov-map @@ -8,14 +8,14 @@ Number of file 0 mappings: 1 Highest counter ID seen: (none) Function name: inline_dead::live:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 01, 01, 09, 05, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 01, 01, 09, 05, 02, 09, 00, 0d, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 15) +- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 13) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) diff --git a/tests/coverage/loop-break.cov-map b/tests/coverage/loop-break.cov-map index f13e82da1514..fccc4d64395b 100644 --- a/tests/coverage/loop-break.cov-map +++ b/tests/coverage/loop-break.cov-map @@ -1,12 +1,12 @@ Function name: loop_break::main -Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 03, 01, 00, 0b, 05, 02, 0c, 00, 27, 01, 01, 0d, 00, 12, 02, 01, 09, 00, 0a, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 03, 01, 00, 0b, 05, 02, 0c, 00, 21, 01, 01, 0d, 00, 12, 02, 01, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 11) -- Code(Counter(1)) at (prev + 2, 12) to (start + 0, 39) +- Code(Counter(1)) at (prev + 2, 12) to (start + 0, 33) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) = (c1 - c0) diff --git a/tests/coverage/mcdc/non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map index c282d53c5ac2..959d21901de8 100644 --- a/tests/coverage/mcdc/non_control_flow.cov-map +++ b/tests/coverage/mcdc/non_control_flow.cov-map @@ -113,15 +113,17 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: non_control_flow::func_call -Raw bytes (50): 0x[01, 01, 02, 01, 05, 05, 09, 06, 01, 29, 01, 01, 0a, 28, 03, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] +Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 29, 01, 00, 20, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 28, 03, 02, 00, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 10) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 9) to (start + 0, 15) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 9) to (start + 0, 10) true = c1 false = (c0 - c1) diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map index 04171fdb79b6..244b0099544b 100644 --- a/tests/coverage/no_cov_crate.cov-map +++ b/tests/coverage/no_cov_crate.cov-map @@ -35,22 +35,22 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer -Raw bytes (14): 0x[01, 01, 00, 02, 01, 33, 05, 02, 23, 01, 0c, 05, 00, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 33, 05, 02, 22, 01, 0c, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 51, 5) to (start + 2, 35) +- Code(Counter(0)) at (prev + 51, 5) to (start + 2, 34) - Code(Counter(0)) at (prev + 12, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered -Raw bytes (14): 0x[01, 01, 00, 02, 01, 41, 05, 02, 17, 01, 0b, 05, 00, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 41, 05, 02, 16, 01, 0b, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 65, 5) to (start + 2, 23) +- Code(Counter(0)) at (prev + 65, 5) to (start + 2, 22) - Code(Counter(0)) at (prev + 11, 5) to (start + 0, 6) Highest counter ID seen: c0 diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map index 69e134222960..898d68171c50 100644 --- a/tests/coverage/sort_groups.cov-map +++ b/tests/coverage/sort_groups.cov-map @@ -55,13 +55,13 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: sort_groups::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 02, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 1c, 05, 04, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 6, 1) to (start + 4, 35) +- Code(Counter(0)) at (prev + 6, 1) to (start + 4, 28) - Code(Counter(1)) at (prev + 4, 36) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index 35b2c36a5751..a4a8e21d8c31 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -41,13 +41,13 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: try_error_result::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0a, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 113, 1) to (start + 2, 12) +- Code(Counter(0)) at (prev + 113, 1) to (start + 2, 10) - Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11) = (c0 - c1) @@ -55,7 +55,7 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: try_error_result::test1 -Raw bytes (67): 0x[01, 01, 04, 07, 05, 01, 09, 05, 01, 05, 09, 0b, 01, 0d, 01, 02, 17, 05, 07, 09, 00, 0e, 09, 02, 09, 04, 1a, 02, 06, 0d, 00, 29, 02, 00, 29, 00, 2a, 00, 01, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0a, 04, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0e, 03, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 04, 07, 05, 01, 09, 05, 01, 05, 09, 0b, 01, 0d, 01, 02, 17, 05, 07, 09, 00, 0e, 09, 02, 09, 04, 1a, 02, 06, 0d, 00, 11, 02, 00, 29, 00, 2a, 00, 01, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0a, 04, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0e, 03, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -67,13 +67,13 @@ Number of file 0 mappings: 11 - Code(Counter(0)) at (prev + 13, 1) to (start + 2, 23) - Code(Counter(1)) at (prev + 7, 9) to (start + 0, 14) - Code(Counter(2)) at (prev + 2, 9) to (start + 4, 26) -- Code(Expression(0, Sub)) at (prev + 6, 13) to (start + 0, 41) +- Code(Expression(0, Sub)) at (prev + 6, 13) to (start + 0, 17) = ((c0 + c2) - c1) - Code(Expression(0, Sub)) at (prev + 0, 41) to (start + 0, 42) = ((c0 + c2) - c1) -- Code(Zero) at (prev + 1, 13) to (start + 0, 42) +- Code(Zero) at (prev + 1, 13) to (start + 0, 17) - Code(Zero) at (prev + 0, 42) to (start + 0, 43) -- Code(Expression(2, Sub)) at (prev + 4, 13) to (start + 0, 42) +- Code(Expression(2, Sub)) at (prev + 4, 13) to (start + 0, 17) = (c1 - c0) - Code(Zero) at (prev + 0, 42) to (start + 0, 43) - Code(Expression(3, Sub)) at (prev + 3, 5) to (start + 0, 11) @@ -82,7 +82,7 @@ Number of file 0 mappings: 11 Highest counter ID seen: c2 Function name: try_error_result::test2 -Raw bytes (336): 0x[01, 01, 36, 0d, 11, 0d, 3f, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 0d, 3f, 11, 15, 0d, 3b, 3f, 19, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 41, 53, 21, 25, 41, 21, 41, 53, 21, 25, 09, 73, 77, 2d, 0d, 29, 09, 0d, 09, 77, 0d, 29, 09, 73, 77, 2d, 0d, 29, 45, 8b, 01, 31, 35, 45, 31, 45, 8b, 01, 31, 35, 49, 9f, 01, 39, 3d, 49, 39, 49, 9f, 01, 39, 3d, 05, 09, ab, 01, 09, af, 01, 3d, b3, 01, 39, b7, 01, 35, bb, 01, 31, bf, 01, 2d, c3, 01, 29, c7, 01, 25, cb, 01, 21, cf, 01, 1d, d3, 01, 19, d7, 01, 15, 05, 11, 28, 01, 3d, 01, 03, 17, 05, 08, 09, 00, 0e, 09, 02, 09, 04, 1a, 0d, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 02, 00, 31, 03, 35, 15, 04, 11, 00, 12, 1e, 02, 11, 04, 12, 32, 05, 11, 00, 14, 1e, 00, 17, 00, 41, 19, 00, 41, 00, 42, 26, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 32, 01, 0d, 00, 20, 4e, 01, 11, 00, 14, 41, 00, 17, 00, 41, 21, 00, 41, 00, 42, 4a, 00, 43, 00, 60, 25, 00, 60, 00, 61, 4e, 01, 0d, 00, 20, 6e, 04, 11, 00, 14, 62, 00, 17, 00, 42, 29, 00, 42, 00, 43, 66, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 6e, 01, 0d, 00, 20, 86, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, 82, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, 86, 01, 01, 0d, 00, 20, 9a, 01, 01, 11, 00, 14, 49, 00, 17, 01, 36, 39, 02, 11, 00, 12, 96, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, 9a, 01, 02, 0d, 00, 20, a2, 01, 03, 05, 00, 0b, a6, 01, 01, 01, 00, 02] +Raw bytes (336): 0x[01, 01, 36, 0d, 11, 0d, 3f, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 0d, 3f, 11, 15, 0d, 3b, 3f, 19, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 41, 53, 21, 25, 41, 21, 41, 53, 21, 25, 09, 73, 77, 2d, 0d, 29, 09, 0d, 09, 77, 0d, 29, 09, 73, 77, 2d, 0d, 29, 45, 8b, 01, 31, 35, 45, 31, 45, 8b, 01, 31, 35, 49, 9f, 01, 39, 3d, 49, 39, 49, 9f, 01, 39, 3d, 05, 09, ab, 01, 09, af, 01, 3d, b3, 01, 39, b7, 01, 35, bb, 01, 31, bf, 01, 2d, c3, 01, 29, c7, 01, 25, cb, 01, 21, cf, 01, 1d, d3, 01, 19, d7, 01, 15, 05, 11, 28, 01, 3d, 01, 03, 17, 05, 08, 09, 00, 0e, 09, 02, 09, 04, 1a, 0d, 06, 0d, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 03, 1c, 15, 04, 11, 00, 12, 1e, 02, 11, 03, 27, 32, 05, 11, 00, 14, 1e, 00, 17, 00, 29, 19, 00, 41, 00, 42, 26, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 32, 01, 0d, 00, 20, 4e, 01, 11, 00, 14, 41, 00, 17, 00, 29, 21, 00, 41, 00, 42, 4a, 00, 43, 00, 47, 25, 00, 60, 00, 61, 4e, 01, 0d, 00, 20, 6e, 04, 11, 00, 14, 62, 00, 17, 00, 29, 29, 00, 42, 00, 43, 66, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 6e, 01, 0d, 00, 20, 86, 01, 01, 11, 00, 14, 45, 00, 17, 01, 1d, 31, 01, 36, 00, 37, 82, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, 86, 01, 01, 0d, 00, 20, 9a, 01, 01, 11, 00, 14, 49, 00, 17, 01, 1d, 39, 02, 11, 00, 12, 96, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, 9a, 01, 02, 0d, 00, 20, a2, 01, 03, 05, 00, 0b, a6, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 54 @@ -144,56 +144,56 @@ Number of file 0 mappings: 40 - Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23) - Code(Counter(1)) at (prev + 8, 9) to (start + 0, 14) - Code(Counter(2)) at (prev + 2, 9) to (start + 4, 26) -- Code(Counter(3)) at (prev + 6, 13) to (start + 0, 47) +- Code(Counter(3)) at (prev + 6, 13) to (start + 0, 31) - Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(0, Sub)) at (prev + 0, 49) to (start + 3, 53) +- Code(Expression(0, Sub)) at (prev + 0, 49) to (start + 3, 28) = (c3 - c4) - Code(Counter(5)) at (prev + 4, 17) to (start + 0, 18) -- Code(Expression(7, Sub)) at (prev + 2, 17) to (start + 4, 18) +- Code(Expression(7, Sub)) at (prev + 2, 17) to (start + 3, 39) = (c3 - (c4 + c5)) - Code(Expression(12, Sub)) at (prev + 5, 17) to (start + 0, 20) = (c3 - (((c4 + c5) + c6) + c7)) -- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 65) +- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 41) = (c3 - (c4 + c5)) - Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66) -- Code(Expression(9, Sub)) at (prev + 0, 67) to (start + 0, 95) +- Code(Expression(9, Sub)) at (prev + 0, 67) to (start + 0, 71) = (c3 - ((c4 + c5) + c6)) - Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96) - Code(Expression(12, Sub)) at (prev + 1, 13) to (start + 0, 32) = (c3 - (((c4 + c5) + c6) + c7)) - Code(Expression(19, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c16 - (c8 + c9)) -- Code(Counter(16)) at (prev + 0, 23) to (start + 0, 65) +- Code(Counter(16)) at (prev + 0, 23) to (start + 0, 41) - Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66) -- Code(Expression(18, Sub)) at (prev + 0, 67) to (start + 0, 96) +- Code(Expression(18, Sub)) at (prev + 0, 67) to (start + 0, 71) = (c16 - c8) - Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97) - Code(Expression(19, Sub)) at (prev + 1, 13) to (start + 0, 32) = (c16 - (c8 + c9)) - Code(Expression(27, Sub)) at (prev + 4, 17) to (start + 0, 20) = (c2 - ((c3 + c10) + c11)) -- Code(Expression(24, Sub)) at (prev + 0, 23) to (start + 0, 66) +- Code(Expression(24, Sub)) at (prev + 0, 23) to (start + 0, 41) = (c2 - c3) - Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67) -- Code(Expression(25, Sub)) at (prev + 0, 68) to (start + 0, 97) +- Code(Expression(25, Sub)) at (prev + 0, 68) to (start + 0, 72) = (c2 - (c3 + c10)) - Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98) - Code(Expression(27, Sub)) at (prev + 1, 13) to (start + 0, 32) = (c2 - ((c3 + c10) + c11)) - Code(Expression(33, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c17 - (c12 + c13)) -- Code(Counter(17)) at (prev + 0, 23) to (start + 1, 54) +- Code(Counter(17)) at (prev + 0, 23) to (start + 1, 29) - Code(Counter(12)) at (prev + 1, 54) to (start + 0, 55) -- Code(Expression(32, Sub)) at (prev + 1, 18) to (start + 0, 47) +- Code(Expression(32, Sub)) at (prev + 1, 18) to (start + 0, 22) = (c17 - c12) - Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48) - Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 32) = (c17 - (c12 + c13)) - Code(Expression(38, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c18 - (c14 + c15)) -- Code(Counter(18)) at (prev + 0, 23) to (start + 1, 54) +- Code(Counter(18)) at (prev + 0, 23) to (start + 1, 29) - Code(Counter(14)) at (prev + 2, 17) to (start + 0, 18) -- Code(Expression(37, Sub)) at (prev + 1, 18) to (start + 0, 47) +- Code(Expression(37, Sub)) at (prev + 1, 18) to (start + 0, 22) = (c18 - c14) - Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18) - Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 32) diff --git a/tests/coverage/try_error_result.coverage b/tests/coverage/try_error_result.coverage index 7100248f7df8..7a89c0452ac4 100644 --- a/tests/coverage/try_error_result.coverage +++ b/tests/coverage/try_error_result.coverage @@ -86,7 +86,7 @@ LL| 1| . LL| 1| expect_err( LL| 1| "call should fail" - LL| 1| ); + LL| | ); LL| 1| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; ^0 ^0 ^0 LL| 0| assert_eq!(val, 57); diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index 7b9dc0b9bc88..29d40a055130 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -1,5 +1,5 @@ Function name: unicode::main -Raw bytes (53): 0x[01, 01, 02, 05, 01, 01, 0d, 09, 01, 0e, 01, 00, 0b, 02, 01, 09, 00, 0c, 05, 00, 10, 00, 1b, 02, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 01, 02] +Raw bytes (53): 0x[01, 01, 02, 05, 01, 01, 0d, 09, 01, 0e, 01, 00, 0b, 02, 01, 09, 00, 0c, 05, 00, 10, 00, 1b, 02, 00, 1c, 00, 28, 01, 02, 08, 00, 23, 09, 00, 29, 00, 44, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -12,8 +12,8 @@ Number of file 0 mappings: 9 - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 27) - Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 0, 40) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 37) -- Code(Counter(2)) at (prev + 0, 41) to (start + 0, 70) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 35) +- Code(Counter(2)) at (prev + 0, 41) to (start + 0, 68) - Code(Counter(3)) at (prev + 0, 71) to (start + 2, 6) - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c3) diff --git a/tests/coverage/unicode.coverage b/tests/coverage/unicode.coverage index 84c5f05a8c4e..443499545500 100644 --- a/tests/coverage/unicode.coverage +++ b/tests/coverage/unicode.coverage @@ -15,7 +15,7 @@ LL| 33| for _İ in 'А'..='Я' { /* Я */ } ^32 ^32 LL| | - LL| 1| if 申し訳ございません() && 申し訳ございません() { + LL| 1| if 申し訳ございません() && 申し訳ございません() { ^0 LL| 0| println!("true"); LL| 1| } diff --git a/tests/coverage/unreachable.cov-map b/tests/coverage/unreachable.cov-map index 97961bc74145..0bc18bfcbd31 100644 --- a/tests/coverage/unreachable.cov-map +++ b/tests/coverage/unreachable.cov-map @@ -1,27 +1,27 @@ Function name: unreachable::UNREACHABLE_CLOSURE::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 27, 00, 47] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 27, 00, 45] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 14, 39) to (start + 0, 71) +- Code(Zero) at (prev + 14, 39) to (start + 0, 69) Highest counter ID seen: (none) Function name: unreachable::unreachable_function (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 10, 01, 01, 25] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 10, 01, 01, 23] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 16, 1) to (start + 1, 37) +- Code(Zero) at (prev + 16, 1) to (start + 1, 35) Highest counter ID seen: (none) Function name: unreachable::unreachable_intrinsic (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 01, 2c] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 01, 2a] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 1) to (start + 1, 44) +- Code(Zero) at (prev + 21, 1) to (start + 1, 42) Highest counter ID seen: (none) diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index 8e1cdb7182b1..542b70bcee96 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -27,10 +27,10 @@ } + coverage Code { bcb: bcb0 } => $DIR/branch_match_arms.rs:14:1: 15:21 (#0); -+ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:17: 16:33 (#0); -+ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:17: 17:33 (#0); -+ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:17: 18:33 (#0); -+ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:33 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:17: 16:32 (#0); ++ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:17: 17:32 (#0); ++ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:17: 18:32 (#0); ++ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:32 (#0); + coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:2: 21:2 (#0); + bb0: { diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff index 1a71cb8dea7f..30de92f3b868 100644 --- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff @@ -8,7 +8,7 @@ let mut _3: !; + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:11 (#0); -+ coverage Code { bcb: bcb1 } => $DIR/instrument_coverage.rs:15:12: 15:17 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/instrument_coverage.rs:15:12: 15:15 (#0); + coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:16:13: 16:18 (#0); + coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:10: 17:10 (#0); + coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:2: 19:2 (#0); From 62a533ce7801ac35344f3ebaa983e90dbeba447a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 25 Mar 2025 20:34:32 +1100 Subject: [PATCH 489/546] coverage: Instead of splitting, just discard any span that overlaps a hole --- .../rustc_mir_transform/src/coverage/spans.rs | 62 +++++-------------- compiler/rustc_mir_transform/src/lib.rs | 1 + tests/coverage/async_block.cov-map | 8 +-- tests/coverage/async_block.coverage | 2 +- tests/coverage/async_closure.cov-map | 14 +++-- tests/coverage/async_closure.coverage | 4 +- tests/coverage/closure.cov-map | 12 ++-- tests/coverage/closure.coverage | 22 +++---- tests/coverage/holes.cov-map | 6 +- tests/coverage/holes.coverage | 20 +++--- 10 files changed, 63 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 8befe9c5d8dd..b1f613432a8b 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,4 +1,5 @@ use std::collections::VecDeque; +use std::iter; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; @@ -83,9 +84,7 @@ pub(super) fn extract_refined_covspans( // Split the covspans into separate buckets that don't overlap any holes. let buckets = divide_spans_into_buckets(covspans, &holes); - for mut covspans in buckets { - // Make sure each individual bucket is internally sorted. - covspans.sort_by(compare_covspans); + for covspans in buckets { let _span = debug_span!("processing bucket", ?covspans).entered(); let mut covspans = remove_unwanted_overlapping_spans(covspans); @@ -161,50 +160,37 @@ fn split_visible_macro_spans(covspans: &mut Vec) { } /// Uses the holes to divide the given covspans into buckets, such that: -/// - No span in any hole overlaps a bucket (truncating the spans if necessary). +/// - No span in any hole overlaps a bucket (discarding spans if necessary). /// - The spans in each bucket are strictly after all spans in previous buckets, /// and strictly before all spans in subsequent buckets. /// -/// The resulting buckets are sorted relative to each other, but might not be -/// internally sorted. +/// The lists of covspans and holes must be sorted. +/// The resulting buckets are sorted relative to each other, and each bucket's +/// contents are sorted. #[instrument(level = "debug")] fn divide_spans_into_buckets(input_covspans: Vec, holes: &[Hole]) -> Vec> { debug_assert!(input_covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); debug_assert!(holes.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); - // Now we're ready to start carving holes out of the initial coverage spans, - // and grouping them in buckets separated by the holes. + // Now we're ready to start grouping spans into buckets separated by holes. let mut input_covspans = VecDeque::from(input_covspans); - let mut fragments = vec![]; // For each hole: // - Identify the spans that are entirely or partly before the hole. - // - Put those spans in a corresponding bucket, truncated to the start of the hole. - // - If one of those spans also extends after the hole, put the rest of it - // in a "fragments" vector that is processed by the next hole. + // - Discard any that overlap with the hole. + // - Add the remaining identified spans to the corresponding bucket. let mut buckets = (0..holes.len()).map(|_| vec![]).collect::>(); for (hole, bucket) in holes.iter().zip(&mut buckets) { - let fragments_from_prev = std::mem::take(&mut fragments); - - // Only inspect spans that precede or overlap this hole, - // leaving the rest to be inspected by later holes. - // (This relies on the spans and holes both being sorted.) - let relevant_input_covspans = - drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()); - - for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) { - let (before, after) = covspan.split_around_hole_span(hole.span); - bucket.extend(before); - fragments.extend(after); - } + bucket.extend( + drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()) + .filter(|c| !c.span.overlaps(hole.span)), + ); } - // After finding the spans before each hole, any remaining fragments/spans - // form their own final bucket, after the final hole. + // Any remaining spans form their own final bucket, after the final hole. // (If there were no holes, this will just be all of the initial spans.) - fragments.extend(input_covspans); - buckets.push(fragments); + buckets.push(Vec::from(input_covspans)); buckets } @@ -215,7 +201,7 @@ fn drain_front_while<'a, T>( queue: &'a mut VecDeque, mut pred_fn: impl FnMut(&T) -> bool, ) -> impl Iterator { - std::iter::from_fn(move || if pred_fn(queue.front()?) { queue.pop_front() } else { None }) + iter::from_fn(move || queue.pop_front_if(|x| pred_fn(x))) } /// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines" @@ -258,22 +244,6 @@ struct Covspan { } impl Covspan { - /// Splits this covspan into 0-2 parts: - /// - The part that is strictly before the hole span, if any. - /// - The part that is strictly after the hole span, if any. - fn split_around_hole_span(&self, hole_span: Span) -> (Option, Option) { - let before = try { - let span = self.span.trim_end(hole_span)?; - Self { span, ..*self } - }; - let after = try { - let span = self.span.trim_start(hole_span)?; - Self { span, ..*self } - }; - - (before, after) - } - /// If `self` and `other` can be merged (i.e. they have the same BCB), /// mutates `self.span` to also include `other.span` and returns true. /// diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 205d388f4fb5..c372b77ad257 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -12,6 +12,7 @@ #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] +#![feature(vec_deque_pop_if)] #![feature(yeet_expr)] // tidy-alphabetical-end diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async_block.cov-map index 5eb69e668ca5..d9196f446f13 100644 --- a/tests/coverage/async_block.cov-map +++ b/tests/coverage/async_block.cov-map @@ -1,5 +1,5 @@ Function name: async_block::main -Raw bytes (36): 0x[01, 01, 01, 05, 01, 06, 01, 07, 01, 00, 0b, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 13, 02, 00, 14, 01, 16, 02, 07, 0a, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 05, 01, 06, 01, 07, 01, 00, 0b, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 13, 02, 01, 0d, 00, 13, 02, 07, 09, 00, 22, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -9,11 +9,11 @@ Number of file 0 mappings: 6 - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) = (c1 - c0) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 19) -- Code(Expression(0, Sub)) at (prev + 0, 20) to (start + 1, 22) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 19) = (c1 - c0) -- Code(Expression(0, Sub)) at (prev + 7, 10) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 7, 9) to (start + 0, 34) = (c1 - c0) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: async_block::main::{closure#0} diff --git a/tests/coverage/async_block.coverage b/tests/coverage/async_block.coverage index 9e3294492cd0..4e00024aebd2 100644 --- a/tests/coverage/async_block.coverage +++ b/tests/coverage/async_block.coverage @@ -15,6 +15,6 @@ LL| 12| } LL| 16| }; LL| 16| executor::block_on(future); - LL| 16| } + LL| | } LL| 1|} diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map index 0e1d98778307..a4ef0ceeb6df 100644 --- a/tests/coverage/async_closure.cov-map +++ b/tests/coverage/async_closure.cov-map @@ -30,21 +30,23 @@ Number of file 0 mappings: 2 Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 23, 00, 24] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36) Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 23, 00, 24] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36) Highest counter ID seen: c0 Function name: async_closure::main::{closure#0}::{closure#0}:: diff --git a/tests/coverage/async_closure.coverage b/tests/coverage/async_closure.coverage index 10a8ea14504b..5aed131de2e5 100644 --- a/tests/coverage/async_closure.coverage +++ b/tests/coverage/async_closure.coverage @@ -9,13 +9,15 @@ LL| | LL| 1|pub fn main() { LL| 2| let async_closure = async || {}; - ^1 ------------------ | async_closure::main::{closure#0}: | LL| 1| let async_closure = async || {}; ------------------ | async_closure::main::{closure#0}: | LL| 1| let async_closure = async || {}; + ------------------ + | async_closure::main::{closure#0}::{closure#0}::: + | LL| 1| let async_closure = async || {}; ------------------ LL| 1| executor::block_on(async_closure()); LL| 1| executor::block_on(call_once(async_closure)); diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index fa20c8cf6d78..2d784ba09b60 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -1,15 +1,15 @@ Function name: closure::main -Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 05, 00, 06, 01, 01, 05, 03, 02] +Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0d, 1b, 01, 1a, 05, 02, 0a, 01, 0c, 05, 11, 1b, 01, 1e, 05, 02, 0a, 01, 0c, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 05, 00, 06, 01, 01, 05, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 24 -- Code(Counter(0)) at (prev + 9, 1) to (start + 15, 13) -- Code(Counter(0)) at (prev + 22, 14) to (start + 6, 10) -- Code(Counter(0)) at (prev + 16, 5) to (start + 19, 13) -- Code(Counter(0)) at (prev + 26, 14) to (start + 6, 10) -- Code(Counter(0)) at (prev + 16, 5) to (start + 12, 22) +- Code(Counter(0)) at (prev + 9, 1) to (start + 13, 27) +- Code(Counter(0)) at (prev + 26, 5) to (start + 2, 10) +- Code(Counter(0)) at (prev + 12, 5) to (start + 17, 27) +- Code(Counter(0)) at (prev + 30, 5) to (start + 2, 10) +- Code(Counter(0)) at (prev + 12, 5) to (start + 12, 22) - Code(Counter(0)) at (prev + 22, 5) to (start + 13, 24) - Code(Counter(0)) at (prev + 25, 9) to (start + 1, 30) - Code(Counter(0)) at (prev + 4, 9) to (start + 0, 41) diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage index 3eac52eb7236..2deeb9806c4d 100644 --- a/tests/coverage/closure.coverage +++ b/tests/coverage/closure.coverage @@ -20,18 +20,18 @@ LL| 1| some_string LL| 1| . LL| 1| unwrap_or_else - LL| 1| ( - LL| 1| || + LL| | ( + LL| | || LL| 0| { LL| 0| let mut countdown = 0; LL| 0| if is_false { LL| 0| countdown = 10; LL| 0| } LL| 0| "alt string 1".to_owned() - LL| 1| } - LL| 1| ) - LL| 1| ); - LL| 1| + LL| 0| } + LL| | ) + LL| | ); + LL| | LL| 1| some_string = Some(String::from("the string content")); LL| 1| let LL| 1| a @@ -62,8 +62,8 @@ LL| 1| some_string LL| 1| . LL| 1| unwrap_or_else - LL| 1| ( - LL| 1| || + LL| | ( + LL| | || LL| 1| { LL| 1| let mut countdown = 0; LL| 1| if is_false { @@ -71,9 +71,9 @@ LL| 1| } LL| 1| "alt string 3".to_owned() LL| 1| } - LL| 1| ) - LL| 1| ); - LL| 1| + LL| | ) + LL| | ); + LL| | LL| 1| some_string = None; LL| 1| let LL| 1| a diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map index 8ff291d2d7d3..6e2d243e8dd2 100644 --- a/tests/coverage/holes.cov-map +++ b/tests/coverage/holes.cov-map @@ -8,7 +8,7 @@ Number of file 0 mappings: 1 Highest counter ID seen: (none) Function name: holes::main -Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 11, 01, 05, 05, 00, 11, 01, 07, 09, 00, 11, 01, 09, 05, 00, 11, 01, 04, 05, 00, 11, 01, 07, 05, 00, 11, 01, 06, 05, 00, 11, 01, 04, 05, 00, 11, 01, 04, 05, 00, 11, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 0c, 0d, 01, 0f, 0e, 05, 02] +Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 11, 01, 05, 05, 00, 11, 01, 07, 09, 00, 11, 01, 09, 05, 00, 11, 01, 04, 05, 00, 11, 01, 07, 05, 00, 11, 01, 06, 05, 00, 11, 01, 04, 05, 00, 11, 01, 04, 05, 00, 11, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 06, 27, 01, 13, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 @@ -24,8 +24,8 @@ Number of file 0 mappings: 13 - Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) - Code(Counter(0)) at (prev + 6, 5) to (start + 3, 15) - Code(Counter(0)) at (prev + 10, 5) to (start + 3, 15) -- Code(Counter(0)) at (prev + 10, 5) to (start + 12, 13) -- Code(Counter(0)) at (prev + 15, 14) to (start + 5, 2) +- Code(Counter(0)) at (prev + 10, 5) to (start + 6, 39) +- Code(Counter(0)) at (prev + 19, 5) to (start + 1, 2) Highest counter ID seen: c0 Function name: holes::main::_unused_fn (unused) diff --git a/tests/coverage/holes.coverage b/tests/coverage/holes.coverage index 1b45c12156ae..a6a02f1b9d08 100644 --- a/tests/coverage/holes.coverage +++ b/tests/coverage/holes.coverage @@ -84,18 +84,18 @@ LL| 1| // `nested_filter::OnlyBodies` or equivalent. LL| 1| #[rustfmt::skip] LL| 1| let _const_block_inside_anon_const = - LL| 1| [ - LL| 1| 0 - LL| 1| ; - LL| 1| 7 - LL| 1| + - LL| 1| const + LL| | [ + LL| | 0 + LL| | ; + LL| | 7 + LL| | + + LL| | const LL| | { LL| | 3 - LL| 1| } - LL| 1| ] - LL| 1| ; - LL| 1| + LL| | } + LL| | ] + LL| | ; + LL| | LL| 1| black_box(()); LL| 1|} From 26cea8a2863a3aa0fd169d8561ce77036ef6983e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 25 Mar 2025 22:02:22 +1100 Subject: [PATCH 490/546] coverage: Don't split bang-macro spans, just truncate them --- .../src/coverage/mappings.rs | 2 +- .../rustc_mir_transform/src/coverage/spans.rs | 43 ++++++------------- tests/coverage/abort.cov-map | 4 +- tests/coverage/assert_not.cov-map | 10 ++--- tests/coverage/bad_counter_ids.cov-map | 16 +++---- tests/coverage/branch/guard.cov-map | 4 +- tests/coverage/branch/if-let.cov-map | 4 +- tests/coverage/branch/if.cov-map | 16 +++---- tests/coverage/branch/lazy-boolean.cov-map | 16 +++---- tests/coverage/branch/let-else.cov-map | 4 +- tests/coverage/branch/match-arms.cov-map | 12 +++--- tests/coverage/branch/match-trivial.cov-map | 8 ++-- tests/coverage/branch/while.cov-map | 16 +++---- tests/coverage/closure_macro.cov-map | 6 +-- tests/coverage/closure_macro_async.cov-map | 6 +-- tests/coverage/coroutine.cov-map | 6 +-- tests/coverage/inline.cov-map | 4 +- tests/coverage/issue-83601.cov-map | 6 +-- tests/coverage/issue-84561.cov-map | 34 +++++++-------- tests/coverage/issue-84561.coverage | 42 +++++++++--------- tests/coverage/loops_branches.cov-map | 12 +++--- tests/coverage/macro_name_span.cov-map | 4 +- tests/coverage/panic_unwind.cov-map | 4 +- tests/coverage/try_error_result.cov-map | 12 +++--- tests/coverage/yield.cov-map | 10 ++--- 25 files changed, 142 insertions(+), 159 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index d83c0d40a7e5..73bd2d0705e1 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -96,7 +96,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( } } else { // Extract coverage spans from MIR statements/terminators as normal. - extract_refined_covspans(mir_body, hir_info, graph, &mut code_mappings); + extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut code_mappings); } branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, graph)); diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index b1f613432a8b..f57a158e3e4a 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -3,6 +3,7 @@ use std::iter; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; +use rustc_middle::ty::TyCtxt; use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; use tracing::{debug, debug_span, instrument}; @@ -12,8 +13,9 @@ use crate::coverage::{ExtractedHirInfo, mappings, unexpand}; mod from_mir; -pub(super) fn extract_refined_covspans( - mir_body: &mir::Body<'_>, +pub(super) fn extract_refined_covspans<'tcx>( + tcx: TyCtxt<'tcx>, + mir_body: &mir::Body<'tcx>, hir_info: &ExtractedHirInfo, graph: &CoverageGraph, code_mappings: &mut impl Extend, @@ -51,7 +53,7 @@ pub(super) fn extract_refined_covspans( // First, perform the passes that need macro information. covspans.sort_by(|a, b| graph.cmp_in_dominator_order(a.bcb, b.bcb)); remove_unwanted_expansion_spans(&mut covspans); - split_visible_macro_spans(&mut covspans); + shrink_visible_macro_spans(tcx, &mut covspans); // We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`. let mut covspans = covspans.into_iter().map(SpanFromMir::into_covspan).collect::>(); @@ -128,35 +130,16 @@ fn remove_unwanted_expansion_spans(covspans: &mut Vec) { } /// When a span corresponds to a macro invocation that is visible from the -/// function body, split it into two parts. The first part covers just the -/// macro name plus `!`, and the second part covers the rest of the macro -/// invocation. This seems to give better results for code that uses macros. -fn split_visible_macro_spans(covspans: &mut Vec) { - let mut extra_spans = vec![]; +/// function body, truncate it to just the macro name plus `!`. +/// This seems to give better results for code that uses macros. +fn shrink_visible_macro_spans(tcx: TyCtxt<'_>, covspans: &mut Vec) { + let source_map = tcx.sess.source_map(); - covspans.retain(|covspan| { - let Some(ExpnKind::Macro(MacroKind::Bang, visible_macro)) = covspan.expn_kind else { - return true; - }; - - let split_len = visible_macro.as_str().len() as u32 + 1; - let (before, after) = covspan.span.split_at(split_len); - if !covspan.span.contains(before) || !covspan.span.contains(after) { - // Something is unexpectedly wrong with the split point. - // The debug assertion in `split_at` will have already caught this, - // but in release builds it's safer to do nothing and maybe get a - // bug report for unexpected coverage, rather than risk an ICE. - return true; + for covspan in covspans { + if matches!(covspan.expn_kind, Some(ExpnKind::Macro(MacroKind::Bang, _))) { + covspan.span = source_map.span_through_char(covspan.span, '!'); } - - extra_spans.push(SpanFromMir::new(before, covspan.expn_kind.clone(), covspan.bcb)); - extra_spans.push(SpanFromMir::new(after, covspan.expn_kind.clone(), covspan.bcb)); - false // Discard the original covspan that we just split. - }); - - // The newly-split spans are added at the end, so any previous sorting - // is not preserved. - covspans.extend(extra_spans); + } } /// Uses the holes to divide the given covspans into buckets, such that: diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 84fae4a595a7..26536caeba52 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -34,14 +34,14 @@ Number of file 0 mappings: 13 Highest counter ID seen: c4 Function name: abort::might_abort -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02] +Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 3, 1) to (start + 1, 20) -- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 36) +- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 15) - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) = (c0 - c1) Highest counter ID seen: c1 diff --git a/tests/coverage/assert_not.cov-map b/tests/coverage/assert_not.cov-map index 526110ebbb76..3aef4274edc3 100644 --- a/tests/coverage/assert_not.cov-map +++ b/tests/coverage/assert_not.cov-map @@ -1,13 +1,13 @@ Function name: assert_not::main -Raw bytes (29): 0x[01, 01, 00, 05, 01, 06, 01, 01, 12, 01, 02, 05, 00, 14, 01, 01, 05, 00, 14, 01, 01, 05, 00, 16, 01, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 06, 01, 01, 11, 01, 02, 05, 00, 13, 01, 01, 05, 00, 13, 01, 01, 05, 00, 15, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 18) -- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 20) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 20) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 17) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 21) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map index baac0073fcbe..f08a70a899d0 100644 --- a/tests/coverage/bad_counter_ids.cov-map +++ b/tests/coverage/bad_counter_ids.cov-map @@ -1,10 +1,10 @@ Function name: bad_counter_ids::eq_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 1f, 00, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 0f, 00, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 15) - Code(Zero) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 @@ -20,12 +20,12 @@ Number of file 0 mappings: 3 Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 1f, 01, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 0f, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 @@ -41,12 +41,12 @@ Number of file 0 mappings: 3 Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 1f, 00, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 0f, 00, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 46, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 46, 1) to (start + 2, 15) - Code(Zero) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 @@ -62,12 +62,12 @@ Number of file 0 mappings: 3 Highest counter ID seen: c0 Function name: bad_counter_ids::ne_good -Raw bytes (14): 0x[01, 01, 00, 02, 01, 1a, 01, 02, 1f, 01, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 1a, 01, 02, 0f, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 15) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map index 55f45daa9c93..46533df00f71 100644 --- a/tests/coverage/branch/guard.cov-map +++ b/tests/coverage/branch/guard.cov-map @@ -1,5 +1,5 @@ Function name: guard::branch_match_guard -Raw bytes (89): 0x[01, 01, 08, 05, 0d, 09, 05, 05, 0f, 0d, 11, 17, 1b, 01, 05, 1f, 11, 09, 0d, 0d, 01, 0c, 01, 01, 10, 02, 03, 0b, 00, 0c, 06, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 0a, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 12, 03, 0e, 02, 0a, 01, 04, 01, 00, 02] +Raw bytes (89): 0x[01, 01, 08, 05, 0d, 09, 05, 05, 0f, 0d, 11, 17, 1b, 01, 05, 1f, 11, 09, 0d, 0d, 01, 0c, 01, 01, 0e, 02, 03, 0b, 00, 0c, 06, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 0a, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 12, 03, 0e, 02, 0a, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -12,7 +12,7 @@ Number of expressions: 8 - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(4) - expression 7 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) - Code(Expression(0, Sub)) at (prev + 3, 11) to (start + 0, 12) = (c1 - c3) - Code(Expression(1, Sub)) at (prev + 1, 20) to (start + 2, 10) diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map index db45df2a5cd0..7f6b174615a9 100644 --- a/tests/coverage/branch/if-let.cov-map +++ b/tests/coverage/branch/if-let.cov-map @@ -1,11 +1,11 @@ Function name: if_let::if_let -Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 10, 20, 02, 05, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 05, 02, 0c, 02, 06, 01, 03, 05, 01, 02] +Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 05, 02, 0c, 02, 06, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 3, 12) to (start + 0, 19) true = (c0 - c1) false = c1 diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index 392ace1683a7..1d40f032aa87 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -1,5 +1,5 @@ Function name: if::branch_and -Raw bytes (54): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 2b, 01, 01, 10, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 09, 06, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (54): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 2b, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 09, 06, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -7,7 +7,7 @@ Number of expressions: 3 - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 43, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 43, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 @@ -23,7 +23,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::branch_not -Raw bytes (116): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 12, 01, 0c, 01, 01, 10, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 10, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (116): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 12, 01, 0c, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 10, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -35,7 +35,7 @@ Number of expressions: 7 - expression 5 operands: lhs = Counter(0), rhs = Counter(4) - expression 6 operands: lhs = Counter(0), rhs = Counter(4) Number of file 0 mappings: 18 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 @@ -68,7 +68,7 @@ Number of file 0 mappings: 18 Highest counter ID seen: c4 Function name: if::branch_not_as -Raw bytes (90): 0x[01, 01, 05, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 0e, 01, 1d, 01, 01, 10, 01, 03, 08, 00, 14, 20, 02, 05, 00, 08, 00, 14, 02, 00, 15, 02, 06, 05, 02, 05, 00, 06, 01, 01, 08, 00, 15, 20, 09, 0a, 00, 08, 00, 15, 09, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 01, 01, 08, 00, 16, 20, 12, 0d, 00, 08, 00, 16, 12, 00, 17, 02, 06, 0d, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (90): 0x[01, 01, 05, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 0e, 01, 1d, 01, 01, 0e, 01, 03, 08, 00, 14, 20, 02, 05, 00, 08, 00, 14, 02, 00, 15, 02, 06, 05, 02, 05, 00, 06, 01, 01, 08, 00, 15, 20, 09, 0a, 00, 08, 00, 15, 09, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 01, 01, 08, 00, 16, 20, 12, 0d, 00, 08, 00, 16, 12, 00, 17, 02, 06, 0d, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 @@ -78,7 +78,7 @@ Number of expressions: 5 - expression 3 operands: lhs = Counter(0), rhs = Counter(3) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 29, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 29, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 8) to (start + 0, 20) - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 0, 8) to (start + 0, 20) true = (c0 - c1) @@ -104,7 +104,7 @@ Number of file 0 mappings: 14 Highest counter ID seen: c3 Function name: if::branch_or -Raw bytes (60): 0x[01, 01, 06, 01, 05, 01, 17, 05, 09, 05, 09, 01, 17, 05, 09, 08, 01, 35, 01, 01, 10, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 09, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (60): 0x[01, 01, 06, 01, 05, 01, 17, 05, 09, 05, 09, 01, 17, 05, 09, 08, 01, 35, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 09, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 6 @@ -115,7 +115,7 @@ Number of expressions: 6 - expression 4 operands: lhs = Counter(0), rhs = Expression(5, Add) - expression 5 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 53, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 53, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map index ff285a038fb8..5d4fc57eb8f7 100644 --- a/tests/coverage/branch/lazy-boolean.cov-map +++ b/tests/coverage/branch/lazy-boolean.cov-map @@ -1,11 +1,11 @@ Function name: lazy_boolean::branch_and -Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 13, 01, 01, 10, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 13, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 19, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 19, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -16,13 +16,13 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: lazy_boolean::branch_or -Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 1b, 01, 01, 10, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 1b, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 27, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 27, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -34,7 +34,7 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: lazy_boolean::chain -Raw bytes (141): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 13, 01, 24, 01, 01, 10, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 01, 02] +Raw bytes (141): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 13, 01, 24, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 15 @@ -54,7 +54,7 @@ Number of expressions: 15 - expression 13 operands: lhs = Expression(14, Add), rhs = Counter(6) - expression 14 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 19 -- Code(Counter(0)) at (prev + 36, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 36, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 18) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 18) @@ -91,7 +91,7 @@ Number of file 0 mappings: 19 Highest counter ID seen: c6 Function name: lazy_boolean::nested_mixed -Raw bytes (137): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 13, 01, 31, 01, 01, 10, 01, 04, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 01, 02] +Raw bytes (137): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 13, 01, 31, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 13 @@ -109,7 +109,7 @@ Number of expressions: 13 - expression 11 operands: lhs = Counter(0), rhs = Expression(12, Add) - expression 12 operands: lhs = Counter(5), rhs = Counter(6) Number of file 0 mappings: 19 -- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 19) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 14) to (start + 0, 19) diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map index 811b9838e3f5..78507a326388 100644 --- a/tests/coverage/branch/let-else.cov-map +++ b/tests/coverage/branch/let-else.cov-map @@ -1,11 +1,11 @@ Function name: let_else::let_else -Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 10, 20, 02, 05, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 01, 0f, 02, 04, 05, 00, 0a, 01, 01, 01, 00, 02] +Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 01, 0f, 02, 04, 05, 00, 0a, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 3, 9) to (start + 0, 16) true = (c0 - c1) false = c1 diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index caa18820cf8e..ef71d12c8af1 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -1,5 +1,5 @@ Function name: match_arms::guards -Raw bytes (88): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 0c, 01, 30, 01, 01, 10, 21, 03, 0b, 00, 10, 05, 01, 11, 00, 28, 20, 05, 02, 00, 17, 00, 1b, 09, 01, 11, 00, 28, 20, 09, 06, 00, 17, 00, 1b, 0d, 01, 11, 00, 28, 20, 0d, 0a, 00, 17, 00, 1b, 11, 01, 11, 00, 28, 20, 11, 0e, 00, 17, 00, 1b, 12, 01, 0e, 00, 15, 01, 03, 05, 01, 02] +Raw bytes (88): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 0c, 01, 30, 01, 01, 0e, 21, 03, 0b, 00, 10, 05, 01, 11, 00, 28, 20, 05, 02, 00, 17, 00, 1b, 09, 01, 11, 00, 28, 20, 09, 06, 00, 17, 00, 1b, 0d, 01, 11, 00, 28, 20, 0d, 0a, 00, 17, 00, 1b, 11, 01, 11, 00, 28, 20, 11, 0e, 00, 17, 00, 1b, 12, 01, 0e, 00, 15, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -12,7 +12,7 @@ Number of expressions: 8 - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(3) - expression 7 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 12 -- Code(Counter(0)) at (prev + 48, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 48, 1) to (start + 1, 14) - Code(Counter(8)) at (prev + 3, 11) to (start + 0, 16) - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 40) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 23) to (start + 0, 27) @@ -36,7 +36,7 @@ Number of file 0 mappings: 12 Highest counter ID seen: c8 Function name: match_arms::match_arms -Raw bytes (45): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 07, 01, 18, 01, 01, 10, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 20, 09, 01, 11, 00, 20, 0d, 01, 11, 00, 20, 02, 01, 11, 00, 20, 01, 03, 05, 01, 02] +Raw bytes (45): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 07, 01, 18, 01, 01, 0e, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 20, 09, 01, 11, 00, 20, 0d, 01, 11, 00, 20, 02, 01, 11, 00, 20, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -44,7 +44,7 @@ Number of expressions: 3 - expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 24, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 24, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 11) to (start + 0, 16) - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 32) - Code(Counter(2)) at (prev + 1, 17) to (start + 0, 32) @@ -55,7 +55,7 @@ Number of file 0 mappings: 7 Highest counter ID seen: c3 Function name: match_arms::or_patterns -Raw bytes (57): 0x[01, 01, 04, 05, 09, 01, 0b, 03, 0d, 01, 03, 09, 01, 25, 01, 01, 10, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2d, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 0e, 00, 24, 00, 2d, 01, 03, 05, 01, 02] +Raw bytes (57): 0x[01, 01, 04, 05, 09, 01, 0b, 03, 0d, 01, 03, 09, 01, 25, 01, 01, 0e, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2d, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 0e, 00, 24, 00, 2d, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -64,7 +64,7 @@ Number of expressions: 4 - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) - expression 3 operands: lhs = Counter(0), rhs = Expression(0, Add) Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 37, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 37, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 11) to (start + 0, 16) - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 18) - Code(Counter(2)) at (prev + 0, 30) to (start + 0, 31) diff --git a/tests/coverage/branch/match-trivial.cov-map b/tests/coverage/branch/match-trivial.cov-map index 31322f127af7..1b0c6d12e3dc 100644 --- a/tests/coverage/branch/match-trivial.cov-map +++ b/tests/coverage/branch/match-trivial.cov-map @@ -1,19 +1,19 @@ Function name: match_trivial::_uninhabited (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 01, 10] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 01, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 22, 1) to (start + 1, 16) +- Code(Zero) at (prev + 22, 1) to (start + 1, 14) Highest counter ID seen: (none) Function name: match_trivial::trivial -Raw bytes (14): 0x[01, 01, 00, 02, 01, 1e, 01, 01, 10, 01, 03, 0b, 05, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 1e, 01, 01, 0e, 01, 03, 0b, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 11) to (start + 5, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map index 5ce92c72b512..67746af051b6 100644 --- a/tests/coverage/branch/while.cov-map +++ b/tests/coverage/branch/while.cov-map @@ -1,11 +1,11 @@ Function name: while::while_cond -Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 0c, 01, 01, 10, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 10, 20, 02, 01, 00, 0b, 00, 10, 02, 00, 11, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 0c, 01, 01, 0e, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 10, 20, 02, 01, 00, 0b, 00, 10, 02, 00, 11, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 18) - Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 0, 11) to (start + 0, 16) @@ -17,13 +17,13 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: while::while_cond_not -Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 15, 01, 01, 10, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 14, 20, 02, 01, 00, 0b, 00, 14, 02, 00, 15, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 15, 01, 01, 0e, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 14, 20, 02, 01, 00, 0b, 00, 14, 02, 00, 15, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 21, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 21, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 18) - Code(Counter(1)) at (prev + 1, 11) to (start + 0, 20) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 0, 11) to (start + 0, 20) @@ -35,7 +35,7 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: while::while_op_and -Raw bytes (58): 0x[01, 01, 05, 05, 09, 05, 01, 0f, 05, 01, 09, 05, 01, 08, 01, 1e, 01, 01, 10, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 09, 00, 14, 00, 19, 20, 12, 0a, 00, 14, 00, 19, 12, 00, 1a, 03, 06, 01, 04, 01, 00, 02] +Raw bytes (58): 0x[01, 01, 05, 05, 09, 05, 01, 0f, 05, 01, 09, 05, 01, 08, 01, 1e, 01, 01, 0e, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 09, 00, 14, 00, 19, 20, 12, 0a, 00, 14, 00, 19, 12, 00, 1a, 03, 06, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 @@ -45,7 +45,7 @@ Number of expressions: 5 - expression 3 operands: lhs = Counter(0), rhs = Counter(2) - expression 4 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 18) - Code(Counter(1)) at (prev + 2, 11) to (start + 0, 16) - Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 11) to (start + 0, 16) @@ -61,7 +61,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: while::while_op_or -Raw bytes (56): 0x[01, 01, 04, 05, 09, 05, 0b, 01, 09, 05, 01, 08, 01, 29, 01, 01, 10, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 02, 00, 14, 00, 19, 20, 06, 01, 00, 14, 00, 19, 0e, 00, 1a, 03, 06, 01, 04, 01, 00, 02] +Raw bytes (56): 0x[01, 01, 04, 05, 09, 05, 0b, 01, 09, 05, 01, 08, 01, 29, 01, 01, 0e, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 02, 00, 14, 00, 19, 20, 06, 01, 00, 14, 00, 19, 0e, 00, 1a, 03, 06, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -70,7 +70,7 @@ Number of expressions: 4 - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 14) - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 18) - Code(Counter(1)) at (prev + 2, 11) to (start + 0, 16) - Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 11) to (start + 0, 16) diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index 653848dd6ffc..9dd99c8fab3f 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -8,16 +8,16 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: closure_macro::main -Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 20, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33) +- Code(Counter(0)) at (prev + 33, 1) to (start + 1, 32) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) -- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 84) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 52) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) = (c0 - c1) diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 1bd1460a147a..2548754d754c 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -17,16 +17,16 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: closure_macro_async::test::{closure#0} -Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 25, 2b, 01, 21, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 25, 2b, 01, 20, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 37, 43) to (start + 1, 33) +- Code(Counter(0)) at (prev + 37, 43) to (start + 1, 32) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) -- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 84) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 52) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) = (c0 - c1) diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index 297dde3b2b0f..fee32376d831 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -13,7 +13,7 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: coroutine::main -Raw bytes (53): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2d, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 35, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 35, 09, 02, 01, 00, 02] +Raw bytes (53): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2d, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -23,12 +23,12 @@ Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22) - Code(Counter(0)) at (prev + 8, 11) to (start + 0, 45) - Code(Counter(1)) at (prev + 1, 43) to (start + 0, 45) -- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 53) +- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c0 - c1) - Code(Counter(1)) at (prev + 2, 11) to (start + 0, 46) - Code(Counter(3)) at (prev + 1, 34) to (start + 0, 39) - Code(Counter(2)) at (prev + 0, 44) to (start + 0, 46) -- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 53) +- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c1 - c2) - Code(Counter(2)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c3 diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map index a569ad53cbc2..7264391baaf7 100644 --- a/tests/coverage/inline.cov-map +++ b/tests/coverage/inline.cov-map @@ -15,12 +15,12 @@ Number of file 0 mappings: 5 Highest counter ID seen: c1 Function name: inline::error -Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 0b] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 20) +- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 11) Highest counter ID seen: c0 Function name: inline::length:: diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index c188cca1b517..f10231090089 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -1,12 +1,12 @@ Function name: issue_83601::main -Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02] +Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 0f, 05, 03, 09, 01, 0f, 02, 02, 05, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 28) -- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 28) +- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 15) +- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 15) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2) = (c1 - c2) Highest counter ID seen: c1 diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index c8f75cddcb5b..3bd4e7d2a366 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -1,11 +1,11 @@ Function name: ::fmt -Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, 8a, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, 8a, 01, 05, 01, 24, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 138, 5) to (start + 1, 37) +- Code(Counter(0)) at (prev + 138, 5) to (start + 1, 36) - Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) @@ -59,7 +59,7 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: issue_84561::test3 -Raw bytes (315): 0x[01, 01, 1b, 1d, 21, 25, 29, 21, 25, 2d, 31, 21, 17, 25, 2d, 41, 45, 49, 4d, 51, 55, 33, 51, 49, 4d, 33, 37, 49, 4d, 51, 59, 55, 59, 55, 59, 47, 5d, 55, 59, 61, 65, 71, 75, 69, 6d, 69, 6d, 69, 6d, 63, 79, 71, 75, 79, 7d, 7d, 81, 01, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 09, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 11, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 19, 02, 05, 00, 1f, 1d, 01, 05, 00, 0f, 02, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 25, 03, 20, 00, 30, 29, 00, 33, 00, 41, 06, 00, 4b, 00, 5a, 0a, 01, 05, 00, 0f, 2d, 05, 09, 03, 10, 31, 05, 0d, 00, 1b, 0e, 02, 0d, 00, 1c, 12, 04, 09, 05, 06, 35, 06, 05, 03, 06, 39, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 41, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 1a, 05, 09, 03, 0a, 33, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 22, 03, 0d, 00, 1d, 26, 03, 09, 00, 13, 2e, 03, 0d, 00, 1d, 47, 03, 05, 00, 0f, 47, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 42, 02, 0d, 00, 13, 61, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 4a, 02, 0d, 00, 13, 63, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 71, 04, 0d, 00, 13, 5a, 02, 0d, 00, 17, 5a, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 5a, 02, 15, 00, 1b, 75, 04, 0d, 00, 13, 5e, 03, 09, 00, 19, 79, 02, 05, 00, 0f, 66, 03, 09, 00, 22, 7d, 02, 05, 00, 0f, 6a, 03, 09, 00, 2c, 81, 01, 02, 01, 00, 02] +Raw bytes (315): 0x[01, 01, 1b, 1d, 21, 25, 29, 21, 25, 2d, 31, 21, 17, 25, 2d, 41, 45, 49, 4d, 51, 55, 33, 51, 49, 4d, 33, 37, 49, 4d, 51, 59, 55, 59, 55, 59, 47, 5d, 55, 59, 61, 65, 71, 75, 69, 6d, 69, 6d, 69, 6d, 63, 79, 71, 75, 79, 7d, 7d, 81, 01, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 0d, 05, 05, 00, 0f, 11, 01, 05, 00, 0f, 15, 01, 09, 01, 0f, 19, 02, 05, 00, 0f, 1d, 01, 05, 00, 0f, 02, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 25, 03, 20, 00, 30, 29, 00, 33, 00, 41, 06, 00, 4b, 00, 5a, 0a, 01, 05, 00, 0f, 2d, 05, 09, 03, 10, 31, 05, 0d, 00, 1b, 0e, 02, 0d, 00, 1c, 12, 04, 09, 02, 0f, 35, 06, 05, 00, 0f, 39, 04, 05, 00, 0f, 3d, 04, 09, 01, 0f, 41, 05, 08, 00, 0f, 45, 01, 09, 00, 13, 1a, 05, 09, 00, 13, 33, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 22, 03, 0d, 00, 1d, 26, 03, 09, 00, 13, 2e, 03, 0d, 00, 1d, 47, 03, 05, 00, 0f, 47, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 42, 02, 0d, 00, 13, 61, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 4a, 02, 0d, 00, 13, 63, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 00, 17, 71, 04, 0d, 00, 13, 5a, 02, 0d, 00, 17, 5a, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 5a, 02, 15, 00, 1b, 75, 04, 0d, 00, 13, 5e, 03, 09, 00, 19, 79, 02, 05, 00, 0f, 66, 03, 09, 00, 22, 7d, 02, 05, 00, 0f, 6a, 03, 09, 00, 2c, 81, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 27 @@ -91,13 +91,13 @@ Number of expressions: 27 - expression 25 operands: lhs = Counter(30), rhs = Counter(31) - expression 26 operands: lhs = Counter(31), rhs = Counter(32) Number of file 0 mappings: 51 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28) -- Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28) -- Code(Counter(2)) at (prev + 2, 5) to (start + 4, 31) -- Code(Counter(3)) at (prev + 5, 5) to (start + 0, 31) -- Code(Counter(4)) at (prev + 1, 5) to (start + 0, 31) -- Code(Counter(5)) at (prev + 1, 9) to (start + 1, 28) -- Code(Counter(6)) at (prev + 2, 5) to (start + 0, 31) +- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 15) +- Code(Counter(1)) at (prev + 4, 9) to (start + 1, 15) +- Code(Counter(2)) at (prev + 2, 5) to (start + 4, 15) +- Code(Counter(3)) at (prev + 5, 5) to (start + 0, 15) +- Code(Counter(4)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(5)) at (prev + 1, 9) to (start + 1, 15) +- Code(Counter(6)) at (prev + 2, 5) to (start + 0, 15) - Code(Counter(7)) at (prev + 1, 5) to (start + 0, 15) - Code(Expression(0, Sub)) at (prev + 0, 32) to (start + 0, 48) = (c7 - c8) @@ -112,14 +112,14 @@ Number of file 0 mappings: 51 - Code(Counter(12)) at (prev + 5, 13) to (start + 0, 27) - Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 28) = (c11 - c12) -- Code(Expression(4, Sub)) at (prev + 4, 9) to (start + 5, 6) +- Code(Expression(4, Sub)) at (prev + 4, 9) to (start + 2, 15) = (c8 - (c9 + c11)) -- Code(Counter(13)) at (prev + 6, 5) to (start + 3, 6) -- Code(Counter(14)) at (prev + 4, 5) to (start + 3, 6) -- Code(Counter(15)) at (prev + 4, 9) to (start + 4, 6) +- Code(Counter(13)) at (prev + 6, 5) to (start + 0, 15) +- Code(Counter(14)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(15)) at (prev + 4, 9) to (start + 1, 15) - Code(Counter(16)) at (prev + 5, 8) to (start + 0, 15) -- Code(Counter(17)) at (prev + 1, 9) to (start + 3, 10) -- Code(Expression(6, Sub)) at (prev + 5, 9) to (start + 3, 10) +- Code(Counter(17)) at (prev + 1, 9) to (start + 0, 19) +- Code(Expression(6, Sub)) at (prev + 5, 9) to (start + 0, 19) = (c16 - c17) - Code(Expression(12, Add)) at (prev + 5, 8) to (start + 0, 15) = (c18 + c19) @@ -144,7 +144,7 @@ Number of file 0 mappings: 51 - Code(Expression(24, Add)) at (prev + 3, 5) to (start + 0, 15) = (c28 + c29) - Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19) -- Code(Counter(27)) at (prev + 1, 13) to (start + 3, 14) +- Code(Counter(27)) at (prev + 1, 13) to (start + 0, 23) - Code(Counter(28)) at (prev + 4, 13) to (start + 0, 19) - Code(Expression(22, Sub)) at (prev + 2, 13) to (start + 0, 23) = (c26 - c27) diff --git a/tests/coverage/issue-84561.coverage b/tests/coverage/issue-84561.coverage index 2a642e2427b9..a55f42a696e6 100644 --- a/tests/coverage/issue-84561.coverage +++ b/tests/coverage/issue-84561.coverage @@ -47,32 +47,32 @@ LL| 1| let is_true = std::env::args().len() == 1; LL| 1| LL| 1| assert_eq!( - LL| 1| Foo(1), - LL| 1| Foo(1) - LL| 1| ); + LL| | Foo(1), + LL| | Foo(1) + LL| | ); LL| 1| assert_ne!( - LL| 1| Foo(0), - LL| 1| Foo(1) - LL| 1| ); + LL| | Foo(0), + LL| | Foo(1) + LL| | ); LL| 1| assert_eq!( - LL| 1| Foo(2), - LL| 1| Foo(2) - LL| 1| ); + LL| | Foo(2), + LL| | Foo(2) + LL| | ); LL| 1| let bar = Foo(1); LL| 1| assert_ne!( - LL| 1| bar, - LL| 1| Foo(3) - LL| 1| ); + LL| | bar, + LL| | Foo(3) + LL| | ); LL| 1| if is_true { LL| 1| assert_ne!( - LL| 1| Foo(0), - LL| 1| Foo(4) - LL| 1| ); + LL| | Foo(0), + LL| | Foo(4) + LL| | ); LL| | } else { LL| 0| assert_eq!( - LL| 0| Foo(3), - LL| 0| Foo(3) - LL| 0| ); + LL| | Foo(3), + LL| | Foo(3) + LL| | ); LL| | } LL| 1| if is_true { LL| 1| assert_ne!( @@ -106,9 +106,9 @@ LL| 1| assert_ne!( LL| 1| if is_true { LL| 1| assert_eq!( - LL| 1| Foo(3), - LL| 1| Foo(3) - LL| 1| ); + LL| | Foo(3), + LL| | Foo(3) + LL| | ); LL| 1| Foo(0) LL| | } else { LL| 0| assert_ne!( diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index 2cb0f948b3e1..2157cd6ee3f8 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -1,5 +1,5 @@ Function name: ::fmt -Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 0d, 05, 09, 09, 0d, 14, 01, 09, 05, 01, 10, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1e, 05, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 0d, 03, 0d, 00, 0e, 09, 00, 12, 00, 17, 0d, 01, 10, 00, 14, 0d, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 0d, 01, 11, 00, 12, 0d, 01, 11, 00, 22, 02, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 0d, 05, 09, 09, 0d, 14, 01, 09, 05, 01, 10, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1d, 05, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 0d, 03, 0d, 00, 0e, 09, 00, 12, 00, 17, 0d, 01, 10, 00, 14, 0d, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 0d, 01, 11, 00, 12, 0d, 01, 11, 00, 21, 02, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -13,7 +13,7 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 29) - Code(Counter(1)) at (prev + 0, 30) to (start + 0, 31) - Code(Zero) at (prev + 1, 16) to (start + 1, 10) - Code(Counter(3)) at (prev + 3, 13) to (start + 0, 14) @@ -23,7 +23,7 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 34) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 33) - Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 35) = ((c0 + c3) - (c1 + c2)) - Code(Zero) at (prev + 1, 20) to (start + 1, 14) @@ -33,7 +33,7 @@ Number of file 0 mappings: 20 Highest counter ID seen: c3 Function name: ::fmt -Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 09, 05, 0d, 05, 09, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1e, 0d, 00, 1e, 00, 1f, 09, 02, 0d, 00, 0e, 05, 00, 12, 00, 17, 09, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 09, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 09, 01, 11, 00, 12, 09, 01, 11, 00, 22, 02, 00, 22, 00, 23, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 09, 05, 0d, 05, 09, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1d, 0d, 00, 1e, 00, 1f, 09, 02, 0d, 00, 0e, 05, 00, 12, 00, 17, 09, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 09, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 09, 01, 11, 00, 12, 09, 01, 11, 00, 21, 02, 00, 22, 00, 23, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -48,7 +48,7 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 29) - Code(Counter(3)) at (prev + 0, 30) to (start + 0, 31) - Code(Counter(2)) at (prev + 2, 13) to (start + 0, 14) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 23) @@ -58,7 +58,7 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 34) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 33) - Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 35) = ((c0 + c2) - (c1 + c3)) - Code(Expression(3, Sub)) at (prev + 3, 9) to (start + 0, 15) diff --git a/tests/coverage/macro_name_span.cov-map b/tests/coverage/macro_name_span.cov-map index 58620452b2ba..bd033faa5510 100644 --- a/tests/coverage/macro_name_span.cov-map +++ b/tests/coverage/macro_name_span.cov-map @@ -1,10 +1,10 @@ Function name: macro_name_span::affected_function -Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 1c, 01, 40] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 1c, 01, 3e] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 64) +- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 62) Highest counter ID seen: c0 Function name: macro_name_span::main diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/panic_unwind.cov-map index 4628a24689e7..18b13919fe5e 100644 --- a/tests/coverage/panic_unwind.cov-map +++ b/tests/coverage/panic_unwind.cov-map @@ -26,14 +26,14 @@ Number of file 0 mappings: 9 Highest counter ID seen: c3 Function name: panic_unwind::might_panic -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 19, 02, 02, 0c, 03, 02] +Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) -- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 25) +- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 15) - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) = (c0 - c1) Highest counter ID seen: c1 diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index a4a8e21d8c31..e45f3de10815 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -82,7 +82,7 @@ Number of file 0 mappings: 11 Highest counter ID seen: c2 Function name: try_error_result::test2 -Raw bytes (336): 0x[01, 01, 36, 0d, 11, 0d, 3f, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 0d, 3f, 11, 15, 0d, 3b, 3f, 19, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 41, 53, 21, 25, 41, 21, 41, 53, 21, 25, 09, 73, 77, 2d, 0d, 29, 09, 0d, 09, 77, 0d, 29, 09, 73, 77, 2d, 0d, 29, 45, 8b, 01, 31, 35, 45, 31, 45, 8b, 01, 31, 35, 49, 9f, 01, 39, 3d, 49, 39, 49, 9f, 01, 39, 3d, 05, 09, ab, 01, 09, af, 01, 3d, b3, 01, 39, b7, 01, 35, bb, 01, 31, bf, 01, 2d, c3, 01, 29, c7, 01, 25, cb, 01, 21, cf, 01, 1d, d3, 01, 19, d7, 01, 15, 05, 11, 28, 01, 3d, 01, 03, 17, 05, 08, 09, 00, 0e, 09, 02, 09, 04, 1a, 0d, 06, 0d, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 03, 1c, 15, 04, 11, 00, 12, 1e, 02, 11, 03, 27, 32, 05, 11, 00, 14, 1e, 00, 17, 00, 29, 19, 00, 41, 00, 42, 26, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 32, 01, 0d, 00, 20, 4e, 01, 11, 00, 14, 41, 00, 17, 00, 29, 21, 00, 41, 00, 42, 4a, 00, 43, 00, 47, 25, 00, 60, 00, 61, 4e, 01, 0d, 00, 20, 6e, 04, 11, 00, 14, 62, 00, 17, 00, 29, 29, 00, 42, 00, 43, 66, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 6e, 01, 0d, 00, 20, 86, 01, 01, 11, 00, 14, 45, 00, 17, 01, 1d, 31, 01, 36, 00, 37, 82, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, 86, 01, 01, 0d, 00, 20, 9a, 01, 01, 11, 00, 14, 49, 00, 17, 01, 1d, 39, 02, 11, 00, 12, 96, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, 9a, 01, 02, 0d, 00, 20, a2, 01, 03, 05, 00, 0b, a6, 01, 01, 01, 00, 02] +Raw bytes (336): 0x[01, 01, 36, 0d, 11, 0d, 3f, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 0d, 3f, 11, 15, 0d, 3b, 3f, 19, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 41, 53, 21, 25, 41, 21, 41, 53, 21, 25, 09, 73, 77, 2d, 0d, 29, 09, 0d, 09, 77, 0d, 29, 09, 73, 77, 2d, 0d, 29, 45, 8b, 01, 31, 35, 45, 31, 45, 8b, 01, 31, 35, 49, 9f, 01, 39, 3d, 49, 39, 49, 9f, 01, 39, 3d, 05, 09, ab, 01, 09, af, 01, 3d, b3, 01, 39, b7, 01, 35, bb, 01, 31, bf, 01, 2d, c3, 01, 29, c7, 01, 25, cb, 01, 21, cf, 01, 1d, d3, 01, 19, d7, 01, 15, 05, 11, 28, 01, 3d, 01, 03, 17, 05, 08, 09, 00, 0e, 09, 02, 09, 04, 1a, 0d, 06, 0d, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 03, 1c, 15, 04, 11, 00, 12, 1e, 02, 11, 03, 27, 32, 05, 11, 00, 14, 1e, 00, 17, 00, 29, 19, 00, 41, 00, 42, 26, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 32, 01, 0d, 00, 17, 4e, 01, 11, 00, 14, 41, 00, 17, 00, 29, 21, 00, 41, 00, 42, 4a, 00, 43, 00, 47, 25, 00, 60, 00, 61, 4e, 01, 0d, 00, 17, 6e, 04, 11, 00, 14, 62, 00, 17, 00, 29, 29, 00, 42, 00, 43, 66, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 6e, 01, 0d, 00, 17, 86, 01, 01, 11, 00, 14, 45, 00, 17, 01, 1d, 31, 01, 36, 00, 37, 82, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, 86, 01, 01, 0d, 00, 17, 9a, 01, 01, 11, 00, 14, 49, 00, 17, 01, 1d, 39, 02, 11, 00, 12, 96, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, 9a, 01, 02, 0d, 00, 17, a2, 01, 03, 05, 00, 0b, a6, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 54 @@ -159,7 +159,7 @@ Number of file 0 mappings: 40 - Code(Expression(9, Sub)) at (prev + 0, 67) to (start + 0, 71) = (c3 - ((c4 + c5) + c6)) - Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96) -- Code(Expression(12, Sub)) at (prev + 1, 13) to (start + 0, 32) +- Code(Expression(12, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c3 - (((c4 + c5) + c6) + c7)) - Code(Expression(19, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c16 - (c8 + c9)) @@ -168,7 +168,7 @@ Number of file 0 mappings: 40 - Code(Expression(18, Sub)) at (prev + 0, 67) to (start + 0, 71) = (c16 - c8) - Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97) -- Code(Expression(19, Sub)) at (prev + 1, 13) to (start + 0, 32) +- Code(Expression(19, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c16 - (c8 + c9)) - Code(Expression(27, Sub)) at (prev + 4, 17) to (start + 0, 20) = (c2 - ((c3 + c10) + c11)) @@ -178,7 +178,7 @@ Number of file 0 mappings: 40 - Code(Expression(25, Sub)) at (prev + 0, 68) to (start + 0, 72) = (c2 - (c3 + c10)) - Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98) -- Code(Expression(27, Sub)) at (prev + 1, 13) to (start + 0, 32) +- Code(Expression(27, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c2 - ((c3 + c10) + c11)) - Code(Expression(33, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c17 - (c12 + c13)) @@ -187,7 +187,7 @@ Number of file 0 mappings: 40 - Code(Expression(32, Sub)) at (prev + 1, 18) to (start + 0, 22) = (c17 - c12) - Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 32) +- Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c17 - (c12 + c13)) - Code(Expression(38, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c18 - (c14 + c15)) @@ -196,7 +196,7 @@ Number of file 0 mappings: 40 - Code(Expression(37, Sub)) at (prev + 1, 18) to (start + 0, 22) = (c18 - c14) - Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 32) +- Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 23) = (c18 - (c14 + c15)) - Code(Expression(40, Sub)) at (prev + 3, 5) to (start + 0, 11) = (c1 - c2) diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index d296f9bd778a..bf0916e5503a 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -1,5 +1,5 @@ Function name: yield::main -Raw bytes (94): 0x[01, 01, 05, 01, 05, 05, 09, 09, 11, 11, 15, 11, 15, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 05, 01, 27, 00, 29, 02, 01, 0e, 00, 34, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 34, 09, 03, 09, 00, 16, 09, 08, 0b, 00, 2e, 11, 01, 27, 00, 29, 0a, 01, 0e, 00, 34, 11, 02, 0b, 00, 2e, 12, 01, 27, 00, 29, 15, 01, 0e, 00, 34, 12, 02, 01, 00, 02] +Raw bytes (94): 0x[01, 01, 05, 01, 05, 05, 09, 09, 11, 11, 15, 11, 15, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 05, 01, 27, 00, 29, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 03, 09, 00, 16, 09, 08, 0b, 00, 2e, 11, 01, 27, 00, 29, 0a, 01, 0e, 00, 14, 11, 02, 0b, 00, 2e, 12, 01, 27, 00, 29, 15, 01, 0e, 00, 14, 12, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 @@ -12,22 +12,22 @@ Number of file 0 mappings: 16 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22) - Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) - Code(Counter(1)) at (prev + 1, 39) to (start + 0, 41) -- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 52) +- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c0 - c1) - Code(Counter(1)) at (prev + 2, 11) to (start + 0, 46) - Code(Counter(3)) at (prev + 1, 34) to (start + 0, 39) - Code(Counter(2)) at (prev + 0, 44) to (start + 0, 46) -- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 52) +- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c1 - c2) - Code(Counter(2)) at (prev + 3, 9) to (start + 0, 22) - Code(Counter(2)) at (prev + 8, 11) to (start + 0, 46) - Code(Counter(4)) at (prev + 1, 39) to (start + 0, 41) -- Code(Expression(2, Sub)) at (prev + 1, 14) to (start + 0, 52) +- Code(Expression(2, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c2 - c4) - Code(Counter(4)) at (prev + 2, 11) to (start + 0, 46) - Code(Expression(4, Sub)) at (prev + 1, 39) to (start + 0, 41) = (c4 - c5) -- Code(Counter(5)) at (prev + 1, 14) to (start + 0, 52) +- Code(Counter(5)) at (prev + 1, 14) to (start + 0, 20) - Code(Expression(4, Sub)) at (prev + 2, 1) to (start + 0, 2) = (c4 - c5) Highest counter ID seen: c5 From 59307fd9fd17b46d0fa65c7e542d39dedd2dec66 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 20 Mar 2025 15:53:22 +1100 Subject: [PATCH 491/546] Factor out some shared code. `global_allocator_spans` and `alloc_error_handler_span` are identical except for `name`. --- compiler/rustc_metadata/src/creader.rs | 46 ++++++++------------------ 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index b7f13e0afdcd..e1ee562dafeb 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1032,14 +1032,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } fn inject_allocator_crate(&mut self, krate: &ast::Crate) { - self.cstore.has_global_allocator = match &*global_allocator_spans(krate) { - [span1, span2, ..] => { - self.dcx().emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 }); - true - } - spans => !spans.is_empty(), - }; - self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) { + self.cstore.has_global_allocator = + match &*fn_spans(krate, Symbol::intern(&global_fn_name(sym::alloc))) { + [span1, span2, ..] => { + self.dcx() + .emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 }); + true + } + spans => !spans.is_empty(), + }; + self.cstore.has_alloc_error_handler = match &*fn_spans( + krate, + Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)), + ) { [span1, span2, ..] => { self.dcx() .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); @@ -1368,7 +1373,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } -fn global_allocator_spans(krate: &ast::Crate) -> Vec { +fn fn_spans(krate: &ast::Crate, name: Symbol) -> Vec { struct Finder { name: Symbol, spans: Vec, @@ -1384,29 +1389,6 @@ fn global_allocator_spans(krate: &ast::Crate) -> Vec { } } - let name = Symbol::intern(&global_fn_name(sym::alloc)); - let mut f = Finder { name, spans: Vec::new() }; - visit::walk_crate(&mut f, krate); - f.spans -} - -fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec { - struct Finder { - name: Symbol, - spans: Vec, - } - impl<'ast> visit::Visitor<'ast> for Finder { - fn visit_item(&mut self, item: &'ast ast::Item) { - if item.ident.name == self.name - && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) - { - self.spans.push(item.span); - } - visit::walk_item(self, item) - } - } - - let name = Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)); let mut f = Finder { name, spans: Vec::new() }; visit::walk_crate(&mut f, krate); f.spans From 4c551bcacd4b6d5652a6e9bc6fd5b7afbac435ae Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 21 Mar 2025 09:47:32 +1100 Subject: [PATCH 492/546] Simplify `ItemVisitorKind`. Instead of putting the item inside it, just pass the ident and visibility (the only things needed) alongside it where necessary. This helps with the next commit, which will move the ident's location. Specifically, it gets rid of the `match visitor_kind` in `rewrite_type_alias`. --- src/tools/rustfmt/src/items.rs | 42 ++++++++++++++++++-------------- src/tools/rustfmt/src/visitor.rs | 29 +++++++++++++--------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 3fb3284e3d7f..415b83060b85 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -6,7 +6,7 @@ use std::cmp::{Ordering, max, min}; use regex::Regex; use rustc_ast::visit; use rustc_ast::{ast, ptr}; -use rustc_span::{BytePos, DUMMY_SP, Span, symbol}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, symbol}; use tracing::debug; use crate::attr::filter_inline_attrs; @@ -1679,11 +1679,12 @@ fn format_tuple_struct( Some(result) } -pub(crate) enum ItemVisitorKind<'a> { - Item(&'a ast::Item), - AssocTraitItem(&'a ast::AssocItem), - AssocImplItem(&'a ast::AssocItem), - ForeignItem(&'a ast::ForeignItem), +#[derive(Clone, Copy)] +pub(crate) enum ItemVisitorKind { + Item, + AssocTraitItem, + AssocImplItem, + ForeignItem, } struct TyAliasRewriteInfo<'c, 'g>( @@ -1695,11 +1696,13 @@ struct TyAliasRewriteInfo<'c, 'g>( Span, ); -pub(crate) fn rewrite_type_alias<'a, 'b>( +pub(crate) fn rewrite_type_alias<'a>( ty_alias_kind: &ast::TyAlias, + vis: &ast::Visibility, + ident: Ident, context: &RewriteContext<'a>, indent: Indent, - visitor_kind: &ItemVisitorKind<'b>, + visitor_kind: ItemVisitorKind, span: Span, ) -> RewriteResult { use ItemVisitorKind::*; @@ -1715,11 +1718,6 @@ pub(crate) fn rewrite_type_alias<'a, 'b>( let rhs_hi = ty .as_ref() .map_or(where_clauses.before.span.hi(), |ty| ty.span.hi()); - let (ident, vis) = match visitor_kind { - Item(i) => (i.ident, &i.vis), - AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis), - ForeignItem(i) => (i.ident, &i.vis), - }; let rw_info = &TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span); let op_ty = opaque_ty(ty); // Type Aliases are formatted slightly differently depending on the context @@ -1727,14 +1725,14 @@ pub(crate) fn rewrite_type_alias<'a, 'b>( // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases match (visitor_kind, &op_ty) { - (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(op_bounds)) => { + (Item | AssocTraitItem | ForeignItem, Some(op_bounds)) => { let op = OpaqueType { bounds: op_bounds }; rewrite_ty(rw_info, Some(bounds), Some(&op), rhs_hi, vis) } - (Item(_) | AssocTraitItem(_) | ForeignItem(_), None) => { + (Item | AssocTraitItem | ForeignItem, None) => { rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis) } - (AssocImplItem(_), _) => { + (AssocImplItem, _) => { let result = if let Some(op_bounds) = op_ty { let op = OpaqueType { bounds: op_bounds }; rewrite_ty( @@ -3498,8 +3496,16 @@ impl Rewrite for ast::ForeignItem { .map(|s| s + ";") } ast::ForeignItemKind::TyAlias(ref ty_alias) => { - let (kind, span) = (&ItemVisitorKind::ForeignItem(self), self.span); - rewrite_type_alias(ty_alias, context, shape.indent, kind, span) + let kind = ItemVisitorKind::ForeignItem; + rewrite_type_alias( + ty_alias, + &self.vis, + self.ident, + context, + shape.indent, + kind, + self.span, + ) } ast::ForeignItemKind::MacCall(ref mac) => { rewrite_macro(mac, None, context, shape, MacroPosition::Item) diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 5749d8c63faf..c70649cc8125 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use std::sync::Arc; use rustc_ast::{ast, token::Delimiter, visit}; -use rustc_span::{BytePos, Pos, Span, symbol}; +use rustc_span::{BytePos, Ident, Pos, Span, symbol}; use tracing::debug; use crate::attr::*; @@ -573,7 +573,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } ast::ItemKind::TyAlias(ref ty_alias) => { use ItemVisitorKind::Item; - self.visit_ty_alias_kind(ty_alias, &Item(item), item.span); + self.visit_ty_alias_kind(ty_alias, &item.vis, item.ident, Item, item.span); } ast::ItemKind::GlobalAsm(..) => { let snippet = Some(self.snippet(item.span).to_owned()); @@ -605,11 +605,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { fn visit_ty_alias_kind( &mut self, ty_kind: &ast::TyAlias, - visitor_kind: &ItemVisitorKind<'_>, + vis: &ast::Visibility, + ident: Ident, + visitor_kind: ItemVisitorKind, span: Span, ) { let rewrite = rewrite_type_alias( ty_kind, + vis, + ident, &self.get_context(), self.block_indent, visitor_kind, @@ -619,15 +623,16 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.push_rewrite(span, rewrite); } - fn visit_assoc_item(&mut self, visitor_kind: &ItemVisitorKind<'_>) { + fn visit_assoc_item(&mut self, ai: &ast::AssocItem, visitor_kind: ItemVisitorKind) { use ItemVisitorKind::*; // TODO(calebcartwright): Not sure the skip spans are correct - let (ai, skip_span, assoc_ctxt) = match visitor_kind { - AssocTraitItem(ai) => (*ai, ai.span(), visit::AssocCtxt::Trait), + let assoc_ctxt = match visitor_kind { + AssocTraitItem => visit::AssocCtxt::Trait, // There is no difference between trait and inherent assoc item formatting - AssocImplItem(ai) => (*ai, ai.span, visit::AssocCtxt::Impl { of_trait: false }), + AssocImplItem => visit::AssocCtxt::Impl { of_trait: false }, _ => unreachable!(), }; + let skip_span = ai.span; skip_out_of_file_lines_range_visitor!(self, ai.span); if self.visit_attrs(&ai.attrs, ast::AttrStyle::Outer) { @@ -637,10 +642,10 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { // TODO(calebcartwright): consider enabling box_patterns feature gate match (&ai.kind, visitor_kind) { - (ast::AssocItemKind::Const(..), AssocTraitItem(_)) => { + (ast::AssocItemKind::Const(..), AssocTraitItem) => { self.visit_static(&StaticParts::from_trait_item(ai)) } - (ast::AssocItemKind::Const(..), AssocImplItem(_)) => { + (ast::AssocItemKind::Const(..), AssocImplItem) => { self.visit_static(&StaticParts::from_impl_item(ai)) } (ast::AssocItemKind::Fn(ref fn_kind), _) => { @@ -670,7 +675,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } } (ast::AssocItemKind::Type(ref ty_alias), _) => { - self.visit_ty_alias_kind(ty_alias, visitor_kind, ai.span); + self.visit_ty_alias_kind(ty_alias, &ai.vis, ai.ident, visitor_kind, ai.span); } (ast::AssocItemKind::MacCall(ref mac), _) => { self.visit_mac(mac, Some(ai.ident), MacroPosition::Item); @@ -680,11 +685,11 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) { - self.visit_assoc_item(&ItemVisitorKind::AssocTraitItem(ti)); + self.visit_assoc_item(ti, ItemVisitorKind::AssocTraitItem); } pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) { - self.visit_assoc_item(&ItemVisitorKind::AssocImplItem(ii)); + self.visit_assoc_item(ii, ItemVisitorKind::AssocImplItem); } fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option, pos: MacroPosition) { From deed0f2480c507f7a3979ea814ade54685c5c45a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 20 Mar 2025 17:28:45 +1100 Subject: [PATCH 493/546] Remove useless `Option` arg. `FmtVisitor::visit_mac` has an `Option` arg which is always either `None` or `Some(kw::Empty)`, because `ItemKind::MacCall` always has an empty ident. This value is passed through various functions until it reaches `rewrite_macro_name`, which treats `None` and `Some(kw::Empty)` the same. In other words, the argument is useless. This commit removes it. There is no change in behaviour. The commit also changes a few `symbol::Ident` occurrences to `Ident` in `macros.rs`; `Symbol` is imported in that file so `Ident` might as well be, too. (This is a good example of why it's a bad idea for `Itemt` to have an `ident` field when various item kinds don't have an identifier. It's easy to get confused when "empty identifier" is used to mean "no identifier". This will be fixed in a subsequent commit.) --- src/tools/rustfmt/src/expr.rs | 2 +- src/tools/rustfmt/src/items.rs | 2 +- src/tools/rustfmt/src/macros.rs | 34 +++++++------------------------ src/tools/rustfmt/src/patterns.rs | 4 +--- src/tools/rustfmt/src/types.rs | 2 +- src/tools/rustfmt/src/visitor.rs | 10 ++++----- 6 files changed, 16 insertions(+), 38 deletions(-) diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index e866f13efc73..65120770edd6 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -246,7 +246,7 @@ pub(crate) fn format_expr( | ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(ast::YieldKind::Postfix(_)) => rewrite_chain(expr, context, shape), ast::ExprKind::MacCall(ref mac) => { - rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|_| { + rewrite_macro(mac, context, shape, MacroPosition::Expression).or_else(|_| { wrap_str( context.snippet(expr.span).to_owned(), context.config.max_width(), diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 415b83060b85..fdda885b7298 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -3508,7 +3508,7 @@ impl Rewrite for ast::ForeignItem { ) } ast::ForeignItemKind::MacCall(ref mac) => { - rewrite_macro(mac, None, context, shape, MacroPosition::Item) + rewrite_macro(mac, context, shape, MacroPosition::Item) } }?; diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index e239ff47c043..ddf3d2ce96af 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -16,10 +16,7 @@ use rustc_ast::token::{Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenStreamIter, TokenTree}; use rustc_ast::{ast, ptr}; use rustc_ast_pretty::pprust; -use rustc_span::{ - BytePos, DUMMY_SP, Span, Symbol, - symbol::{self, kw}, -}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol}; use tracing::debug; use crate::comment::{ @@ -60,7 +57,7 @@ pub(crate) enum MacroArg { Ty(ptr::P), Pat(ptr::P), Item(ptr::P), - Keyword(symbol::Ident, Span), + Keyword(Ident, Span), } impl MacroArg { @@ -103,20 +100,12 @@ impl Rewrite for MacroArg { } /// Rewrite macro name without using pretty-printer if possible. -fn rewrite_macro_name( - context: &RewriteContext<'_>, - path: &ast::Path, - extra_ident: Option, -) -> String { - let name = if path.segments.len() == 1 { +fn rewrite_macro_name(context: &RewriteContext<'_>, path: &ast::Path) -> String { + if path.segments.len() == 1 { // Avoid using pretty-printer in the common case. format!("{}!", rewrite_ident(context, path.segments[0].ident)) } else { format!("{}!", pprust::path_to_string(path)) - }; - match extra_ident { - Some(ident) if ident.name != kw::Empty => format!("{name} {ident}"), - _ => name, } } @@ -165,7 +154,6 @@ fn return_macro_parse_failure_fallback( pub(crate) fn rewrite_macro( mac: &ast::MacCall, - extra_ident: Option, context: &RewriteContext<'_>, shape: Shape, position: MacroPosition, @@ -179,14 +167,7 @@ pub(crate) fn rewrite_macro( } else { let guard = context.enter_macro(); let result = catch_unwind(AssertUnwindSafe(|| { - rewrite_macro_inner( - mac, - extra_ident, - context, - shape, - position, - guard.is_nested(), - ) + rewrite_macro_inner(mac, context, shape, position, guard.is_nested()) })); match result { Err(..) => { @@ -207,7 +188,6 @@ pub(crate) fn rewrite_macro( fn rewrite_macro_inner( mac: &ast::MacCall, - extra_ident: Option, context: &RewriteContext<'_>, shape: Shape, position: MacroPosition, @@ -222,7 +202,7 @@ fn rewrite_macro_inner( let original_style = macro_style(mac, context); - let macro_name = rewrite_macro_name(context, &mac.path, extra_ident); + let macro_name = rewrite_macro_name(context, &mac.path); let is_forced_bracket = FORCED_BRACKET_MACROS.contains(&¯o_name[..]); let style = if is_forced_bracket && !is_nested_macro { @@ -432,7 +412,7 @@ pub(crate) fn rewrite_macro_def( shape: Shape, indent: Indent, def: &ast::MacroDef, - ident: symbol::Ident, + ident: Ident, vis: &ast::Visibility, span: Span, ) -> RewriteResult { diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index bafed41e39f4..8dc945745032 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -307,9 +307,7 @@ impl Rewrite for Pat { context, shape, ), - PatKind::MacCall(ref mac) => { - rewrite_macro(mac, None, context, shape, MacroPosition::Pat) - } + PatKind::MacCall(ref mac) => rewrite_macro(mac, context, shape, MacroPosition::Pat), PatKind::Paren(ref pat) => pat .rewrite_result( context, diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 06a67334086c..75a5a8532b84 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1018,7 +1018,7 @@ impl Rewrite for ast::Ty { ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape), ast::TyKind::Never => Ok(String::from("!")), ast::TyKind::MacCall(ref mac) => { - rewrite_macro(mac, None, context, shape, MacroPosition::Expression) + rewrite_macro(mac, context, shape, MacroPosition::Expression) } ast::TyKind::ImplicitSelf => Ok(String::from("")), ast::TyKind::ImplTrait(_, ref it) => { diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index c70649cc8125..c73976d90b1e 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -172,7 +172,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { get_span_without_attrs(stmt.as_ast_node()), ); } else { - self.visit_mac(&mac_stmt.mac, None, MacroPosition::Statement); + self.visit_mac(&mac_stmt.mac, MacroPosition::Statement); } self.format_missing(stmt.span().hi()); } @@ -531,7 +531,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.format_mod(mod_kind, safety, &item.vis, item.span, item.ident, attrs); } ast::ItemKind::MacCall(ref mac) => { - self.visit_mac(mac, Some(item.ident), MacroPosition::Item); + self.visit_mac(mac, MacroPosition::Item); } ast::ItemKind::ForeignMod(ref foreign_mod) => { self.format_missing_with_indent(source!(self, item.span).lo()); @@ -678,7 +678,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.visit_ty_alias_kind(ty_alias, &ai.vis, ai.ident, visitor_kind, ai.span); } (ast::AssocItemKind::MacCall(ref mac), _) => { - self.visit_mac(mac, Some(ai.ident), MacroPosition::Item); + self.visit_mac(mac, MacroPosition::Item); } _ => unreachable!(), } @@ -692,12 +692,12 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.visit_assoc_item(ii, ItemVisitorKind::AssocImplItem); } - fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option, pos: MacroPosition) { + fn visit_mac(&mut self, mac: &ast::MacCall, pos: MacroPosition) { skip_out_of_file_lines_range_visitor!(self, mac.span()); // 1 = ; let shape = self.shape().saturating_sub_width(1); - let rewrite = self.with_context(|ctx| rewrite_macro(mac, ident, ctx, shape, pos).ok()); + let rewrite = self.with_context(|ctx| rewrite_macro(mac, ctx, shape, pos).ok()); // As of v638 of the rustc-ap-* crates, the associated span no longer includes // the trailing semicolon. This determines the correct span to ensure scenarios // with whitespace between the delimiters and trailing semi (i.e. `foo!(abc) ;`) From 43018eacb61da96b718f70b7719bf5e51207df61 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 21 Mar 2025 15:25:30 +1100 Subject: [PATCH 494/546] Ignore `#[test_case]` on anything other than `fn`/`const`/`static`. `expand_test_case` looks for any item with a `#[test_case]` attribute and adds a `test_path_symbol` attribute to it while also fiddling with the item's ident's span. This is pretty weird, because `#[test_case]` is only valid on `fn`/`const`/`static` items, as far as I can tell. But you don't currently get an error or warning if you use it on other kinds of items. This commit changes things so that a `#[test_case]` item is modified only if it is `fn`/`const`/`static`. This is relevant for moving idents from `Item` to `ItemKind`, because some item kinds don't have an ident, e.g. `impl` blocks. The commit also does the following. - Renames a local variable `test_id` as `test_ident`. - Changes a `const` to `static` in `tests/ui/custom_test_frameworks/full.rs` to give the `static` case some test coverage. - Adds a `struct` and `impl` to the same test to give some test coverage to the non-affected item kinds. These have a `FIXME` comment identifying the weirdness here. Hopefully this will be useful breadcrumbs for somebody else in the future. --- compiler/rustc_builtin_macros/src/test.rs | 46 +++++++++++++---------- tests/ui/custom_test_frameworks/full.rs | 14 ++++++- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 239f8657284d..db3e431495bf 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -51,21 +51,26 @@ pub(crate) fn expand_test_case( return vec![]; } }; - item = item.map(|mut item| { - let test_path_symbol = Symbol::intern(&item_path( - // skip the name of the root module - &ecx.current_expansion.module.mod_path[1..], - &item.ident, - )); - item.vis = ast::Visibility { - span: item.vis.span, - kind: ast::VisibilityKind::Public, - tokens: None, - }; - item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); - item.attrs.push(ecx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, sp)); - item - }); + + // `#[test_case]` is valid on functions, consts, and statics. Only modify + // the item in those cases. + match &mut item.kind { + ast::ItemKind::Fn(_) | ast::ItemKind::Const(_) | ast::ItemKind::Static(_) => { + item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); + let test_path_symbol = Symbol::intern(&item_path( + // skip the name of the root module + &ecx.current_expansion.module.mod_path[1..], + &item.ident, + )); + item.vis = ast::Visibility { + span: item.vis.span, + kind: ast::VisibilityKind::Public, + tokens: None, + }; + item.attrs.push(ecx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, sp)); + } + _ => {} + } let ret = if is_stmt { Annotatable::Stmt(P(ecx.stmt_item(item.span, item))) @@ -162,17 +167,17 @@ pub(crate) fn expand_test_or_bench( let ret_ty_sp = cx.with_def_site_ctxt(fn_.sig.decl.output.span()); let attr_sp = cx.with_def_site_ctxt(attr_sp); - let test_id = Ident::new(sym::test, attr_sp); + let test_ident = Ident::new(sym::test, attr_sp); // creates test::$name - let test_path = |name| cx.path(ret_ty_sp, vec![test_id, Ident::from_str_and_span(name, sp)]); + let test_path = |name| cx.path(ret_ty_sp, vec![test_ident, Ident::from_str_and_span(name, sp)]); // creates test::ShouldPanic::$name let should_panic_path = |name| { cx.path( sp, vec![ - test_id, + test_ident, Ident::from_str_and_span("ShouldPanic", sp), Ident::from_str_and_span(name, sp), ], @@ -184,7 +189,7 @@ pub(crate) fn expand_test_or_bench( cx.path( sp, vec![ - test_id, + test_ident, Ident::from_str_and_span("TestType", sp), Ident::from_str_and_span(name, sp), ], @@ -380,7 +385,8 @@ pub(crate) fn expand_test_or_bench( }); // extern crate test - let test_extern = cx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)); + let test_extern = + cx.item(sp, test_ident, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)); debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); diff --git a/tests/ui/custom_test_frameworks/full.rs b/tests/ui/custom_test_frameworks/full.rs index 289767b1f698..6be29f0418d6 100644 --- a/tests/ui/custom_test_frameworks/full.rs +++ b/tests/ui/custom_test_frameworks/full.rs @@ -25,4 +25,16 @@ impl example_runner::Testable for IsFoo { const TEST_1: IsFoo = IsFoo("hello"); #[test_case] -const TEST_2: IsFoo = IsFoo("foo"); +static TEST_2: IsFoo = IsFoo("foo"); + +// FIXME: `test_case` is currently ignored on anything other than +// fn/const/static. Should this be a warning/error? +#[test_case] +struct _S; + +// FIXME: `test_case` is currently ignored on anything other than +// fn/const/static. Should this be a warning/error? +#[test_case] +impl _S { + fn _f() {} +} From df247968f267d30fb8b048c21f595f2293d8ff62 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 21 Mar 2025 09:47:43 +1100 Subject: [PATCH 495/546] Move `ast::Item::ident` into `ast::ItemKind`. `ast::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, `Trait`, `TraitAlias`, `MacroDef`, `Delegation`. - It's always empty for these item kinds: `Use`, `ForeignMod`, `GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`. There is a similar story for `AssocItemKind` and `ForeignItemKind`. Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - `ast::Item` got 8 bytes bigger. This could be avoided by boxing the fields within some of the `ast::ItemKind` variants (specifically: `Struct`, `Union`, `Enum`). I might do that in a follow-up; this commit is big enough already. - For the visitors: `FnKind` no longer needs an `ident` field because the `Fn` within how has one. - In the parser, the `ItemInfo` typedef is no longer needed. It was used in various places to return an `Ident` alongside an `ItemKind`, but now the `Ident` (if present) is within the `ItemKind`. - In a few places I renamed identifier variables called `name` (or `foo_name`) as `ident` (or `foo_ident`), to better match the type, and because `name` is normally used for `Symbol`s. It's confusing to see something like `foo_name.name`. --- compiler/rustc_ast/src/ast.rs | 107 ++++-- compiler/rustc_ast/src/mut_visit.rs | 84 +++-- compiler/rustc_ast/src/visit.rs | 87 +++-- compiler/rustc_ast_lowering/src/delegation.rs | 8 +- compiler/rustc_ast_lowering/src/item.rs | 353 ++++++++++-------- .../rustc_ast_passes/src/ast_validation.rs | 83 ++-- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 83 ++-- .../src/alloc_error_handler.rs | 11 +- compiler/rustc_builtin_macros/src/asm.rs | 3 +- .../src/assert/context.rs | 1 - compiler/rustc_builtin_macros/src/autodiff.rs | 28 +- .../src/deriving/clone.rs | 4 +- .../src/deriving/cmp/partial_ord.rs | 2 +- .../src/deriving/coerce_pointee.rs | 6 +- .../src/deriving/generic/mod.rs | 17 +- .../src/global_allocator.rs | 20 +- .../src/proc_macro_harness.rs | 41 +- .../src/standard_library_imports.rs | 4 +- compiler/rustc_builtin_macros/src/test.rs | 24 +- .../rustc_builtin_macros/src/test_harness.rs | 46 +-- compiler/rustc_expand/src/base.rs | 7 +- compiler/rustc_expand/src/build.rs | 17 +- compiler/rustc_expand/src/expand.rs | 13 +- compiler/rustc_expand/src/placeholders.rs | 7 +- compiler/rustc_lint/src/builtin.rs | 4 +- compiler/rustc_lint/src/nonstandard_style.rs | 22 +- compiler/rustc_metadata/src/creader.rs | 12 +- compiler/rustc_parse/src/parser/item.rs | 201 +++++----- compiler/rustc_parse/src/parser/tests.rs | 2 +- compiler/rustc_passes/src/lang_items.rs | 14 +- .../rustc_resolve/src/build_reduced_graph.rs | 81 ++-- compiler/rustc_resolve/src/check_unused.rs | 4 +- compiler/rustc_resolve/src/def_collector.rs | 33 +- compiler/rustc_resolve/src/diagnostics.rs | 2 +- .../src/effective_visibilities.rs | 4 +- compiler/rustc_resolve/src/late.rs | 68 ++-- .../rustc_resolve/src/late/diagnostics.rs | 56 +-- src/librustdoc/doctest/make.rs | 8 +- .../clippy_lints/src/crate_in_macro_def.rs | 2 +- .../src/doc/needless_doctest_main.rs | 16 +- .../clippy/clippy_lints/src/duplicate_mod.rs | 2 +- .../clippy_lints/src/empty_line_after.rs | 16 +- .../clippy_lints/src/empty_with_brackets.rs | 5 +- .../src/field_scoped_visibility_modifiers.rs | 2 +- .../src/multiple_bound_locations.rs | 2 +- .../clippy_lints/src/partial_pub_fields.rs | 2 +- .../src/single_component_path_imports.rs | 6 +- .../clippy/clippy_utils/src/ast_utils/mod.rs | 79 +++- src/tools/rustfmt/src/items.rs | 78 ++-- src/tools/rustfmt/src/modules.rs | 10 +- src/tools/rustfmt/src/reorder.rs | 17 +- src/tools/rustfmt/src/visitor.rs | 52 +-- tests/ui/stats/input-stats.stderr | 78 ++-- 54 files changed, 1072 insertions(+), 864 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 064f05ef1f3e..33c20602dfd2 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3303,9 +3303,6 @@ pub struct Item { pub id: NodeId, pub span: Span, pub vis: Visibility, - /// The name of the item. - /// It might be a dummy name in case of anonymous items. - pub ident: Ident, pub kind: K, @@ -3327,23 +3324,23 @@ impl Item { pub fn opt_generics(&self) -> Option<&Generics> { match &self.kind { - ItemKind::ExternCrate(_) + ItemKind::ExternCrate(..) | ItemKind::Use(_) - | ItemKind::Mod(_, _) + | ItemKind::Mod(..) | ItemKind::ForeignMod(_) | ItemKind::GlobalAsm(_) | ItemKind::MacCall(_) | ItemKind::Delegation(_) | ItemKind::DelegationMac(_) - | ItemKind::MacroDef(_) => None, + | ItemKind::MacroDef(..) => None, ItemKind::Static(_) => None, ItemKind::Const(i) => Some(&i.generics), ItemKind::Fn(i) => Some(&i.generics), ItemKind::TyAlias(i) => Some(&i.generics), - ItemKind::TraitAlias(generics, _) - | ItemKind::Enum(_, generics) - | ItemKind::Struct(_, generics) - | ItemKind::Union(_, generics) => Some(&generics), + ItemKind::TraitAlias(_, generics, _) + | ItemKind::Enum(_, _, generics) + | ItemKind::Struct(_, _, generics) + | ItemKind::Union(_, _, generics) => Some(&generics), ItemKind::Trait(i) => Some(&i.generics), ItemKind::Impl(i) => Some(&i.generics), } @@ -3420,6 +3417,7 @@ impl Default for FnHeader { pub struct Trait { pub safety: Safety, pub is_auto: IsAuto, + pub ident: Ident, pub generics: Generics, pub bounds: GenericBounds, pub items: ThinVec>, @@ -3465,6 +3463,7 @@ pub struct TyAliasWhereClauses { #[derive(Clone, Encodable, Decodable, Debug)] pub struct TyAlias { pub defaultness: Defaultness, + pub ident: Ident, pub generics: Generics, pub where_clauses: TyAliasWhereClauses, pub bounds: GenericBounds, @@ -3493,6 +3492,7 @@ pub struct FnContract { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Fn { pub defaultness: Defaultness, + pub ident: Ident, pub generics: Generics, pub sig: FnSig, pub contract: Option>, @@ -3506,6 +3506,7 @@ pub struct Delegation { pub id: NodeId, pub qself: Option>, pub path: Path, + pub ident: Ident, pub rename: Option, pub body: Option>, /// The item was expanded from a glob delegation item. @@ -3523,6 +3524,7 @@ pub struct DelegationMac { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticItem { + pub ident: Ident, pub ty: P, pub safety: Safety, pub mutability: Mutability, @@ -3533,6 +3535,7 @@ pub struct StaticItem { #[derive(Clone, Encodable, Decodable, Debug)] pub struct ConstItem { pub defaultness: Defaultness, + pub ident: Ident, pub generics: Generics, pub ty: P, pub expr: Option>, @@ -3545,7 +3548,7 @@ pub enum ItemKind { /// An `extern crate` item, with the optional *original* crate name if the crate was renamed. /// /// E.g., `extern crate foo` or `extern crate foo_bar as foo`. - ExternCrate(Option), + ExternCrate(Option, Ident), /// A use declaration item (`use`). /// /// E.g., `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`. @@ -3567,7 +3570,7 @@ pub enum ItemKind { /// E.g., `mod foo;` or `mod foo { .. }`. /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not /// semantically by Rust. - Mod(Safety, ModKind), + Mod(Safety, Ident, ModKind), /// An external module (`extern`). /// /// E.g., `extern {}` or `extern "C" {}`. @@ -3581,15 +3584,15 @@ pub enum ItemKind { /// An enum definition (`enum`). /// /// E.g., `enum Foo { C, D }`. - Enum(EnumDef, Generics), + Enum(Ident, EnumDef, Generics), /// A struct definition (`struct`). /// /// E.g., `struct Foo { x: A }`. - Struct(VariantData, Generics), + Struct(Ident, VariantData, Generics), /// A union definition (`union`). /// /// E.g., `union Foo { x: A, y: B }`. - Union(VariantData, Generics), + Union(Ident, VariantData, Generics), /// A trait declaration (`trait`). /// /// E.g., `trait Foo { .. }`, `trait Foo { .. }` or `auto trait Foo {}`. @@ -3597,7 +3600,7 @@ pub enum ItemKind { /// Trait alias. /// /// E.g., `trait Foo = Bar + Quux;`. - TraitAlias(Generics, GenericBounds), + TraitAlias(Ident, Generics, GenericBounds), /// An implementation. /// /// E.g., `impl Foo { .. }` or `impl Trait for Foo { .. }`. @@ -3608,7 +3611,7 @@ pub enum ItemKind { MacCall(P), /// A macro definition. - MacroDef(MacroDef), + MacroDef(Ident, MacroDef), /// A single delegation item (`reuse`). /// @@ -3620,6 +3623,31 @@ pub enum ItemKind { } impl ItemKind { + pub fn ident(&self) -> Option { + match *self { + ItemKind::ExternCrate(_, ident) + | ItemKind::Static(box StaticItem { ident, .. }) + | ItemKind::Const(box ConstItem { ident, .. }) + | ItemKind::Fn(box Fn { ident, .. }) + | ItemKind::Mod(_, ident, _) + | ItemKind::TyAlias(box TyAlias { ident, .. }) + | ItemKind::Enum(ident, ..) + | ItemKind::Struct(ident, ..) + | ItemKind::Union(ident, ..) + | ItemKind::Trait(box Trait { ident, .. }) + | ItemKind::TraitAlias(ident, ..) + | ItemKind::MacroDef(ident, _) + | ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), + + ItemKind::Use(_) + | ItemKind::ForeignMod(_) + | ItemKind::GlobalAsm(_) + | ItemKind::Impl(_) + | ItemKind::MacCall(_) + | ItemKind::DelegationMac(_) => None, + } + } + /// "a" or "an" pub fn article(&self) -> &'static str { use ItemKind::*; @@ -3660,11 +3688,11 @@ impl ItemKind { Self::Fn(box Fn { generics, .. }) | Self::TyAlias(box TyAlias { generics, .. }) | Self::Const(box ConstItem { generics, .. }) - | Self::Enum(_, generics) - | Self::Struct(_, generics) - | Self::Union(_, generics) + | Self::Enum(_, _, generics) + | Self::Struct(_, _, generics) + | Self::Union(_, _, generics) | Self::Trait(box Trait { generics, .. }) - | Self::TraitAlias(generics, _) + | Self::TraitAlias(_, generics, _) | Self::Impl(box Impl { generics, .. }) => Some(generics), _ => None, } @@ -3700,6 +3728,17 @@ pub enum AssocItemKind { } impl AssocItemKind { + pub fn ident(&self) -> Option { + match *self { + AssocItemKind::Const(box ConstItem { ident, .. }) + | AssocItemKind::Fn(box Fn { ident, .. }) + | AssocItemKind::Type(box TyAlias { ident, .. }) + | AssocItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), + + AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(_) => None, + } + } + pub fn defaultness(&self) -> Defaultness { match *self { Self::Const(box ConstItem { defaultness, .. }) @@ -3746,14 +3785,26 @@ impl TryFrom for AssocItemKind { pub enum ForeignItemKind { /// A foreign static item (`static FOO: u8`). Static(Box), - /// An foreign function. + /// A foreign function. Fn(Box), - /// An foreign type. + /// A foreign type. TyAlias(Box), /// A macro expanding to foreign items. MacCall(P), } +impl ForeignItemKind { + pub fn ident(&self) -> Option { + match *self { + ForeignItemKind::Static(box StaticItem { ident, .. }) + | ForeignItemKind::Fn(box Fn { ident, .. }) + | ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => Some(ident), + + ForeignItemKind::MacCall(_) => None, + } + } +} + impl From for ItemKind { fn from(foreign_item_kind: ForeignItemKind) -> ItemKind { match foreign_item_kind { @@ -3790,21 +3841,21 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(AssocItem, 88); + static_assert_size!(AssocItem, 80); static_assert_size!(AssocItemKind, 16); static_assert_size!(Attribute, 32); static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 176); - static_assert_size!(ForeignItem, 88); + static_assert_size!(Fn, 184); + static_assert_size!(ForeignItem, 80); static_assert_size!(ForeignItemKind, 16); static_assert_size!(GenericArg, 24); static_assert_size!(GenericBound, 88); static_assert_size!(Generics, 40); static_assert_size!(Impl, 136); - static_assert_size!(Item, 136); - static_assert_size!(ItemKind, 64); + static_assert_size!(Item, 144); + static_assert_size!(ItemKind, 80); static_assert_size!(LitKind, 24); static_assert_size!(Local, 80); static_assert_size!(MetaItemLit, 40); diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 274fe312f7fa..30af6d910bfa 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -41,7 +41,6 @@ pub trait WalkItemKind { &mut self, span: Span, id: NodeId, - ident: &mut Ident, visibility: &mut Visibility, ctxt: Self::Ctxt, visitor: &mut impl MutVisitor, @@ -963,10 +962,10 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { match kind { FnKind::Fn( _ctxt, - _ident, _vis, Fn { defaultness, + ident, generics, contract, body, @@ -974,8 +973,9 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { define_opaque, }, ) => { - // Identifier and visibility are visited as a part of the item. + // Visibility is visited as a part of the item. visit_defaultness(vis, defaultness); + vis.visit_ident(ident); vis.visit_fn_header(header); vis.visit_generics(generics); vis.visit_fn_decl(decl); @@ -1233,12 +1233,11 @@ pub fn walk_item_kind( kind: &mut K, span: Span, id: NodeId, - ident: &mut Ident, visibility: &mut Visibility, ctxt: K::Ctxt, vis: &mut impl MutVisitor, ) { - kind.walk(span, id, ident, visibility, ctxt, vis) + kind.walk(span, id, visibility, ctxt, vis) } impl WalkItemKind for ItemKind { @@ -1247,21 +1246,22 @@ impl WalkItemKind for ItemKind { &mut self, span: Span, id: NodeId, - ident: &mut Ident, visibility: &mut Visibility, _ctxt: Self::Ctxt, vis: &mut impl MutVisitor, ) { match self { - ItemKind::ExternCrate(_orig_name) => {} + ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident), ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), ItemKind::Static(box StaticItem { + ident, ty, safety: _, mutability: _, expr, define_opaque, }) => { + vis.visit_ident(ident); vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); walk_define_opaques(vis, define_opaque); @@ -1270,10 +1270,11 @@ impl WalkItemKind for ItemKind { walk_const_item(vis, item); } ItemKind::Fn(func) => { - vis.visit_fn(FnKind::Fn(FnCtxt::Free, ident, visibility, &mut *func), span, id); + vis.visit_fn(FnKind::Fn(FnCtxt::Free, visibility, &mut *func), span, id); } - ItemKind::Mod(safety, mod_kind) => { + ItemKind::Mod(safety, ident, mod_kind) => { visit_safety(vis, safety); + vis.visit_ident(ident); match mod_kind { ModKind::Loaded( items, @@ -1290,18 +1291,29 @@ impl WalkItemKind for ItemKind { } ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), - ItemKind::TyAlias(box TyAlias { defaultness, generics, where_clauses, bounds, ty }) => { + ItemKind::TyAlias(box TyAlias { + defaultness, + ident, + generics, + where_clauses, + bounds, + ty, + }) => { visit_defaultness(vis, defaultness); + vis.visit_ident(ident); vis.visit_generics(generics); visit_bounds(vis, bounds, BoundKind::Bound); visit_opt(ty, |ty| vis.visit_ty(ty)); walk_ty_alias_where_clauses(vis, where_clauses); } - ItemKind::Enum(EnumDef { variants }, generics) => { + ItemKind::Enum(ident, EnumDef { variants }, generics) => { + vis.visit_ident(ident); vis.visit_generics(generics); variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); } - ItemKind::Struct(variant_data, generics) | ItemKind::Union(variant_data, generics) => { + ItemKind::Struct(ident, variant_data, generics) + | ItemKind::Union(ident, variant_data, generics) => { + vis.visit_ident(ident); vis.visit_generics(generics); vis.visit_variant_data(variant_data); } @@ -1326,22 +1338,28 @@ impl WalkItemKind for ItemKind { vis.flat_map_assoc_item(item, AssocCtxt::Impl { of_trait: of_trait.is_some() }) }); } - ItemKind::Trait(box Trait { safety, is_auto: _, generics, bounds, items }) => { + ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { visit_safety(vis, safety); + vis.visit_ident(ident); vis.visit_generics(generics); visit_bounds(vis, bounds, BoundKind::Bound); items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Trait)); } - ItemKind::TraitAlias(generics, bounds) => { + ItemKind::TraitAlias(ident, generics, bounds) => { + vis.visit_ident(ident); vis.visit_generics(generics); visit_bounds(vis, bounds, BoundKind::Bound); } ItemKind::MacCall(m) => vis.visit_mac_call(m), - ItemKind::MacroDef(def) => vis.visit_macro_def(def), + ItemKind::MacroDef(ident, def) => { + vis.visit_ident(ident); + vis.visit_macro_def(def) + } ItemKind::Delegation(box Delegation { id, qself, path, + ident, rename, body, from_glob: _, @@ -1349,6 +1367,7 @@ impl WalkItemKind for ItemKind { vis.visit_id(id); vis.visit_qself(qself); vis.visit_path(path); + vis.visit_ident(ident); if let Some(rename) = rename { vis.visit_ident(rename); } @@ -1381,7 +1400,6 @@ impl WalkItemKind for AssocItemKind { &mut self, span: Span, id: NodeId, - ident: &mut Ident, visibility: &mut Visibility, ctxt: Self::Ctxt, visitor: &mut impl MutVisitor, @@ -1391,20 +1409,18 @@ impl WalkItemKind for AssocItemKind { walk_const_item(visitor, item); } AssocItemKind::Fn(func) => { - visitor.visit_fn( - FnKind::Fn(FnCtxt::Assoc(ctxt), ident, visibility, &mut *func), - span, - id, - ); + visitor.visit_fn(FnKind::Fn(FnCtxt::Assoc(ctxt), visibility, &mut *func), span, id); } AssocItemKind::Type(box TyAlias { defaultness, + ident, generics, where_clauses, bounds, ty, }) => { visit_defaultness(visitor, defaultness); + visitor.visit_ident(ident); visitor.visit_generics(generics); visit_bounds(visitor, bounds, BoundKind::Bound); visit_opt(ty, |ty| visitor.visit_ty(ty)); @@ -1415,6 +1431,7 @@ impl WalkItemKind for AssocItemKind { id, qself, path, + ident, rename, body, from_glob: _, @@ -1422,6 +1439,7 @@ impl WalkItemKind for AssocItemKind { visitor.visit_id(id); visitor.visit_qself(qself); visitor.visit_path(path); + visitor.visit_ident(ident); if let Some(rename) = rename { visitor.visit_ident(rename); } @@ -1449,8 +1467,9 @@ impl WalkItemKind for AssocItemKind { } fn walk_const_item(vis: &mut T, item: &mut ConstItem) { - let ConstItem { defaultness, generics, ty, expr, define_opaque } = item; + let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; visit_defaultness(vis, defaultness); + vis.visit_ident(ident); vis.visit_generics(generics); vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); @@ -1487,12 +1506,11 @@ fn walk_item_ctxt( item: &mut P>, ctxt: K::Ctxt, ) { - let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut(); + let Item { attrs, id, kind, vis, span, tokens } = item.deref_mut(); visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); - visitor.visit_ident(ident); - kind.walk(*span, *id, ident, vis, ctxt, visitor); + kind.walk(*span, *id, vis, ctxt, visitor); visit_lazy_tts(visitor, tokens); visitor.visit_span(span); } @@ -1525,38 +1543,37 @@ impl WalkItemKind for ForeignItemKind { &mut self, span: Span, id: NodeId, - ident: &mut Ident, visibility: &mut Visibility, _ctxt: Self::Ctxt, visitor: &mut impl MutVisitor, ) { match self { ForeignItemKind::Static(box StaticItem { + ident, ty, mutability: _, expr, safety: _, define_opaque, }) => { + visitor.visit_ident(ident); visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); walk_define_opaques(visitor, define_opaque); } ForeignItemKind::Fn(func) => { - visitor.visit_fn( - FnKind::Fn(FnCtxt::Foreign, ident, visibility, &mut *func), - span, - id, - ); + visitor.visit_fn(FnKind::Fn(FnCtxt::Foreign, visibility, &mut *func), span, id); } ForeignItemKind::TyAlias(box TyAlias { defaultness, + ident, generics, where_clauses, bounds, ty, }) => { visit_defaultness(visitor, defaultness); + visitor.visit_ident(ident); visitor.visit_generics(generics); visit_bounds(visitor, bounds, BoundKind::Bound); visit_opt(ty, |ty| visitor.visit_ty(ty)); @@ -1984,8 +2001,7 @@ impl DummyAstNode for Item { span: Default::default(), tokens: Default::default(), }, - ident: Ident::dummy(), - kind: ItemKind::ExternCrate(None), + kind: ItemKind::ExternCrate(None, Ident::dummy()), tokens: Default::default(), } } @@ -2052,7 +2068,7 @@ impl DummyAstNode for crate::ast_traits::AstNo #[derive(Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, &'a mut Ident, &'a mut Visibility, &'a mut Fn), + Fn(FnCtxt, &'a mut Visibility, &'a mut Fn), /// E.g., `|x, y| body`. Closure( diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 2716601ca4f9..1ef92ff8898e 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -66,7 +66,7 @@ impl BoundKind { #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, &'a Ident, &'a Visibility, &'a Fn), + Fn(FnCtxt, &'a Visibility, &'a Fn), /// E.g., `|x, y| body`. Closure(&'a ClosureBinder, &'a Option, &'a FnDecl, &'a Expr), @@ -75,21 +75,21 @@ pub enum FnKind<'a> { impl<'a> FnKind<'a> { pub fn header(&self) -> Option<&'a FnHeader> { match *self { - FnKind::Fn(_, _, _, Fn { sig, .. }) => Some(&sig.header), + FnKind::Fn(_, _, Fn { sig, .. }) => Some(&sig.header), FnKind::Closure(..) => None, } } pub fn ident(&self) -> Option<&Ident> { match self { - FnKind::Fn(_, ident, ..) => Some(ident), + FnKind::Fn(_, _, Fn { ident, .. }) => Some(ident), _ => None, } } pub fn decl(&self) -> &'a FnDecl { match self { - FnKind::Fn(_, _, _, Fn { sig, .. }) => &sig.decl, + FnKind::Fn(_, _, Fn { sig, .. }) => &sig.decl, FnKind::Closure(_, _, decl, _) => decl, } } @@ -118,7 +118,6 @@ pub trait WalkItemKind { &'a self, span: Span, id: NodeId, - ident: &'a Ident, visibility: &'a Visibility, ctxt: Self::Ctxt, visitor: &mut V, @@ -364,63 +363,72 @@ impl WalkItemKind for ItemKind { &'a self, span: Span, id: NodeId, - ident: &'a Ident, vis: &'a Visibility, _ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result { match self { - ItemKind::ExternCrate(_rename) => {} + ItemKind::ExternCrate(_rename, ident) => try_visit!(visitor.visit_ident(ident)), ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)), ItemKind::Static(box StaticItem { + ident, ty, safety: _, mutability: _, expr, define_opaque, }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); try_visit!(walk_define_opaques(visitor, define_opaque)); } ItemKind::Const(box ConstItem { defaultness: _, + ident, generics, ty, expr, define_opaque, }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); try_visit!(walk_define_opaques(visitor, define_opaque)); } ItemKind::Fn(func) => { - let kind = FnKind::Fn(FnCtxt::Free, ident, vis, &*func); + let kind = FnKind::Fn(FnCtxt::Free, vis, &*func); try_visit!(visitor.visit_fn(kind, span, id)); } - ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { - ModKind::Loaded(items, _inline, _inner_span, _) => { - walk_list!(visitor, visit_item, items); + ItemKind::Mod(_unsafety, ident, mod_kind) => { + try_visit!(visitor.visit_ident(ident)); + match mod_kind { + ModKind::Loaded(items, _inline, _inner_span, _) => { + walk_list!(visitor, visit_item, items); + } + ModKind::Unloaded => {} } - ModKind::Unloaded => {} - }, + } ItemKind::ForeignMod(ForeignMod { extern_span: _, safety: _, abi: _, items }) => { walk_list!(visitor, visit_foreign_item, items); } ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), ItemKind::TyAlias(box TyAlias { generics, + ident, bounds, ty, defaultness: _, where_clauses: _, }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); } - ItemKind::Enum(enum_definition, generics) => { + ItemKind::Enum(ident, enum_definition, generics) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_enum_def(enum_definition)); } @@ -444,32 +452,47 @@ impl WalkItemKind for ItemKind { AssocCtxt::Impl { of_trait: of_trait.is_some() } ); } - ItemKind::Struct(struct_definition, generics) - | ItemKind::Union(struct_definition, generics) => { + ItemKind::Struct(ident, struct_definition, generics) + | ItemKind::Union(ident, struct_definition, generics) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_variant_data(struct_definition)); } - ItemKind::Trait(box Trait { safety: _, is_auto: _, generics, bounds, items }) => { + ItemKind::Trait(box Trait { + safety: _, + is_auto: _, + ident, + generics, + bounds, + items, + }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits); walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); } - ItemKind::TraitAlias(generics, bounds) => { + ItemKind::TraitAlias(ident, generics, bounds) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, id)), + ItemKind::MacroDef(ident, ts) => { + try_visit!(visitor.visit_ident(ident)); + try_visit!(visitor.visit_mac_def(ts, id)) + } ItemKind::Delegation(box Delegation { id, qself, path, + ident, rename, body, from_glob: _, }) => { try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } @@ -743,34 +766,37 @@ impl WalkItemKind for ForeignItemKind { &'a self, span: Span, id: NodeId, - ident: &'a Ident, vis: &'a Visibility, _ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result { match self { ForeignItemKind::Static(box StaticItem { + ident, ty, mutability: _, expr, safety: _, define_opaque, }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); try_visit!(walk_define_opaques(visitor, define_opaque)); } ForeignItemKind::Fn(func) => { - let kind = FnKind::Fn(FnCtxt::Foreign, ident, vis, &*func); + let kind = FnKind::Fn(FnCtxt::Foreign, vis, &*func); try_visit!(visitor.visit_fn(kind, span, id)); } ForeignItemKind::TyAlias(box TyAlias { generics, + ident, bounds, ty, defaultness: _, where_clauses: _, }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); @@ -917,10 +943,10 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu match kind { FnKind::Fn( _ctxt, - _ident, _vis, Fn { defaultness: _, + ident, sig: FnSig { header, decl, span: _ }, generics, contract, @@ -928,7 +954,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu define_opaque, }, ) => { - // Identifier and visibility are visited as a part of the item. + // Visibility is visited as a part of the item. + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_fn_header(header)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(decl)); @@ -952,7 +979,6 @@ impl WalkItemKind for AssocItemKind { &'a self, span: Span, id: NodeId, - ident: &'a Ident, vis: &'a Visibility, ctxt: Self::Ctxt, visitor: &mut V, @@ -960,28 +986,32 @@ impl WalkItemKind for AssocItemKind { match self { AssocItemKind::Const(box ConstItem { defaultness: _, + ident, generics, ty, expr, define_opaque, }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); try_visit!(walk_define_opaques(visitor, define_opaque)); } AssocItemKind::Fn(func) => { - let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, vis, &*func); + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), vis, &*func); try_visit!(visitor.visit_fn(kind, span, id)); } AssocItemKind::Type(box TyAlias { generics, + ident, bounds, ty, defaultness: _, where_clauses: _, }) => { try_visit!(visitor.visit_generics(generics)); + try_visit!(visitor.visit_ident(ident)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); } @@ -992,12 +1022,14 @@ impl WalkItemKind for AssocItemKind { id, qself, path, + ident, rename, body, from_glob: _, }) => { try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } @@ -1039,11 +1071,10 @@ fn walk_item_ctxt<'a, V: Visitor<'a>, K: WalkItemKind>( item: &'a Item, ctxt: K::Ctxt, ) -> V::Result { - let Item { id, span, ident, vis, attrs, kind, tokens: _ } = item; + let Item { id, span, vis, attrs, kind, tokens: _ } = item; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(ident)); - try_visit!(kind.walk(*span, *id, ident, vis, ctxt, visitor)); + try_visit!(kind.walk(*span, *id, vis, ctxt, visitor)); V::Result::output() } diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index f7640c602d6f..9899ee03a513 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -56,6 +56,7 @@ use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt}; pub(crate) struct DelegationResults<'hir> { pub body_id: hir::BodyId, pub sig: hir::FnSig<'hir>, + pub ident: Ident, pub generics: &'hir hir::Generics<'hir>, } @@ -104,9 +105,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span); let sig = self.lower_delegation_sig(sig_id, decl, span); let body_id = self.lower_delegation_body(delegation, param_count, span); - + let ident = self.lower_ident(delegation.ident); let generics = self.lower_delegation_generics(span); - DelegationResults { body_id, sig, generics } + DelegationResults { body_id, sig, ident, generics } } Err(err) => self.generate_delegation_error(err, span), } @@ -405,8 +406,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let header = self.generate_header_error(); let sig = hir::FnSig { decl, header, span }; + let ident = Ident::dummy(); let body_id = self.lower_body(|this| (&[], this.mk_expr(hir::ExprKind::Err(err), span))); - DelegationResults { generics, body_id, sig } + DelegationResults { ident, generics, body_id, sig } } fn generate_header_error(&self) -> hir::FnHeader { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 43bf951eddc6..28f596ac0926 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -107,7 +107,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { } fn lower_foreign_item(&mut self, item: &ForeignItem) { - debug_assert_ne!(item.ident.name, kw::Empty); self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))) } } @@ -151,7 +150,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); - let kind = self.lower_item_kind(i.span, i.id, hir_id, i.ident, attrs, vis_span, &i.kind); + let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), kind, @@ -166,41 +165,44 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, id: NodeId, hir_id: hir::HirId, - ident: Ident, attrs: &'hir [hir::Attribute], vis_span: Span, i: &ItemKind, ) -> hir::ItemKind<'hir> { match i { - ItemKind::ExternCrate(orig_name) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::ExternCrate(orig_name, ident) => { + let ident = self.lower_ident(*ident); hir::ItemKind::ExternCrate(*orig_name, ident) } ItemKind::Use(use_tree) => { - debug_assert_eq!(ident.name, kw::Empty); // Start with an empty prefix. let prefix = Path { segments: ThinVec::new(), span: use_tree.span, tokens: None }; self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs) } ItemKind::Static(box ast::StaticItem { + ident, ty: t, safety: _, mutability: m, expr: e, define_opaque, }) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + let ident = self.lower_ident(*ident); let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(ident, ty, *m, body_id) } - ItemKind::Const(box ast::ConstItem { generics, ty, expr, define_opaque, .. }) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::Const(box ast::ConstItem { + ident, + generics, + ty, + expr, + define_opaque, + .. + }) => { + let ident = self.lower_ident(*ident); let (generics, (ty, body_id)) = self.lower_generics( generics, id, @@ -214,13 +216,13 @@ impl<'hir> LoweringContext<'_, 'hir> { } ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, + ident, generics, body, contract, define_opaque, .. }) => { - debug_assert_ne!(ident.name, kw::Empty); self.with_new_scopes(*fn_sig_span, |this| { // Note: we don't need to change the return type from `T` to // `impl Future` here because lower_body @@ -248,7 +250,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: this.lower_span(*fn_sig_span), }; this.lower_define_opaque(hir_id, define_opaque); - let ident = this.lower_ident(ident); + let ident = this.lower_ident(*ident); hir::ItemKind::Fn { ident, sig, @@ -258,9 +260,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } }) } - ItemKind::Mod(_, mod_kind) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::Mod(_, ident, mod_kind) => { + let ident = self.lower_ident(*ident); match mod_kind { ModKind::Loaded(items, _, spans, _) => { hir::ItemKind::Mod(ident, self.lower_mod(items, spans)) @@ -268,24 +269,19 @@ impl<'hir> LoweringContext<'_, 'hir> { ModKind::Unloaded => panic!("`mod` items should have been loaded by now"), } } - ItemKind::ForeignMod(fm) => { - debug_assert_eq!(ident.name, kw::Empty); - hir::ItemKind::ForeignMod { - abi: fm.abi.map_or(ExternAbi::FALLBACK, |abi| self.lower_abi(abi)), - items: self - .arena - .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), - } - } + ItemKind::ForeignMod(fm) => hir::ItemKind::ForeignMod { + abi: fm.abi.map_or(ExternAbi::FALLBACK, |abi| self.lower_abi(abi)), + items: self + .arena + .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), + }, ItemKind::GlobalAsm(asm) => { - debug_assert_eq!(ident.name, kw::Empty); let asm = self.lower_inline_asm(span, asm); let fake_body = self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm)))); hir::ItemKind::GlobalAsm { asm, fake_body } } - ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => { - debug_assert_ne!(ident.name, kw::Empty); + ItemKind::TyAlias(box TyAlias { ident, generics, where_clauses, ty, .. }) => { // We lower // // type Foo = impl Trait @@ -294,7 +290,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // type Foo = Foo1 // opaque type Foo1: Trait - let ident = self.lower_ident(ident); + let ident = self.lower_ident(*ident); let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, *where_clauses, true); let (generics, ty) = self.lower_generics( @@ -322,9 +318,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::TyAlias(ident, ty, generics) } - ItemKind::Enum(enum_definition, generics) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::Enum(ident, enum_definition, generics) => { + let ident = self.lower_ident(*ident); let (generics, variants) = self.lower_generics( generics, id, @@ -337,9 +332,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Enum(ident, hir::EnumDef { variants }, generics) } - ItemKind::Struct(struct_def, generics) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::Struct(ident, struct_def, generics) => { + let ident = self.lower_ident(*ident); let (generics, struct_def) = self.lower_generics( generics, id, @@ -348,9 +342,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Struct(ident, struct_def, generics) } - ItemKind::Union(vdata, generics) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::Union(ident, vdata, generics) => { + let ident = self.lower_ident(*ident); let (generics, vdata) = self.lower_generics( generics, id, @@ -369,7 +362,6 @@ impl<'hir> LoweringContext<'_, 'hir> { self_ty: ty, items: impl_items, }) => { - debug_assert_eq!(ident.name, kw::Empty); // Lower the "impl header" first. This ordering is important // for in-band lifetimes! Consider `'a` here: // @@ -435,9 +427,8 @@ impl<'hir> LoweringContext<'_, 'hir> { items: new_impl_items, })) } - ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::Trait(box Trait { is_auto, safety, ident, generics, bounds, items }) => { + let ident = self.lower_ident(*ident); let (generics, (safety, items, bounds)) = self.lower_generics( generics, id, @@ -456,9 +447,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items) } - ItemKind::TraitAlias(generics, bounds) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::TraitAlias(ident, generics, bounds) => { + let ident = self.lower_ident(*ident); let (generics, bounds) = self.lower_generics( generics, id, @@ -472,9 +462,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::TraitAlias(ident, generics, bounds) } - ItemKind::MacroDef(MacroDef { body, macro_rules }) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); + ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => { + let ident = self.lower_ident(*ident); let body = P(self.lower_delim_args(body)); let def_id = self.local_def_id(id); let def_kind = self.tcx.def_kind(def_id); @@ -488,11 +477,9 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Macro(ident, macro_def, macro_kind) } ItemKind::Delegation(box delegation) => { - debug_assert_ne!(ident.name, kw::Empty); - let ident = self.lower_ident(ident); let delegation_results = self.lower_delegation(delegation, id, false); hir::ItemKind::Fn { - ident, + ident: delegation_results.ident, sig: delegation_results.sig, generics: delegation_results.generics, body: delegation_results.body_id, @@ -649,61 +636,64 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); - let item = hir::ForeignItem { - owner_id, - ident: self.lower_ident(i.ident), - kind: match &i.kind { - ForeignItemKind::Fn(box Fn { sig, generics, define_opaque, .. }) => { - let fdec = &sig.decl; - let itctx = ImplTraitContext::Universal; - let (generics, (decl, fn_args)) = - self.lower_generics(generics, i.id, itctx, |this| { - ( - // Disallow `impl Trait` in foreign items. - this.lower_fn_decl( - fdec, - i.id, - sig.span, - FnDeclKind::ExternFn, - None, - ), - this.lower_fn_params_to_names(fdec), - ) - }); + let (ident, kind) = match &i.kind { + ForeignItemKind::Fn(box Fn { sig, ident, generics, define_opaque, .. }) => { + let fdec = &sig.decl; + let itctx = ImplTraitContext::Universal; + let (generics, (decl, fn_args)) = + self.lower_generics(generics, i.id, itctx, |this| { + ( + // Disallow `impl Trait` in foreign items. + this.lower_fn_decl(fdec, i.id, sig.span, FnDeclKind::ExternFn, None), + this.lower_fn_params_to_names(fdec), + ) + }); - // Unmarked safety in unsafe block defaults to unsafe. - let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); + // Unmarked safety in unsafe block defaults to unsafe. + let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); - if define_opaque.is_some() { - self.dcx().span_err(i.span, "foreign functions cannot define opaque types"); - } + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign functions cannot define opaque types"); + } + ( + ident, hir::ForeignItemKind::Fn( hir::FnSig { header, decl, span: self.lower_span(sig.span) }, fn_args, generics, - ) - } - ForeignItemKind::Static(box StaticItem { - ty, - mutability, - expr: _, - safety, - define_opaque, - }) => { - let ty = self - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); - let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + ), + ) + } + ForeignItemKind::Static(box StaticItem { + ident, + ty, + mutability, + expr: _, + safety, + define_opaque, + }) => { + let ty = + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let safety = self.lower_safety(*safety, hir::Safety::Unsafe); - if define_opaque.is_some() { - self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); - } - - hir::ForeignItemKind::Static(ty, *mutability, safety) + // njn: where for this? + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); } - ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, - ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), - }, + + (ident, hir::ForeignItemKind::Static(ty, *mutability, safety)) + } + ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => { + (ident, hir::ForeignItemKind::Type) + } + ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), + }; + + let item = hir::ForeignItem { + owner_id, + ident: self.lower_ident(*ident), + kind, vis_span: self.lower_span(i.vis.span), span: self.lower_span(i.span), }; @@ -713,7 +703,9 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef { hir::ForeignItemRef { id: hir::ForeignItemId { owner_id: self.owner_id(i.id) }, - ident: self.lower_ident(i.ident), + // `unwrap` is safe because `ForeignItemKind::MacCall` is the only foreign item kind + // without an identifier and it cannot reach here. + ident: self.lower_ident(i.kind.ident().unwrap()), span: self.lower_span(i.span), } } @@ -800,13 +792,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { - debug_assert_ne!(i.ident.name, kw::Empty); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let trait_item_def_id = hir_id.expect_owner(); - let (generics, kind, has_default) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, define_opaque, .. }) => { + let (ident, generics, kind, has_default) = match &i.kind { + AssocItemKind::Const(box ConstItem { + ident, + generics, + ty, + expr, + define_opaque, + .. + }) => { let (generics, kind) = self.lower_generics( generics, i.id, @@ -831,9 +829,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - (generics, kind, expr.is_some()) + (*ident, generics, kind, expr.is_some()) } - AssocItemKind::Fn(box Fn { sig, generics, body: None, define_opaque, .. }) => { + AssocItemKind::Fn(box Fn { + sig, ident, generics, body: None, define_opaque, .. + }) => { // FIXME(contracts): Deny contract here since it won't apply to // any impl method or callees. let names = self.lower_fn_params_to_names(&sig.decl); @@ -851,10 +851,16 @@ impl<'hir> LoweringContext<'_, 'hir> { "only trait methods with default bodies can define opaque types", ); } - (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) + ( + *ident, + generics, + hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), + false, + ) } AssocItemKind::Fn(box Fn { sig, + ident, generics, body: Some(body), contract, @@ -880,9 +886,16 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs, ); self.lower_define_opaque(hir_id, &define_opaque); - (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) + ( + *ident, + generics, + hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), + true, + ) } - AssocItemKind::Type(box TyAlias { generics, where_clauses, bounds, ty, .. }) => { + AssocItemKind::Type(box TyAlias { + ident, generics, where_clauses, bounds, ty, .. + }) => { let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, *where_clauses, false); let (generics, kind) = self.lower_generics( @@ -905,7 +918,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }, ); - (generics, kind, ty.is_some()) + (*ident, generics, kind, ty.is_some()) } AssocItemKind::Delegation(box delegation) => { let delegation_results = self.lower_delegation(delegation, i.id, false); @@ -913,7 +926,7 @@ impl<'hir> LoweringContext<'_, 'hir> { delegation_results.sig, hir::TraitFn::Provided(delegation_results.body_id), ); - (delegation_results.generics, item_kind, true) + (delegation.ident, delegation_results.generics, item_kind, true) } AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") @@ -922,7 +935,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let item = hir::TraitItem { owner_id: trait_item_def_id, - ident: self.lower_ident(i.ident), + ident: self.lower_ident(ident), generics, kind, span: self.lower_span(i.span), @@ -932,15 +945,20 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef { - let kind = match &i.kind { - AssocItemKind::Const(..) => hir::AssocItemKind::Const, - AssocItemKind::Type(..) => hir::AssocItemKind::Type, - AssocItemKind::Fn(box Fn { sig, .. }) => { - hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } + let (ident, kind) = match &i.kind { + AssocItemKind::Const(box ConstItem { ident, .. }) => { + (*ident, hir::AssocItemKind::Const) } - AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { - has_self: self.delegatee_is_method(i.id, delegation.id, i.span, false), - }, + AssocItemKind::Type(box TyAlias { ident, .. }) => (*ident, hir::AssocItemKind::Type), + AssocItemKind::Fn(box Fn { ident, sig, .. }) => { + (*ident, hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }) + } + AssocItemKind::Delegation(box delegation) => ( + delegation.ident, + hir::AssocItemKind::Fn { + has_self: self.delegatee_is_method(i.id, delegation.id, i.span, false), + }, + ), AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") } @@ -948,7 +966,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let id = hir::TraitItemId { owner_id: self.owner_id(i.id) }; hir::TraitItemRef { id, - ident: self.lower_ident(i.ident), + ident: self.lower_ident(ident), span: self.lower_span(i.span), kind, } @@ -964,16 +982,23 @@ impl<'hir> LoweringContext<'_, 'hir> { i: &AssocItem, is_in_trait_impl: bool, ) -> &'hir hir::ImplItem<'hir> { - debug_assert_ne!(i.ident.name, kw::Empty); // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); - let (generics, kind) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, define_opaque, .. }) => self - .lower_generics( + let (ident, (generics, kind)) = match &i.kind { + AssocItemKind::Const(box ConstItem { + ident, + generics, + ty, + expr, + define_opaque, + .. + }) => ( + *ident, + self.lower_generics( generics, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), @@ -982,11 +1007,19 @@ impl<'hir> LoweringContext<'_, 'hir> { .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); let body = this.lower_const_body(i.span, expr.as_deref()); this.lower_define_opaque(hir_id, &define_opaque); - hir::ImplItemKind::Const(ty, body) }, ), - AssocItemKind::Fn(box Fn { sig, generics, body, contract, define_opaque, .. }) => { + ), + AssocItemKind::Fn(box Fn { + sig, + ident, + generics, + body, + contract, + define_opaque, + .. + }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -1007,44 +1040,50 @@ impl<'hir> LoweringContext<'_, 'hir> { ); self.lower_define_opaque(hir_id, &define_opaque); - (generics, hir::ImplItemKind::Fn(sig, body_id)) + (*ident, (generics, hir::ImplItemKind::Fn(sig, body_id))) } - AssocItemKind::Type(box TyAlias { generics, where_clauses, ty, .. }) => { + AssocItemKind::Type(box TyAlias { ident, generics, where_clauses, ty, .. }) => { let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, *where_clauses, false); - self.lower_generics( - &generics, - i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| match ty { - None => { - let guar = this.dcx().span_delayed_bug( - i.span, - "expected to lower associated type, but it was missing", - ); - let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err(guar))); - hir::ImplItemKind::Type(ty) - } - Some(ty) => { - let ty = this.lower_ty( - ty, - ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(i.id), - in_assoc_ty: true, + ( + *ident, + self.lower_generics( + &generics, + i.id, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| match ty { + None => { + let guar = this.dcx().span_delayed_bug( + i.span, + "expected to lower associated type, but it was missing", + ); + let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err(guar))); + hir::ImplItemKind::Type(ty) + } + Some(ty) => { + let ty = this.lower_ty( + ty, + ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(i.id), + in_assoc_ty: true, + }, }, - }, - ); - hir::ImplItemKind::Type(ty) - } - }, + ); + hir::ImplItemKind::Type(ty) + } + }, + ), ) } AssocItemKind::Delegation(box delegation) => { let delegation_results = self.lower_delegation(delegation, i.id, is_in_trait_impl); ( - delegation_results.generics, - hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id), + delegation.ident, + ( + delegation_results.generics, + hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id), + ), ) } AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { @@ -1054,7 +1093,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let item = hir::ImplItem { owner_id: hir_id.expect_owner(), - ident: self.lower_ident(i.ident), + ident: self.lower_ident(ident), generics, kind, vis_span: self.lower_span(i.vis.span), @@ -1067,7 +1106,9 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_impl_item_ref(&mut self, i: &AssocItem, is_in_trait_impl: bool) -> hir::ImplItemRef { hir::ImplItemRef { id: hir::ImplItemId { owner_id: self.owner_id(i.id) }, - ident: self.lower_ident(i.ident), + // `unwrap` is safe because `AssocItemKind::{MacCall,DelegationMac}` are the only + // assoc item kinds without an identifier and they cannot reach here. + ident: self.lower_ident(i.kind.ident().unwrap()), span: self.lower_span(i.span), kind: match &i.kind { AssocItemKind::Const(..) => hir::AssocItemKind::Const, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index da739b0e4532..86661f3f3590 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -607,7 +607,7 @@ impl<'a> AstValidator<'a> { fn deny_items(&self, trait_items: &[P], ident: Span) { if !trait_items.is_empty() { - let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); + let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect(); let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident }); } @@ -818,7 +818,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } if attr::contains_name(&item.attrs, sym::no_mangle) { - self.check_nomangle_item_asciionly(item.ident, item.span); + if let Some(ident) = item.kind.ident() { + self.check_nomangle_item_asciionly(ident, item.span); + } } match &item.kind { @@ -852,7 +854,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } this.visit_vis(&item.vis); - this.visit_ident(&item.ident); let disallowed = matches!(constness, Const::No) .then(|| TildeConstReason::TraitImpl { span: item.span }); this.with_tilde_const(disallowed, |this| this.visit_generics(generics)); @@ -906,7 +907,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } this.visit_vis(&item.vis); - this.visit_ident(&item.ident); this.with_tilde_const( Some(TildeConstReason::Impl { span: item.span }), |this| this.visit_generics(generics), @@ -918,8 +918,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { return; // Avoid visiting again. } ItemKind::Fn( - func - @ box Fn { defaultness, generics: _, sig, contract: _, body, define_opaque: _ }, + func @ box Fn { + defaultness, + ident, + generics: _, + sig, + contract: _, + body, + define_opaque: _, + }, ) => { self.check_defaultness(item.span, *defaultness); @@ -949,8 +956,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.visit_vis(&item.vis); - self.visit_ident(&item.ident); - let kind = FnKind::Fn(FnCtxt::Free, &item.ident, &item.vis, &*func); + self.visit_ident(ident); + let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func); self.visit_fn(kind, item.span, item.id); walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. @@ -986,7 +993,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); return; // Avoid visiting again. } - ItemKind::Enum(def, _) => { + ItemKind::Enum(_, def, _) => { for variant in &def.variants { self.visibility_not_permitted( &variant.vis, @@ -1000,22 +1007,22 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } } - ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => { + ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => { let is_const_trait = attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); self.with_in_trait(item.span, is_const_trait, |this| { if *is_auto == IsAuto::Yes { // Auto traits cannot have generics, super traits nor contain items. - this.deny_generic_params(generics, item.ident.span); - this.deny_super_traits(bounds, item.ident.span); - this.deny_where_clause(&generics.where_clause, item.ident.span); - this.deny_items(items, item.ident.span); + this.deny_generic_params(generics, ident.span); + this.deny_super_traits(bounds, ident.span); + this.deny_where_clause(&generics.where_clause, ident.span); + this.deny_items(items, ident.span); } // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound // context for the supertraits. this.visit_vis(&item.vis); - this.visit_ident(&item.ident); + this.visit_ident(ident); let disallowed = is_const_trait .is_none() .then(|| TildeConstReason::Trait { span: item.span }); @@ -1028,7 +1035,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again } - ItemKind::Mod(safety, mod_kind) => { + ItemKind::Mod(safety, ident, mod_kind) => { if let &Safety::Unsafe(span) = safety { self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); } @@ -1036,13 +1043,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) && !attr::contains_name(&item.attrs, sym::path) { - self.check_mod_file_item_asciionly(item.ident); + self.check_mod_file_item_asciionly(*ident); } } - ItemKind::Struct(vdata, generics) => match vdata { + ItemKind::Struct(ident, vdata, generics) => match vdata { VariantData::Struct { fields, .. } => { self.visit_vis(&item.vis); - self.visit_ident(&item.ident); + self.visit_ident(ident); self.visit_generics(generics); // Permit `Anon{Struct,Union}` as field type. walk_list!(self, visit_struct_field_def, fields); @@ -1051,14 +1058,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } _ => {} }, - ItemKind::Union(vdata, generics) => { + ItemKind::Union(ident, vdata, generics) => { if vdata.fields().is_empty() { self.dcx().emit_err(errors::FieldlessUnion { span: item.span }); } match vdata { VariantData::Struct { fields, .. } => { self.visit_vis(&item.vis); - self.visit_ident(&item.ident); + self.visit_ident(ident); self.visit_generics(generics); // Permit `Anon{Struct,Union}` as field type. walk_list!(self, visit_struct_field_def, fields); @@ -1121,14 +1128,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match &fi.kind { - ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { + ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => { self.check_defaultness(fi.span, *defaultness); - self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); + self.check_foreign_fn_bodyless(*ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); - self.check_foreign_item_ascii_only(fi.ident); + self.check_foreign_item_ascii_only(*ident); } ForeignItemKind::TyAlias(box TyAlias { defaultness, + ident, generics, where_clauses, bounds, @@ -1136,15 +1144,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .. }) => { self.check_defaultness(fi.span, *defaultness); - self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span)); + self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span)); self.check_type_no_bounds(bounds, "`extern` blocks"); self.check_foreign_ty_genericless(generics, where_clauses); - self.check_foreign_item_ascii_only(fi.ident); + self.check_foreign_item_ascii_only(*ident); } - ForeignItemKind::Static(box StaticItem { expr, safety, .. }) => { + ForeignItemKind::Static(box StaticItem { ident, safety, expr, .. }) => { self.check_item_safety(fi.span, *safety); - self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span)); - self.check_foreign_item_ascii_only(fi.ident); + self.check_foreign_kind_bodyless(*ident, "static", expr.as_ref().map(|b| b.span)); + self.check_foreign_item_ascii_only(*ident); } ForeignItemKind::MacCall(..) => {} } @@ -1351,7 +1359,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } if let FnKind::Fn( - _, _, _, Fn { @@ -1364,7 +1371,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } // Functions without bodies cannot have patterns. - if let FnKind::Fn(ctxt, _, _, Fn { body: None, sig, .. }) = fk { + if let FnKind::Fn(ctxt, _, Fn { body: None, sig, .. }) = fk { Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { if let Some(ident) = ident { @@ -1398,7 +1405,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .is_some(); let disallowed = (!tilde_const_allowed).then(|| match fk { - FnKind::Fn(_, ident, _, _) => TildeConstReason::Function { ident: ident.span }, + FnKind::Fn(_, _, f) => TildeConstReason::Function { ident: f.ident.span }, FnKind::Closure(..) => TildeConstReason::Closure, }); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); @@ -1406,7 +1413,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { if attr::contains_name(&item.attrs, sym::no_mangle) { - self.check_nomangle_item_asciionly(item.ident, item.span); + if let Some(ident) = item.kind.ident() { + self.check_nomangle_item_asciionly(ident, item.span); + } } if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() { @@ -1466,8 +1475,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - if let AssocItemKind::Const(..) = item.kind { - self.check_item_named(item.ident, "const"); + if let AssocItemKind::Const(ci) = &item.kind { + self.check_item_named(ci.ident, "const"); } let parent_is_const = @@ -1480,8 +1489,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { || matches!(func.sig.header.constness, Const::Yes(_)) => { self.visit_vis(&item.vis); - self.visit_ident(&item.ident); - let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, &item.vis, &*func); + self.visit_ident(&func.ident); + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func); walk_list!(self, visit_attribute, &item.attrs); self.visit_fn(kind, item.span, item.id); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index a3fcc110a166..2fac881f4c42 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -236,7 +236,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate!(&self, trait_alias, i.span, "trait aliases are experimental"); } - ast::ItemKind::MacroDef(ast::MacroDef { macro_rules: false, .. }) => { + ast::ItemKind::MacroDef(_, ast::MacroDef { macro_rules: false, .. }) => { let msg = "`macro` is experimental"; gate!(&self, decl_macro, i.span, msg); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index d406a56c05da..653bd77cc4dd 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -28,23 +28,24 @@ impl<'a> State<'a> { } fn print_foreign_item(&mut self, item: &ast::ForeignItem) { - let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; + let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); self.maybe_print_comment(span.lo()); self.print_outer_attributes(attrs); match kind { ast::ForeignItemKind::Fn(func) => { - self.print_fn_full(ident, vis, attrs, &*func); + self.print_fn_full(vis, attrs, &*func); } ast::ForeignItemKind::Static(box ast::StaticItem { + ident, ty, mutability, expr, safety, define_opaque, }) => self.print_item_const( - ident, + *ident, Some(*mutability), &ast::Generics::default(), ty, @@ -56,13 +57,14 @@ impl<'a> State<'a> { ), ast::ForeignItemKind::TyAlias(box ast::TyAlias { defaultness, + ident, generics, where_clauses, bounds, ty, }) => { self.print_associated_type( - ident, + *ident, generics, *where_clauses, bounds, @@ -162,7 +164,7 @@ impl<'a> State<'a> { self.print_outer_attributes(&item.attrs); self.ann.pre(self, AnnNode::Item(item)); match &item.kind { - ast::ItemKind::ExternCrate(orig_name) => { + ast::ItemKind::ExternCrate(orig_name, ident) => { self.head(visibility_qualified(&item.vis, "extern crate")); if let &Some(orig_name) = orig_name { self.print_name(orig_name); @@ -170,7 +172,7 @@ impl<'a> State<'a> { self.word("as"); self.space(); } - self.print_ident(item.ident); + self.print_ident(*ident); self.word(";"); self.end(); // end inner head-block self.end(); // end outer head-block @@ -182,6 +184,7 @@ impl<'a> State<'a> { self.word(";"); } ast::ItemKind::Static(box StaticItem { + ident, ty, safety, mutability: mutbl, @@ -190,7 +193,7 @@ impl<'a> State<'a> { }) => { self.print_safety(*safety); self.print_item_const( - item.ident, + *ident, Some(*mutbl), &ast::Generics::default(), ty, @@ -203,13 +206,14 @@ impl<'a> State<'a> { } ast::ItemKind::Const(box ast::ConstItem { defaultness, + ident, generics, ty, expr, define_opaque, }) => { self.print_item_const( - item.ident, + *ident, None, generics, ty, @@ -221,15 +225,15 @@ impl<'a> State<'a> { ); } ast::ItemKind::Fn(func) => { - self.print_fn_full(item.ident, &item.vis, &item.attrs, &*func); + self.print_fn_full(&item.vis, &item.attrs, &*func); } - ast::ItemKind::Mod(safety, mod_kind) => { + ast::ItemKind::Mod(safety, ident, mod_kind) => { self.head(Self::to_string(|s| { s.print_visibility(&item.vis); s.print_safety(*safety); s.word("mod"); })); - self.print_ident(item.ident); + self.print_ident(*ident); match mod_kind { ModKind::Loaded(items, ..) => { @@ -273,13 +277,14 @@ impl<'a> State<'a> { } ast::ItemKind::TyAlias(box ast::TyAlias { defaultness, + ident, generics, where_clauses, bounds, ty, }) => { self.print_associated_type( - item.ident, + *ident, generics, *where_clauses, bounds, @@ -288,16 +293,16 @@ impl<'a> State<'a> { *defaultness, ); } - ast::ItemKind::Enum(enum_definition, params) => { - self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis); + ast::ItemKind::Enum(ident, enum_definition, params) => { + self.print_enum_def(enum_definition, params, *ident, item.span, &item.vis); } - ast::ItemKind::Struct(struct_def, generics) => { + ast::ItemKind::Struct(ident, struct_def, generics) => { self.head(visibility_qualified(&item.vis, "struct")); - self.print_struct(struct_def, generics, item.ident, item.span, true); + self.print_struct(struct_def, generics, *ident, item.span, true); } - ast::ItemKind::Union(struct_def, generics) => { + ast::ItemKind::Union(ident, struct_def, generics) => { self.head(visibility_qualified(&item.vis, "union")); - self.print_struct(struct_def, generics, item.ident, item.span, true); + self.print_struct(struct_def, generics, *ident, item.span, true); } ast::ItemKind::Impl(box ast::Impl { safety, @@ -347,19 +352,19 @@ impl<'a> State<'a> { self.bclose(item.span, empty); } ast::ItemKind::Trait(box ast::Trait { - is_auto, safety, + is_auto, + ident, generics, bounds, items, - .. }) => { self.head(""); self.print_visibility(&item.vis); self.print_safety(*safety); self.print_is_auto(*is_auto); self.word_nbsp("trait"); - self.print_ident(item.ident); + self.print_ident(*ident); self.print_generic_params(&generics.params); if !bounds.is_empty() { self.word_nbsp(":"); @@ -375,9 +380,9 @@ impl<'a> State<'a> { let empty = item.attrs.is_empty() && items.is_empty(); self.bclose(item.span, empty); } - ast::ItemKind::TraitAlias(generics, bounds) => { + ast::ItemKind::TraitAlias(ident, generics, bounds) => { self.head(visibility_qualified(&item.vis, "trait")); - self.print_ident(item.ident); + self.print_ident(*ident); self.print_generic_params(&generics.params); self.nbsp(); if !bounds.is_empty() { @@ -395,8 +400,8 @@ impl<'a> State<'a> { self.word(";"); } } - ast::ItemKind::MacroDef(macro_def) => { - self.print_mac_def(macro_def, &item.ident, item.span, |state| { + ast::ItemKind::MacroDef(ident, macro_def) => { + self.print_mac_def(macro_def, &ident, item.span, |state| { state.print_visibility(&item.vis) }); } @@ -549,24 +554,25 @@ impl<'a> State<'a> { } fn print_assoc_item(&mut self, item: &ast::AssocItem) { - let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; + let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); self.maybe_print_comment(span.lo()); self.print_outer_attributes(attrs); match kind { ast::AssocItemKind::Fn(func) => { - self.print_fn_full(ident, vis, attrs, &*func); + self.print_fn_full(vis, attrs, &*func); } ast::AssocItemKind::Const(box ast::ConstItem { defaultness, + ident, generics, ty, expr, define_opaque, }) => { self.print_item_const( - ident, + *ident, None, generics, ty, @@ -579,13 +585,14 @@ impl<'a> State<'a> { } ast::AssocItemKind::Type(box ast::TyAlias { defaultness, + ident, generics, where_clauses, bounds, ty, }) => { self.print_associated_type( - ident, + *ident, generics, *where_clauses, bounds, @@ -671,14 +678,8 @@ impl<'a> State<'a> { } } - fn print_fn_full( - &mut self, - name: Ident, - vis: &ast::Visibility, - attrs: &[ast::Attribute], - func: &ast::Fn, - ) { - let ast::Fn { defaultness, generics, sig, contract, body, define_opaque } = func; + fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], func: &ast::Fn) { + let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque } = func; self.print_define_opaques(define_opaque.as_deref()); @@ -687,7 +688,7 @@ impl<'a> State<'a> { } self.print_visibility(vis); self.print_defaultness(*defaultness); - self.print_fn(&sig.decl, sig.header, Some(name), generics); + self.print_fn(&sig.decl, sig.header, Some(*ident), generics); if let Some(contract) = &contract { self.nbsp(); self.print_contract(contract); @@ -734,13 +735,13 @@ impl<'a> State<'a> { &mut self, decl: &ast::FnDecl, header: ast::FnHeader, - name: Option, + ident: Option, generics: &ast::Generics, ) { self.print_fn_header_info(header); - if let Some(name) = name { + if let Some(ident) = ident { self.nbsp(); - self.print_ident(name); + self.print_ident(ident); } self.print_generic_params(&generics.params); self.print_fn_params_and_ret(decl, false); diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 1c1b2c88f76e..ea406e706660 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -21,15 +21,15 @@ pub(crate) fn expand( // Allow using `#[alloc_error_handler]` on an item statement // FIXME - if we get deref patterns, use them to reduce duplication here - let (item, is_stmt, sig_span) = if let Annotatable::Item(item) = &item + let (item, ident, is_stmt, sig_span) = if let Annotatable::Item(item) = &item && let ItemKind::Fn(fn_kind) = &item.kind { - (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)) + (item, fn_kind.ident, false, ecx.with_def_site_ctxt(fn_kind.sig.span)) } else if let Annotatable::Stmt(stmt) = &item && let StmtKind::Item(item) = &stmt.kind && let ItemKind::Fn(fn_kind) = &item.kind { - (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) + (item, fn_kind.ident, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) } else { ecx.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() }); return vec![orig_item]; @@ -39,7 +39,7 @@ pub(crate) fn expand( let span = ecx.with_def_site_ctxt(item.span); // Generate item statements for the allocator methods. - let stmts = thin_vec![generate_handler(ecx, item.ident, span, sig_span)]; + let stmts = thin_vec![generate_handler(ecx, ident, span, sig_span)]; // Generate anonymous constant serving as container for the allocator methods. let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new())); @@ -85,6 +85,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span let kind = ItemKind::Fn(Box::new(Fn { defaultness: ast::Defaultness::Final, sig, + ident: Ident::from_str_and_span("__rg_oom", span), generics: Generics::default(), contract: None, body, @@ -93,6 +94,6 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; - let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind); + let item = cx.item(span, attrs, kind); cx.stmt_item(sig_span, item) } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index eb5b345e49ec..3e8ddb8abd43 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -10,7 +10,7 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_parse::exp; use rustc_parse::parser::{ExpKeywordPair, Parser}; use rustc_session::lint; -use rustc_span::{ErrorGuaranteed, Ident, InnerSpan, Span, Symbol, kw}; +use rustc_span::{ErrorGuaranteed, InnerSpan, Span, Symbol, kw}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; use {rustc_ast as ast, rustc_parse_format as parse}; @@ -888,7 +888,6 @@ pub(super) fn expand_global_asm<'cx>( }; match mac { Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item { - ident: Ident::empty(), attrs: ast::AttrVec::new(), id: ast::DUMMY_NODE_ID, kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index a949ab94f3ad..ea7248ca5393 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -112,7 +112,6 @@ impl<'cx, 'a> Context<'cx, 'a> { self.span, self.cx.item( self.span, - Ident::empty(), thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)], ItemKind::Use(UseTree { prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])), diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index be11711757e4..8937d35d53ae 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -146,26 +146,26 @@ mod llvm_enzyme { } let dcx = ecx.sess.dcx(); // first get the annotable item: - let (sig, is_impl): (FnSig, bool) = match &item { + let (primal, sig, is_impl): (Ident, FnSig, bool) = match &item { Annotatable::Item(iitem) => { - let sig = match &iitem.kind { - ItemKind::Fn(box ast::Fn { sig, .. }) => sig, + let (ident, sig) = match &iitem.kind { + ItemKind::Fn(box ast::Fn { ident, sig, .. }) => (ident, sig), _ => { dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); return vec![item]; } }; - (sig.clone(), false) + (*ident, sig.clone(), false) } Annotatable::AssocItem(assoc_item, Impl { of_trait: false }) => { - let sig = match &assoc_item.kind { - ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) => sig, + let (ident, sig) = match &assoc_item.kind { + ast::AssocItemKind::Fn(box ast::Fn { ident, sig, .. }) => (ident, sig), _ => { dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); return vec![item]; } }; - (sig.clone(), true) + (*ident, sig.clone(), true) } _ => { dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); @@ -184,11 +184,9 @@ mod llvm_enzyme { let has_ret = has_ret(&sig.decl.output); let sig_span = ecx.with_call_site_ctxt(sig.span); - let (vis, primal) = match &item { - Annotatable::Item(iitem) => (iitem.vis.clone(), iitem.ident.clone()), - Annotatable::AssocItem(assoc_item, _) => { - (assoc_item.vis.clone(), assoc_item.ident.clone()) - } + let vis = match &item { + Annotatable::Item(iitem) => iitem.vis.clone(), + Annotatable::AssocItem(assoc_item, _) => assoc_item.vis.clone(), _ => { dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); return vec![item]; @@ -237,12 +235,12 @@ mod llvm_enzyme { let d_body = gen_enzyme_body( ecx, &x, n_active, &sig, &d_sig, primal, &new_args, span, sig_span, idents, errored, ); - let d_ident = first_ident(&meta_item_vec[0]); // The first element of it is the name of the function to be generated let asdf = Box::new(ast::Fn { defaultness: ast::Defaultness::Final, sig: d_sig, + ident: first_ident(&meta_item_vec[0]), generics: Generics::default(), contract: None, body: Some(d_body), @@ -323,14 +321,12 @@ mod llvm_enzyme { id: ast::DUMMY_NODE_ID, span, vis, - ident: d_ident, kind: assoc_item, tokens: None, }); Annotatable::AssocItem(d_fn, Impl { of_trait: false }) } else { - let mut d_fn = - ecx.item(span, d_ident, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); + let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); d_fn.vis = vis; Annotatable::Item(d_fn) }; diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index c3656e8244fe..44cf215c6622 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -34,8 +34,8 @@ pub(crate) fn expand_deriving_clone( let is_simple; match item { Annotatable::Item(annitem) => match &annitem.kind { - ItemKind::Struct(_, Generics { params, .. }) - | ItemKind::Enum(_, Generics { params, .. }) => { + ItemKind::Struct(_, _, Generics { params, .. }) + | ItemKind::Enum(_, _, Generics { params, .. }) => { let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let has_derive_copy = cx.resolver.has_derive_copy(container_id); if has_derive_copy diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 7958e037555d..aa01da3151eb 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -21,7 +21,7 @@ pub(crate) fn expand_deriving_partial_ord( // Order in which to perform matching let discr_then_data = if let Annotatable::Item(item) = item - && let ItemKind::Enum(def, _) = &item.kind + && let ItemKind::Enum(_, def, _) = &item.kind { let dataful: Vec = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); match dataful.iter().filter(|&&b| b).count() { diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 46b79e097808..446d8afeedd7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -30,7 +30,7 @@ pub(crate) fn expand_deriving_coerce_pointee( item.visit_with(&mut DetectNonGenericPointeeAttr { cx }); let (name_ident, generics) = if let Annotatable::Item(aitem) = item - && let ItemKind::Struct(struct_data, g) = &aitem.kind + && let ItemKind::Struct(ident, struct_data, g) = &aitem.kind { if !matches!( struct_data, @@ -40,7 +40,7 @@ pub(crate) fn expand_deriving_coerce_pointee( cx.dcx().emit_err(RequireOneField { span }); return; } - (aitem.ident, g) + (*ident, g) } else { cx.dcx().emit_err(RequireTransparent { span }); return; @@ -108,7 +108,6 @@ pub(crate) fn expand_deriving_coerce_pointee( push(Annotatable::Item( cx.item( span, - Ident::empty(), attrs.clone(), ast::ItemKind::Impl(Box::new(ast::Impl { safety: ast::Safety::Default, @@ -153,7 +152,6 @@ pub(crate) fn expand_deriving_coerce_pointee( let trait_ref = cx.trait_ref(trait_path); let item = cx.item( span, - Ident::empty(), attrs.clone(), ast::ItemKind::Impl(Box::new(ast::Impl { safety: ast::Safety::Default, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 03ee59de70e1..b9197be44426 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -487,28 +487,28 @@ impl<'a> TraitDef<'a> { ); let newitem = match &item.kind { - ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( + ast::ItemKind::Struct(ident, struct_def, generics) => self.expand_struct_def( cx, struct_def, - item.ident, + *ident, generics, from_scratch, is_packed, ), - ast::ItemKind::Enum(enum_def, generics) => { + ast::ItemKind::Enum(ident, enum_def, generics) => { // We ignore `is_packed` here, because `repr(packed)` // enums cause an error later on. // // This can only cause further compilation errors // downstream in blatantly illegal code, so it is fine. - self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch) + self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch) } - ast::ItemKind::Union(struct_def, generics) => { + ast::ItemKind::Union(ident, struct_def, generics) => { if self.supports_unions { self.expand_struct_def( cx, struct_def, - item.ident, + *ident, generics, from_scratch, is_packed, @@ -596,7 +596,6 @@ impl<'a> TraitDef<'a> { P(ast::AssocItem { id: ast::DUMMY_NODE_ID, span: self.span, - ident, vis: ast::Visibility { span: self.span.shrink_to_lo(), kind: ast::VisibilityKind::Inherited, @@ -605,6 +604,7 @@ impl<'a> TraitDef<'a> { attrs: ast::AttrVec::new(), kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias { defaultness: ast::Defaultness::Final, + ident, generics: Generics::default(), where_clauses: ast::TyAliasWhereClauses::default(), bounds: Vec::new(), @@ -789,7 +789,6 @@ impl<'a> TraitDef<'a> { cx.item( self.span, - Ident::empty(), attrs, ast::ItemKind::Impl(Box::new(ast::Impl { safety: ast::Safety::Default, @@ -1033,10 +1032,10 @@ impl<'a> MethodDef<'a> { kind: ast::VisibilityKind::Inherited, tokens: None, }, - ident: method_ident, kind: ast::AssocItemKind::Fn(Box::new(ast::Fn { defaultness, sig, + ident: method_ident, generics: fn_generics, contract: None, body: Some(body_block), diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 90d79235820f..4b1958bce322 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -25,15 +25,15 @@ pub(crate) fn expand( // Allow using `#[global_allocator]` on an item statement // FIXME - if we get deref patterns, use them to reduce duplication here - let (item, is_stmt, ty_span) = if let Annotatable::Item(item) = &item - && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind + let (item, ident, is_stmt, ty_span) = if let Annotatable::Item(item) = &item + && let ItemKind::Static(box ast::StaticItem { ident, ty, .. }) = &item.kind { - (item, false, ecx.with_def_site_ctxt(ty.span)) + (item, *ident, false, ecx.with_def_site_ctxt(ty.span)) } else if let Annotatable::Stmt(stmt) = &item && let StmtKind::Item(item) = &stmt.kind - && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind + && let ItemKind::Static(box ast::StaticItem { ident, ty, .. }) = &item.kind { - (item, true, ecx.with_def_site_ctxt(ty.span)) + (item, *ident, true, ecx.with_def_site_ctxt(ty.span)) } else { ecx.dcx().emit_err(errors::AllocMustStatics { span: item.span() }); return vec![orig_item]; @@ -41,7 +41,7 @@ pub(crate) fn expand( // Generate a bunch of new items using the AllocFnFactory let span = ecx.with_def_site_ctxt(item.span); - let f = AllocFnFactory { span, ty_span, global: item.ident, cx: ecx }; + let f = AllocFnFactory { span, ty_span, global: ident, cx: ecx }; // Generate item statements for the allocator methods. let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect(); @@ -80,17 +80,13 @@ impl AllocFnFactory<'_, '_> { let kind = ItemKind::Fn(Box::new(Fn { defaultness: ast::Defaultness::Final, sig, + ident: Ident::from_str_and_span(&global_fn_name(method.name), self.span), generics: Generics::default(), contract: None, body, define_opaque: None, })); - let item = self.cx.item( - self.span, - Ident::from_str_and_span(&global_fn_name(method.name), self.span), - self.attrs(), - kind, - ); + let item = self.cx.item(self.span, self.attrs(), kind); self.cx.stmt_item(self.ty_span, item) } diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index ee6475c8b8e9..7c25f26895ca 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -92,7 +92,12 @@ impl<'a> CollectProcMacros<'a> { } } - fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) { + fn collect_custom_derive( + &mut self, + item: &'a ast::Item, + function_name: Ident, + attr: &'a ast::Attribute, + ) { let Some((trait_name, proc_attrs)) = parse_macro_name_and_helper_attrs(self.dcx, attr, "derive") else { @@ -104,7 +109,7 @@ impl<'a> CollectProcMacros<'a> { id: item.id, span: item.span, trait_name, - function_name: item.ident, + function_name, attrs: proc_attrs, })); } else { @@ -118,12 +123,12 @@ impl<'a> CollectProcMacros<'a> { } } - fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { + fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, function_name: Ident) { if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Attr(ProcMacroDef { id: item.id, span: item.span, - function_name: item.ident, + function_name, })); } else { let msg = if !self.in_root { @@ -136,12 +141,12 @@ impl<'a> CollectProcMacros<'a> { } } - fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { + fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, function_name: Ident) { if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Bang(ProcMacroDef { id: item.id, span: item.span, - function_name: item.ident, + function_name, })); } else { let msg = if !self.in_root { @@ -165,12 +170,6 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { } } - // First up, make sure we're checking a bare function. If we're not then - // we're just not interested in this item. - // - // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. - let is_fn = matches!(item.kind, ast::ItemKind::Fn(..)); - let mut found_attr: Option<&'a ast::Attribute> = None; for attr in &item.attrs { @@ -214,7 +213,13 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { return; }; - if !is_fn { + // First up, make sure we're checking a bare function. If we're not then + // we're just not interested in this item. + // + // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. + let fn_ident = if let ast::ItemKind::Fn(fn_) = &item.kind { + fn_.ident + } else { self.dcx .create_err(errors::AttributeOnlyBeUsedOnBareFunctions { span: attr.span, @@ -222,7 +227,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { }) .emit(); return; - } + }; if self.is_test_crate { return; @@ -239,11 +244,11 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { } if attr.has_name(sym::proc_macro_derive) { - self.collect_custom_derive(item, attr); + self.collect_custom_derive(item, fn_ident, attr); } else if attr.has_name(sym::proc_macro_attribute) { - self.collect_attr_proc_macro(item); + self.collect_attr_proc_macro(item, fn_ident); } else if attr.has_name(sym::proc_macro) { - self.collect_bang_proc_macro(item); + self.collect_bang_proc_macro(item, fn_ident); }; let prev_in_root = mem::replace(&mut self.in_root, false); @@ -278,7 +283,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); let proc_macro = Ident::new(sym::proc_macro, span); - let krate = cx.item(span, proc_macro, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)); + let krate = cx.item(span, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None, proc_macro)); let bridge = Ident::new(sym::bridge, span); let client = Ident::new(sym::client, span); diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index ba63b185e096..a1ee53b7ca21 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -43,9 +43,8 @@ pub fn inject( let item = cx.item( span, - Ident::new(name, ident_span), thin_vec![cx.attr_word(sym::macro_use, span)], - ast::ItemKind::ExternCrate(None), + ast::ItemKind::ExternCrate(None, Ident::new(name, ident_span)), ); krate.items.insert(0, item); @@ -68,7 +67,6 @@ pub fn inject( // Inject the relevant crate's prelude. let use_item = cx.item( span, - Ident::empty(), thin_vec![cx.attr_word(sym::prelude_import, span)], ast::ItemKind::Use(ast::UseTree { prefix: cx.path(span, import_path), diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index db3e431495bf..1cef4f9514cd 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -55,12 +55,14 @@ pub(crate) fn expand_test_case( // `#[test_case]` is valid on functions, consts, and statics. Only modify // the item in those cases. match &mut item.kind { - ast::ItemKind::Fn(_) | ast::ItemKind::Const(_) | ast::ItemKind::Static(_) => { - item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); + ast::ItemKind::Fn(box ast::Fn { ident, .. }) + | ast::ItemKind::Const(box ast::ConstItem { ident, .. }) + | ast::ItemKind::Static(box ast::StaticItem { ident, .. }) => { + ident.span = ident.span.with_ctxt(sp.ctxt()); let test_path_symbol = Symbol::intern(&item_path( // skip the name of the root module &ecx.current_expansion.module.mod_path[1..], - &item.ident, + ident, )); item.vis = ast::Visibility { span: item.vis.span, @@ -228,7 +230,7 @@ pub(crate) fn expand_test_or_bench( // super::$test_fn(b) cx.expr_call( ret_ty_sp, - cx.expr_path(cx.path(sp, vec![item.ident])), + cx.expr_path(cx.path(sp, vec![fn_.ident])), thin_vec![cx.expr_ident(sp, b)], ), ], @@ -254,7 +256,7 @@ pub(crate) fn expand_test_or_bench( // $test_fn() cx.expr_call( ret_ty_sp, - cx.expr_path(cx.path(sp, vec![item.ident])), + cx.expr_path(cx.path(sp, vec![fn_.ident])), ThinVec::new(), ), // ) ], @@ -267,15 +269,14 @@ pub(crate) fn expand_test_or_bench( let test_path_symbol = Symbol::intern(&item_path( // skip the name of the root module &cx.current_expansion.module.mod_path[1..], - &item.ident, + &fn_.ident, )); - let location_info = get_location_info(cx, &item); + let location_info = get_location_info(cx, &fn_); let mut test_const = cx.item( sp, - Ident::new(item.ident.name, sp), thin_vec![ // #[cfg(test)] cx.attr_nested_word(sym::cfg, sym::test, attr_sp), @@ -288,6 +289,7 @@ pub(crate) fn expand_test_or_bench( ast::ItemKind::Const( ast::ConstItem { defaultness: ast::Defaultness::Final, + ident: Ident::new(fn_.ident.name, sp), generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), define_opaque: None, @@ -386,7 +388,7 @@ pub(crate) fn expand_test_or_bench( // extern crate test let test_extern = - cx.item(sp, test_ident, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)); + cx.item(sp, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None, test_ident)); debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); @@ -440,8 +442,8 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) .emit(); } -fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) { - let span = item.ident.span; +fn get_location_info(cx: &ExtCtxt<'_>, fn_: &ast::Fn) -> (Symbol, usize, usize, usize, usize) { + let span = fn_.ident.span; let (source_file, lo_line, lo_col, hi_line, hi_col) = cx.sess.source_map().span_to_location_info(span); diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 768b459ec5e3..56a67b0534d9 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -134,27 +134,21 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { if let Some(name) = get_test_name(&item) { debug!("this is a test item"); - let test = Test { span: item.span, ident: item.ident, name }; + // `unwrap` is ok because only functions, consts, and static should reach here. + let test = Test { span: item.span, ident: item.kind.ident().unwrap(), name }; self.tests.push(test); } // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things if let ast::ItemKind::Mod( + _, _, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _), ) = item.kind { let prev_tests = mem::take(&mut self.tests); - walk_item_kind( - &mut item.kind, - item.span, - item.id, - &mut item.ident, - &mut item.vis, - (), - self, - ); + walk_item_kind(&mut item.kind, item.span, item.id, &mut item.vis, (), self); self.add_test_cases(item.id, span, prev_tests); } else { // But in those cases, we emit a lint to warn the user of these missing tests. @@ -181,9 +175,9 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> { } fn entry_point_type(item: &ast::Item, at_root: bool) -> EntryPointType { - match item.kind { - ast::ItemKind::Fn(..) => { - rustc_ast::entry::entry_point_type(&item.attrs, at_root, Some(item.ident.name)) + match &item.kind { + ast::ItemKind::Fn(fn_) => { + rustc_ast::entry::entry_point_type(&item.attrs, at_root, Some(fn_.ident.name)) } _ => EntryPointType::None, } @@ -295,7 +289,7 @@ fn generate_test_harness( fn mk_main(cx: &mut TestCtxt<'_>) -> P { let sp = cx.def_site; let ecx = &cx.ext_cx; - let test_id = Ident::new(sym::test, sp); + let test_ident = Ident::new(sym::test, sp); let runner_name = match cx.panic_strategy { PanicStrategy::Unwind => "test_main_static", @@ -303,10 +297,9 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { }; // test::test_main_static(...) - let mut test_runner = cx - .test_runner - .clone() - .unwrap_or_else(|| ecx.path(sp, vec![test_id, Ident::from_str_and_span(runner_name, sp)])); + let mut test_runner = cx.test_runner.clone().unwrap_or_else(|| { + ecx.path(sp, vec![test_ident, Ident::from_str_and_span(runner_name, sp)]) + }); test_runner.span = sp; @@ -317,7 +310,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { // extern crate test let test_extern_stmt = ecx.stmt_item( sp, - ecx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)), + ecx.item(sp, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None, test_ident)), ); // #[rustc_main] @@ -340,23 +333,24 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty)); let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp }; let defaultness = ast::Defaultness::Final; + + // Honor the reexport_test_harness_main attribute + let main_ident = match cx.reexport_test_harness_main { + Some(sym) => Ident::new(sym, sp.with_ctxt(SyntaxContext::root())), + None => Ident::new(sym::main, sp), + }; + let main = ast::ItemKind::Fn(Box::new(ast::Fn { defaultness, sig, + ident: main_ident, generics: ast::Generics::default(), contract: None, body: Some(main_body), define_opaque: None, })); - // Honor the reexport_test_harness_main attribute - let main_id = match cx.reexport_test_harness_main { - Some(sym) => Ident::new(sym, sp.with_ctxt(SyntaxContext::root())), - None => Ident::new(sym::main, sp), - }; - let main = P(ast::Item { - ident: main_id, attrs: thin_vec![main_attr, coverage_attr, doc_hidden_attr], id: ast::DUMMY_NODE_ID, kind: main, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 990d0f2e028a..d14e476ba322 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1424,12 +1424,11 @@ pub fn parse_macro_name_and_helper_attrs( /// See #73345 and #83125 for more details. /// FIXME(#73933): Remove this eventually. fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) { - let name = item.ident.name; - if name == sym::ProceduralMasqueradeDummyType - && let ast::ItemKind::Enum(enum_def, _) = &item.kind + if let ast::ItemKind::Enum(ident, enum_def, _) = &item.kind + && ident.name == sym::ProceduralMasqueradeDummyType && let [variant] = &*enum_def.variants && variant.ident.name == sym::Input - && let FileName::Real(real) = psess.source_map().span_to_filename(item.ident.span) + && let FileName::Real(real) = psess.source_map().span_to_filename(ident.span) && let Some(c) = real .local_path() .unwrap_or(Path::new("")) diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 89a750bb39f0..f68172c1f67c 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -662,15 +662,8 @@ impl<'a> ExtCtxt<'a> { P(ast::FnDecl { inputs, output }) } - pub fn item( - &self, - span: Span, - name: Ident, - attrs: ast::AttrVec, - kind: ast::ItemKind, - ) -> P { + pub fn item(&self, span: Span, attrs: ast::AttrVec, kind: ast::ItemKind) -> P { P(ast::Item { - ident: name, attrs, id: ast::DUMMY_NODE_ID, kind, @@ -687,17 +680,17 @@ impl<'a> ExtCtxt<'a> { pub fn item_static( &self, span: Span, - name: Ident, + ident: Ident, ty: P, mutability: ast::Mutability, expr: P, ) -> P { self.item( span, - name, AttrVec::new(), ast::ItemKind::Static( ast::StaticItem { + ident, ty, safety: ast::Safety::Default, mutability, @@ -712,18 +705,18 @@ impl<'a> ExtCtxt<'a> { pub fn item_const( &self, span: Span, - name: Ident, + ident: Ident, ty: P, expr: P, ) -> P { let defaultness = ast::Defaultness::Final; self.item( span, - name, AttrVec::new(), ast::ItemKind::Const( ast::ConstItem { defaultness, + ident, // FIXME(generic_const_items): Pass the generics as a parameter. generics: ast::Generics::default(), ty, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 22da1179feb9..d1dd454fa73d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -743,6 +743,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { && matches!( item_inner.kind, ItemKind::Mod( + _, _, ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _), ) @@ -911,7 +912,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> { fn visit_item(&mut self, item: &'ast ast::Item) { match &item.kind { - ItemKind::Mod(_, mod_kind) + ItemKind::Mod(_, _, mod_kind) if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) => { feature_err( @@ -1221,8 +1222,9 @@ impl InvocationCollectorNode for P { } // Work around borrow checker not seeing through `P`'s deref. - let (ident, span, mut attrs) = (node.ident, node.span, mem::take(&mut node.attrs)); - let ItemKind::Mod(_, mod_kind) = &mut node.kind else { unreachable!() }; + let (span, mut attrs) = (node.span, mem::take(&mut node.attrs)); + let ItemKind::Mod(_, ident, mod_kind) = &mut node.kind else { unreachable!() }; + let ident = *ident; let ecx = &mut collector.cx; let (file_path, dir_path, dir_ownership) = match mod_kind { @@ -1305,6 +1307,7 @@ impl InvocationCollectorNode for P { collector.cx.current_expansion.module = orig_module; res } + fn declared_names(&self) -> Vec { if let ItemKind::Use(ut) = &self.kind { fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec) { @@ -1324,7 +1327,7 @@ impl InvocationCollectorNode for P { return idents; } - vec![self.ident] + if let Some(ident) = self.kind.ident() { vec![ident] } else { vec![] } } } @@ -1844,11 +1847,11 @@ fn build_single_delegations<'a, Node: InvocationCollectorNode>( id: ast::DUMMY_NODE_ID, span: if from_glob { item_span } else { ident.span }, vis: item.vis.clone(), - ident: rename.unwrap_or(ident), kind: Node::delegation_item_kind(Box::new(ast::Delegation { id: ast::DUMMY_NODE_ID, qself: deleg.qself.clone(), path, + ident: rename.unwrap_or(ident), rename, body: deleg.body.clone(), from_glob, diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index a60a87244cc6..0136292decbc 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -26,7 +26,7 @@ pub(crate) fn placeholder( }) } - let ident = Ident::empty(); + let ident = Ident::dummy(); let attrs = ast::AttrVec::new(); let vis = vis.unwrap_or(ast::Visibility { span: DUMMY_SP, @@ -62,7 +62,6 @@ pub(crate) fn placeholder( AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item { id, span, - ident, vis, attrs, kind: ast::ItemKind::MacCall(mac_placeholder()), @@ -71,7 +70,6 @@ pub(crate) fn placeholder( AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![P(ast::AssocItem { id, span, - ident, vis, attrs, kind: ast::AssocItemKind::MacCall(mac_placeholder()), @@ -80,7 +78,6 @@ pub(crate) fn placeholder( AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![P(ast::AssocItem { id, span, - ident, vis, attrs, kind: ast::AssocItemKind::MacCall(mac_placeholder()), @@ -90,7 +87,6 @@ pub(crate) fn placeholder( AstFragment::TraitImplItems(smallvec![P(ast::AssocItem { id, span, - ident, vis, attrs, kind: ast::AssocItemKind::MacCall(mac_placeholder()), @@ -101,7 +97,6 @@ pub(crate) fn placeholder( AstFragment::ForeignItems(smallvec![P(ast::ForeignItem { id, span, - ident, vis, attrs, kind: ast::ForeignItemKind::MacCall(mac_placeholder()), diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 9dccd4a0552c..c56dbc2e1c40 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -330,7 +330,6 @@ impl EarlyLintPass for UnsafeCode { if let FnKind::Fn( ctxt, _, - _, ast::Fn { sig: ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. }, body, @@ -3116,6 +3115,7 @@ impl EarlyLintPass for SpecialModuleName { for item in &krate.items { if let ast::ItemKind::Mod( _, + ident, ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _), ) = item.kind { @@ -3123,7 +3123,7 @@ impl EarlyLintPass for SpecialModuleName { continue; } - match item.ident.name.as_str() { + match ident.name.as_str() { "lib" => cx.emit_span_lint( SPECIAL_MODULE_NAME, item.span, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 752636ccaf06..df567e80e556 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -172,20 +172,22 @@ impl EarlyLintPass for NonCamelCaseTypes { } match &it.kind { - ast::ItemKind::TyAlias(..) - | ast::ItemKind::Enum(..) - | ast::ItemKind::Struct(..) - | ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident), - ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident), - ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident), + ast::ItemKind::TyAlias(box ast::TyAlias { ident, .. }) + | ast::ItemKind::Enum(ident, ..) + | ast::ItemKind::Struct(ident, ..) + | ast::ItemKind::Union(ident, ..) => self.check_case(cx, "type", ident), + ast::ItemKind::Trait(box ast::Trait { ident, .. }) => { + self.check_case(cx, "trait", ident) + } + ast::ItemKind::TraitAlias(ident, _, _) => self.check_case(cx, "trait alias", ident), // N.B. This check is only for inherent associated types, so that we don't lint against // trait impls where we should have warned for the trait definition already. ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => { for it in items { // FIXME: this doesn't respect `#[allow(..)]` on the item itself. - if let ast::AssocItemKind::Type(..) = it.kind { - self.check_case(cx, "associated type", &it.ident); + if let ast::AssocItemKind::Type(alias) = &it.kind { + self.check_case(cx, "associated type", &alias.ident); } } } @@ -194,8 +196,8 @@ impl EarlyLintPass for NonCamelCaseTypes { } fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { - if let ast::AssocItemKind::Type(..) = it.kind { - self.check_case(cx, "associated type", &it.ident); + if let ast::AssocItemKind::Type(alias) = &it.kind { + self.check_case(cx, "associated type", &alias.ident); } } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e1ee562dafeb..16f87ab79bee 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1315,17 +1315,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { definitions: &Definitions, ) -> Option { match item.kind { - ast::ItemKind::ExternCrate(orig_name) => { - debug!( - "resolving extern crate stmt. ident: {} orig_name: {:?}", - item.ident, orig_name - ); + ast::ItemKind::ExternCrate(orig_name, ident) => { + debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", ident, orig_name); let name = match orig_name { Some(orig_name) => { validate_crate_name(self.sess, orig_name, Some(item.span)); orig_name } - None => item.ident.name, + None => ident.name, }; let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) { CrateDepKind::MacrosOnly @@ -1380,7 +1377,8 @@ fn fn_spans(krate: &ast::Crate, name: Symbol) -> Vec { } impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, item: &'ast ast::Item) { - if item.ident.name == self.name + if let Some(ident) = item.kind.ident() + && ident.name == self.name && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { self.spans.push(item.span); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index aad185783755..ed6522850960 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -34,10 +34,10 @@ impl<'a> Parser<'a> { } /// Parses a `mod { ... }` or `mod ;` item. - fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> { + fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemKind> { let safety = self.parse_safety(Case::Sensitive); self.expect_keyword(exp!(Mod))?; - let id = self.parse_ident()?; + let ident = self.parse_ident()?; let mod_kind = if self.eat(exp!(Semi)) { ModKind::Unloaded } else { @@ -46,7 +46,7 @@ impl<'a> Parser<'a> { attrs.extend(inner_attrs); ModKind::Loaded(items, Inline::Yes, inner_span, Ok(())) }; - Ok((id, ItemKind::Mod(safety, mod_kind))) + Ok(ItemKind::Mod(safety, ident, mod_kind)) } /// Parses the contents of a module (inner attributes followed by module items). @@ -115,8 +115,6 @@ impl<'a> Parser<'a> { } } -pub(super) type ItemInfo = (Ident, ItemKind); - impl<'a> Parser<'a> { pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option>> { let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true }; @@ -163,11 +161,11 @@ impl<'a> Parser<'a> { fn_parse_mode, Case::Sensitive, )?; - if let Some((ident, kind)) = kind { + if let Some(kind) = kind { this.error_on_unconsumed_default(def, &kind); let span = lo.to(this.prev_token.span); let id = DUMMY_NODE_ID; - let item = Item { ident, attrs, id, kind, vis, span, tokens: None }; + let item = Item { attrs, id, kind, vis, span, tokens: None }; return Ok((Some(item), Trailing::No, UsePreAttrPos::No)); } @@ -208,7 +206,7 @@ impl<'a> Parser<'a> { def: &mut Defaultness, fn_parse_mode: FnParseMode, case: Case, - ) -> PResult<'a, Option> { + ) -> PResult<'a, Option> { let check_pub = def == &Defaultness::Final; let mut def_ = || mem::replace(def, Defaultness::Final); @@ -218,17 +216,15 @@ impl<'a> Parser<'a> { // FUNCTION ITEM let (ident, sig, generics, contract, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?; - ( + ItemKind::Fn(Box::new(Fn { + defaultness: def_(), ident, - ItemKind::Fn(Box::new(Fn { - defaultness: def_(), - sig, - generics, - contract, - body, - define_opaque: None, - })), - ) + sig, + generics, + contract, + body, + define_opaque: None, + })) } else if self.eat_keyword(exp!(Extern)) { if self.eat_keyword(exp!(Crate)) { // EXTERN CRATE @@ -247,8 +243,8 @@ impl<'a> Parser<'a> { // STATIC ITEM self.bump(); // `static` let mutability = self.parse_mutability(); - let (ident, item) = self.parse_static_item(safety, mutability)?; - (ident, ItemKind::Static(Box::new(item))) + let item = self.parse_static_item(safety, mutability)?; + ItemKind::Static(Box::new(item)) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -258,16 +254,14 @@ impl<'a> Parser<'a> { self.recover_const_mut(const_span); self.recover_missing_kw_before_item()?; let (ident, generics, ty, expr) = self.parse_const_item()?; - ( + ItemKind::Const(Box::new(ConstItem { + defaultness: def_(), ident, - ItemKind::Const(Box::new(ConstItem { - defaultness: def_(), - generics, - ty, - expr, - define_opaque: None, - })), - ) + generics, + ty, + expr, + define_opaque: None, + })) } } else if self.check_keyword(exp!(Trait)) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM @@ -334,14 +328,14 @@ impl<'a> Parser<'a> { self.recover_missing_kw_before_item()?; } // MACRO INVOCATION ITEM - (Ident::empty(), ItemKind::MacCall(P(self.parse_item_macro(vis)?))) + ItemKind::MacCall(P(self.parse_item_macro(vis)?)) } else { return Ok(None); }; Ok(Some(info)) } - fn recover_import_as_use(&mut self) -> PResult<'a, Option> { + fn recover_import_as_use(&mut self) -> PResult<'a, Option> { let span = self.token.span; let token_name = super::token_descr(&self.token); let snapshot = self.create_snapshot_for_diagnostic(); @@ -359,7 +353,7 @@ impl<'a> Parser<'a> { } } - fn parse_use_item(&mut self) -> PResult<'a, ItemInfo> { + fn parse_use_item(&mut self) -> PResult<'a, ItemKind> { let tree = self.parse_use_tree()?; if let Err(mut e) = self.expect_semi() { match tree.kind { @@ -373,7 +367,7 @@ impl<'a> Parser<'a> { } return Err(e); } - Ok((Ident::empty(), ItemKind::Use(tree))) + Ok(ItemKind::Use(tree)) } /// When parsing a statement, would the start of a path be an item? @@ -483,7 +477,7 @@ impl<'a> Parser<'a> { if let Some(err) = err { Err(self.dcx().create_err(err)) } else { Ok(()) } } - fn parse_item_builtin(&mut self) -> PResult<'a, Option> { + fn parse_item_builtin(&mut self) -> PResult<'a, Option> { // To be expanded Ok(None) } @@ -577,7 +571,7 @@ impl<'a> Parser<'a> { &mut self, attrs: &mut AttrVec, defaultness: Defaultness, - ) -> PResult<'a, ItemInfo> { + ) -> PResult<'a, ItemKind> { let safety = self.parse_safety(Case::Sensitive); self.expect_keyword(exp!(Impl))?; @@ -698,10 +692,10 @@ impl<'a> Parser<'a> { items: impl_items, })); - Ok((Ident::empty(), item_kind)) + Ok(item_kind) } - fn parse_item_delegation(&mut self) -> PResult<'a, ItemInfo> { + fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> { let span = self.token.span; self.expect_keyword(exp!(Reuse))?; @@ -724,7 +718,7 @@ impl<'a> Parser<'a> { }) }; - let (ident, item_kind) = if self.eat_path_sep() { + let item_kind = if self.eat_path_sep() { let suffixes = if self.eat(exp!(Star)) { None } else { @@ -732,7 +726,7 @@ impl<'a> Parser<'a> { Some(self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0) }; let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? }; - (Ident::empty(), ItemKind::DelegationMac(Box::new(deleg))) + ItemKind::DelegationMac(Box::new(deleg)) } else { let rename = rename(self)?; let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); @@ -740,17 +734,18 @@ impl<'a> Parser<'a> { id: DUMMY_NODE_ID, qself, path, + ident, rename, body: body(self)?, from_glob: false, }; - (ident, ItemKind::Delegation(Box::new(deleg))) + ItemKind::Delegation(Box::new(deleg)) }; let span = span.to(self.prev_token.span); self.psess.gated_spans.gate(sym::fn_delegation, span); - Ok((ident, item_kind)) + Ok(item_kind) } fn parse_item_list( @@ -900,7 +895,7 @@ impl<'a> Parser<'a> { } /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. - fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> { + fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> { let safety = self.parse_safety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(exp!(Auto)) { @@ -941,15 +936,12 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::trait_alias, whole_span); - Ok((ident, ItemKind::TraitAlias(generics, bounds))) + Ok(ItemKind::TraitAlias(ident, generics, bounds)) } else { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?; - Ok(( - ident, - ItemKind::Trait(Box::new(Trait { is_auto, safety, generics, bounds, items })), - )) + Ok(ItemKind::Trait(Box::new(Trait { is_auto, safety, ident, generics, bounds, items }))) } } @@ -977,11 +969,12 @@ impl<'a> Parser<'a> { force_collect: ForceCollect, ) -> PResult<'a, Option>>> { Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( - |Item { attrs, id, span, vis, ident, kind, tokens }| { + |Item { attrs, id, span, vis, kind, tokens }| { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { ItemKind::Static(box StaticItem { + ident, ty, safety: _, mutability: _, @@ -991,6 +984,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, + ident, generics: Generics::default(), ty, expr, @@ -1000,7 +994,7 @@ impl<'a> Parser<'a> { _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), }, }; - Some(P(Item { attrs, id, span, vis, ident, kind, tokens })) + Some(P(Item { attrs, id, span, vis, kind, tokens })) }, )) } @@ -1010,7 +1004,7 @@ impl<'a> Parser<'a> { /// TypeAlias = "type" Ident Generics (":" GenericBounds)? WhereClause ("=" Ty)? WhereClause ";" ; /// ``` /// The `"type"` has already been eaten. - fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo> { + fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemKind> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; @@ -1045,16 +1039,14 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok(( + Ok(ItemKind::TyAlias(Box::new(TyAlias { + defaultness, ident, - ItemKind::TyAlias(Box::new(TyAlias { - defaultness, - generics, - where_clauses, - bounds, - ty, - })), - )) + generics, + where_clauses, + bounds, + ty, + }))) } /// Parses a `UseTree`. @@ -1158,16 +1150,16 @@ impl<'a> Parser<'a> { /// extern crate foo; /// extern crate bar as foo; /// ``` - fn parse_item_extern_crate(&mut self) -> PResult<'a, ItemInfo> { + fn parse_item_extern_crate(&mut self) -> PResult<'a, ItemKind> { // Accept `extern crate name-like-this` for better diagnostics - let orig_name = self.parse_crate_name_with_dashes()?; - let (item_name, orig_name) = if let Some(rename) = self.parse_rename()? { - (rename, Some(orig_name.name)) + let orig_ident = self.parse_crate_name_with_dashes()?; + let (orig_name, item_ident) = if let Some(rename) = self.parse_rename()? { + (Some(orig_ident.name), rename) } else { - (orig_name, None) + (None, orig_ident) }; self.expect_semi()?; - Ok((item_name, ItemKind::ExternCrate(orig_name))) + Ok(ItemKind::ExternCrate(orig_name, item_ident)) } fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> { @@ -1218,7 +1210,7 @@ impl<'a> Parser<'a> { &mut self, attrs: &mut AttrVec, mut safety: Safety, - ) -> PResult<'a, ItemInfo> { + ) -> PResult<'a, ItemKind> { let extern_span = self.prev_token.uninterpolated_span(); let abi = self.parse_abi(); // ABI? // FIXME: This recovery should be tested better. @@ -1236,7 +1228,7 @@ impl<'a> Parser<'a> { abi, items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?, }; - Ok((Ident::empty(), ItemKind::ForeignMod(module))) + Ok(ItemKind::ForeignMod(module)) } /// Parses a foreign item (one in an `extern { ... }` block). @@ -1246,11 +1238,11 @@ impl<'a> Parser<'a> { ) -> PResult<'a, Option>>> { let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: false }; Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( - |Item { attrs, id, span, vis, ident, kind, tokens }| { + |Item { attrs, id, span, vis, kind, tokens }| { let kind = match ForeignItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Const(box ConstItem { ty, expr, .. }) => { + ItemKind::Const(box ConstItem { ident, ty, expr, .. }) => { let const_span = Some(span.with_hi(ident.span.lo())) .filter(|span| span.can_be_used_for_suggestions()); self.dcx().emit_err(errors::ExternItemCannotBeConst { @@ -1258,6 +1250,7 @@ impl<'a> Parser<'a> { const_span, }); ForeignItemKind::Static(Box::new(StaticItem { + ident, ty, mutability: Mutability::Not, expr, @@ -1268,7 +1261,7 @@ impl<'a> Parser<'a> { _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), }, }; - Some(P(Item { attrs, id, span, vis, ident, kind, tokens })) + Some(P(Item { attrs, id, span, vis, kind, tokens })) }, )) } @@ -1343,13 +1336,13 @@ impl<'a> Parser<'a> { const_span: Span, attrs: &mut AttrVec, defaultness: Defaultness, - ) -> PResult<'a, ItemInfo> { + ) -> PResult<'a, ItemKind> { let impl_span = self.token.span; let err = self.expected_ident_found_err(); // Only try to recover if this is implementing a trait for a type - let mut impl_info = match self.parse_item_impl(attrs, defaultness) { - Ok(impl_info) => impl_info, + let mut item_kind = match self.parse_item_impl(attrs, defaultness) { + Ok(item_kind) => item_kind, Err(recovery_error) => { // Recovery failed, raise the "expected identifier" error recovery_error.cancel(); @@ -1357,7 +1350,7 @@ impl<'a> Parser<'a> { } }; - match &mut impl_info.1 { + match &mut item_kind { ItemKind::Impl(box Impl { of_trait: Some(trai), constness, .. }) => { *constness = Const::Yes(const_span); @@ -1374,7 +1367,7 @@ impl<'a> Parser<'a> { _ => unreachable!(), } - Ok(impl_info) + Ok(item_kind) } /// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in `mutability`. @@ -1386,7 +1379,7 @@ impl<'a> Parser<'a> { &mut self, safety: Safety, mutability: Mutability, - ) -> PResult<'a, (Ident, StaticItem)> { + ) -> PResult<'a, StaticItem> { let ident = self.parse_ident()?; if self.token == TokenKind::Lt && self.may_recover() { @@ -1406,7 +1399,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, StaticItem { ty, safety, mutability, expr, define_opaque: None })) + Ok(StaticItem { ident, ty, safety, mutability, expr, define_opaque: None }) } /// Parse a constant item with the prefix `"const"` already parsed. @@ -1531,7 +1524,7 @@ impl<'a> Parser<'a> { } /// Parses an enum declaration. - fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { + fn parse_item_enum(&mut self) -> PResult<'a, ItemKind> { if self.token.is_keyword(kw::Struct) { let span = self.prev_token.span.to(self.token.span); let err = errors::EnumStructMutuallyExclusive { span }; @@ -1584,7 +1577,7 @@ impl<'a> Parser<'a> { }; let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() }; - Ok((id, ItemKind::Enum(enum_definition, generics))) + Ok(ItemKind::Enum(id, enum_definition, generics)) } fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option> { @@ -1676,8 +1669,8 @@ impl<'a> Parser<'a> { } /// Parses `struct Foo { ... }`. - fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { - let class_name = self.parse_ident()?; + fn parse_item_struct(&mut self) -> PResult<'a, ItemKind> { + let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; @@ -1698,7 +1691,7 @@ impl<'a> Parser<'a> { let vdata = if self.token.is_keyword(kw::Where) { let tuple_struct_body; (generics.where_clause, tuple_struct_body) = - self.parse_struct_where_clause(class_name, generics.span)?; + self.parse_struct_where_clause(ident, generics.span)?; if let Some(body) = tuple_struct_body { // If we see a misplaced tuple struct body: `struct Foo where T: Copy, (T);` @@ -1712,7 +1705,7 @@ impl<'a> Parser<'a> { // If we see: `struct Foo where T: Copy { ... }` let (fields, recovered) = self.parse_record_struct_body( "struct", - class_name.span, + ident.span, generics.where_clause.has_where_token, )?; VariantData::Struct { fields, recovered } @@ -1724,7 +1717,7 @@ impl<'a> Parser<'a> { } else if self.token == token::OpenDelim(Delimiter::Brace) { let (fields, recovered) = self.parse_record_struct_body( "struct", - class_name.span, + ident.span, generics.where_clause.has_where_token, )?; VariantData::Struct { fields, recovered } @@ -1740,12 +1733,12 @@ impl<'a> Parser<'a> { return Err(self.dcx().create_err(err)); }; - Ok((class_name, ItemKind::Struct(vdata, generics))) + Ok(ItemKind::Struct(ident, vdata, generics)) } /// Parses `union Foo { ... }`. - fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { - let class_name = self.parse_ident()?; + fn parse_item_union(&mut self) -> PResult<'a, ItemKind> { + let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; @@ -1753,14 +1746,14 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; let (fields, recovered) = self.parse_record_struct_body( "union", - class_name.span, + ident.span, generics.where_clause.has_where_token, )?; VariantData::Struct { fields, recovered } } else if self.token == token::OpenDelim(Delimiter::Brace) { let (fields, recovered) = self.parse_record_struct_body( "union", - class_name.span, + ident.span, generics.where_clause.has_where_token, )?; VariantData::Struct { fields, recovered } @@ -1772,7 +1765,7 @@ impl<'a> Parser<'a> { return Err(err); }; - Ok((class_name, ItemKind::Union(vdata, generics))) + Ok(ItemKind::Union(ident, vdata, generics)) } /// This function parses the fields of record structs: @@ -2124,15 +2117,17 @@ impl<'a> Parser<'a> { } } else if self.eat_keyword(exp!(Struct)) { match self.parse_item_struct() { - Ok((ident, _)) => self - .dcx() - .struct_span_err( - lo.with_hi(ident.span.hi()), - format!("structs are not allowed in {adt_ty} definitions"), - ) - .with_help( - "consider creating a new `struct` definition instead of nesting", - ), + Ok(item) => { + let ItemKind::Struct(ident, ..) = item else { unreachable!() }; + self.dcx() + .struct_span_err( + lo.with_hi(ident.span.hi()), + format!("structs are not allowed in {adt_ty} definitions"), + ) + .with_help( + "consider creating a new `struct` definition instead of nesting", + ) + } Err(err) => { err.cancel(); self.restore_snapshot(snapshot); @@ -2177,7 +2172,7 @@ impl<'a> Parser<'a> { /// MacParams = "(" TOKEN_STREAM ")" ; /// DeclMac = "macro" Ident MacParams? MacBody ; /// ``` - fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> { + fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemKind> { let ident = self.parse_ident()?; let body = if self.check(exp!(OpenBrace)) { self.parse_delim_args()? // `MacBody` @@ -2199,7 +2194,7 @@ impl<'a> Parser<'a> { }; self.psess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_token.span)); - Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: false }))) + Ok(ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: false })) } /// Is this a possibly malformed start of a `macro_rules! foo` item definition? @@ -2228,7 +2223,7 @@ impl<'a> Parser<'a> { &mut self, vis: &Visibility, has_bang: bool, - ) -> PResult<'a, ItemInfo> { + ) -> PResult<'a, ItemKind> { self.expect_keyword(exp!(MacroRules))?; // `macro_rules` if has_bang { @@ -2246,7 +2241,7 @@ impl<'a> Parser<'a> { self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); - Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: true }))) + Ok(ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: true })) } /// Item macro invocations or `macro_rules!` definitions need inherited visibility. diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 471966d086d5..49ae6cb9b726 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2922,7 +2922,7 @@ fn out_of_line_mod() { .unwrap() .unwrap(); - let ast::ItemKind::Mod(_, mod_kind) = &item.kind else { panic!() }; + let ast::ItemKind::Mod(_, _, mod_kind) = &item.kind else { panic!() }; assert_matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2); }); } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 9d4b46cd3066..664bd4ad0a25 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -268,22 +268,22 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { fn visit_item(&mut self, i: &'ast ast::Item) { let target = match &i.kind { - ast::ItemKind::ExternCrate(_) => Target::ExternCrate, + ast::ItemKind::ExternCrate(..) => Target::ExternCrate, ast::ItemKind::Use(_) => Target::Use, ast::ItemKind::Static(_) => Target::Static, ast::ItemKind::Const(_) => Target::Const, ast::ItemKind::Fn(_) | ast::ItemKind::Delegation(..) => Target::Fn, - ast::ItemKind::Mod(_, _) => Target::Mod, + ast::ItemKind::Mod(..) => Target::Mod, ast::ItemKind::ForeignMod(_) => Target::ForeignFn, ast::ItemKind::GlobalAsm(_) => Target::GlobalAsm, ast::ItemKind::TyAlias(_) => Target::TyAlias, - ast::ItemKind::Enum(_, _) => Target::Enum, - ast::ItemKind::Struct(_, _) => Target::Struct, - ast::ItemKind::Union(_, _) => Target::Union, + ast::ItemKind::Enum(..) => Target::Enum, + ast::ItemKind::Struct(..) => Target::Struct, + ast::ItemKind::Union(..) => Target::Union, ast::ItemKind::Trait(_) => Target::Trait, - ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias, + ast::ItemKind::TraitAlias(..) => Target::TraitAlias, ast::ItemKind::Impl(_) => Target::Impl, - ast::ItemKind::MacroDef(_) => Target::MacroDef, + ast::ItemKind::MacroDef(..) => Target::MacroDef, ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => { unreachable!("macros should have been expanded") } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 97fbf7e378ac..7f29f1a084e6 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -10,8 +10,8 @@ use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::{ - self as ast, AssocItem, AssocItemKind, Block, ForeignItem, ForeignItemKind, Impl, Item, - ItemKind, MetaItemKind, NodeId, StmtKind, + self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, ForeignItem, + ForeignItemKind, Impl, Item, ItemKind, MetaItemKind, NodeId, StaticItem, StmtKind, }; use rustc_attr_parsing as attr; use rustc_expand::base::ResolverExpand; @@ -735,7 +735,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; - let ident = item.ident; let sp = item.span; let vis = self.resolve_visibility(&item.vis); let feed = self.r.feed(item.id); @@ -762,9 +761,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); } - ItemKind::ExternCrate(orig_name) => { + ItemKind::ExternCrate(orig_name, ident) => { self.build_reduced_graph_for_extern_crate( orig_name, + ident, item, local_def_id, vis, @@ -772,7 +772,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); } - ItemKind::Mod(.., ref mod_kind) => { + ItemKind::Mod(_, ident, ref mod_kind) => { let module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), @@ -792,10 +792,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items live in the value namespace. - ItemKind::Const(..) | ItemKind::Delegation(..) | ItemKind::Static(..) => { + ItemKind::Const(box ConstItem { ident, .. }) + | ItemKind::Delegation(box Delegation { ident, .. }) + | ItemKind::Static(box StaticItem { ident, .. }) => { self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } - ItemKind::Fn(..) => { + ItemKind::Fn(box ast::Fn { ident, .. }) => { self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); // Functions introducing procedural macros reserve a slot @@ -804,11 +806,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items live in the type namespace. - ItemKind::TyAlias(..) | ItemKind::TraitAlias(..) => { + ItemKind::TyAlias(box ast::TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } - ItemKind::Enum(_, _) | ItemKind::Trait(..) => { + ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { let module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), @@ -821,7 +823,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items live in both the type and value namespaces. - ItemKind::Struct(ref vdata, _) => { + ItemKind::Struct(ident, ref vdata, _) => { self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, @@ -872,7 +874,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } } - ItemKind::Union(ref vdata, _) => { + ItemKind::Union(ident, ref vdata, _) => { self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, @@ -898,12 +900,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { fn build_reduced_graph_for_extern_crate( &mut self, orig_name: Option, + ident: Ident, item: &Item, local_def_id: LocalDefId, vis: ty::Visibility, parent: Module<'ra>, ) { - let ident = item.ident; let sp = item.span; let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; @@ -987,7 +989,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } /// Constructs the reduced graph for one foreign item. - fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) { + fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, ident: Ident) { let feed = self.r.feed(item.id); let local_def_id = feed.key(); let def_id = local_def_id.to_def_id(); @@ -1000,7 +1002,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; let vis = self.resolve_visibility(&item.vis); - self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion)); + self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); self.r.feed_visibility(feed, vis); } @@ -1043,7 +1045,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span: item.span, }); } - if let ItemKind::ExternCrate(Some(orig_name)) = item.kind + if let ItemKind::ExternCrate(Some(orig_name), _) = item.kind && orig_name == kw::SelfLower { self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); @@ -1177,11 +1179,15 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } - fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { + fn proc_macro_stub( + &self, + item: &ast::Item, + fn_ident: Ident, + ) -> Option<(MacroKind, Ident, Span)> { if ast::attr::contains_name(&item.attrs, sym::proc_macro) { - return Some((MacroKind::Bang, item.ident, item.span)); + return Some((MacroKind::Bang, fn_ident, item.span)); } else if ast::attr::contains_name(&item.attrs, sym::proc_macro_attribute) { - return Some((MacroKind::Attr, item.ident, item.span)); + return Some((MacroKind::Attr, fn_ident, item.span)); } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) && let Some(meta_item_inner) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) @@ -1214,17 +1220,21 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(item.id); let def_id = feed.key(); let (res, ident, span, macro_rules) = match &item.kind { - ItemKind::MacroDef(def) => (self.res(def_id), item.ident, item.span, def.macro_rules), - ItemKind::Fn(..) => match self.proc_macro_stub(item) { - Some((macro_kind, ident, span)) => { - let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id()); - let macro_data = MacroData::new(self.r.dummy_ext(macro_kind)); - self.r.macro_map.insert(def_id.to_def_id(), macro_data); - self.r.proc_macro_stubs.insert(def_id); - (res, ident, span, false) + ItemKind::MacroDef(ident, def) => { + (self.res(def_id), *ident, item.span, def.macro_rules) + } + ItemKind::Fn(box ast::Fn { ident: fn_ident, .. }) => { + match self.proc_macro_stub(item, *fn_ident) { + Some((macro_kind, ident, span)) => { + let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id()); + let macro_data = MacroData::new(self.r.dummy_ext(macro_kind)); + self.r.macro_map.insert(def_id.to_def_id(), macro_data); + self.r.proc_macro_stubs.insert(def_id); + (res, ident, span, false) + } + None => return parent_scope.macro_rules, } - None => return parent_scope.macro_rules, - }, + } _ => unreachable!(), }; @@ -1327,8 +1337,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Visit attributes after items for backward compatibility. // This way they can use `macro_rules` defined later. self.visit_vis(&item.vis); - self.visit_ident(&item.ident); - item.kind.walk(item.span, item.id, &item.ident, &item.vis, (), self); + item.kind.walk(item.span, item.id, &item.vis, (), self); visit::walk_list!(self, visit_attribute, &item.attrs); } _ => visit::walk_item(self, item), @@ -1358,7 +1367,10 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { return; } - self.build_reduced_graph_for_foreign_item(foreign_item); + // `unwrap` is safe because `MacCall` has been excluded, and other foreign item kinds have + // an ident. + let ident = foreign_item.kind.ident().unwrap(); + self.build_reduced_graph_for_foreign_item(foreign_item, ident); visit::walk_item(self, foreign_item); } @@ -1413,13 +1425,16 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { AssocItemKind::Type(..) => TypeNS, AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above }; + // `unwrap` is safe because `MacCall`/`DelegationMac` have been excluded, and other foreign + // item kinds have an ident. + let ident = item.kind.ident().unwrap(); if ctxt == AssocCtxt::Trait { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; - self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion)); + self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) { let impl_def_id = self.r.tcx.local_parent(local_def_id); - let key = BindingKey::new(item.ident.normalize_to_macros_2_0(), ns); + let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns); self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key); } diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 51ff4aa834ba..e97233e97ce5 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -219,14 +219,14 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. ast::ItemKind::Use(..) if item.span.is_dummy() => return, - ast::ItemKind::ExternCrate(orig_name) => { + ast::ItemKind::ExternCrate(orig_name, ident) => { self.extern_crate_items.push(ExternCrateToLint { id: item.id, span: item.span, vis_span: item.vis.span, span_with_attributes: item.span_with_attributes(), has_attrs: !item.attrs.is_empty(), - ident: item.ident, + ident, renames: orig_name.is_some(), }); } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 6f48a75d6174..6ad056edbaf8 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -122,7 +122,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { }, ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, - ItemKind::MacroDef(def) => { + ItemKind::MacroDef(ident, def) => { let edition = i.span.edition(); // FIXME(jdonszelmann) make one of these in the resolver? @@ -141,7 +141,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ); let macro_data = - self.resolver.compile_macro(def, i.ident, &attrs, i.span, i.id, edition); + self.resolver.compile_macro(def, *ident, &attrs, i.span, i.id, edition); let macro_kind = macro_data.ext.macro_kind(); opt_macro_data = Some(macro_data); DefKind::Macro(macro_kind) @@ -152,7 +152,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { return self.visit_macro_invoc(i.id); } }; - let def_id = self.create_def(i.id, Some(i.ident.name), def_kind, i.span); + let def_id = + self.create_def(i.id, i.kind.ident().map(|ident| ident.name), def_kind, i.span); if let Some(macro_data) = opt_macro_data { self.resolver.macro_map.insert(def_id.to_def_id(), macro_data); @@ -161,7 +162,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { self.with_parent(def_id, |this| { this.with_impl_trait(ImplTraitContext::Existential, |this| { match i.kind { - ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { + ItemKind::Struct(_, ref struct_def, _) + | ItemKind::Union(_, ref struct_def, _) => { // If this is a unit or tuple-like struct, register the constructor. if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) { this.create_def( @@ -183,7 +185,6 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { match fn_kind { FnKind::Fn( _ctxt, - _ident, _vis, Fn { sig: FnSig { header, decl, span: _ }, generics, contract, body, .. }, ) if let Some(coroutine_kind) = header.coroutine_kind => { @@ -234,8 +235,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { - let def_kind = match fi.kind { + let (ident, def_kind) = match fi.kind { ForeignItemKind::Static(box StaticItem { + ident, ty: _, mutability, expr: _, @@ -247,14 +249,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ast::Safety::Safe(_) => hir::Safety::Safe, }; - DefKind::Static { safety, mutability, nested: false } + (ident, DefKind::Static { safety, mutability, nested: false }) } - ForeignItemKind::Fn(_) => DefKind::Fn, - ForeignItemKind::TyAlias(_) => DefKind::ForeignTy, + ForeignItemKind::Fn(box Fn { ident, .. }) => (ident, DefKind::Fn), + ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => (ident, DefKind::ForeignTy), ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id), }; - let def = self.create_def(fi.id, Some(fi.ident.name), def_kind, fi.span); + let def = self.create_def(fi.id, Some(ident.name), def_kind, fi.span); self.with_parent(def, |this| visit::walk_item(this, fi)); } @@ -318,16 +320,17 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { - let def_kind = match &i.kind { - AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn, - AssocItemKind::Const(..) => DefKind::AssocConst, - AssocItemKind::Type(..) => DefKind::AssocTy, + let (ident, def_kind) = match &i.kind { + AssocItemKind::Fn(box Fn { ident, .. }) + | AssocItemKind::Delegation(box Delegation { ident, .. }) => (*ident, DefKind::AssocFn), + AssocItemKind::Const(box ConstItem { ident, .. }) => (*ident, DefKind::AssocConst), + AssocItemKind::Type(box TyAlias { ident, .. }) => (*ident, DefKind::AssocTy), AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { return self.visit_macro_invoc(i.id); } }; - let def = self.create_def(i.id, Some(i.ident.name), def_kind, i.span); + let def = self.create_def(i.id, Some(ident.name), def_kind, i.span); self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 63ea8c4ced13..7d6af12909c7 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3063,7 +3063,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { fn visit_item(&mut self, item: &'tcx ast::Item) { if self.target_module == item.id { - if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind { + if let ItemKind::Mod(_, _, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind { let inject = mod_spans.inject_use_span; if is_span_suitable_for_use_injection(inject) { self.first_legal_span = Some(inject); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 6ef4aa407253..a5ca4565d7b4 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -252,7 +252,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> self.current_private_vis = prev_private_vis; } - ast::ItemKind::Enum(EnumDef { ref variants }, _) => { + ast::ItemKind::Enum(_, EnumDef { ref variants }, _) => { self.set_bindings_effective_visibilities(def_id); for variant in variants { let variant_def_id = self.r.local_def_id(variant.id); @@ -262,7 +262,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> } } - ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { + ast::ItemKind::Struct(_, ref def, _) | ast::ItemKind::Union(_, ref def, _) => { for field in def.fields() { self.update_field(self.r.local_def_id(field.id), def_id); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0d23ae501f04..d4dd0800452a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1025,8 +1025,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. - FnKind::Fn(FnCtxt::Foreign, _, _, Fn { sig, generics, .. }) - | FnKind::Fn(_, _, _, Fn { sig, generics, body: None, .. }) => { + FnKind::Fn(FnCtxt::Foreign, _, Fn { sig, generics, .. }) + | FnKind::Fn(_, _, Fn { sig, generics, body: None, .. }) => { self.visit_fn_header(&sig.header); self.visit_generics(generics); self.with_lifetime_rib( @@ -1058,7 +1058,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r // Create a label rib for the function. this.with_label_rib(RibKind::FnOrCoroutine, |this| { match fn_kind { - FnKind::Fn(_, _, _, Fn { sig, generics, contract, body, .. }) => { + FnKind::Fn(_, _, Fn { sig, generics, contract, body, .. }) => { this.visit_generics(generics); let declaration = &sig.decl; @@ -2632,8 +2632,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); } - let name = item.ident.name; - debug!("(resolving item) resolving {} ({:?})", name, item.kind); + debug!("(resolving item) resolving {:?} ({:?})", item.kind.ident(), item.kind); let def_kind = self.r.local_def_kind(item.id); match item.kind { @@ -2664,9 +2663,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_define_opaques(define_opaque); } - ItemKind::Enum(_, ref generics) - | ItemKind::Struct(_, ref generics) - | ItemKind::Union(_, ref generics) => { + ItemKind::Enum(_, _, ref generics) + | ItemKind::Struct(_, _, ref generics) + | ItemKind::Union(_, _, ref generics) => { self.resolve_adt(item, generics); } @@ -2710,7 +2709,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - ItemKind::TraitAlias(ref generics, ref bounds) => { + ItemKind::TraitAlias(_, ref generics, ref bounds) => { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, @@ -2748,7 +2747,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ItemKind::Static(box ast::StaticItem { - ref ty, ref expr, ref define_opaque, .. + ident, + ref ty, + ref expr, + ref define_opaque, + .. }) => { self.with_static_rib(def_kind, |this| { this.with_lifetime_rib( @@ -2762,13 +2765,14 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if let Some(expr) = expr { // We already forbid generic params because of the above item rib, // so it doesn't matter whether this is a trivial constant. - this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static))); + this.resolve_const_body(expr, Some((ident, ConstantItemKind::Static))); } }); self.resolve_define_opaques(define_opaque); } ItemKind::Const(box ast::ConstItem { + ident, ref generics, ref ty, ref expr, @@ -2801,10 +2805,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); if let Some(expr) = expr { - this.resolve_const_body( - expr, - Some((item.ident, ConstantItemKind::Const)), - ); + this.resolve_const_body(expr, Some((ident, ConstantItemKind::Const))); } }, ); @@ -2821,7 +2822,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.future_proof_import(use_tree); } - ItemKind::MacroDef(ref macro_def) => { + ItemKind::MacroDef(_, ref macro_def) => { // Maintain macro_rules scopes in the same way as during early resolution // for diagnostics and doc links. if macro_def.macro_rules { @@ -3319,7 +3320,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); match &item.kind { AssocItemKind::Const(box ast::ConstItem { - generics, ty, expr, define_opaque, .. + ident, + generics, + ty, + expr, + define_opaque, + .. }) => { debug!("resolve_implementation AssocItemKind::Const"); self.with_generic_param_rib( @@ -3350,7 +3356,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // exists in trait this.check_trait_item( item.id, - item.ident, + *ident, &item.kind, ValueNS, item.span, @@ -3376,7 +3382,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); self.resolve_define_opaques(define_opaque); } - AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { + AssocItemKind::Fn(box Fn { ident, generics, define_opaque, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); // We also need a new scope for the impl item type parameters. self.with_generic_param_rib( @@ -3392,7 +3398,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // exists in trait this.check_trait_item( item.id, - item.ident, + *ident, &item.kind, ValueNS, item.span, @@ -3406,7 +3412,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_define_opaques(define_opaque); } - AssocItemKind::Type(box TyAlias { generics, .. }) => { + AssocItemKind::Type(box TyAlias { ident, generics, .. }) => { self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty()); debug!("resolve_implementation AssocItemKind::Type"); // We also need a new scope for the impl item type parameters. @@ -3424,7 +3430,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // exists in trait this.check_trait_item( item.id, - item.ident, + *ident, &item.kind, TypeNS, item.span, @@ -3451,7 +3457,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| { this.check_trait_item( item.id, - item.ident, + delegation.ident, &item.kind, ValueNS, item.span, @@ -4337,7 +4343,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if let Some(items) = self.diag_metadata.current_trait_assoc_items && let [Segment { ident, .. }] = path && items.iter().any(|item| { - item.ident == *ident && matches!(item.kind, AssocItemKind::Type(_)) + if let AssocItemKind::Type(alias) = &item.kind + && alias.ident == *ident + { + true + } else { + false + } }) { let mut diag = self.r.tcx.dcx().struct_allow(""); @@ -5159,12 +5171,12 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { ItemKind::TyAlias(box TyAlias { generics, .. }) | ItemKind::Const(box ConstItem { generics, .. }) | ItemKind::Fn(box Fn { generics, .. }) - | ItemKind::Enum(_, generics) - | ItemKind::Struct(_, generics) - | ItemKind::Union(_, generics) + | ItemKind::Enum(_, _, generics) + | ItemKind::Struct(_, _, generics) + | ItemKind::Union(_, _, generics) | ItemKind::Impl(box Impl { generics, .. }) | ItemKind::Trait(box Trait { generics, .. }) - | ItemKind::TraitAlias(generics, _) => { + | ItemKind::TraitAlias(_, generics, _) => { if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind { self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e40f84e7e598..2a2b1ecef161 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -224,12 +224,17 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let suggestion = if self.current_trait_ref.is_none() && let Some((fn_kind, _)) = self.diag_metadata.current_function && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt() - && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = fn_kind + && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = fn_kind && let Some(items) = self.diag_metadata.current_impl_items && let Some(item) = items.iter().find(|i| { - i.ident.name == item_str.name + if let Some(ident) = i.kind.ident() + && ident.name == item_str.name + { // Don't suggest if the item is in Fn signature arguments (#112590). - && !sig.span.contains(item_span) + !sig.span.contains(item_span) + } else { + false + } }) { let sp = item_span.shrink_to_lo(); @@ -268,14 +273,14 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // you can't call `fn foo(&self)` from `fn bar()` (#115992). // We also want to mention that the method exists. span_label = Some(( - item.ident.span, + fn_.ident.span, "a method by that name is available on `Self` here", )); None } AssocItemKind::Fn(fn_) if !fn_.sig.decl.has_self() && !is_call => { span_label = Some(( - item.ident.span, + fn_.ident.span, "an associated function by that name is available on `Self` here", )); None @@ -604,7 +609,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { Applicability::MaybeIncorrect, ); if !self.self_value_is_available(path[0].ident.span) { - if let Some((FnKind::Fn(_, _, _, ast::Fn { sig, .. }), fn_span)) = + if let Some((FnKind::Fn(_, _, ast::Fn { sig, .. }), fn_span)) = &self.diag_metadata.current_function { let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) { @@ -1064,15 +1069,11 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } err.code(E0411); err.span_label(span, "`Self` is only available in impls, traits, and type definitions"); - if let Some(item_kind) = self.diag_metadata.current_item { - if !item_kind.ident.span.is_dummy() { + if let Some(item) = self.diag_metadata.current_item { + if let Some(ident) = item.kind.ident() { err.span_label( - item_kind.ident.span, - format!( - "`Self` not allowed in {} {}", - item_kind.kind.article(), - item_kind.kind.descr() - ), + ident.span, + format!("`Self` not allowed in {} {}", item.kind.article(), item.kind.descr()), ); } } @@ -1150,17 +1151,14 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ); } } - } else if let Some(item_kind) = self.diag_metadata.current_item { - if matches!(item_kind.kind, ItemKind::Delegation(..)) { - err.span_label(item_kind.span, format!("delegation supports {self_from_macro}")); + } else if let Some(item) = self.diag_metadata.current_item { + if matches!(item.kind, ItemKind::Delegation(..)) { + err.span_label(item.span, format!("delegation supports {self_from_macro}")); } else { + let span = if let Some(ident) = item.kind.ident() { ident.span } else { item.span }; err.span_label( - item_kind.ident.span, - format!( - "`self` not allowed in {} {}", - item_kind.kind.article(), - item_kind.kind.descr() - ), + span, + format!("`self` not allowed in {} {}", item.kind.article(), item.kind.descr()), ); } } @@ -2196,7 +2194,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(items) = self.diag_metadata.current_trait_assoc_items { for assoc_item in items { - if assoc_item.ident == ident { + if let Some(assoc_ident) = assoc_item.kind.ident() + && assoc_ident == ident + { return Some(match &assoc_item.kind { ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst, ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => { @@ -2735,7 +2735,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { return None; } match (self.diag_metadata.current_item, single_uppercase_char, self.diag_metadata.currently_processing_generic_args) { - (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => { + (Some(Item { kind: ItemKind::Fn(fn_), .. }), _, _) if fn_.ident.name == sym::main => { // Ignore `fn main()` as we don't want to suggest `fn main()` } ( @@ -3400,7 +3400,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { { let pre = if lt.kind == MissingLifetimeKind::Ampersand && let Some((kind, _span)) = self.diag_metadata.current_function - && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind + && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind && !sig.decl.inputs.is_empty() && let sugg = sig .decl @@ -3441,7 +3441,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else if (lt.kind == MissingLifetimeKind::Ampersand || lt.kind == MissingLifetimeKind::Underscore) && let Some((kind, _span)) = self.diag_metadata.current_function - && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind + && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output && !sig.decl.inputs.is_empty() && let arg_refs = sig @@ -3501,7 +3501,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand; let mut sugg = vec![(lt.span, String::new())]; if let Some((kind, _span)) = self.diag_metadata.current_function - && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind + && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind && let ast::FnRetTy::Ty(ty) = &sig.decl.output { let mut lt_finder = diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 56b1e76ae8cf..4edd5433de6c 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -350,21 +350,21 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { + ast::ItemKind::Fn(ref fn_item) if !info.has_main_fn => { // We only push if it's the top item because otherwise, we would duplicate // its content since the top-level item was already added. - if item.ident.name == sym::main { + if fn_item.ident.name == sym::main { info.has_main_fn = true; } } - ast::ItemKind::ExternCrate(original) => { + ast::ItemKind::ExternCrate(original, ident) => { is_extern_crate = true; if !info.already_has_extern_crate && let Some(crate_name) = crate_name { info.already_has_extern_crate = match original { Some(name) => name.as_str() == *crate_name, - None => item.ident.as_str() == *crate_name, + None => ident.as_str() == *crate_name, }; } } diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index 7d86bd3e540a..c2aac7ca090b 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -53,7 +53,7 @@ declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]); impl EarlyLintPass for CrateInMacroDef { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::MacroDef(macro_def) = &item.kind + if let ItemKind::MacroDef(_, macro_def) = &item.kind && item.attrs.iter().any(is_macro_export) && let Some(span) = contains_unhygienic_crate_reference(¯o_def.body.tokens) { diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index 3008082c2329..f6c10da1596b 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -13,16 +13,16 @@ use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{FileName, Pos, sym}; +use rustc_span::{FileName, Ident, Pos, sym}; use super::Fragments; -fn get_test_spans(item: &Item, test_attr_spans: &mut Vec>) { +fn get_test_spans(item: &Item, ident: Ident, test_attr_spans: &mut Vec>) { test_attr_spans.extend( item.attrs .iter() .find(|attr| attr.has_name(sym::test)) - .map(|attr| attr.span.lo().to_usize()..item.ident.span.hi().to_usize()), + .map(|attr| attr.span.lo().to_usize()..ident.span.hi().to_usize()), ); } @@ -64,10 +64,10 @@ pub fn check( match parser.parse_item(ForceCollect::No) { Ok(Some(item)) => match &item.kind { ItemKind::Fn(box Fn { - sig, body: Some(block), .. - }) if item.ident.name == sym::main => { + ident, sig, body: Some(block), .. + }) if ident.name == sym::main => { if !ignore { - get_test_spans(&item, &mut test_attr_spans); + get_test_spans(&item, *ident, &mut test_attr_spans); } let is_async = matches!(sig.header.coroutine_kind, Some(CoroutineKind::Async { .. })); let returns_nothing = match &sig.decl.output { @@ -85,10 +85,10 @@ pub fn check( } }, // Another function was found; this case is ignored for needless_doctest_main - ItemKind::Fn(box Fn { .. }) => { + ItemKind::Fn(fn_) => { eligible = false; if !ignore { - get_test_spans(&item, &mut test_attr_spans); + get_test_spans(&item, fn_.ident, &mut test_attr_spans); } }, // Tests with one of these items are ignored diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs index 1dac7b971f95..243c99a19ce1 100644 --- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs +++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs @@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]); impl EarlyLintPass for DuplicateMod { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind + if let ItemKind::Mod(_, _, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind && let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span) && let Some(local_path) = real.into_local_path() && let Ok(absolute_path) = local_path.canonicalize() diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs index 80c2b03c41cf..899b5c595261 100644 --- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs +++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs @@ -9,7 +9,7 @@ use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol}; +use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, sym}; declare_clippy_lint! { /// ### What it does @@ -375,21 +375,21 @@ impl EmptyLineAfter { &mut self, cx: &EarlyContext<'_>, kind: &ItemKind, - ident: &Ident, + ident: &Option, span: Span, attrs: &[Attribute], id: NodeId, ) { self.items.push(ItemInfo { kind: kind.descr(), - name: ident.name, - span: if span.contains(ident.span) { + name: if let Some(ident) = ident { ident.name } else { sym::dummy }, + span: if let Some(ident) = ident { span.with_hi(ident.span.hi()) } else { span.with_hi(span.lo()) }, mod_items: match kind { - ItemKind::Mod(_, ModKind::Loaded(items, _, _, _)) => items + ItemKind::Mod(_, _, ModKind::Loaded(items, _, _, _)) => items .iter() .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_))) .map(|i| i.id) @@ -471,7 +471,7 @@ impl EarlyLintPass for EmptyLineAfter { self.check_item_kind( cx, &item.kind.clone().into(), - &item.ident, + &item.kind.ident(), item.span, &item.attrs, item.id, @@ -482,7 +482,7 @@ impl EarlyLintPass for EmptyLineAfter { self.check_item_kind( cx, &item.kind.clone().into(), - &item.ident, + &item.kind.ident(), item.span, &item.attrs, item.id, @@ -490,6 +490,6 @@ impl EarlyLintPass for EmptyLineAfter { } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - self.check_item_kind(cx, &item.kind, &item.ident, item.span, &item.attrs, item.id); + self.check_item_kind(cx, &item.kind, &item.kind.ident(), item.span, &item.attrs, item.id); } } diff --git a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs index 743ec5b9ea7f..7d87f04fef9d 100644 --- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs +++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs @@ -74,10 +74,9 @@ declare_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM impl EarlyLintPass for EmptyWithBrackets { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - let span_after_ident = item.span.with_lo(item.ident.span.hi()); - - if let ItemKind::Struct(var_data, _) = &item.kind + if let ItemKind::Struct(ident, var_data, _) = &item.kind && has_brackets(var_data) + && let span_after_ident = item.span.with_lo(ident.span.hi()) && has_no_fields(cx, var_data, span_after_ident) { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs index ba2b37fbf11a..aae8291905d3 100644 --- a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs +++ b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs @@ -51,7 +51,7 @@ declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MO impl EarlyLintPass for FieldScopedVisibilityModifiers { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - let ItemKind::Struct(ref st, _) = item.kind else { + let ItemKind::Struct(_, ref st, _) = item.kind else { return; }; for field in st.fields() { diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs index 0e1980a6acb6..4b32ba83b325 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs @@ -39,7 +39,7 @@ declare_lint_pass!(MultipleBoundLocations => [MULTIPLE_BOUND_LOCATIONS]); impl EarlyLintPass for MultipleBoundLocations { fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: NodeId) { - if let FnKind::Fn(_, _, _, Fn { generics, .. }) = kind + if let FnKind::Fn(_, _, Fn { generics, .. }) = kind && !generics.params.is_empty() && !generics.where_clause.predicates.is_empty() { diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs index 267e2067e101..cda752d003fa 100644 --- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs +++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs @@ -41,7 +41,7 @@ declare_lint_pass!(PartialPubFields => [PARTIAL_PUB_FIELDS]); impl EarlyLintPass for PartialPubFields { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - let ItemKind::Struct(ref st, _) = item.kind else { + let ItemKind::Struct(_, ref st, _) = item.kind else { return; }; diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index fa0824535042..35f80b2acda6 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -174,11 +174,11 @@ impl SingleComponentPathImports { } match &item.kind { - ItemKind::Mod(_, ModKind::Loaded(items, ..)) => { + ItemKind::Mod(_, _, ModKind::Loaded(items, ..)) => { self.check_mod(items); }, - ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => { - macros.push(item.ident.name); + ItemKind::MacroDef(ident, MacroDef { macro_rules: true, .. }) => { + macros.push(ident.name); }, ItemKind::Use(use_tree) => { let segments = &use_tree.prefix.segments; diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 6023ae9cc7b1..ff63eb505a5c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -321,17 +321,18 @@ pub fn eq_local_kind(l: &LocalKind, r: &LocalKind) -> bool { } pub fn eq_item(l: &Item, r: &Item, mut eq_kind: impl FnMut(&K, &K) -> bool) -> bool { - eq_id(l.ident, r.ident) && over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind) + over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind) } #[expect(clippy::similar_names, clippy::too_many_lines)] // Just a big match statement pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { use ItemKind::*; match (l, r) { - (ExternCrate(l), ExternCrate(r)) => l == r, + (ExternCrate(ls, li), ExternCrate(rs, ri)) => ls == rs && eq_id(*li, *ri), (Use(l), Use(r)) => eq_use_tree(l, r), ( Static(box StaticItem { + ident: li, ty: lt, mutability: lm, expr: le, @@ -339,16 +340,22 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { define_opaque: _, }), Static(box StaticItem { + ident: ri, ty: rt, mutability: rm, expr: re, safety: rs, define_opaque: _, }), - ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), + ) => eq_id(*li, *ri) + && lm == rm + && ls == rs + && eq_ty(lt, rt) + && eq_expr_opt(le.as_ref(), re.as_ref()), ( Const(box ConstItem { defaultness: ld, + ident: li, generics: lg, ty: lt, expr: le, @@ -356,16 +363,22 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }), Const(box ConstItem { defaultness: rd, + ident: ri, generics: rg, ty: rt, expr: re, define_opaque: _, }), - ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), + ) => eq_defaultness(*ld, *rd) + && eq_id(*li, *ri) + && eq_generics(lg, rg) + && eq_ty(lt, rt) + && eq_expr_opt(le.as_ref(), re.as_ref()), ( Fn(box ast::Fn { defaultness: ld, sig: lf, + ident: li, generics: lg, contract: lc, body: lb, @@ -374,6 +387,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { Fn(box ast::Fn { defaultness: rd, sig: rf, + ident: ri, generics: rg, contract: rc, body: rb, @@ -382,12 +396,14 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ) => { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) + && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_opt_fn_contract(lc, rc) && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r)) }, - (Mod(lu, lmk), Mod(ru, rmk)) => { - lu == ru + (Mod(ls, li, lmk), Mod(rs, ri, rmk)) => { + ls == rs + && eq_id(*li, *ri) && match (lmk, rmk) { (ModKind::Loaded(litems, linline, _, _), ModKind::Loaded(ritems, rinline, _, _)) => { linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind)) @@ -421,33 +437,40 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && over(lb, rb, eq_generic_bound) && both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r)) }, - (Enum(le, lg), Enum(re, rg)) => over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg), - (Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => { - eq_variant_data(lv, rv) && eq_generics(lg, rg) + (Enum(li, le, lg), Enum(ri, re, rg)) => { + eq_id(*li, *ri) && over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg) + } + (Struct(li, lv, lg), Struct(ri, rv, rg)) | (Union(li, lv, lg), Union(ri, rv, rg)) => { + eq_id(*li, *ri) && eq_variant_data(lv, rv) && eq_generics(lg, rg) }, ( Trait(box ast::Trait { is_auto: la, safety: lu, + ident: li, generics: lg, bounds: lb, - items: li, + items: lis, }), Trait(box ast::Trait { is_auto: ra, safety: ru, + ident: ri, generics: rg, bounds: rb, - items: ri, + items: ris, }), ) => { la == ra && matches!(lu, Safety::Default) == matches!(ru, Safety::Default) + && eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) - && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind)) + && over(lis, ris, |l, r| eq_item(l, r, eq_assoc_item_kind)) }, - (TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, eq_generic_bound), + (TraitAlias(li, lg, lb), TraitAlias(ri, rg, rb)) => { + eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) + } ( Impl(box ast::Impl { safety: lu, @@ -480,7 +503,9 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind)) }, (MacCall(l), MacCall(r)) => eq_mac_call(l, r), - (MacroDef(l), MacroDef(r)) => l.macro_rules == r.macro_rules && eq_delim_args(&l.body, &r.body), + (MacroDef(li, ld), MacroDef(ri, rd)) => { + eq_id(*li, *ri) && ld.macro_rules == rd.macro_rules && eq_delim_args(&ld.body, &rd.body) + } _ => false, } } @@ -490,6 +515,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { match (l, r) { ( Static(box StaticItem { + ident: li, ty: lt, mutability: lm, expr: le, @@ -497,17 +523,25 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { define_opaque: _, }), Static(box StaticItem { + ident: ri, ty: rt, mutability: rm, expr: re, safety: rs, define_opaque: _, }), - ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs, + ) => { + eq_id(*li, *ri) + && eq_ty(lt, rt) + && lm == rm + && eq_expr_opt(le.as_ref(), re.as_ref()) + && ls == rs + } ( Fn(box ast::Fn { defaultness: ld, sig: lf, + ident: li, generics: lg, contract: lc, body: lb, @@ -516,6 +550,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { Fn(box ast::Fn { defaultness: rd, sig: rf, + ident: ri, generics: rg, contract: rc, body: rb, @@ -524,6 +559,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { ) => { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) + && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_opt_fn_contract(lc, rc) && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r)) @@ -560,6 +596,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ( Const(box ConstItem { defaultness: ld, + ident: li, generics: lg, ty: lt, expr: le, @@ -567,16 +604,24 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { }), Const(box ConstItem { defaultness: rd, + ident: ri, generics: rg, ty: rt, expr: re, define_opaque: _, }), - ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), + ) => { + eq_defaultness(*ld, *rd) + && eq_id(*li, *ri) + && eq_generics(lg, rg) + && eq_ty(lt, rt) + && eq_expr_opt(le.as_ref(), re.as_ref()) + } ( Fn(box ast::Fn { defaultness: ld, sig: lf, + ident: li, generics: lg, contract: lc, body: lb, @@ -585,6 +630,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { Fn(box ast::Fn { defaultness: rd, sig: rf, + ident: ri, generics: rg, contract: rc, body: rb, @@ -593,6 +639,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ) => { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) + && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_opt_fn_contract(lc, rc) && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r)) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index fdda885b7298..322af97d9dc4 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -333,12 +333,12 @@ impl<'a> FnSig<'a> { defaultness: ast::Defaultness, ) -> FnSig<'a> { match *fn_kind { - visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, vis, ast::Fn { sig, generics, .. }) => { + visit::FnKind::Fn(visit::FnCtxt::Assoc(..), vis, ast::Fn { sig, generics, .. }) => { let mut fn_sig = FnSig::from_method_sig(sig, generics, vis); fn_sig.defaultness = defaultness; fn_sig } - visit::FnKind::Fn(_, _, vis, ast::Fn { sig, generics, .. }) => FnSig { + visit::FnKind::Fn(_, vis, ast::Fn { sig, generics, .. }) => FnSig { decl, generics, ext: sig.header.ext, @@ -750,11 +750,10 @@ impl<'a> FmtVisitor<'a> { (Type(lty), Type(rty)) if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) => { - a.ident.as_str().cmp(b.ident.as_str()) - } - (Const(..), Const(..)) | (MacCall(..), MacCall(..)) => { - a.ident.as_str().cmp(b.ident.as_str()) + lty.ident.as_str().cmp(rty.ident.as_str()) } + (Const(ca), Const(cb)) => ca.ident.as_str().cmp(cb.ident.as_str()), + (MacCall(..), MacCall(..)) => Ordering::Equal, (Fn(..), Fn(..)) | (Delegation(..), Delegation(..)) => { a.span.lo().cmp(&b.span.lo()) } @@ -1105,14 +1104,16 @@ impl<'a> StructParts<'a> { } pub(crate) fn from_item(item: &'a ast::Item) -> Self { - let (prefix, def, generics) = match item.kind { - ast::ItemKind::Struct(ref def, ref generics) => ("struct ", def, generics), - ast::ItemKind::Union(ref def, ref generics) => ("union ", def, generics), + let (prefix, def, ident, generics) = match item.kind { + ast::ItemKind::Struct(ident, ref def, ref generics) => { + ("struct ", def, ident, generics) + } + ast::ItemKind::Union(ident, ref def, ref generics) => ("union ", def, ident, generics), _ => unreachable!(), }; StructParts { prefix, - ident: item.ident, + ident, vis: &item.vis, def, generics: Some(generics), @@ -1168,6 +1169,7 @@ pub(crate) fn format_trait( let ast::Trait { is_auto, safety, + ident, ref generics, ref bounds, ref items, @@ -1186,13 +1188,13 @@ pub(crate) fn format_trait( let shape = Shape::indented(offset, context.config).offset_left(result.len())?; let generics_str = - rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape).ok()?; + rewrite_generics(context, rewrite_ident(context, ident), generics, shape).ok()?; result.push_str(&generics_str); // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds. if !bounds.is_empty() { // Retrieve *unnormalized* ident (See #6069) - let source_ident = context.snippet(item.ident.span); + let source_ident = context.snippet(ident.span); let ident_hi = context.snippet_provider.span_after(item.span, source_ident); let bound_hi = bounds.last().unwrap().span().hi(); let snippet = context.snippet(mk_sp(ident_hi, bound_hi)); @@ -1699,7 +1701,6 @@ struct TyAliasRewriteInfo<'c, 'g>( pub(crate) fn rewrite_type_alias<'a>( ty_alias_kind: &ast::TyAlias, vis: &ast::Visibility, - ident: Ident, context: &RewriteContext<'a>, indent: Indent, visitor_kind: ItemVisitorKind, @@ -1709,6 +1710,7 @@ pub(crate) fn rewrite_type_alias<'a>( let ast::TyAlias { defaultness, + ident, ref generics, ref bounds, ref ty, @@ -2022,14 +2024,23 @@ pub(crate) struct StaticParts<'a> { impl<'a> StaticParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { - let (defaultness, prefix, safety, ty, mutability, expr, generics) = match &item.kind { - ast::ItemKind::Static(s) => { - (None, "static", s.safety, &s.ty, s.mutability, &s.expr, None) - } + let (defaultness, prefix, safety, ident, ty, mutability, expr, generics) = match &item.kind + { + ast::ItemKind::Static(s) => ( + None, + "static", + s.safety, + s.ident, + &s.ty, + s.mutability, + &s.expr, + None, + ), ast::ItemKind::Const(c) => ( Some(c.defaultness), "const", ast::Safety::Default, + c.ident, &c.ty, ast::Mutability::Not, &c.expr, @@ -2041,7 +2052,7 @@ impl<'a> StaticParts<'a> { prefix, safety, vis: &item.vis, - ident: item.ident, + ident, generics, ty, mutability, @@ -2051,7 +2062,7 @@ impl<'a> StaticParts<'a> { } } - pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self { + pub(crate) fn from_trait_item(ti: &'a ast::AssocItem, ident: Ident) -> Self { let (defaultness, ty, expr_opt, generics) = match &ti.kind { ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)), _ => unreachable!(), @@ -2060,7 +2071,7 @@ impl<'a> StaticParts<'a> { prefix: "const", safety: ast::Safety::Default, vis: &ti.vis, - ident: ti.ident, + ident, generics, ty, mutability: ast::Mutability::Not, @@ -2070,7 +2081,7 @@ impl<'a> StaticParts<'a> { } } - pub(crate) fn from_impl_item(ii: &'a ast::AssocItem) -> Self { + pub(crate) fn from_impl_item(ii: &'a ast::AssocItem, ident: Ident) -> Self { let (defaultness, ty, expr, generics) = match &ii.kind { ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)), _ => unreachable!(), @@ -2079,7 +2090,7 @@ impl<'a> StaticParts<'a> { prefix: "const", safety: ast::Safety::Default, vis: &ii.vis, - ident: ii.ident, + ident, generics, ty, mutability: ast::Mutability::Not, @@ -3440,6 +3451,7 @@ impl Rewrite for ast::ForeignItem { let ast::Fn { defaultness, ref sig, + ident, ref generics, ref body, .. @@ -3451,7 +3463,8 @@ impl Rewrite for ast::ForeignItem { let inner_attrs = inner_attributes(&self.attrs); let fn_ctxt = visit::FnCtxt::Foreign; visitor.visit_fn( - visit::FnKind::Fn(fn_ctxt, &self.ident, &self.vis, fn_kind), + ident, + visit::FnKind::Fn(fn_ctxt, &self.vis, fn_kind), &sig.decl, self.span, defaultness, @@ -3462,7 +3475,7 @@ impl Rewrite for ast::ForeignItem { rewrite_fn_base( context, shape.indent, - self.ident, + ident, &FnSig::from_method_sig(sig, generics, &self.vis), span, FnBraceStyle::None, @@ -3481,7 +3494,7 @@ impl Rewrite for ast::ForeignItem { vis, safety, mut_str, - rewrite_ident(context, self.ident) + rewrite_ident(context, static_foreign_item.ident) ); // 1 = ; rewrite_assign_rhs( @@ -3497,15 +3510,7 @@ impl Rewrite for ast::ForeignItem { } ast::ForeignItemKind::TyAlias(ref ty_alias) => { let kind = ItemVisitorKind::ForeignItem; - rewrite_type_alias( - ty_alias, - &self.vis, - self.ident, - context, - shape.indent, - kind, - self.span, - ) + rewrite_type_alias(ty_alias, &self.vis, context, shape.indent, kind, self.span) } ast::ForeignItemKind::MacCall(ref mac) => { rewrite_macro(mac, context, shape, MacroPosition::Item) @@ -3568,12 +3573,13 @@ fn rewrite_attrs( pub(crate) fn rewrite_mod( context: &RewriteContext<'_>, item: &ast::Item, + ident: Ident, attrs_shape: Shape, ) -> Option { let mut result = String::with_capacity(32); result.push_str(&*format_visibility(context, &item.vis)); result.push_str("mod "); - result.push_str(rewrite_ident(context, item.ident)); + result.push_str(rewrite_ident(context, ident)); result.push(';'); rewrite_attrs(context, item, &result, attrs_shape) } @@ -3600,7 +3606,7 @@ pub(crate) fn rewrite_extern_crate( pub(crate) fn is_mod_decl(item: &ast::Item) -> bool { !matches!( item.kind, - ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _)) + ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _)) ) } diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index a40ee7f66a97..bc5a6d3e7040 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -152,7 +152,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { let mut visitor = visitor::CfgIfVisitor::new(self.psess); visitor.visit_item(&item); for module_item in visitor.mods() { - if let ast::ItemKind::Mod(_, ref sub_mod_kind) = module_item.item.kind { + if let ast::ItemKind::Mod(_, _, ref sub_mod_kind) = module_item.item.kind { self.visit_sub_mod( &module_item.item, Module::new( @@ -178,7 +178,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { continue; } - if let ast::ItemKind::Mod(_, ref sub_mod_kind) = item.kind { + if let ast::ItemKind::Mod(_, _, ref sub_mod_kind) = item.kind { let span = item.span; self.visit_sub_mod( &item, @@ -204,7 +204,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { self.visit_cfg_if(Cow::Borrowed(item))?; } - if let ast::ItemKind::Mod(_, ref sub_mod_kind) = item.kind { + if let ast::ItemKind::Mod(_, _, ref sub_mod_kind) = item.kind { let span = item.span; self.visit_sub_mod( item, @@ -248,7 +248,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { if is_mod_decl(item) { // mod foo; // Look for an extern file. - self.find_external_module(item.ident, &item.attrs, sub_mod) + self.find_external_module(item.kind.ident().unwrap(), &item.attrs, sub_mod) } else { // An internal module (`mod foo { /* ... */ }`); Ok(Some(SubModKind::Internal(item))) @@ -291,7 +291,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { self.visit_sub_mod_after_directory_update(sub_mod, Some(directory)) } SubModKind::Internal(item) => { - self.push_inline_mod_directory(item.ident, &item.attrs); + self.push_inline_mod_directory(item.kind.ident().unwrap(), &item.attrs); self.visit_sub_mod_after_directory_update(sub_mod, None) } SubModKind::MultiExternal(mods) => { diff --git a/src/tools/rustfmt/src/reorder.rs b/src/tools/rustfmt/src/reorder.rs index 8a31e0ac816e..2460b61698cc 100644 --- a/src/tools/rustfmt/src/reorder.rs +++ b/src/tools/rustfmt/src/reorder.rs @@ -25,14 +25,17 @@ use crate::visitor::FmtVisitor; /// Choose the ordering between the given two items. fn compare_items(a: &ast::Item, b: &ast::Item) -> Ordering { match (&a.kind, &b.kind) { - (&ast::ItemKind::Mod(..), &ast::ItemKind::Mod(..)) => { - a.ident.as_str().cmp(b.ident.as_str()) + (&ast::ItemKind::Mod(_, a_ident, _), &ast::ItemKind::Mod(_, b_ident, _)) => { + a_ident.as_str().cmp(b_ident.as_str()) } - (&ast::ItemKind::ExternCrate(ref a_name), &ast::ItemKind::ExternCrate(ref b_name)) => { + ( + &ast::ItemKind::ExternCrate(ref a_name, a_ident), + &ast::ItemKind::ExternCrate(ref b_name, b_ident), + ) => { // `extern crate foo as bar;` // ^^^ Comparing this. - let a_orig_name = a_name.unwrap_or(a.ident.name); - let b_orig_name = b_name.unwrap_or(b.ident.name); + let a_orig_name = a_name.unwrap_or(a_ident.name); + let b_orig_name = b_name.unwrap_or(b_ident.name); let result = a_orig_name.as_str().cmp(b_orig_name.as_str()); if result != Ordering::Equal { return result; @@ -44,7 +47,7 @@ fn compare_items(a: &ast::Item, b: &ast::Item) -> Ordering { (Some(..), None) => Ordering::Greater, (None, Some(..)) => Ordering::Less, (None, None) => Ordering::Equal, - (Some(..), Some(..)) => a.ident.as_str().cmp(b.ident.as_str()), + (Some(..), Some(..)) => a_ident.as_str().cmp(b_ident.as_str()), } } _ => unreachable!(), @@ -69,7 +72,7 @@ fn rewrite_reorderable_item( ) -> Option { match item.kind { ast::ItemKind::ExternCrate(..) => rewrite_extern_crate(context, item, shape), - ast::ItemKind::Mod(..) => rewrite_mod(context, item, shape), + ast::ItemKind::Mod(_, ident, _) => rewrite_mod(context, item, ident, shape), _ => None, } } diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index c73976d90b1e..1dc0a9069231 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -377,6 +377,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { // on traits do not get handled here. pub(crate) fn visit_fn( &mut self, + ident: Ident, fk: visit::FnKind<'_>, fd: &ast::FnDecl, s: Span, @@ -388,7 +389,6 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let rewrite = match fk { visit::FnKind::Fn( _, - ident, _, ast::Fn { body: Some(ref b), .. @@ -397,7 +397,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { block = b; self.rewrite_fn_before_block( indent, - *ident, + ident, &FnSig::from_fn_kind(&fk, fd, defaultness), mk_sp(s.lo(), b.span.lo()), ) @@ -444,7 +444,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let should_visit_node_again = match item.kind { // For use/extern crate items, skip rewriting attributes but check for a skip attribute. - ast::ItemKind::Use(..) | ast::ItemKind::ExternCrate(_) => { + ast::ItemKind::Use(..) | ast::ItemKind::ExternCrate(..) => { if contains_skip(attrs) { self.push_skipped_with_span(attrs.as_slice(), item.span(), item.span()); false @@ -497,11 +497,11 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent)); self.push_rewrite(item.span, rw); } - ast::ItemKind::TraitAlias(ref generics, ref generic_bounds) => { + ast::ItemKind::TraitAlias(ident, ref generics, ref generic_bounds) => { let shape = Shape::indented(self.block_indent, self.config); let rw = format_trait_alias( &self.get_context(), - item.ident, + ident, &item.vis, generics, generic_bounds, @@ -509,7 +509,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ); self.push_rewrite(item.span, rw); } - ast::ItemKind::ExternCrate(_) => { + ast::ItemKind::ExternCrate(..) => { let rw = rewrite_extern_crate(&self.get_context(), item, self.shape()); let span = if attrs.is_empty() { item.span @@ -521,14 +521,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => { self.visit_struct(&StructParts::from_item(item)); } - ast::ItemKind::Enum(ref def, ref generics) => { + ast::ItemKind::Enum(ident, ref def, ref generics) => { self.format_missing_with_indent(source!(self, item.span).lo()); - self.visit_enum(item.ident, &item.vis, def, generics, item.span); + self.visit_enum(ident, &item.vis, def, generics, item.span); self.last_pos = source!(self, item.span).hi(); } - ast::ItemKind::Mod(safety, ref mod_kind) => { + ast::ItemKind::Mod(safety, ident, ref mod_kind) => { self.format_missing_with_indent(source!(self, item.span).lo()); - self.format_mod(mod_kind, safety, &item.vis, item.span, item.ident, attrs); + self.format_mod(mod_kind, safety, &item.vis, item.span, ident, attrs); } ast::ItemKind::MacCall(ref mac) => { self.visit_mac(mac, MacroPosition::Item); @@ -544,6 +544,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let ast::Fn { defaultness, ref sig, + ident, ref generics, ref body, .. @@ -555,7 +556,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { _ => visit::FnCtxt::Foreign, }; self.visit_fn( - visit::FnKind::Fn(fn_ctxt, &item.ident, &item.vis, fn_kind), + ident, + visit::FnKind::Fn(fn_ctxt, &item.vis, fn_kind), &sig.decl, item.span, defaultness, @@ -564,28 +566,26 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } else { let indent = self.block_indent; let rewrite = self - .rewrite_required_fn( - indent, item.ident, sig, &item.vis, generics, item.span, - ) + .rewrite_required_fn(indent, ident, sig, &item.vis, generics, item.span) .ok(); self.push_rewrite(item.span, rewrite); } } ast::ItemKind::TyAlias(ref ty_alias) => { use ItemVisitorKind::Item; - self.visit_ty_alias_kind(ty_alias, &item.vis, item.ident, Item, item.span); + self.visit_ty_alias_kind(ty_alias, &item.vis, Item, item.span); } ast::ItemKind::GlobalAsm(..) => { let snippet = Some(self.snippet(item.span).to_owned()); self.push_rewrite(item.span, snippet); } - ast::ItemKind::MacroDef(ref def) => { + ast::ItemKind::MacroDef(ident, ref def) => { let rewrite = rewrite_macro_def( &self.get_context(), self.shape(), self.block_indent, def, - item.ident, + ident, &item.vis, item.span, ) @@ -606,14 +606,12 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { &mut self, ty_kind: &ast::TyAlias, vis: &ast::Visibility, - ident: Ident, visitor_kind: ItemVisitorKind, span: Span, ) { let rewrite = rewrite_type_alias( ty_kind, vis, - ident, &self.get_context(), self.block_indent, visitor_kind, @@ -642,16 +640,17 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { // TODO(calebcartwright): consider enabling box_patterns feature gate match (&ai.kind, visitor_kind) { - (ast::AssocItemKind::Const(..), AssocTraitItem) => { - self.visit_static(&StaticParts::from_trait_item(ai)) + (ast::AssocItemKind::Const(c), AssocTraitItem) => { + self.visit_static(&StaticParts::from_trait_item(ai, c.ident)) } - (ast::AssocItemKind::Const(..), AssocImplItem) => { - self.visit_static(&StaticParts::from_impl_item(ai)) + (ast::AssocItemKind::Const(c), AssocImplItem) => { + self.visit_static(&StaticParts::from_impl_item(ai, c.ident)) } (ast::AssocItemKind::Fn(ref fn_kind), _) => { let ast::Fn { defaultness, ref sig, + ident, ref generics, ref body, .. @@ -660,7 +659,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let inner_attrs = inner_attributes(&ai.attrs); let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt); self.visit_fn( - visit::FnKind::Fn(fn_ctxt, &ai.ident, &ai.vis, fn_kind), + ident, + visit::FnKind::Fn(fn_ctxt, &ai.vis, fn_kind), &sig.decl, ai.span, defaultness, @@ -669,13 +669,13 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } else { let indent = self.block_indent; let rewrite = self - .rewrite_required_fn(indent, ai.ident, sig, &ai.vis, generics, ai.span) + .rewrite_required_fn(indent, fn_kind.ident, sig, &ai.vis, generics, ai.span) .ok(); self.push_rewrite(ai.span, rewrite); } } (ast::AssocItemKind::Type(ref ty_alias), _) => { - self.visit_ty_alias_kind(ty_alias, &ai.vis, ai.ident, visitor_kind, ai.span); + self.visit_ty_alias_kind(ty_alias, &ai.vis, visitor_kind, ai.span); } (ast::AssocItemKind::MacCall(ref mac), _) => { self.visit_mac(mac, MacroPosition::Item); diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 191daff2137d..24e389486478 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -10,9 +10,9 @@ ast-stats-1 - DocComment 32 ( 0.5%) 1 ast-stats-1 - Normal 32 ( 0.5%) 1 ast-stats-1 WherePredicate 72 ( 1.1%) 1 72 ast-stats-1 - BoundPredicate 72 ( 1.1%) 1 +ast-stats-1 ForeignItem 80 ( 1.2%) 1 80 +ast-stats-1 - Fn 80 ( 1.2%) 1 ast-stats-1 Local 80 ( 1.2%) 1 80 -ast-stats-1 ForeignItem 88 ( 1.3%) 1 88 -ast-stats-1 - Fn 88 ( 1.3%) 1 ast-stats-1 Arm 96 ( 1.4%) 2 48 ast-stats-1 FnDecl 120 ( 1.8%) 5 24 ast-stats-1 Param 160 ( 2.4%) 4 40 @@ -23,37 +23,37 @@ ast-stats-1 - Expr 96 ( 1.4%) 3 ast-stats-1 Block 192 ( 2.9%) 6 32 ast-stats-1 FieldDef 208 ( 3.1%) 2 104 ast-stats-1 Variant 208 ( 3.1%) 2 104 -ast-stats-1 AssocItem 352 ( 5.3%) 4 88 -ast-stats-1 - Fn 176 ( 2.6%) 2 -ast-stats-1 - Type 176 ( 2.6%) 2 -ast-stats-1 GenericBound 352 ( 5.3%) 4 88 -ast-stats-1 - Trait 352 ( 5.3%) 4 -ast-stats-1 GenericParam 480 ( 7.2%) 5 96 +ast-stats-1 AssocItem 320 ( 4.8%) 4 80 +ast-stats-1 - Fn 160 ( 2.4%) 2 +ast-stats-1 - Type 160 ( 2.4%) 2 +ast-stats-1 GenericBound 352 ( 5.2%) 4 88 +ast-stats-1 - Trait 352 ( 5.2%) 4 +ast-stats-1 GenericParam 480 ( 7.1%) 5 96 ast-stats-1 Pat 504 ( 7.5%) 7 72 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1 -ast-stats-1 - Ident 360 ( 5.4%) 5 +ast-stats-1 - Ident 360 ( 5.3%) 5 ast-stats-1 Expr 576 ( 8.6%) 8 72 ast-stats-1 - Match 72 ( 1.1%) 1 ast-stats-1 - Path 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Lit 144 ( 2.1%) 2 ast-stats-1 - Block 216 ( 3.2%) 3 -ast-stats-1 PathSegment 744 (11.1%) 31 24 -ast-stats-1 Ty 896 (13.4%) 14 64 +ast-stats-1 PathSegment 744 (11.0%) 31 24 +ast-stats-1 Ty 896 (13.3%) 14 64 ast-stats-1 - Ptr 64 ( 1.0%) 1 ast-stats-1 - Ref 64 ( 1.0%) 1 ast-stats-1 - ImplicitSelf 128 ( 1.9%) 2 ast-stats-1 - Path 640 ( 9.5%) 10 -ast-stats-1 Item 1_224 (18.3%) 9 136 -ast-stats-1 - Enum 136 ( 2.0%) 1 -ast-stats-1 - ForeignMod 136 ( 2.0%) 1 -ast-stats-1 - Impl 136 ( 2.0%) 1 -ast-stats-1 - Trait 136 ( 2.0%) 1 -ast-stats-1 - Fn 272 ( 4.1%) 2 -ast-stats-1 - Use 408 ( 6.1%) 3 +ast-stats-1 Item 1_296 (19.2%) 9 144 +ast-stats-1 - Enum 144 ( 2.1%) 1 +ast-stats-1 - ForeignMod 144 ( 2.1%) 1 +ast-stats-1 - Impl 144 ( 2.1%) 1 +ast-stats-1 - Trait 144 ( 2.1%) 1 +ast-stats-1 - Fn 288 ( 4.3%) 2 +ast-stats-1 - Use 432 ( 6.4%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_704 116 +ast-stats-1 Total 6_736 116 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -61,12 +61,12 @@ ast-stats-2 ---------------------------------------------------------------- ast-stats-2 Crate 40 ( 0.5%) 1 40 ast-stats-2 GenericArgs 40 ( 0.5%) 1 40 ast-stats-2 - AngleBracketed 40 ( 0.5%) 1 -ast-stats-2 ExprField 48 ( 0.7%) 1 48 +ast-stats-2 ExprField 48 ( 0.6%) 1 48 ast-stats-2 WherePredicate 72 ( 1.0%) 1 72 ast-stats-2 - BoundPredicate 72 ( 1.0%) 1 +ast-stats-2 ForeignItem 80 ( 1.1%) 1 80 +ast-stats-2 - Fn 80 ( 1.1%) 1 ast-stats-2 Local 80 ( 1.1%) 1 80 -ast-stats-2 ForeignItem 88 ( 1.2%) 1 88 -ast-stats-2 - Fn 88 ( 1.2%) 1 ast-stats-2 Arm 96 ( 1.3%) 2 48 ast-stats-2 FnDecl 120 ( 1.6%) 5 24 ast-stats-2 InlineAsm 120 ( 1.6%) 1 120 @@ -81,13 +81,13 @@ ast-stats-2 - Expr 96 ( 1.3%) 3 ast-stats-2 Block 192 ( 2.6%) 6 32 ast-stats-2 FieldDef 208 ( 2.8%) 2 104 ast-stats-2 Variant 208 ( 2.8%) 2 104 -ast-stats-2 AssocItem 352 ( 4.8%) 4 88 -ast-stats-2 - Fn 176 ( 2.4%) 2 -ast-stats-2 - Type 176 ( 2.4%) 2 +ast-stats-2 AssocItem 320 ( 4.3%) 4 80 +ast-stats-2 - Fn 160 ( 2.2%) 2 +ast-stats-2 - Type 160 ( 2.2%) 2 ast-stats-2 GenericBound 352 ( 4.8%) 4 88 ast-stats-2 - Trait 352 ( 4.8%) 4 ast-stats-2 GenericParam 480 ( 6.5%) 5 96 -ast-stats-2 Pat 504 ( 6.9%) 7 72 +ast-stats-2 Pat 504 ( 6.8%) 7 72 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1 ast-stats-2 - Ident 360 ( 4.9%) 5 @@ -96,24 +96,24 @@ ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - Match 72 ( 1.0%) 1 ast-stats-2 - Path 72 ( 1.0%) 1 ast-stats-2 - Struct 72 ( 1.0%) 1 -ast-stats-2 - Lit 144 ( 2.0%) 2 +ast-stats-2 - Lit 144 ( 1.9%) 2 ast-stats-2 - Block 216 ( 2.9%) 3 -ast-stats-2 PathSegment 864 (11.8%) 36 24 -ast-stats-2 Ty 896 (12.2%) 14 64 +ast-stats-2 PathSegment 864 (11.7%) 36 24 +ast-stats-2 Ty 896 (12.1%) 14 64 ast-stats-2 - Ptr 64 ( 0.9%) 1 ast-stats-2 - Ref 64 ( 0.9%) 1 ast-stats-2 - ImplicitSelf 128 ( 1.7%) 2 -ast-stats-2 - Path 640 ( 8.7%) 10 -ast-stats-2 Item 1_496 (20.3%) 11 136 -ast-stats-2 - Enum 136 ( 1.8%) 1 -ast-stats-2 - ExternCrate 136 ( 1.8%) 1 -ast-stats-2 - ForeignMod 136 ( 1.8%) 1 -ast-stats-2 - Impl 136 ( 1.8%) 1 -ast-stats-2 - Trait 136 ( 1.8%) 1 -ast-stats-2 - Fn 272 ( 3.7%) 2 -ast-stats-2 - Use 544 ( 7.4%) 4 +ast-stats-2 - Path 640 ( 8.6%) 10 +ast-stats-2 Item 1_584 (21.4%) 11 144 +ast-stats-2 - Enum 144 ( 1.9%) 1 +ast-stats-2 - ExternCrate 144 ( 1.9%) 1 +ast-stats-2 - ForeignMod 144 ( 1.9%) 1 +ast-stats-2 - Impl 144 ( 1.9%) 1 +ast-stats-2 - Trait 144 ( 1.9%) 1 +ast-stats-2 - Fn 288 ( 3.9%) 2 +ast-stats-2 - Use 576 ( 7.8%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_352 127 +ast-stats-2 Total 7_400 127 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size From ec10833609aa63327437aabfaedfbe8a0edcc4d9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Apr 2025 14:49:58 +1100 Subject: [PATCH 496/546] Address review comments. --- .../rustc_ast_passes/src/ast_validation.rs | 16 ++-- .../src/proc_macro_harness.rs | 7 +- compiler/rustc_expand/src/expand.rs | 4 +- compiler/rustc_parse/src/parser/item.rs | 33 ++++--- .../rustc_resolve/src/build_reduced_graph.rs | 85 ++++++++++--------- compiler/rustc_resolve/src/def_collector.rs | 5 +- compiler/rustc_resolve/src/late.rs | 5 +- .../rustc_resolve/src/late/diagnostics.rs | 10 +-- .../clippy_lints/src/empty_line_after.rs | 15 ++-- .../clippy/clippy_utils/src/ast_utils/mod.rs | 14 ++- src/tools/rustfmt/src/visitor.rs | 2 +- tests/ui/custom_test_frameworks/full.rs | 7 +- 12 files changed, 104 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 86661f3f3590..839d5d3bb954 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -817,10 +817,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } - if attr::contains_name(&item.attrs, sym::no_mangle) { - if let Some(ident) = item.kind.ident() { - self.check_nomangle_item_asciionly(ident, item.span); - } + if let Some(ident) = item.kind.ident() + && attr::contains_name(&item.attrs, sym::no_mangle) + { + self.check_nomangle_item_asciionly(ident, item.span); } match &item.kind { @@ -1412,10 +1412,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - if attr::contains_name(&item.attrs, sym::no_mangle) { - if let Some(ident) = item.kind.ident() { - self.check_nomangle_item_asciionly(ident, item.span); - } + if let Some(ident) = item.kind.ident() + && attr::contains_name(&item.attrs, sym::no_mangle) + { + self.check_nomangle_item_asciionly(ident, item.span); } if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() { diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 7c25f26895ca..8862965c0532 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -213,10 +213,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { return; }; - // First up, make sure we're checking a bare function. If we're not then - // we're just not interested in this item. - // - // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. + // Make sure we're checking a bare function. If we're not then we're + // just not interested any further in this item. let fn_ident = if let ast::ItemKind::Fn(fn_) = &item.kind { fn_.ident } else { @@ -243,6 +241,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { return; } + // Try to locate a `#[proc_macro_derive]` attribute. if attr.has_name(sym::proc_macro_derive) { self.collect_custom_derive(item, fn_ident, attr); } else if attr.has_name(sym::proc_macro_attribute) { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index d1dd454fa73d..bca846d2ec42 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1223,9 +1223,7 @@ impl InvocationCollectorNode for P { // Work around borrow checker not seeing through `P`'s deref. let (span, mut attrs) = (node.span, mem::take(&mut node.attrs)); - let ItemKind::Mod(_, ident, mod_kind) = &mut node.kind else { unreachable!() }; - let ident = *ident; - + let ItemKind::Mod(_, ident, ref mut mod_kind) = node.kind else { unreachable!() }; let ecx = &mut collector.cx; let (file_path, dir_path, dir_ownership) = match mod_kind { ModKind::Loaded(_, inline, _, _) => { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ed6522850960..e93fb2473fbf 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -243,8 +243,7 @@ impl<'a> Parser<'a> { // STATIC ITEM self.bump(); // `static` let mutability = self.parse_mutability(); - let item = self.parse_static_item(safety, mutability)?; - ItemKind::Static(Box::new(item)) + self.parse_static_item(safety, mutability)? } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -681,7 +680,7 @@ impl<'a> Parser<'a> { } None => (None, ty_first), // impl Type }; - let item_kind = ItemKind::Impl(Box::new(Impl { + Ok(ItemKind::Impl(Box::new(Impl { safety, polarity, defaultness, @@ -690,9 +689,7 @@ impl<'a> Parser<'a> { of_trait, self_ty, items: impl_items, - })); - - Ok(item_kind) + }))) } fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> { @@ -1222,13 +1219,12 @@ impl<'a> Parser<'a> { safety = Safety::Unsafe(self.token.span); let _ = self.eat_keyword(exp!(Unsafe)); } - let module = ast::ForeignMod { + Ok(ItemKind::ForeignMod(ast::ForeignMod { extern_span, safety, abi, items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?, - }; - Ok(ItemKind::ForeignMod(module)) + })) } /// Parses a foreign item (one in an `extern { ... }` block). @@ -1370,7 +1366,8 @@ impl<'a> Parser<'a> { Ok(item_kind) } - /// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in `mutability`. + /// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in + /// `mutability`. /// /// ```ebnf /// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ; @@ -1379,7 +1376,7 @@ impl<'a> Parser<'a> { &mut self, safety: Safety, mutability: Mutability, - ) -> PResult<'a, StaticItem> { + ) -> PResult<'a, ItemKind> { let ident = self.parse_ident()?; if self.token == TokenKind::Lt && self.may_recover() { @@ -1391,7 +1388,8 @@ impl<'a> Parser<'a> { // FIXME: This could maybe benefit from `.may_recover()`? let ty = match (self.eat(exp!(Colon)), self.check(exp!(Eq)) | self.check(exp!(Semi))) { (true, false) => self.parse_ty()?, - // If there wasn't a `:` or the colon was followed by a `=` or `;`, recover a missing type. + // If there wasn't a `:` or the colon was followed by a `=` or `;`, recover a missing + // type. (colon, _) => self.recover_missing_global_item_type(colon, Some(mutability)), }; @@ -1399,7 +1397,8 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok(StaticItem { ident, ty, safety, mutability, expr, define_opaque: None }) + let item = StaticItem { ident, ty, safety, mutability, expr, define_opaque: None }; + Ok(ItemKind::Static(Box::new(item))) } /// Parse a constant item with the prefix `"const"` already parsed. @@ -1537,7 +1536,7 @@ impl<'a> Parser<'a> { } let prev_span = self.prev_token.span; - let id = self.parse_ident()?; + let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; @@ -1548,10 +1547,10 @@ impl<'a> Parser<'a> { (thin_vec![], Trailing::No) } else { self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |p| { - p.parse_enum_variant(id.span) + p.parse_enum_variant(ident.span) }) .map_err(|mut err| { - err.span_label(id.span, "while parsing this enum"); + err.span_label(ident.span, "while parsing this enum"); if self.token == token::Colon { let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); @@ -1577,7 +1576,7 @@ impl<'a> Parser<'a> { }; let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() }; - Ok(ItemKind::Enum(id, enum_definition, generics)) + Ok(ItemKind::Enum(ident, enum_definition, generics)) } fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option> { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7f29f1a084e6..4368f7882ff4 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -10,8 +10,8 @@ use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::{ - self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, ForeignItem, - ForeignItemKind, Impl, Item, ItemKind, MetaItemKind, NodeId, StaticItem, StmtKind, + self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, + ForeignItemKind, Impl, Item, ItemKind, MetaItemKind, NodeId, StaticItem, StmtKind, TyAlias, }; use rustc_attr_parsing as attr; use rustc_expand::base::ResolverExpand; @@ -764,8 +764,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::ExternCrate(orig_name, ident) => { self.build_reduced_graph_for_extern_crate( orig_name, - ident, item, + ident, local_def_id, vis, parent, @@ -797,7 +797,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { | ItemKind::Static(box StaticItem { ident, .. }) => { self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } - ItemKind::Fn(box ast::Fn { ident, .. }) => { + ItemKind::Fn(box Fn { ident, .. }) => { self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); // Functions introducing procedural macros reserve a slot @@ -806,7 +806,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items live in the type namespace. - ItemKind::TyAlias(box ast::TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { + ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } @@ -900,8 +900,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { fn build_reduced_graph_for_extern_crate( &mut self, orig_name: Option, - ident: Ident, item: &Item, + ident: Ident, local_def_id: LocalDefId, vis: ty::Visibility, parent: Module<'ra>, @@ -1362,14 +1362,16 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { - if let ForeignItemKind::MacCall(_) = foreign_item.kind { - self.visit_invoc_in_module(foreign_item.id); - return; - } + let ident = match foreign_item.kind { + ForeignItemKind::Static(box StaticItem { ident, .. }) + | ForeignItemKind::Fn(box Fn { ident, .. }) + | ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => ident, + ForeignItemKind::MacCall(_) => { + self.visit_invoc_in_module(foreign_item.id); + return; + } + }; - // `unwrap` is safe because `MacCall` has been excluded, and other foreign item kinds have - // an ident. - let ident = foreign_item.kind.ident().unwrap(); self.build_reduced_graph_for_foreign_item(foreign_item, ident); visit::walk_item(self, foreign_item); } @@ -1384,26 +1386,35 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - if let AssocItemKind::MacCall(_) = item.kind { - match ctxt { - AssocCtxt::Trait => { - self.visit_invoc_in_module(item.id); - } - AssocCtxt::Impl { .. } => { - let invoc_id = item.id.placeholder_to_expn_id(); - if !self.r.glob_delegation_invoc_ids.contains(&invoc_id) { - self.r - .impl_unexpanded_invocations - .entry(self.r.invocation_parent(invoc_id)) - .or_default() - .insert(invoc_id); - } - self.visit_invoc(item.id); - } - } - return; - } + let (ident, ns) = match item.kind { + AssocItemKind::Const(box ConstItem { ident, .. }) + | AssocItemKind::Fn(box Fn { ident, .. }) + | AssocItemKind::Delegation(box Delegation { ident, .. }) => (ident, ValueNS), + AssocItemKind::Type(box TyAlias { ident, .. }) => (ident, TypeNS), + + AssocItemKind::MacCall(_) => { + match ctxt { + AssocCtxt::Trait => { + self.visit_invoc_in_module(item.id); + } + AssocCtxt::Impl { .. } => { + let invoc_id = item.id.placeholder_to_expn_id(); + if !self.r.glob_delegation_invoc_ids.contains(&invoc_id) { + self.r + .impl_unexpanded_invocations + .entry(self.r.invocation_parent(invoc_id)) + .or_default() + .insert(invoc_id); + } + self.visit_invoc(item.id); + } + } + return; + } + + AssocItemKind::DelegationMac(..) => bug!(), + }; let vis = self.resolve_visibility(&item.vis); let feed = self.r.feed(item.id); let local_def_id = feed.key(); @@ -1418,16 +1429,6 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.feed_visibility(feed, vis); } - let ns = match item.kind { - AssocItemKind::Const(..) | AssocItemKind::Delegation(..) | AssocItemKind::Fn(..) => { - ValueNS - } - AssocItemKind::Type(..) => TypeNS, - AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above - }; - // `unwrap` is safe because `MacCall`/`DelegationMac` have been excluded, and other foreign - // item kinds have an ident. - let ident = item.kind.ident().unwrap(); if ctxt == AssocCtxt::Trait { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 6ad056edbaf8..13dfb59f27fc 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -186,8 +186,11 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { FnKind::Fn( _ctxt, _vis, - Fn { sig: FnSig { header, decl, span: _ }, generics, contract, body, .. }, + Fn { + sig: FnSig { header, decl, span: _ }, ident, generics, contract, body, .. + }, ) if let Some(coroutine_kind) = header.coroutine_kind => { + self.visit_ident(ident); self.visit_fn_header(header); self.visit_generics(generics); if let Some(contract) = contract { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index d4dd0800452a..20e19caf9096 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1025,9 +1025,10 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. - FnKind::Fn(FnCtxt::Foreign, _, Fn { sig, generics, .. }) - | FnKind::Fn(_, _, Fn { sig, generics, body: None, .. }) => { + FnKind::Fn(FnCtxt::Foreign, _, Fn { sig, ident, generics, .. }) + | FnKind::Fn(_, _, Fn { sig, ident, generics, body: None, .. }) => { self.visit_fn_header(&sig.header); + self.visit_ident(ident); self.visit_generics(generics); self.with_lifetime_rib( LifetimeRibKind::AnonymousCreateParameter { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2a2b1ecef161..b62bc6c45e0c 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -227,14 +227,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = fn_kind && let Some(items) = self.diag_metadata.current_impl_items && let Some(item) = items.iter().find(|i| { - if let Some(ident) = i.kind.ident() - && ident.name == item_str.name - { + i.kind.ident().is_some_and(|ident| { // Don't suggest if the item is in Fn signature arguments (#112590). - !sig.span.contains(item_span) - } else { - false - } + ident.name == item_str.name && !sig.span.contains(item_span) + }) }) { let sp = item_span.shrink_to_lo(); diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs index 899b5c595261..c67dcd3c82b5 100644 --- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs +++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs @@ -8,8 +8,7 @@ use rustc_errors::{Applicability, Diag, SuggestionStyle}; use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::kw; -use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, sym}; +use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, kw}; declare_clippy_lint! { /// ### What it does @@ -375,14 +374,16 @@ impl EmptyLineAfter { &mut self, cx: &EarlyContext<'_>, kind: &ItemKind, - ident: &Option, + ident: Option, span: Span, attrs: &[Attribute], id: NodeId, ) { self.items.push(ItemInfo { kind: kind.descr(), - name: if let Some(ident) = ident { ident.name } else { sym::dummy }, + // FIXME: this `sym::empty` can be leaked, see + // https://github.com/rust-lang/rust/pull/138740#discussion_r2021979899 + name: if let Some(ident) = ident { ident.name } else { kw::Empty }, span: if let Some(ident) = ident { span.with_hi(ident.span.hi()) } else { @@ -471,7 +472,7 @@ impl EarlyLintPass for EmptyLineAfter { self.check_item_kind( cx, &item.kind.clone().into(), - &item.kind.ident(), + item.kind.ident(), item.span, &item.attrs, item.id, @@ -482,7 +483,7 @@ impl EarlyLintPass for EmptyLineAfter { self.check_item_kind( cx, &item.kind.clone().into(), - &item.kind.ident(), + item.kind.ident(), item.span, &item.attrs, item.id, @@ -490,6 +491,6 @@ impl EarlyLintPass for EmptyLineAfter { } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - self.check_item_kind(cx, &item.kind, &item.kind.ident(), item.span, &item.attrs, item.id); + self.check_item_kind(cx, &item.kind, item.kind.ident(), item.span, &item.attrs, item.id); } } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index ff63eb505a5c..eba576392ebc 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -567,20 +567,23 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { ( TyAlias(box ast::TyAlias { defaultness: ld, + ident: li, generics: lg, + where_clauses: _, bounds: lb, ty: lt, - .. }), TyAlias(box ast::TyAlias { defaultness: rd, + ident: ri, generics: rg, + where_clauses: _, bounds: rb, ty: rt, - .. }), ) => { eq_defaultness(*ld, *rd) + && eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) && both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r)) @@ -647,20 +650,23 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ( Type(box TyAlias { defaultness: ld, + ident: li, generics: lg, + where_clauses: _, bounds: lb, ty: lt, - .. }), Type(box TyAlias { defaultness: rd, + ident: ri, generics: rg, + where_clauses: _, bounds: rb, ty: rt, - .. }), ) => { eq_defaultness(*ld, *rd) + && eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) && both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r)) diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 1dc0a9069231..16d1f5105d5f 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -623,13 +623,13 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { fn visit_assoc_item(&mut self, ai: &ast::AssocItem, visitor_kind: ItemVisitorKind) { use ItemVisitorKind::*; - // TODO(calebcartwright): Not sure the skip spans are correct let assoc_ctxt = match visitor_kind { AssocTraitItem => visit::AssocCtxt::Trait, // There is no difference between trait and inherent assoc item formatting AssocImplItem => visit::AssocCtxt::Impl { of_trait: false }, _ => unreachable!(), }; + // TODO(calebcartwright): Not sure the skip spans are correct let skip_span = ai.span; skip_out_of_file_lines_range_visitor!(self, ai.span); diff --git a/tests/ui/custom_test_frameworks/full.rs b/tests/ui/custom_test_frameworks/full.rs index 6be29f0418d6..57b55e9437bf 100644 --- a/tests/ui/custom_test_frameworks/full.rs +++ b/tests/ui/custom_test_frameworks/full.rs @@ -28,12 +28,13 @@ const TEST_1: IsFoo = IsFoo("hello"); static TEST_2: IsFoo = IsFoo("foo"); // FIXME: `test_case` is currently ignored on anything other than -// fn/const/static. Should this be a warning/error? +// fn/const/static. This should be an error. Compare this with `#[test]` and +// #[bench] whose expanders emit "error: expected a non-associated function, +// found […]" if applied to invalid items. #[test_case] struct _S; -// FIXME: `test_case` is currently ignored on anything other than -// fn/const/static. Should this be a warning/error? +// FIXME: as above. #[test_case] impl _S { fn _f() {} From cb7ebf6f05a08a3dc7d2562eed1a3e3c5523ff3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 1 Apr 2025 07:57:05 +0200 Subject: [PATCH 497/546] Bump metadata version --- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index bbdc986ef7a2..f4cf338ffb5d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -56,7 +56,7 @@ pub(crate) fn rustc_version(cfg_version: &'static str) -> String { /// Metadata encoding version. /// N.B., increment this if you change the format of metadata such that /// the rustc version can't be found to compare with `rustc_version()`. -const METADATA_VERSION: u8 = 9; +const METADATA_VERSION: u8 = 10; /// Metadata header which includes `METADATA_VERSION`. /// From 27b866d59a3e5ccbaf9723a37d353db6d2079f16 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 1 Apr 2025 13:22:45 +0800 Subject: [PATCH 498/546] Add ui test ui/traits/object/suggestion-trait-object-issue-139174.rs Signed-off-by: xizheyin --- .../suggestion-trait-object-issue-139174.rs | 24 ++++++++ ...uggestion-trait-object-issue-139174.stderr | 55 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/ui/traits/object/suggestion-trait-object-issue-139174.rs create mode 100644 tests/ui/traits/object/suggestion-trait-object-issue-139174.stderr diff --git a/tests/ui/traits/object/suggestion-trait-object-issue-139174.rs b/tests/ui/traits/object/suggestion-trait-object-issue-139174.rs new file mode 100644 index 000000000000..f8fa410b7d49 --- /dev/null +++ b/tests/ui/traits/object/suggestion-trait-object-issue-139174.rs @@ -0,0 +1,24 @@ +//@compile-flags: --edition 2021 + +fn f<'a>(x: Box Option>) -> usize { + //~^ ERROR expected trait, found builtin type `usize` + //~| ERROR expected a type, found a trait [E0782] + 0 +} + +fn create_adder<'a>(x: i32) -> usize + 'a { + //~^ ERROR expected trait, found builtin type `usize` + //~| ERROR expected a type, found a trait [E0782] + move |y| x + y +} + +struct Struct<'a>{ + x: usize + 'a, + //~^ ERROR expected trait, found builtin type `usize` + //~| ERROR expected a type, found a trait [E0782] +} + + +fn main() { + +} diff --git a/tests/ui/traits/object/suggestion-trait-object-issue-139174.stderr b/tests/ui/traits/object/suggestion-trait-object-issue-139174.stderr new file mode 100644 index 000000000000..ddee0d5586b0 --- /dev/null +++ b/tests/ui/traits/object/suggestion-trait-object-issue-139174.stderr @@ -0,0 +1,55 @@ +error[E0404]: expected trait, found builtin type `usize` + --> $DIR/suggestion-trait-object-issue-139174.rs:3:36 + | +LL | fn f<'a>(x: Box Option>) -> usize { + | ^^^^^ not a trait + +error[E0404]: expected trait, found builtin type `usize` + --> $DIR/suggestion-trait-object-issue-139174.rs:9:32 + | +LL | fn create_adder<'a>(x: i32) -> usize + 'a { + | ^^^^^ not a trait + +error[E0404]: expected trait, found builtin type `usize` + --> $DIR/suggestion-trait-object-issue-139174.rs:16:8 + | +LL | x: usize + 'a, + | ^^^^^ not a trait + +error[E0782]: expected a type, found a trait + --> $DIR/suggestion-trait-object-issue-139174.rs:3:36 + | +LL | fn f<'a>(x: Box Option>) -> usize { + | ^^^^^^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | fn f<'a>(x: Box Option>) -> usize { + | +++ + +error[E0782]: expected a type, found a trait + --> $DIR/suggestion-trait-object-issue-139174.rs:9:32 + | +LL | fn create_adder<'a>(x: i32) -> usize + 'a { + | ^^^^^^^^^^ + | +help: `usize + 'a` is dyn-incompatible, use `impl usize + 'a` to return an opaque type, as long as you return a single underlying type + | +LL | fn create_adder<'a>(x: i32) -> impl usize + 'a { + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/suggestion-trait-object-issue-139174.rs:16:8 + | +LL | x: usize + 'a, + | ^^^^^^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | x: dyn usize + 'a, + | +++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0404, E0782. +For more information about an error, try `rustc --explain E0404`. From 12604fa071b01f7342520224507e43e432294c2c Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 1 Apr 2025 14:19:40 +0800 Subject: [PATCH 499/546] Skip suggest impl or dyn when poly trait is not a real trait Signed-off-by: xizheyin --- .../src/hir_ty_lowering/lint.rs | 1 + .../suggestion-trait-object-issue-139174.stderr | 15 --------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 558863122844..8e62dce21913 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -86,6 +86,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { "expected a type, found a trait" ); if self_ty.span.can_be_used_for_suggestions() + && poly_trait_ref.trait_ref.trait_def_id().is_some() && !self.maybe_suggest_impl_trait(self_ty, &mut diag) && !self.maybe_suggest_dyn_trait(self_ty, sugg, &mut diag) { diff --git a/tests/ui/traits/object/suggestion-trait-object-issue-139174.stderr b/tests/ui/traits/object/suggestion-trait-object-issue-139174.stderr index ddee0d5586b0..0d1ce85fc288 100644 --- a/tests/ui/traits/object/suggestion-trait-object-issue-139174.stderr +++ b/tests/ui/traits/object/suggestion-trait-object-issue-139174.stderr @@ -21,33 +21,18 @@ error[E0782]: expected a type, found a trait | LL | fn f<'a>(x: Box Option>) -> usize { | ^^^^^^^^^^ - | -help: you can add the `dyn` keyword if you want a trait object - | -LL | fn f<'a>(x: Box Option>) -> usize { - | +++ error[E0782]: expected a type, found a trait --> $DIR/suggestion-trait-object-issue-139174.rs:9:32 | LL | fn create_adder<'a>(x: i32) -> usize + 'a { | ^^^^^^^^^^ - | -help: `usize + 'a` is dyn-incompatible, use `impl usize + 'a` to return an opaque type, as long as you return a single underlying type - | -LL | fn create_adder<'a>(x: i32) -> impl usize + 'a { - | ++++ error[E0782]: expected a type, found a trait --> $DIR/suggestion-trait-object-issue-139174.rs:16:8 | LL | x: usize + 'a, | ^^^^^^^^^^ - | -help: you can add the `dyn` keyword if you want a trait object - | -LL | x: dyn usize + 'a, - | +++ error: aborting due to 6 previous errors From f0efb9748ea02b7e6f15bef45881403ddcfba125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 1 Apr 2025 08:59:04 +0200 Subject: [PATCH 500/546] Support metadata version 10 in proc-macro-srv --- .../rust-analyzer/crates/proc-macro-srv/src/dylib/version.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/version.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/version.rs index 4e28aaced9b0..7668f419040c 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/version.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/version.rs @@ -110,7 +110,7 @@ pub fn read_version(obj: &object::File<'_>) -> io::Result { )); } let version = u32::from_be_bytes([dot_rustc[4], dot_rustc[5], dot_rustc[6], dot_rustc[7]]); - // Last supported version is: + // Last breaking version change is: // https://github.com/rust-lang/rust/commit/b94cfefc860715fb2adf72a6955423d384c69318 let (mut metadata_portion, bytes_before_version) = match version { 8 => { @@ -118,7 +118,7 @@ pub fn read_version(obj: &object::File<'_>) -> io::Result { let data_len = u32::from_be_bytes(len_bytes.try_into().unwrap()) as usize; (&dot_rustc[12..data_len + 12], 13) } - 9 => { + 9 | 10 => { let len_bytes = &dot_rustc[8..16]; let data_len = u64::from_le_bytes(len_bytes.try_into().unwrap()) as usize; (&dot_rustc[16..data_len + 12], 17) From f153685fd0478fbbc346cfeb49f57965a9bc43d1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 25 Mar 2025 15:36:26 +0100 Subject: [PATCH 501/546] Improve docs of ValTreeKind --- compiler/rustc_middle/src/ty/consts/valtree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 72263d845808..2f21d19e03c7 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -33,7 +33,7 @@ pub enum ValTreeKind<'tcx> { /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by /// listing their fields' values in order. /// - /// Enums are represented by storing their discriminant as a field, followed by all + /// Enums are represented by storing their variant index as a u32 field, followed by all /// the fields of the variant. /// /// ZST types are represented as an empty slice. From a7b687c26ef55bfc3481761fef6e46154e5f95ea Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 11:48:06 +0000 Subject: [PATCH 502/546] Decouple trait impls of different traits wrt incremental --- compiler/rustc_hir_analysis/src/coherence/mod.rs | 5 ++++- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_middle/src/hir/mod.rs | 2 ++ compiler/rustc_middle/src/query/mod.rs | 5 +++++ src/tools/clippy/clippy_lints/src/derive.rs | 6 ++---- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 15e0a72fdcbd..16bac4304910 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -153,9 +153,12 @@ pub(crate) fn provide(providers: &mut Providers) { } fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> { + let impls = tcx.local_trait_impls(def_id); // 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(()) }; + if impls.is_empty() { + return Ok(()); + } // Trigger building the specialization graph for the trait. This will detect and report any // overlap errors. let mut res = tcx.ensure_ok().specialization_graph_of(def_id); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 52f155a16b86..80370910032d 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -368,7 +368,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn hir_trait_impls(self, trait_did: DefId) -> &'tcx [LocalDefId] { - self.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..]) + self.local_trait_impls(trait_did) } /// Gets the attributes on the crate. This is preferable to diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 347bc5ea3128..cae9b2fb5448 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -238,6 +238,8 @@ pub fn provide(providers: &mut Providers) { } }; providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; + providers.local_trait_impls = + |tcx, trait_id| tcx.resolutions(()).trait_impls.get(&trait_id).map_or(&[], |xs| &xs[..]); providers.expn_that_defined = |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()); providers.in_scope_traits_map = |tcx, id| { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d7ed703f4ae3..4b3236e4b841 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1502,6 +1502,11 @@ rustc_queries! { desc { "finding local trait impls" } } + /// Return all `impl` blocks of the given trait in the current crate. + query local_trait_impls(trait_id: DefId) -> &'tcx [LocalDefId] { + desc { "finding local trait impls of `{}`", tcx.def_path_str(trait_id) } + } + /// Given a trait `trait_id`, return all known `impl` blocks. query trait_impls_of(trait_id: DefId) -> &'tcx ty::trait_def::TraitImpls { arena_cache diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 2ae35b400557..fae01026487a 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -324,11 +324,9 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h // there's a Copy impl for any instance of the adt. if !is_copy(cx, ty) { if ty_subs.non_erasable_generics().next().is_some() { - let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).is_some_and(|impls| { - impls.iter().any(|&id| { - matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) + let has_copy_impl = cx.tcx.local_trait_impls(copy_id).iter().any(|&id| { + matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()) - }) }); if !has_copy_impl { return; From aec77398378cc7af99043c3d1dd2394eb3d33c43 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:03:48 +0000 Subject: [PATCH 503/546] Remove an unnecessary dtor computation and use the cached query result instead --- compiler/rustc_mir_transform/src/check_const_item_mutation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index ceea72c6755a..76d1e671c5d8 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -53,7 +53,7 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { // // #[const_mutation_allowed] // pub const LOG: Log = Log { msg: "" }; - match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) { + match self.tcx.adt_destructor(def_id) { Some(_) => None, None => Some(def_id), } From c0fe46d6b72c96bda16bf62e7476e6d85ba68afe Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:08:00 +0000 Subject: [PATCH 504/546] Make missing optimized MIR error more informative --- compiler/rustc_monomorphize/messages.ftl | 2 +- compiler/rustc_monomorphize/src/collector.rs | 1 + compiler/rustc_monomorphize/src/errors.rs | 1 + tests/ui/rmeta/no_optitimized_mir.rs | 2 +- tests/ui/rmeta/no_optitimized_mir.stderr | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index aae2d79c1610..6b6653e7de02 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -48,7 +48,7 @@ monomorphize_large_assignments = .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` monomorphize_no_optimized_mir = - missing optimized MIR for an item in the crate `{$crate_name}` + missing optimized MIR for `{$instance}` in the crate `{$crate_name}` .note = missing optimized MIR for this item (was the crate `{$crate_name}` compiled with `--emit=metadata`?) monomorphize_recursion_limit = diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 2a1b20ba48b8..6e676ac6b8d5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -989,6 +989,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> tcx.dcx().emit_fatal(NoOptimizedMir { span: tcx.def_span(def_id), crate_name: tcx.crate_name(def_id.krate), + instance: instance.to_string(), }); } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index dffa372279f9..adfe096f0cdc 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -24,6 +24,7 @@ pub(crate) struct NoOptimizedMir { #[note] pub span: Span, pub crate_name: Symbol, + pub instance: String, } #[derive(LintDiagnostic)] diff --git a/tests/ui/rmeta/no_optitimized_mir.rs b/tests/ui/rmeta/no_optitimized_mir.rs index 708cdfc803fa..c8ed00b039b2 100644 --- a/tests/ui/rmeta/no_optitimized_mir.rs +++ b/tests/ui/rmeta/no_optitimized_mir.rs @@ -10,4 +10,4 @@ fn main() { rmeta_meta::missing_optimized_mir(); } -//~? ERROR missing optimized MIR for an item in the crate `rmeta_meta` +//~? ERROR missing optimized MIR for `missing_optimized_mir` in the crate `rmeta_meta` diff --git a/tests/ui/rmeta/no_optitimized_mir.stderr b/tests/ui/rmeta/no_optitimized_mir.stderr index 92f22d780005..254f100aa7b5 100644 --- a/tests/ui/rmeta/no_optitimized_mir.stderr +++ b/tests/ui/rmeta/no_optitimized_mir.stderr @@ -1,4 +1,4 @@ -error: missing optimized MIR for an item in the crate `rmeta_meta` +error: missing optimized MIR for `missing_optimized_mir` in the crate `rmeta_meta` | note: missing optimized MIR for this item (was the crate `rmeta_meta` compiled with `--emit=metadata`?) --> $DIR/auxiliary/rmeta-meta.rs:10:1 From 23f1fb58f201cce980128a0dae491c4e5393629a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:08:00 +0000 Subject: [PATCH 505/546] Store adt_destructor in metadata --- compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 5 +---- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/ty/parameterized.rs | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 776b081a4630..5c425e7a4185 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -330,10 +330,7 @@ provide! { tcx, def_id, other, cdata, visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } - adt_destructor => { - let _ = cdata; - tcx.calculate_dtor(def_id, |_,_| Ok(())) - } + adt_destructor => { table } adt_async_destructor => { let _ = cdata; tcx.calculate_async_dtor(def_id, |_,_| Ok(())) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7ab3d432bdf8..a9beab1a70a3 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1633,6 +1633,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.fn_sig[variant.def_id] <- fn_sig); } } + + if let Some(destructor) = tcx.adt_destructor(local_def_id) { + record!(self.tables.adt_destructor[def_id] <- destructor); + } } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index dc453b1e747c..fb5fcff8d33d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -446,6 +446,7 @@ define_tables! { fn_arg_names: Table>>, coroutine_kind: Table, coroutine_for_closure: Table, + adt_destructor: Table>, coroutine_by_move_body_def_id: Table, eval_static_initializer: Table>>, trait_def: Table>, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 19e2b5745632..d6f181669563 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! { ty::AssocItemContainer, ty::Asyncness, ty::DeducedParamAttrs, + ty::Destructor, ty::Generics, ty::ImplPolarity, ty::ImplTraitInTraitData, From 2b1c416da724a45f5a9c8e501c27a87ca4b536cc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:46:04 +0000 Subject: [PATCH 506/546] Store adt_async_destructor in metadata --- compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 5 +---- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/ty/parameterized.rs | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 5c425e7a4185..3dc82ce9d183 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -331,10 +331,7 @@ provide! { tcx, def_id, other, cdata, visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { table } - adt_async_destructor => { - let _ = cdata; - tcx.calculate_async_dtor(def_id, |_,_| Ok(())) - } + adt_async_destructor => { table } associated_item_def_ids => { tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index)) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a9beab1a70a3..b6f799e7ff79 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1637,6 +1637,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let Some(destructor) = tcx.adt_destructor(local_def_id) { record!(self.tables.adt_destructor[def_id] <- destructor); } + + if let Some(destructor) = tcx.adt_async_destructor(local_def_id) { + record!(self.tables.adt_async_destructor[def_id] <- destructor); + } } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index fb5fcff8d33d..8fef3ef23555 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -447,6 +447,7 @@ define_tables! { coroutine_kind: Table, coroutine_for_closure: Table, adt_destructor: Table>, + adt_async_destructor: Table>, coroutine_by_move_body_def_id: Table, eval_static_initializer: Table>>, trait_def: Table>, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index d6f181669563..61b35b33a096 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -65,6 +65,7 @@ trivially_parameterized_over_tcx! { crate::middle::lib_features::FeatureStability, crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, + ty::AsyncDestructor, ty::AssocItemContainer, ty::Asyncness, ty::DeducedParamAttrs, From 51184c70c897619f6a2883538f8a85292306a0c8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:48:54 +0000 Subject: [PATCH 507/546] Ensure `calculcate_dtor` is only ever called on local types --- compiler/rustc_hir_analysis/src/check/mod.rs | 4 ++-- compiler/rustc_middle/src/ty/util.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index d8ae42145275..ee1e78a79cd4 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -114,11 +114,11 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_dtor(def_id.to_def_id(), always_applicable::check_drop_impl) + tcx.calculate_dtor(def_id, always_applicable::check_drop_impl) } fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_async_dtor(def_id.to_def_id(), always_applicable::check_drop_impl) + tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl) } /// Given a `DefId` for an opaque type in return position, find its parent item's return diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c0d4130336e5..61d8b5ce52ed 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -389,7 +389,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Calculate the destructor of a given type. pub fn calculate_dtor( self, - adt_did: DefId, + adt_did: LocalDefId, validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let drop_trait = self.lang_items().drop_trait()?; @@ -426,7 +426,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Calculate the async destructor of a given type. pub fn calculate_async_dtor( self, - adt_did: DefId, + adt_did: LocalDefId, validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let async_drop_trait = self.lang_items().async_drop_trait()?; From 2dc650b97b240c0bd279704b01916970c2031c4b Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 28 Mar 2025 18:12:29 +0530 Subject: [PATCH 508/546] replace commit placeholder in vendor status with actual commit --- src/bootstrap/bootstrap.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 68400ba0ea02..140f601253c3 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1162,6 +1162,30 @@ class RustBuild(object): config = self.get_toml("build") return config or default_build_triple(self.verbose) + def is_git_repository(self, repo_path): + return os.path.isdir(os.path.join(repo_path, ".git")) + + def get_latest_commit(self): + repo_path = self.rust_root + author_email = self.stage0_data.get("git_merge_commit_email") + if not self.is_git_repository(repo_path): + return "" + cmd = [ + "git", + "-C", + repo_path, + "rev-list", + "--author", + author_email, + "-n1", + "HEAD", + ] + try: + commit = subprocess.check_output(cmd, universal_newlines=True).strip() + return commit or "" + except subprocess.CalledProcessError: + return "" + def check_vendored_status(self): """Check that vendoring is configured properly""" # keep this consistent with the equivalent check in bootstrap: @@ -1174,7 +1198,8 @@ class RustBuild(object): eprint(" use vendored sources by default.") cargo_dir = os.path.join(self.rust_root, ".cargo") - url = "https://ci-artifacts.rust-lang.org/rustc-builds//rustc-nightly-src.tar.xz" + commit = self.get_latest_commit() + url = f"https://ci-artifacts.rust-lang.org/rustc-builds/{commit}/rustc-nightly-src.tar.xz" if self.use_vendored_sources: vendor_dir = os.path.join(self.rust_root, "vendor") if not os.path.exists(vendor_dir): From 624eb8550b8411a8b8773acf3fce0082f9554a7b Mon Sep 17 00:00:00 2001 From: highcloudwind Date: Tue, 1 Apr 2025 21:05:34 +0800 Subject: [PATCH 509/546] chore: remove redundant backtick Signed-off-by: highcloudwind --- src/etc/test-float-parse/src/ui.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/test-float-parse/src/ui.rs b/src/etc/test-float-parse/src/ui.rs index 1ee57723e6a6..73473eef0bfd 100644 --- a/src/etc/test-float-parse/src/ui.rs +++ b/src/etc/test-float-parse/src/ui.rs @@ -157,7 +157,7 @@ pub fn set_panic_hook(drop_bars: &[ProgressBar]) { })); } -/// Allow non-Debug items in a `derive(Debug)` struct`. +/// Allow non-Debug items in a `derive(Debug)` struct. #[derive(Clone)] struct NoDebug(T); From e638ba69f09d72b0f1e2f00b03ff530460d1bfe3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Apr 2025 15:11:10 +0200 Subject: [PATCH 510/546] interpret: add a version of run_for_validation for &self --- .../rustc_const_eval/src/interpret/memory.rs | 43 ++++++++++++++----- .../src/interpret/validity.rs | 2 +- src/tools/miri/src/concurrency/data_race.rs | 2 +- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 8f286971e638..d077900587e9 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -8,8 +8,9 @@ use std::assert_matches::assert_matches; use std::borrow::{Borrow, Cow}; +use std::cell::Cell; use std::collections::VecDeque; -use std::{fmt, mem, ptr}; +use std::{fmt, ptr}; use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; @@ -131,7 +132,7 @@ pub struct Memory<'tcx, M: Machine<'tcx>> { /// This stores whether we are currently doing reads purely for the purpose of validation. /// Those reads do not trigger the machine's hooks for memory reads. /// Needless to say, this must only be set with great care! - validation_in_progress: bool, + validation_in_progress: Cell, } /// A reference to some allocation that was already bounds-checked for the given region @@ -158,7 +159,7 @@ impl<'tcx, M: Machine<'tcx>> Memory<'tcx, M> { alloc_map: M::MemoryMap::default(), extra_fn_ptr_map: FxIndexMap::default(), dead_alloc_map: FxIndexMap::default(), - validation_in_progress: false, + validation_in_progress: Cell::new(false), } } @@ -715,7 +716,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // We want to call the hook on *all* accesses that involve an AllocId, including zero-sized // accesses. That means we cannot rely on the closure above or the `Some` branch below. We // do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked. - if !self.memory.validation_in_progress { + if !self.memory.validation_in_progress.get() { if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) { M::before_alloc_read(self, alloc_id)?; } @@ -723,7 +724,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { let range = alloc_range(offset, size); - if !self.memory.validation_in_progress { + if !self.memory.validation_in_progress.get() { M::before_memory_read( self.tcx, &self.machine, @@ -801,7 +802,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option>> { let tcx = self.tcx; - let validation_in_progress = self.memory.validation_in_progress; + let validation_in_progress = self.memory.validation_in_progress.get(); let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes let ptr_and_alloc = Self::check_and_deref_ptr( @@ -1087,23 +1088,43 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// /// We do this so Miri's allocation access tracking does not show the validation /// reads as spurious accesses. - pub fn run_for_validation(&mut self, f: impl FnOnce(&mut Self) -> R) -> R { + pub fn run_for_validation_mut(&mut self, f: impl FnOnce(&mut Self) -> R) -> R { // This deliberately uses `==` on `bool` to follow the pattern // `assert!(val.replace(new) == old)`. assert!( - mem::replace(&mut self.memory.validation_in_progress, true) == false, + self.memory.validation_in_progress.replace(true) == false, "`validation_in_progress` was already set" ); let res = f(self); assert!( - mem::replace(&mut self.memory.validation_in_progress, false) == true, + self.memory.validation_in_progress.replace(false) == true, + "`validation_in_progress` was unset by someone else" + ); + res + } + + /// Runs the closure in "validation" mode, which means the machine's memory read hooks will be + /// suppressed. Needless to say, this must only be set with great care! Cannot be nested. + /// + /// We do this so Miri's allocation access tracking does not show the validation + /// reads as spurious accesses. + pub fn run_for_validation_ref(&self, f: impl FnOnce(&Self) -> R) -> R { + // This deliberately uses `==` on `bool` to follow the pattern + // `assert!(val.replace(new) == old)`. + assert!( + self.memory.validation_in_progress.replace(true) == false, + "`validation_in_progress` was already set" + ); + let res = f(self); + assert!( + self.memory.validation_in_progress.replace(false) == true, "`validation_in_progress` was unset by someone else" ); res } pub(super) fn validation_in_progress(&self) -> bool { - self.memory.validation_in_progress + self.memory.validation_in_progress.get() } } @@ -1375,7 +1396,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); - assert!(!self.memory.validation_in_progress, "we can't be copying during validation"); + assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation"); // For the overlapping case, it is crucial that we trigger the read hook // before the write hook -- the aliasing model cares about the order. M::before_memory_read( diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index eb3f552cd278..fb7ba6d7ef57 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1322,7 +1322,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty); // Run the visitor. - self.run_for_validation(|ecx| { + self.run_for_validation_mut(|ecx| { let reset_padding = reset_provenance_and_padding && { // Check if `val` is actually stored in memory. If not, padding is not even // represented and we need not reset it. diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index b1ca434361b4..923031dbbd1e 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -717,7 +717,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // The program didn't actually do a read, so suppress the memory access hooks. // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! - let old_val = this.run_for_validation(|this| this.read_scalar(dest)).discard_err(); + let old_val = this.run_for_validation_mut(|this| this.read_scalar(dest)).discard_err(); this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; this.validate_atomic_store(dest, atomic)?; this.buffered_atomic_write(val, dest, atomic, old_val) From d2358f7f2e1ec1a058308fc3149ecd5e7d3d4a12 Mon Sep 17 00:00:00 2001 From: futreall <86553580+futreall@users.noreply.github.com> Date: Tue, 1 Apr 2025 15:26:55 +0300 Subject: [PATCH 511/546] fix link in netbsd.md Update netbsd.md Update netbsd.md --- src/doc/rustc/src/platform-support/netbsd.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md index ef9337befa64..5c2ce0ee9005 100644 --- a/src/doc/rustc/src/platform-support/netbsd.md +++ b/src/doc/rustc/src/platform-support/netbsd.md @@ -34,7 +34,7 @@ are built for NetBSD 8.x but also work on newer OS versions). ## Designated Developers - [@he32](https://github.com/he32), `he@NetBSD.org` -- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust +- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust185/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust - [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc. - [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself From 6c3be19f578f589431d0bcc8c0b71b204d2241c1 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 1 Apr 2025 06:47:55 -0700 Subject: [PATCH 512/546] Update mdbook to 0.4.48 This brings in several updates. Two significant ones are to halve the search index size, and the other introduces major changes to footnote rendering. Changelog: https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-0448 --- src/doc/rustc/src/SUMMARY.md | 3 +-- src/tools/rustbook/Cargo.lock | 4 ++-- src/tools/rustbook/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index d08e0bd1edf2..e1ba27c07dae 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -102,7 +102,7 @@ - [s390x-unknown-linux-gnu](platform-support/s390x-unknown-linux-gnu.md) - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) - - [sparcv9-sun-solaris](platform-support/solaris.md) + - [solaris](platform-support/solaris.md) - [\*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) - [\*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md) @@ -126,7 +126,6 @@ - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md) - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md) - [x86_64-pc-cygwin](platform-support/x86_64-pc-cygwin.md) - - [x86_64-pc-solaris](platform-support/solaris.md) - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [xtensa-\*-none-elf](platform-support/xtensa.md) diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index e54747c129a0..a1ccaa487490 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -880,9 +880,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.47" +version = "0.4.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e1a8fe3a4a01f28dab245c474cb7b95ccb4d3d2f17a5419a3d949f474c45e84" +checksum = "8b6fbb4ac2d9fd7aa987c3510309ea3c80004a968d063c42f0d34fea070817c1" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 831233e3065d..a0b220c3557d 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.47" +version = "0.4.48" default-features = false features = ["search"] From 770fcbf8c13871620b689fcadec36f5936c5fe5a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:11:58 +0000 Subject: [PATCH 513/546] Move test-float-parse to the 2024 edition --- src/etc/test-float-parse/Cargo.toml | 2 +- .../src/{gen => gen_}/exhaustive.rs | 0 .../src/{gen => gen_}/exponents.rs | 0 .../src/{gen => gen_}/fuzz.rs | 0 .../src/{gen => gen_}/integers.rs | 0 .../src/{gen => gen_}/long_fractions.rs | 0 .../src/{gen => gen_}/many_digits.rs | 0 .../src/{gen => gen_}/sparse.rs | 0 .../src/{gen => gen_}/spot_checks.rs | 0 .../src/{gen => gen_}/subnorm.rs | 0 src/etc/test-float-parse/src/lib.rs | 36 +++++++++---------- 11 files changed, 19 insertions(+), 19 deletions(-) rename src/etc/test-float-parse/src/{gen => gen_}/exhaustive.rs (100%) rename src/etc/test-float-parse/src/{gen => gen_}/exponents.rs (100%) rename src/etc/test-float-parse/src/{gen => gen_}/fuzz.rs (100%) rename src/etc/test-float-parse/src/{gen => gen_}/integers.rs (100%) rename src/etc/test-float-parse/src/{gen => gen_}/long_fractions.rs (100%) rename src/etc/test-float-parse/src/{gen => gen_}/many_digits.rs (100%) rename src/etc/test-float-parse/src/{gen => gen_}/sparse.rs (100%) rename src/etc/test-float-parse/src/{gen => gen_}/spot_checks.rs (100%) rename src/etc/test-float-parse/src/{gen => gen_}/subnorm.rs (100%) diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index bacb9e09f3f6..8a9c5322ef7b 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "test-float-parse" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [dependencies] diff --git a/src/etc/test-float-parse/src/gen/exhaustive.rs b/src/etc/test-float-parse/src/gen_/exhaustive.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/exhaustive.rs rename to src/etc/test-float-parse/src/gen_/exhaustive.rs diff --git a/src/etc/test-float-parse/src/gen/exponents.rs b/src/etc/test-float-parse/src/gen_/exponents.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/exponents.rs rename to src/etc/test-float-parse/src/gen_/exponents.rs diff --git a/src/etc/test-float-parse/src/gen/fuzz.rs b/src/etc/test-float-parse/src/gen_/fuzz.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/fuzz.rs rename to src/etc/test-float-parse/src/gen_/fuzz.rs diff --git a/src/etc/test-float-parse/src/gen/integers.rs b/src/etc/test-float-parse/src/gen_/integers.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/integers.rs rename to src/etc/test-float-parse/src/gen_/integers.rs diff --git a/src/etc/test-float-parse/src/gen/long_fractions.rs b/src/etc/test-float-parse/src/gen_/long_fractions.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/long_fractions.rs rename to src/etc/test-float-parse/src/gen_/long_fractions.rs diff --git a/src/etc/test-float-parse/src/gen/many_digits.rs b/src/etc/test-float-parse/src/gen_/many_digits.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/many_digits.rs rename to src/etc/test-float-parse/src/gen_/many_digits.rs diff --git a/src/etc/test-float-parse/src/gen/sparse.rs b/src/etc/test-float-parse/src/gen_/sparse.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/sparse.rs rename to src/etc/test-float-parse/src/gen_/sparse.rs diff --git a/src/etc/test-float-parse/src/gen/spot_checks.rs b/src/etc/test-float-parse/src/gen_/spot_checks.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/spot_checks.rs rename to src/etc/test-float-parse/src/gen_/spot_checks.rs diff --git a/src/etc/test-float-parse/src/gen/subnorm.rs b/src/etc/test-float-parse/src/gen_/subnorm.rs similarity index 100% rename from src/etc/test-float-parse/src/gen/subnorm.rs rename to src/etc/test-float-parse/src/gen_/subnorm.rs diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs index e2f84b085c6f..3c3ef5802b6a 100644 --- a/src/etc/test-float-parse/src/lib.rs +++ b/src/etc/test-float-parse/src/lib.rs @@ -17,7 +17,7 @@ use traits::{Float, Generator, Int}; use validate::CheckError; /// Test generators. -mod gen { +mod gen_ { pub mod exhaustive; pub mod exponents; pub mod fuzz; @@ -136,24 +136,24 @@ where { if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE { // Only run exhaustive tests if there is a chance of completion. - TestInfo::register::>(tests); + TestInfo::register::>(tests); } - gen::fuzz::Fuzz::::set_iterations(cfg.fuzz_count); + gen_::fuzz::Fuzz::::set_iterations(cfg.fuzz_count); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::(tests); - TestInfo::register::(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::(tests); - TestInfo::register::(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::(tests); + TestInfo::register::(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::(tests); + TestInfo::register::(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); } /// Configuration for a single test. @@ -343,7 +343,7 @@ fn launch_tests(tests: &mut [TestInfo], cfg: &Config) -> Duration { /// /// This calls the generator's iterator multiple times (in parallel) and validates each output. fn test_runner>(test: &TestInfo, cfg: &Config) { - let gen = G::new(); + let gen_ = G::new(); let executed = AtomicU64::new(0); let failures = AtomicU64::new(0); @@ -387,7 +387,7 @@ fn test_runner>(test: &TestInfo, cfg: &Config) { // Run the test iterations in parallel. Each thread gets a string buffer to write // its check values to. - let res = gen.par_bridge().try_for_each_init(String::new, check_one); + let res = gen_.par_bridge().try_for_each_init(String::new, check_one); let elapsed = started.elapsed(); let executed = executed.into_inner(); From f922e74f71371abe3eceda4a131c4d0137591548 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:12:07 +0000 Subject: [PATCH 514/546] Make coroutine_drop_cleanup 2024 edition compatible --- tests/mir-opt/coroutine_drop_cleanup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mir-opt/coroutine_drop_cleanup.rs b/tests/mir-opt/coroutine_drop_cleanup.rs index 33fdd2dd0d9c..4ae97273cd90 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.rs +++ b/tests/mir-opt/coroutine_drop_cleanup.rs @@ -8,7 +8,7 @@ // EMIT_MIR coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.mir fn main() { - let gen = #[coroutine] + let gen_ = #[coroutine] || { let _s = String::new(); yield; From a2f29439bf0fbf9823cf99cee61254875379e2c4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:12:30 +0000 Subject: [PATCH 515/546] Use the 2024 edition in ./x.py fmt --- src/bootstrap/src/core/build_steps/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 7aa5cb2b6e5e..b1a97bde97b5 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -31,7 +31,7 @@ fn rustfmt( // Avoid the submodule config paths from coming into play. We only allow a single global config // for the workspace for now. cmd.arg("--config-path").arg(src.canonicalize().unwrap()); - cmd.arg("--edition").arg("2021"); + cmd.arg("--edition").arg("2024"); cmd.arg("--unstable-features"); cmd.arg("--skip-children"); if check { From 242558058a0aa3d5b64d911f45a07f27930016e7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:13:53 +0000 Subject: [PATCH 516/546] Allow formatting example/gen_block_iterate.rs --- .../example/gen_block_iterate.rs | 16 ++++++++++++---- compiler/rustc_codegen_cranelift/rustfmt.toml | 4 ---- rustfmt.toml | 1 - 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs b/compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs index 25bfe542d228..de9a3d550ecc 100644 --- a/compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs +++ b/compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs @@ -6,16 +6,25 @@ #![feature(gen_blocks)] fn foo() -> impl Iterator { - gen { yield 42; for x in 3..6 { yield x } } + gen { + yield 42; + for x in 3..6 { + yield x + } + } } fn moved() -> impl Iterator { let mut x = "foo".to_string(); gen move { yield 42; - if x == "foo" { return } + if x == "foo" { + return; + } x.clear(); - for x in 3..6 { yield x } + for x in 3..6 { + yield x + } } } @@ -32,5 +41,4 @@ fn main() { let mut iter = moved(); assert_eq!(iter.next(), Some(42)); assert_eq!(iter.next(), None); - } diff --git a/compiler/rustc_codegen_cranelift/rustfmt.toml b/compiler/rustc_codegen_cranelift/rustfmt.toml index f31fa9c76abc..35c92663eb90 100644 --- a/compiler/rustc_codegen_cranelift/rustfmt.toml +++ b/compiler/rustc_codegen_cranelift/rustfmt.toml @@ -1,7 +1,3 @@ -ignore = [ - "example/gen_block_iterate.rs", # uses edition 2024 -] - # Matches rustfmt.toml of rustc style_edition = "2024" use_small_heuristics = "Max" diff --git a/rustfmt.toml b/rustfmt.toml index 8feeb60ca12c..c884a33729c4 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -49,7 +49,6 @@ ignore = [ # These are ignored by a standard cargo fmt run. "compiler/rustc_codegen_cranelift/scripts", - "compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs", # uses edition 2024 "compiler/rustc_codegen_gcc/tests", # Code automatically generated and included. "compiler/rustc_codegen_gcc/src/intrinsic/archs.rs", From df18de57a540cc9ae2309fd53e49c9a627f7d849 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 30 Mar 2025 15:56:41 +0200 Subject: [PATCH 517/546] Add unstable `--print=crate-root-lint-levels` --- compiler/rustc_driver_impl/src/lib.rs | 28 +++++ compiler/rustc_session/src/config.rs | 3 + .../print-crate-root-lint-levels.md | 23 ++++ .../print-crate-root-lint-levels/lib.rs | 5 + .../print-crate-root-lint-levels/rmake.rs | 118 ++++++++++++++++++ tests/run-make/rustc-help/help-v.stdout | 2 +- tests/run-make/rustc-help/help.stdout | 2 +- .../print-without-arg.stderr | 2 +- tests/ui/invalid-compile-flags/print.stderr | 2 +- .../ui/print-request/print-lints-help.stderr | 2 +- tests/ui/print-request/stability.rs | 4 + 11 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/print-crate-root-lint-levels.md create mode 100644 tests/run-make/print-crate-root-lint-levels/lib.rs create mode 100644 tests/run-make/print-crate-root-lint-levels/rmake.rs diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 37755e7d61db..f1dc4bb795e5 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -691,6 +691,34 @@ fn print_crate_info( }; println_info!("{}", passes::get_crate_name(sess, attrs)); } + CrateRootLintLevels => { + let Some(attrs) = attrs.as_ref() else { + // no crate attributes, print out an error and exit + return Compilation::Continue; + }; + let crate_name = passes::get_crate_name(sess, attrs); + let lint_store = crate::unerased_lint_store(sess); + let registered_tools = rustc_resolve::registered_tools_ast(sess.dcx(), attrs); + let features = rustc_expand::config::features(sess, attrs, crate_name); + let lint_levels = rustc_lint::LintLevelsBuilder::crate_root( + sess, + &features, + true, + lint_store, + ®istered_tools, + attrs, + ); + for lint in lint_store.get_lints() { + if let Some(feature_symbol) = lint.feature_gate + && !features.enabled(feature_symbol) + { + // lint is unstable and feature gate isn't active, don't print + continue; + } + let level = lint_levels.lint_level(lint).0; + println_info!("{}={}", lint.name_lower(), level.as_str()); + } + } Cfg => { let mut cfgs = sess .psess diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ed336cc55961..1b01efda2a9e 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -50,6 +50,7 @@ pub const PRINT_KINDS: &[(&str, PrintKind)] = &[ ("check-cfg", PrintKind::CheckCfg), ("code-models", PrintKind::CodeModels), ("crate-name", PrintKind::CrateName), + ("crate-root-lint-levels", PrintKind::CrateRootLintLevels), ("deployment-target", PrintKind::DeploymentTarget), ("file-names", PrintKind::FileNames), ("host-tuple", PrintKind::HostTuple), @@ -881,6 +882,7 @@ pub enum PrintKind { CheckCfg, CodeModels, CrateName, + CrateRootLintLevels, DeploymentTarget, FileNames, HostTuple, @@ -2067,6 +2069,7 @@ fn check_print_request_stability( match print_kind { PrintKind::AllTargetSpecsJson | PrintKind::CheckCfg + | PrintKind::CrateRootLintLevels | PrintKind::SupportedCrateTypes | PrintKind::TargetSpecJson if !unstable_opts.unstable_options => diff --git a/src/doc/unstable-book/src/compiler-flags/print-crate-root-lint-levels.md b/src/doc/unstable-book/src/compiler-flags/print-crate-root-lint-levels.md new file mode 100644 index 000000000000..0bad8b8ab96b --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/print-crate-root-lint-levels.md @@ -0,0 +1,23 @@ +# `print=crate-root-lint-levels` + +The tracking issue for this feature is: [#139180](https://github.com/rust-lang/rust/issues/139180). + +------------------------ + +This option of the `--print` flag print the list of lints with print out all the lints and their associated levels (`allow`, `warn`, `deny`, `forbid`) based on the regular Rust rules at crate root, that is *(roughly)*: + - command line args (`-W`, `-A`, `--force-warn`, `--cap-lints`, ...) + - crate root attributes (`#![allow]`, `#![warn]`, `#[expect]`, ...) + - *the special `warnings` lint group* + - the default lint level + +The output format is `LINT_NAME=LINT_LEVEL`, e.g.: +```text +unknown_lint=warn +arithmetic_overflow=deny +``` + +To be used like this: + +```bash +rustc --print=crate-root-lint-levels -Zunstable-options lib.rs +``` diff --git a/tests/run-make/print-crate-root-lint-levels/lib.rs b/tests/run-make/print-crate-root-lint-levels/lib.rs new file mode 100644 index 000000000000..dc846f8fd951 --- /dev/null +++ b/tests/run-make/print-crate-root-lint-levels/lib.rs @@ -0,0 +1,5 @@ +#![allow(unexpected_cfgs)] +#![expect(unused_mut)] + +#[deny(unknown_lints)] +mod my_mod {} diff --git a/tests/run-make/print-crate-root-lint-levels/rmake.rs b/tests/run-make/print-crate-root-lint-levels/rmake.rs new file mode 100644 index 000000000000..e373c91102df --- /dev/null +++ b/tests/run-make/print-crate-root-lint-levels/rmake.rs @@ -0,0 +1,118 @@ +//! This checks the output of `--print=crate-root-lint-levels` + +extern crate run_make_support; + +use std::collections::HashSet; +use std::iter::FromIterator; + +use run_make_support::rustc; + +struct CrateRootLintLevels { + args: &'static [&'static str], + contains: Contains, +} + +struct Contains { + contains: &'static [&'static str], + doesnt_contain: &'static [&'static str], +} + +fn main() { + check(CrateRootLintLevels { + args: &[], + contains: Contains { + contains: &[ + "unexpected_cfgs=allow", + "unused_mut=expect", + "warnings=warn", + "stable_features=warn", + "unknown_lints=warn", + ], + doesnt_contain: &["unexpected_cfgs=warn", "unused_mut=warn"], + }, + }); + check(CrateRootLintLevels { + args: &["-Wunexpected_cfgs"], + contains: Contains { + contains: &["unexpected_cfgs=allow", "warnings=warn"], + doesnt_contain: &["unexpected_cfgs=warn"], + }, + }); + check(CrateRootLintLevels { + args: &["-Dwarnings"], + contains: Contains { + contains: &[ + "unexpected_cfgs=allow", + "warnings=deny", + "stable_features=deny", + "unknown_lints=deny", + ], + doesnt_contain: &["warnings=warn"], + }, + }); + check(CrateRootLintLevels { + args: &["-Dstable_features"], + contains: Contains { + contains: &["warnings=warn", "stable_features=deny", "unexpected_cfgs=allow"], + doesnt_contain: &["warnings=deny"], + }, + }); + check(CrateRootLintLevels { + args: &["-Dwarnings", "--force-warn=stable_features"], + contains: Contains { + contains: &["warnings=deny", "stable_features=force-warn", "unknown_lints=deny"], + doesnt_contain: &["warnings=warn"], + }, + }); + check(CrateRootLintLevels { + args: &["-Dwarnings", "--cap-lints=warn"], + contains: Contains { + contains: &[ + "unexpected_cfgs=allow", + "warnings=warn", + "stable_features=warn", + "unknown_lints=warn", + ], + doesnt_contain: &["warnings=deny"], + }, + }); +} + +#[track_caller] +fn check(CrateRootLintLevels { args, contains }: CrateRootLintLevels) { + let output = rustc() + .input("lib.rs") + .arg("-Zunstable-options") + .print("crate-root-lint-levels") + .args(args) + .run(); + + let stdout = output.stdout_utf8(); + + let mut found = HashSet::::new(); + + for l in stdout.lines() { + assert!(l == l.trim()); + if let Some((left, right)) = l.split_once('=') { + assert!(!left.contains("\"")); + assert!(!right.contains("\"")); + } else { + assert!(l.contains('=')); + } + assert!(found.insert(l.to_string()), "{}", &l); + } + + let Contains { contains, doesnt_contain } = contains; + + { + let should_found = HashSet::::from_iter(contains.iter().map(|s| s.to_string())); + let diff: Vec<_> = should_found.difference(&found).collect(); + assert!(diff.is_empty(), "should found: {:?}, didn't found {:?}", &should_found, &diff); + } + { + let should_not_find = + HashSet::::from_iter(doesnt_contain.iter().map(|s| s.to_string())); + let diff: Vec<_> = should_not_find.intersection(&found).collect(); + assert!(diff.is_empty(), "should not find {:?}, did found {:?}", &should_not_find, &diff); + } +} diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index 98e56735082d..f19ca1e9f90a 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -29,7 +29,7 @@ Options: --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] Comma separated list of types of output for the compiler to emit - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] + --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] Compiler information to print on stdout -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index 040555f1d04f..f7d352966035 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -29,7 +29,7 @@ Options: --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] Comma separated list of types of output for the compiler to emit - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] + --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] Compiler information to print on stdout -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr index aa8a2ae42db2..8abaee5056ba 100644 --- a/tests/ui/invalid-compile-flags/print-without-arg.stderr +++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr @@ -1,5 +1,5 @@ error: Argument to option 'print' missing Usage: - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] + --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] Compiler information to print on stdout diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr index f9cfb1616ce5..e3374eb1e6e7 100644 --- a/tests/ui/invalid-compile-flags/print.stderr +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -1,5 +1,5 @@ error: unknown print request: `yyyy` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/ui/print-request/print-lints-help.stderr b/tests/ui/print-request/print-lints-help.stderr index 0530d11f2e80..bc48b2fa73cc 100644 --- a/tests/ui/print-request/print-lints-help.stderr +++ b/tests/ui/print-request/print-lints-help.stderr @@ -1,6 +1,6 @@ error: unknown print request: `lints` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` = help: use `-Whelp` to print a list of lints = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/ui/print-request/stability.rs b/tests/ui/print-request/stability.rs index c3421224d720..0ec0886e941e 100644 --- a/tests/ui/print-request/stability.rs +++ b/tests/ui/print-request/stability.rs @@ -18,6 +18,10 @@ //@[all_target_specs_json] compile-flags: --print=all-target-specs-json //@[all_target_specs_json] error-pattern: the `-Z unstable-options` flag must also be passed +//@ revisions: crate_root_lint_levels +//@[crate_root_lint_levels] compile-flags: --print=crate-root-lint-levels +//@[crate_root_lint_levels] error-pattern: the `-Z unstable-options` flag must also be passed + //@ revisions: check_cfg //@[check_cfg] compile-flags: --print=check-cfg //@[check_cfg] error-pattern: the `-Z unstable-options` flag must also be passed From 49ed25b5d2d5dc88f9fa3e268d9bd210acc875de Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 21:31:17 +1000 Subject: [PATCH 518/546] Remove `NtExpr` and `NtLiteral`. Notes about tests: - tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs: some messages are now duplicated due to repeated parsing. - tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs: ditto. - `tests/ui/proc-macro/macro-rules-derive-cfg.rs`: the diff looks large but the only difference is the insertion of a single invisible-delimited group around a metavar. - `tests/ui/attributes/nonterminal-expansion.rs`: a slight span degradation, somehow related to the recent massive attr parsing rewrite (#135726). I couldn't work out exactly what is going wrong, but I don't think it's worth holding things up for a single slightly suboptimal error message. --- compiler/rustc_ast/src/ast_traits.rs | 2 - compiler/rustc_ast/src/mut_visit.rs | 2 - compiler/rustc_ast/src/token.rs | 71 ++-- compiler/rustc_ast/src/tokenstream.rs | 1 - compiler/rustc_expand/src/mbe/transcribe.rs | 35 +- compiler/rustc_parse/messages.ftl | 2 +- compiler/rustc_parse/src/errors.rs | 4 +- compiler/rustc_parse/src/parser/expr.rs | 220 +++++++----- compiler/rustc_parse/src/parser/item.rs | 53 ++- compiler/rustc_parse/src/parser/mod.rs | 32 +- .../rustc_parse/src/parser/nonterminal.rs | 16 +- compiler/rustc_parse/src/parser/pat.rs | 2 +- tests/ui/attributes/nonterminal-expansion.rs | 4 +- .../attributes/nonterminal-expansion.stderr | 11 +- .../cfg-attr-syntax-validation.rs | 2 +- .../cfg-attr-syntax-validation.stderr | 2 +- tests/ui/macros/nonterminal-matching.rs | 4 +- tests/ui/macros/nonterminal-matching.stderr | 4 +- .../extern-abi-from-mac-literal-frag.rs | 4 + tests/ui/parser/float-field-interpolated.rs | 8 +- .../ui/parser/float-field-interpolated.stderr | 8 +- .../ui/parser/macro/trait-non-item-macros.rs | 2 +- .../parser/macro/trait-non-item-macros.stderr | 2 +- .../proc-macro/macro-rules-derive-cfg.stdout | 129 +++---- .../rfc-2294-if-let-guard/feature-gate.rs | 2 + .../rfc-2294-if-let-guard/feature-gate.stderr | 26 +- .../disallowed-positions.feature.stderr | 306 +++++++++-------- .../disallowed-positions.no_feature.stderr | 316 ++++++++++-------- .../disallowed-positions.nothing.stderr | 238 ++++++------- .../disallowed-positions.rs | 4 + 30 files changed, 864 insertions(+), 648 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 849cc650e9d6..c9e2e9911ef0 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -209,13 +209,11 @@ impl HasTokens for Attribute { impl HasTokens for Nonterminal { fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), Nonterminal::NtBlock(block) => block.tokens(), } } fn tokens_mut(&mut self) -> Option<&mut Option> { match self { - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 30af6d910bfa..f7d13acdfc40 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -899,8 +899,6 @@ pub fn visit_token(vis: &mut T, t: &mut Token) { fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { match nt { token::NtBlock(block) => vis.visit_block(block), - token::NtExpr(expr) => vis.visit_expr(expr), - token::NtLiteral(expr) => vis.visit_expr(expr), } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 6e6f0f1b2660..2081777fff35 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -198,16 +198,17 @@ impl Lit { } } - /// Keep this in sync with `Token::can_begin_literal_maybe_minus` excluding unary negation. + /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and + /// `Parser::eat_token_lit` (excluding unary negation). pub fn from_token(token: &Token) -> Option { match token.uninterpolate().kind { Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), Literal(token_lit) => Some(token_lit), - Interpolated(ref nt) - if let NtExpr(expr) | NtLiteral(expr) = &**nt - && let ast::ExprKind::Lit(token_lit) = expr.kind => - { - Some(token_lit) + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Literal | MetaVarKind::Expr { .. }, + ))) => { + // Unreachable with the current test suite. + panic!("from_token metavar"); } _ => None, } @@ -590,6 +591,9 @@ impl Token { /// for which spans affect name resolution and edition checks. /// Note that keywords are also identifiers, so they should use this /// if they keep spans or perform edition checks. + // + // Note: `Parser::uninterpolated_token_span` may give better information + // than this method does. pub fn uninterpolated_span(&self) -> Span { match self.kind { NtIdent(ident, _) | NtLifetime(ident, _) => ident.span, @@ -642,12 +646,7 @@ impl Token { PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => - matches!(&**nt, - NtBlock(..) | - NtExpr(..) | - NtLiteral(..) - ), + Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Block | MetaVarKind::Expr { .. } | @@ -677,11 +676,6 @@ impl Token { Lt | // path (UFCS constant) Shl => true, // path (double UFCS) Or => matches!(pat_kind, PatWithOr), // leading vert `|` or-pattern - Interpolated(nt) => - matches!(&**nt, - | NtExpr(..) - | NtLiteral(..) - ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Literal | @@ -724,7 +718,7 @@ impl Token { match self.kind { OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), + Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal, ))) => true, @@ -768,22 +762,12 @@ impl Token { /// /// In other words, would this token be a valid start of `parse_literal_maybe_minus`? /// - /// Keep this in sync with and `Lit::from_token`, excluding unary negation. + /// Keep this in sync with `Lit::from_token` and `Parser::eat_token_lit` + /// (excluding unary negation). pub fn can_begin_literal_maybe_minus(&self) -> bool { match self.uninterpolate().kind { Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => match &**nt { - NtLiteral(_) => true, - NtExpr(e) => match &e.kind { - ast::ExprKind::Lit(_) => true, - ast::ExprKind::Unary(ast::UnOp::Neg, e) => { - matches!(&e.kind, ast::ExprKind::Lit(_)) - } - _ => false, - }, - _ => false, - }, OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind { MetaVarKind::Literal => true, MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => { @@ -798,14 +782,6 @@ impl Token { pub fn can_begin_string_literal(&self) -> bool { match self.uninterpolate().kind { Literal(..) => true, - Interpolated(ref nt) => match &**nt { - NtLiteral(_) => true, - NtExpr(e) => match &e.kind { - ast::ExprKind::Lit(_) => true, - _ => false, - }, - _ => false, - }, OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind { MetaVarKind::Literal => true, MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal, @@ -869,12 +845,17 @@ impl Token { /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? - pub fn is_whole_expr(&self) -> bool { + pub fn is_metavar_expr(&self) -> bool { #[allow(irrefutable_let_patterns)] // FIXME: temporary if let Interpolated(nt) = &self.kind - && let NtExpr(_) | NtLiteral(_) | NtBlock(_) = &**nt + && let NtBlock(_) = &**nt { true + } else if matches!( + self.is_metavar_seq(), + Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path) + ) { + true } else { matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) } @@ -882,6 +863,7 @@ impl Token { /// Is the token an interpolated block (`$b:block`)? pub fn is_whole_block(&self) -> bool { + #[allow(irrefutable_let_patterns)] // FIXME: temporary if let Interpolated(nt) = &self.kind && let NtBlock(..) = &**nt { @@ -1100,8 +1082,6 @@ pub enum NtExprKind { /// For interpolation during macro expansion. pub enum Nonterminal { NtBlock(P), - NtExpr(P), - NtLiteral(P), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] @@ -1191,15 +1171,12 @@ impl Nonterminal { pub fn use_span(&self) -> Span { match self { NtBlock(block) => block.span, - NtExpr(expr) | NtLiteral(expr) => expr.span, } } pub fn descr(&self) -> &'static str { match self { NtBlock(..) => "block", - NtExpr(..) => "expression", - NtLiteral(..) => "literal", } } } @@ -1218,8 +1195,6 @@ impl fmt::Debug for Nonterminal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { NtBlock(..) => f.pad("NtBlock(..)"), - NtExpr(..) => f.pad("NtExpr(..)"), - NtLiteral(..) => f.pad("NtLiteral(..)"), } } } @@ -1242,7 +1217,7 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(Lit, 12); static_assert_size!(LitKind, 2); - static_assert_size!(Nonterminal, 16); + static_assert_size!(Nonterminal, 8); static_assert_size!(Token, 24); static_assert_size!(TokenKind, 16); // tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index bdd244be6d1c..161f8e67551f 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -462,7 +462,6 @@ impl TokenStream { pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { match nt { Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index cffa4af6ac3d..6e47ed6eb67c 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -3,11 +3,10 @@ use std::sync::Arc; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Nonterminal, Token, - TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Token, TokenKind, }; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; -use rustc_ast::{ExprKind, StmtKind, TyKind}; +use rustc_ast::{ExprKind, StmtKind, TyKind, UnOp}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize}; use rustc_parse::lexer::nfc_normalize; @@ -340,6 +339,30 @@ pub(super) fn transcribe<'a>( MetaVarKind::Pat(*pat_kind), TokenStream::from_ast(pat), ), + MatchedSingle(ParseNtResult::Expr(expr, kind)) => { + let (can_begin_literal_maybe_minus, can_begin_string_literal) = + match &expr.kind { + ExprKind::Lit(_) => (true, true), + ExprKind::Unary(UnOp::Neg, e) + if matches!(&e.kind, ExprKind::Lit(_)) => + { + (true, false) + } + _ => (false, false), + }; + mk_delimited( + expr.span, + MetaVarKind::Expr { + kind: *kind, + can_begin_literal_maybe_minus, + can_begin_string_literal, + }, + TokenStream::from_ast(expr), + ) + } + MatchedSingle(ParseNtResult::Literal(lit)) => { + mk_delimited(lit.span, MetaVarKind::Literal, TokenStream::from_ast(lit)) + } MatchedSingle(ParseNtResult::Ty(ty)) => { let is_path = matches!(&ty.kind, TyKind::Path(None, _path)); mk_delimited( @@ -869,10 +892,8 @@ fn extract_symbol_from_pnr<'a>( }, _, )) => Ok(*symbol), - ParseNtResult::Nt(nt) - if let Nonterminal::NtLiteral(expr) = &**nt - && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = - &expr.kind => + ParseNtResult::Literal(expr) + if let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind => { Ok(*symbol) } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 24679692a0b0..93fa89b68b97 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -858,7 +858,7 @@ parse_unexpected_parentheses_in_match_arm_pattern = unexpected parentheses surro parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters .note = you cannot use `Self` as a generic parameter because it is reserved for associated items -parse_unexpected_token_after_dot = unexpected token: `{$actual}` +parse_unexpected_token_after_dot = unexpected token: {$actual} parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label .suggestion_remove_label = consider removing the label diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 55cb76878238..dfdef018bc37 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1696,10 +1696,10 @@ pub(crate) struct SelfArgumentPointer { #[derive(Diagnostic)] #[diag(parse_unexpected_token_after_dot)] -pub(crate) struct UnexpectedTokenAfterDot<'a> { +pub(crate) struct UnexpectedTokenAfterDot { #[primary_span] pub span: Span, - pub actual: Cow<'a, str>, + pub actual: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 00e75cc2c2fc..424fee968e1d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4,10 +4,10 @@ use core::mem; use core::ops::{Bound, ControlFlow}; use ast::mut_visit::{self, MutVisitor}; -use ast::token::{IdentIsRaw, MetaVarKind}; +use ast::token::IdentIsRaw; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; use rustc_ast::util::case::Case; use rustc_ast::util::classify; @@ -19,7 +19,6 @@ use rustc_ast::{ MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; -use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; use rustc_lexer::unescape::unescape_char; @@ -605,7 +604,7 @@ impl<'a> Parser<'a> { // can't continue an expression after an ident token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw), token::Literal(..) | token::Pound => true, - _ => t.is_whole_expr(), + _ => t.is_metavar_expr(), }; self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr) } @@ -641,6 +640,13 @@ impl<'a> Parser<'a> { TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => { self.prev_token.span } + TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { + // `expr.span` is the interpolated span, because invisible open + // and close delims both get marked with the same span, one + // that covers the entire thing between them. (See + // `rustc_expand::mbe::transcribe::transcribe`.) + self.prev_token.span + } _ => expr.span, } } @@ -979,12 +985,30 @@ impl<'a> Parser<'a> { } fn error_unexpected_after_dot(&self) { - let actual = pprust::token_to_string(&self.token); + let actual = super::token_descr(&self.token); let span = self.token.span; let sm = self.psess.source_map(); let (span, actual) = match (&self.token.kind, self.subparser_name) { - (token::Eof, Some(_)) if let Ok(actual) = sm.span_to_snippet(sm.next_point(span)) => { - (span.shrink_to_hi(), actual.into()) + (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => { + (span.shrink_to_hi(), format!("`{}`", snippet)) + } + (token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))), _) => { + // No need to report an error. This case will only occur when parsing a pasted + // metavariable, and we should have emitted an error when parsing the macro call in + // the first place. E.g. in this code: + // ``` + // macro_rules! m { ($e:expr) => { $e }; } + // + // fn main() { + // let f = 1; + // m!(f.); + // } + // ``` + // we'll get an error "unexpected token: `)` when parsing the `m!(f.)`, so we don't + // want to issue a second error when parsing the expansion `«f.»` (where `«`/`»` + // represent the invisible delimiters). + self.dcx().span_delayed_bug(span, "bad dot expr in metavariable"); + return; } _ => (span, actual), }; @@ -1364,17 +1388,31 @@ impl<'a> Parser<'a> { let span = self.token.span; if let token::Interpolated(nt) = &self.token.kind { match &**nt { - token::NtExpr(e) | token::NtLiteral(e) => { - let e = e.clone(); - self.bump(); - return Ok(e); - } token::NtBlock(block) => { let block = block.clone(); self.bump(); return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); } }; + } else if let Some(expr) = self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }), + |this| { + let expr = this.parse_expr(); + // FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly + // related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line + // `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in + // `compiler/rustc_index/src/bit_set/tests.rs`. + if this.token.kind == token::Comma { + this.bump(); + } + expr + }, + ) { + return Ok(expr); + } else if let Some(lit) = + self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) + { + return Ok(lit); } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| { this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) }) { @@ -2062,87 +2100,107 @@ impl<'a> Parser<'a> { .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char)) } - fn recover_after_dot(&mut self) -> Option { - let mut recovered = None; + fn recover_after_dot(&mut self) { if self.token == token::Dot { // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where // dot would follow an optional literal, so we do this unconditionally. - recovered = self.look_ahead(1, |next_token| { + let recovered = self.look_ahead(1, |next_token| { + // If it's an integer that looks like a float, then recover as such. + // + // We will never encounter the exponent part of a floating + // point literal here, since there's no use of the exponent + // syntax that also constitutes a valid integer, so we need + // not check for that. if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = next_token.kind + && suffix.is_none_or(|s| s == sym::f32 || s == sym::f64) + && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_') + && self.token.span.hi() == next_token.span.lo() { - // If this integer looks like a float, then recover as such. - // - // We will never encounter the exponent part of a floating - // point literal here, since there's no use of the exponent - // syntax that also constitutes a valid integer, so we need - // not check for that. - if suffix.is_none_or(|s| s == sym::f32 || s == sym::f64) - && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_') - && self.token.span.hi() == next_token.span.lo() - { - let s = String::from("0.") + symbol.as_str(); - let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); - return Some(Token::new(kind, self.token.span.to(next_token.span))); - } + let s = String::from("0.") + symbol.as_str(); + let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); + Some(Token::new(kind, self.token.span.to(next_token.span))) + } else { + None } - None }); - if let Some(token) = &recovered { - self.bump(); + if let Some(recovered) = recovered { self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart { - span: token.span, - suggestion: token.span.shrink_to_lo(), + span: recovered.span, + suggestion: recovered.span.shrink_to_lo(), }); + self.bump(); + self.token = recovered; } } + } - recovered + /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and + /// `Lit::from_token` (excluding unary negation). + fn eat_token_lit(&mut self) -> Option { + match self.token.uninterpolate().kind { + token::Ident(name, IdentIsRaw::No) if name.is_bool_lit() => { + self.bump(); + Some(token::Lit::new(token::Bool, name, None)) + } + token::Literal(token_lit) => { + self.bump(); + Some(token_lit) + } + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Literal, + ))) => { + let lit = self + .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) + .expect("metavar seq literal"); + let ast::ExprKind::Lit(token_lit) = lit.kind else { + panic!("didn't reparse a literal"); + }; + Some(token_lit) + } + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. }, + ))) => { + let expr = self + .eat_metavar_seq(mv_kind, |this| this.parse_expr()) + .expect("metavar seq expr"); + let ast::ExprKind::Lit(token_lit) = expr.kind else { + panic!("didn't reparse an expr"); + }; + Some(token_lit) + } + _ => None, + } } /// Matches `lit = true | false | token_lit`. /// Returns `None` if the next token is not a literal. - pub(super) fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> { - let recovered = self.recover_after_dot(); - let token = recovered.as_ref().unwrap_or(&self.token); - let span = token.span; - - token::Lit::from_token(token).map(|token_lit| { - self.bump(); - (token_lit, span) - }) + fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> { + self.recover_after_dot(); + let span = self.token.span; + self.eat_token_lit().map(|token_lit| (token_lit, span)) } /// Matches `lit = true | false | token_lit`. /// Returns `None` if the next token is not a literal. - pub(super) fn parse_opt_meta_item_lit(&mut self) -> Option { - let recovered = self.recover_after_dot(); - let token = recovered.as_ref().unwrap_or(&self.token); - match token::Lit::from_token(token) { - Some(lit) => { - match MetaItemLit::from_token_lit(lit, token.span) { - Ok(lit) => { - self.bump(); - Some(lit) - } - Err(err) => { - let span = token.uninterpolated_span(); - self.bump(); - let guar = report_lit_error(self.psess, err, lit, span); - // Pack possible quotes and prefixes from the original literal into - // the error literal's symbol so they can be pretty-printed faithfully. - let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); - let symbol = Symbol::intern(&suffixless_lit.to_string()); - let lit = token::Lit::new(token::Err(guar), symbol, lit.suffix); - Some( - MetaItemLit::from_token_lit(lit, span) - .unwrap_or_else(|_| unreachable!()), - ) - } + fn parse_opt_meta_item_lit(&mut self) -> Option { + self.recover_after_dot(); + let span = self.token.span; + let uninterpolated_span = self.uninterpolated_token_span(); + self.eat_token_lit().map(|token_lit| { + match MetaItemLit::from_token_lit(token_lit, span) { + Ok(lit) => lit, + Err(err) => { + let guar = report_lit_error(&self.psess, err, token_lit, uninterpolated_span); + // Pack possible quotes and prefixes from the original literal into + // the error literal's symbol so they can be pretty-printed faithfully. + let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None); + let symbol = Symbol::intern(&suffixless_lit.to_string()); + let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix); + MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap() } } - None => None, - } + }) } pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) { @@ -2166,9 +2224,10 @@ impl<'a> Parser<'a> { /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { - if let token::Interpolated(nt) = &self.token.kind { - match &**nt { - // FIXME(nnethercote) The `NtExpr` case should only match if + if let Some(expr) = self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }), + |this| { + // FIXME(nnethercote) The `expr` case should only match if // `e` is an `ExprKind::Lit` or an `ExprKind::Unary` containing // an `UnOp::Neg` and an `ExprKind::Lit`, like how // `can_begin_literal_maybe_minus` works. But this method has @@ -2178,13 +2237,14 @@ impl<'a> Parser<'a> { // `ExprKind::Path` must be accepted when parsing range // patterns. That requires some care. So for now, we continue // being less strict here than we should be. - token::NtExpr(e) | token::NtLiteral(e) => { - let e = e.clone(); - self.bump(); - return Ok(e); - } - _ => {} - }; + this.parse_expr() + }, + ) { + return Ok(expr); + } else if let Some(lit) = + self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) + { + return Ok(lit); } let lo = self.token.span; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index e93fb2473fbf..20833a0f70f2 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1290,12 +1290,24 @@ impl<'a> Parser<'a> { } fn is_unsafe_foreign_mod(&self) -> bool { - self.token.is_keyword(kw::Unsafe) - && self.is_keyword_ahead(1, &[kw::Extern]) - && self.look_ahead( - 2 + self.look_ahead(2, |t| t.can_begin_string_literal() as usize), - |t| *t == token::OpenDelim(Delimiter::Brace), - ) + // Look for `unsafe`. + if !self.token.is_keyword(kw::Unsafe) { + return false; + } + // Look for `extern`. + if !self.is_keyword_ahead(1, &[kw::Extern]) { + return false; + } + + // Look for the optional ABI string literal. + let n = if self.look_ahead(2, |t| t.can_begin_string_literal()) { 3 } else { 2 }; + + // Look for the `{`. Use `tree_look_ahead` because the ABI (if present) + // might be a metavariable i.e. an invisible-delimited sequence, and + // `tree_look_ahead` will consider that a single element when looking + // ahead. + self.tree_look_ahead(n, |t| matches!(t, TokenTree::Delimited(_, _, Delimiter::Brace, _))) + == Some(true) } fn is_static_global(&mut self) -> bool { @@ -2604,13 +2616,36 @@ impl<'a> Parser<'a> { }) // `extern ABI fn` || self.check_keyword_case(exp!(Extern), case) + // Use `tree_look_ahead` because `ABI` might be a metavariable, + // i.e. an invisible-delimited sequence, and `tree_look_ahead` + // will consider that a single element when looking ahead. && self.look_ahead(1, |t| t.can_begin_string_literal()) - && (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) || + && (self.tree_look_ahead(2, |tt| { + match tt { + TokenTree::Token(t, _) => t.is_keyword_case(kw::Fn, case), + TokenTree::Delimited(..) => false, + } + }) == Some(true) || // This branch is only for better diagnostics; `pub`, `unsafe`, etc. are not // allowed here. (self.may_recover() - && self.look_ahead(2, |t| ALL_QUALS.iter().any(|exp| t.is_keyword(exp.kw))) - && self.look_ahead(3, |t| t.is_keyword_case(kw::Fn, case)))) + && self.tree_look_ahead(2, |tt| { + match tt { + TokenTree::Token(t, _) => + ALL_QUALS.iter().any(|exp| { + t.is_keyword(exp.kw) + }), + TokenTree::Delimited(..) => false, + } + }) == Some(true) + && self.tree_look_ahead(3, |tt| { + match tt { + TokenTree::Token(t, _) => t.is_keyword_case(kw::Fn, case), + TokenTree::Delimited(..) => false, + } + }) == Some(true) + ) + ) } /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d865fd427641..a08fbde52a7c 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -24,8 +24,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtPatKind, Token, - TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtExprKind, NtPatKind, + Token, TokenKind, }; use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree}; use rustc_ast::util::case::Case; @@ -101,6 +101,7 @@ pub enum ForceCollect { #[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { + #[allow(irrefutable_let_patterns)] // FIXME: temporary if let token::Interpolated(nt) = &$p.token.kind && let token::$constructor(x) = &**nt { @@ -299,6 +300,10 @@ impl TokenTreeCursor { self.stream.get(self.index) } + fn look_ahead(&self, n: usize) -> Option<&TokenTree> { + self.stream.get(self.index + n) + } + #[inline] fn bump(&mut self) { self.index += 1; @@ -1290,6 +1295,17 @@ impl<'a> Parser<'a> { looker(&token) } + /// Like `lookahead`, but skips over token trees rather than tokens. Useful + /// when looking past possible metavariable pasting sites. + pub fn tree_look_ahead( + &self, + dist: usize, + looker: impl FnOnce(&TokenTree) -> R, + ) -> Option { + assert_ne!(dist, 0); + self.token_cursor.curr.look_ahead(dist - 1).map(looker) + } + /// Returns whether any of the given keywords are `dist` tokens ahead of the current one. pub(crate) fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool { self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw))) @@ -1706,6 +1722,16 @@ impl<'a> Parser<'a> { pub fn approx_token_stream_pos(&self) -> u32 { self.num_bump_calls } + + pub fn uninterpolated_token_span(&self) -> Span { + match &self.token.kind { + token::Interpolated(nt) => nt.use_span(), + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { + self.look_ahead(1, |t| t.span) + } + _ => self.token.span, + } + } } pub(crate) fn make_unclosed_delims_error( @@ -1758,6 +1784,8 @@ pub enum ParseNtResult { Item(P), Stmt(P), Pat(P, NtPatKind), + Expr(P, NtExprKind), + Literal(P), Ty(P), Meta(P), Path(P), diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 1123755ce003..b4e540d670d1 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -48,10 +48,6 @@ impl<'a> Parser<'a> { /// Old variant of `may_be_ident`. Being phased out. fn nt_may_be_ident(nt: &Nonterminal) -> bool { match nt { - NtExpr(_) - | NtLiteral(_) // `true`, `false` - => true, - NtBlock(_) => false, } } @@ -95,7 +91,7 @@ impl<'a> Parser<'a> { token::OpenDelim(Delimiter::Brace) => true, token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { - NtBlock(_) | NtExpr(_) | NtLiteral(_) => true, + NtBlock(_) => true, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -179,10 +175,14 @@ impl<'a> Parser<'a> { pat_kind, )); } - NonterminalKind::Expr(_) => NtExpr(self.parse_expr_force_collect()?), + NonterminalKind::Expr(expr_kind) => { + return Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind)); + } NonterminalKind::Literal => { - // The `:literal` matcher does not support attributes - NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?) + // The `:literal` matcher does not support attributes. + return Ok(ParseNtResult::Literal( + self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?, + )); } NonterminalKind::Ty => { return Ok(ParseNtResult::Ty( diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 174cc929fa70..9612f71b2af9 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1252,7 +1252,7 @@ impl<'a> Parser<'a> { || *t == token::Dot // e.g. `.5` for recovery; || matches!(t.kind, token::Literal(..) | token::Minus) || t.is_bool_lit() - || t.is_whole_expr() + || t.is_metavar_expr() || t.is_lifetime() // recover `'a` instead of `'a'` || (self.may_recover() // recover leading `(` && *t == token::OpenDelim(Delimiter::Parenthesis) diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs index 83c8f00999a7..004a8a23fd61 100644 --- a/tests/ui/attributes/nonterminal-expansion.rs +++ b/tests/ui/attributes/nonterminal-expansion.rs @@ -5,8 +5,7 @@ macro_rules! pass_nonterminal { ($n:expr) => { #[repr(align($n))] - //~^ ERROR expected unsuffixed literal, found expression `n!()` - //~^^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693] + //~^ ERROR expected unsuffixed literal, found `expr` metavariable struct S; }; } @@ -16,5 +15,6 @@ macro_rules! n { } pass_nonterminal!(n!()); +//~^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693] fn main() {} diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr index 8a85731bd5a1..9c6cb98f6196 100644 --- a/tests/ui/attributes/nonterminal-expansion.stderr +++ b/tests/ui/attributes/nonterminal-expansion.stderr @@ -1,4 +1,4 @@ -error: expected unsuffixed literal, found expression `n!()` +error: expected unsuffixed literal, found `expr` metavariable --> $DIR/nonterminal-expansion.rs:7:22 | LL | #[repr(align($n))] @@ -10,15 +10,10 @@ LL | pass_nonterminal!(n!()); = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0693]: incorrect `repr(align)` attribute format: `align` expects a literal integer as argument - --> $DIR/nonterminal-expansion.rs:7:22 + --> $DIR/nonterminal-expansion.rs:17:19 | -LL | #[repr(align($n))] - | ^^ -... LL | pass_nonterminal!(n!()); - | ----------------------- in this macro invocation - | - = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^ error: aborting due to 2 previous errors diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 416145a0c156..47418b4e091b 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -28,7 +28,7 @@ struct S9; macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] - //~^ ERROR expected unsuffixed literal, found expression `concat!("nonexistent")` + //~^ ERROR expected unsuffixed literal, found `expr` metavariable struct S10; } } diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index d02d0d70a8bc..66ce2ee98589 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")] | | | help: consider removing the prefix -error: expected unsuffixed literal, found expression `concat!("nonexistent")` +error: expected unsuffixed literal, found `expr` metavariable --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index b0a7f3e4650f..a03ede20c549 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -29,8 +29,8 @@ macro_rules! foo { (ident $x:ident) => { bar!(ident $x); }; (lifetime $x:lifetime) => { bar!(lifetime $x); }; (tt $x:tt) => { bar!(tt $x); }; - (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3` - (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4` + (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected `expr` metavariable + (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected `literal` metavariable (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected `path` metavariable (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected `stmt` metavariable } diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index 2d9252fbfc1f..d01561415664 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -23,7 +23,7 @@ LL | complex_nonterminal!(enum E {}); = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected expression `3` +error: no rules expected `expr` metavariable --> $DIR/nonterminal-matching.rs:32:35 | LL | (expr $x:expr) => { bar!(expr $x); }; @@ -45,7 +45,7 @@ LL | (expr 3) => {}; = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected literal `4` +error: no rules expected `literal` metavariable --> $DIR/nonterminal-matching.rs:33:44 | LL | (literal $x:literal) => { bar!(literal $x); }; diff --git a/tests/ui/parser/extern-abi-from-mac-literal-frag.rs b/tests/ui/parser/extern-abi-from-mac-literal-frag.rs index a4e9134218ce..12b6c98705ce 100644 --- a/tests/ui/parser/extern-abi-from-mac-literal-frag.rs +++ b/tests/ui/parser/extern-abi-from-mac-literal-frag.rs @@ -12,6 +12,8 @@ macro_rules! abi_from_lit_frag { fn _import(); } + unsafe extern $abi {} + extern $abi fn _export() {} type _PTR = extern $abi fn(); @@ -24,6 +26,8 @@ macro_rules! abi_from_expr_frag { fn _import(); } + unsafe extern $abi {} + extern $abi fn _export() {} type _PTR = extern $abi fn(); diff --git a/tests/ui/parser/float-field-interpolated.rs b/tests/ui/parser/float-field-interpolated.rs index 990f2926dc86..bf7163039c42 100644 --- a/tests/ui/parser/float-field-interpolated.rs +++ b/tests/ui/parser/float-field-interpolated.rs @@ -5,10 +5,10 @@ macro_rules! generate_field_accesses { let s = S(0, (0, 0)); s.$a; // OK - { s.$b; } //~ ERROR unexpected token: `1.1` - //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found literal `1.1` - { s.$c; } //~ ERROR unexpected token: `1.1` - //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found expression `1.1` + { s.$b; } //~ ERROR unexpected token: `literal` metavariable + //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `literal` metavariable + { s.$c; } //~ ERROR unexpected token: `expr` metavariable + //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `expr` metavariable }; } diff --git a/tests/ui/parser/float-field-interpolated.stderr b/tests/ui/parser/float-field-interpolated.stderr index 2a1a4926cb3c..e2b7e3a7dbe7 100644 --- a/tests/ui/parser/float-field-interpolated.stderr +++ b/tests/ui/parser/float-field-interpolated.stderr @@ -1,4 +1,4 @@ -error: unexpected token: `1.1` +error: unexpected token: `literal` metavariable --> $DIR/float-field-interpolated.rs:8:13 | LL | { s.$b; } @@ -9,7 +9,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1); | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected one of `.`, `;`, `?`, `}`, or an operator, found literal `1.1` +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `literal` metavariable --> $DIR/float-field-interpolated.rs:8:13 | LL | { s.$b; } @@ -20,7 +20,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1); | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) -error: unexpected token: `1.1` +error: unexpected token: `expr` metavariable --> $DIR/float-field-interpolated.rs:10:13 | LL | { s.$c; } @@ -31,7 +31,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1); | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected one of `.`, `;`, `?`, `}`, or an operator, found expression `1.1` +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `expr` metavariable --> $DIR/float-field-interpolated.rs:10:13 | LL | { s.$c; } diff --git a/tests/ui/parser/macro/trait-non-item-macros.rs b/tests/ui/parser/macro/trait-non-item-macros.rs index e93000193b6e..b4140613cbae 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.rs +++ b/tests/ui/parser/macro/trait-non-item-macros.rs @@ -1,7 +1,7 @@ macro_rules! bah { ($a:expr) => { $a - }; //~^ ERROR macro expansion ignores expression `2` and any tokens following + }; //~^ ERROR macro expansion ignores `expr` metavariable and any tokens following } trait Bar { diff --git a/tests/ui/parser/macro/trait-non-item-macros.stderr b/tests/ui/parser/macro/trait-non-item-macros.stderr index 1a8284837789..62b42fa8b8dd 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.stderr +++ b/tests/ui/parser/macro/trait-non-item-macros.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores expression `2` and any tokens following +error: macro expansion ignores `expr` metavariable and any tokens following --> $DIR/trait-non-item-macros.rs:3:9 | LL | $a diff --git a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout index c1e46b50d40c..9482b2784d22 100644 --- a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout +++ b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout @@ -1,8 +1,9 @@ PRINT-DERIVE INPUT (DISPLAY): struct -Foo([bool; #[rustc_dummy(first)] #[rustc_dummy(second)] -{ #![rustc_dummy(third)] #[rustc_dummy(fourth)] 30 }]); +Foo([bool; #[rustc_dummy(first)] +#[rustc_dummy(second)] { #![rustc_dummy(third)] #[rustc_dummy(fourth)] 30 }]); PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct -Foo([bool; #[rustc_dummy(first)] #[rustc_dummy(second)] +Foo([bool; #[rustc_dummy(first)] +#[rustc_dummy(second)] { #! [rustc_dummy(third)] #[rustc_dummy(fourth)] 30 }]); PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { @@ -53,97 +54,103 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ ], span: $DIR/macro-rules-derive-cfg.rs:18:21: 18:63 (#3), }, - Punct { - ch: '#', - spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:23:13: 23:14 (#0), - }, Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "rustc_dummy", - span: $DIR/macro-rules-derive-cfg.rs:23:36: 23:47 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "second", - span: $DIR/macro-rules-derive-cfg.rs:23:48: 23:54 (#0), - }, - ], - span: $DIR/macro-rules-derive-cfg.rs:23:47: 23:55 (#0), - }, - ], - span: $DIR/macro-rules-derive-cfg.rs:23:14: 23:57 (#0), - }, - Group { - delimiter: Brace, + delimiter: None, stream: TokenStream [ Punct { ch: '#', - spacing: Joint, - span: $DIR/macro-rules-derive-cfg.rs:24:5: 24:6 (#0), - }, - Punct { - ch: '!', spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:24:6: 24:7 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:13: 23:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "rustc_dummy", - span: $DIR/macro-rules-derive-cfg.rs:24:29: 24:40 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:36: 23:47 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "third", - span: $DIR/macro-rules-derive-cfg.rs:24:41: 24:46 (#0), + ident: "second", + span: $DIR/macro-rules-derive-cfg.rs:23:48: 23:54 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:24:40: 24:47 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:47: 23:55 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:24:7: 24:49 (#0), - }, - Punct { - ch: '#', - spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:25:5: 25:6 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:14: 23:57 (#0), }, Group { - delimiter: Bracket, + delimiter: Brace, stream: TokenStream [ - Ident { - ident: "rustc_dummy", - span: $DIR/macro-rules-derive-cfg.rs:25:28: 25:39 (#0), + Punct { + ch: '#', + spacing: Joint, + span: $DIR/macro-rules-derive-cfg.rs:24:5: 24:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/macro-rules-derive-cfg.rs:24:6: 24:7 (#0), }, Group { - delimiter: Parenthesis, + delimiter: Bracket, stream: TokenStream [ Ident { - ident: "fourth", - span: $DIR/macro-rules-derive-cfg.rs:25:40: 25:46 (#0), + ident: "rustc_dummy", + span: $DIR/macro-rules-derive-cfg.rs:24:29: 24:40 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "third", + span: $DIR/macro-rules-derive-cfg.rs:24:41: 24:46 (#0), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:24:40: 24:47 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:25:39: 25:47 (#0), + span: $DIR/macro-rules-derive-cfg.rs:24:7: 24:49 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/macro-rules-derive-cfg.rs:25:5: 25:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/macro-rules-derive-cfg.rs:25:28: 25:39 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "fourth", + span: $DIR/macro-rules-derive-cfg.rs:25:40: 25:46 (#0), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:25:39: 25:47 (#0), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:25:6: 25:49 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/macro-rules-derive-cfg.rs:26:5: 26:7 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:25:6: 25:49 (#0), - }, - Literal { - kind: Integer, - symbol: "30", - suffix: None, - span: $DIR/macro-rules-derive-cfg.rs:26:5: 26:7 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:58: 27:2 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:23:58: 27:2 (#0), + span: $DIR/macro-rules-derive-cfg.rs:18:64: 18:69 (#3), }, ], span: $DIR/macro-rules-derive-cfg.rs:18:13: 18:70 (#3), diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs index 4b2fc4a03b62..110c03d0e549 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -59,8 +59,10 @@ fn _macros() { } use_expr!((let 0 = 1 && 0 == 0)); //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement match () { #[cfg(FALSE)] () if let 0 = 1 => {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr index 1c710b04897c..0997f0c81a01 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr @@ -124,15 +124,33 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/feature-gate.rs:62:16 + --> $DIR/feature-gate.rs:60:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:63:16 | LL | use_expr!((let 0 = 1)); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:63:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: no rules expected keyword `let` - --> $DIR/feature-gate.rs:70:15 + --> $DIR/feature-gate.rs:72:15 | LL | macro_rules! use_expr { | --------------------- when calling this macro @@ -202,7 +220,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: you can write `if matches!(, )` instead of `if let = ` error[E0658]: `if let` guards are experimental - --> $DIR/feature-gate.rs:66:12 + --> $DIR/feature-gate.rs:68:12 | LL | () if let 0 = 1 => {} | ^^^^^^^^^^^^ @@ -262,6 +280,6 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 23 previous errors +error: aborting due to 25 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr index db32b8c1de4f..817e226bc45d 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr @@ -233,7 +233,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:99:9 + --> $DIR/disallowed-positions.rs:103:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:102:9 + --> $DIR/disallowed-positions.rs:106:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:104:9 + --> $DIR/disallowed-positions.rs:108:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:106:9 + --> $DIR/disallowed-positions.rs:110:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:114:9 + --> $DIR/disallowed-positions.rs:118:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:117:16 + --> $DIR/disallowed-positions.rs:121:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:117:13 + --> $DIR/disallowed-positions.rs:121:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:119:17 + --> $DIR/disallowed-positions.rs:123:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:121:25 + --> $DIR/disallowed-positions.rs:125:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:123:25 + --> $DIR/disallowed-positions.rs:127:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:127:12 + --> $DIR/disallowed-positions.rs:131:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:130:15 + --> $DIR/disallowed-positions.rs:134:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:133:11 + --> $DIR/disallowed-positions.rs:137:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:135:9 + --> $DIR/disallowed-positions.rs:139:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:139:8 + --> $DIR/disallowed-positions.rs:143:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:142:8 + --> $DIR/disallowed-positions.rs:146:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:148:8 + --> $DIR/disallowed-positions.rs:152:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:154:8 + --> $DIR/disallowed-positions.rs:158:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:158:19 + --> $DIR/disallowed-positions.rs:162:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:161:15 + --> $DIR/disallowed-positions.rs:165:15 | LL | if return let 0 = 0 {} | ^^^ @@ -390,7 +390,7 @@ LL | if return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:164:21 + --> $DIR/disallowed-positions.rs:168:21 | LL | loop { if break let 0 = 0 {} } | ^^^ @@ -398,7 +398,7 @@ LL | loop { if break let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:167:15 + --> $DIR/disallowed-positions.rs:171:15 | LL | if (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -406,7 +406,7 @@ LL | if (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:170:9 + --> $DIR/disallowed-positions.rs:174:9 | LL | if (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -414,7 +414,7 @@ LL | if (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:173:9 + --> $DIR/disallowed-positions.rs:177:9 | LL | if (let 0 = 0,) {} | ^^^^^^^^^ @@ -422,7 +422,7 @@ LL | if (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:177:13 + --> $DIR/disallowed-positions.rs:181:13 | LL | if (let 0 = 0).await {} | ^^^^^^^^^ @@ -430,7 +430,7 @@ LL | if (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:12 + --> $DIR/disallowed-positions.rs:185:12 | LL | if (|| let 0 = 0) {} | ^^^ @@ -438,7 +438,7 @@ LL | if (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:184:9 + --> $DIR/disallowed-positions.rs:188:9 | LL | if (let 0 = 0)() {} | ^^^^^^^^^ @@ -446,7 +446,7 @@ LL | if (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:190:12 + --> $DIR/disallowed-positions.rs:194:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -454,7 +454,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:193:12 + --> $DIR/disallowed-positions.rs:197:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -462,7 +462,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:195:12 + --> $DIR/disallowed-positions.rs:199:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -470,7 +470,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:12 + --> $DIR/disallowed-positions.rs:201:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -478,7 +478,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:205:12 + --> $DIR/disallowed-positions.rs:209:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -486,20 +486,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:208:19 + --> $DIR/disallowed-positions.rs:212:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:208:16 + --> $DIR/disallowed-positions.rs:212:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:210:20 + --> $DIR/disallowed-positions.rs:214:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -507,7 +507,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:28 + --> $DIR/disallowed-positions.rs:216:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -515,7 +515,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:214:28 + --> $DIR/disallowed-positions.rs:218:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -523,7 +523,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:15 + --> $DIR/disallowed-positions.rs:222:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -531,7 +531,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:221:18 + --> $DIR/disallowed-positions.rs:225:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -539,7 +539,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:224:14 + --> $DIR/disallowed-positions.rs:228:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -547,7 +547,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:226:12 + --> $DIR/disallowed-positions.rs:230:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -555,7 +555,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:230:11 + --> $DIR/disallowed-positions.rs:234:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -563,7 +563,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:233:11 + --> $DIR/disallowed-positions.rs:237:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -571,7 +571,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:239:11 + --> $DIR/disallowed-positions.rs:243:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -579,7 +579,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:245:11 + --> $DIR/disallowed-positions.rs:249:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -587,7 +587,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:249:22 + --> $DIR/disallowed-positions.rs:253:22 | LL | while let true = let true = true {} | ^^^ @@ -595,7 +595,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:252:18 + --> $DIR/disallowed-positions.rs:256:18 | LL | while return let 0 = 0 {} | ^^^ @@ -603,7 +603,7 @@ LL | while return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:255:39 + --> $DIR/disallowed-positions.rs:259:39 | LL | 'outer: loop { while break 'outer let 0 = 0 {} } | ^^^ @@ -611,7 +611,7 @@ LL | 'outer: loop { while break 'outer let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:258:18 + --> $DIR/disallowed-positions.rs:262:18 | LL | while (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -619,7 +619,7 @@ LL | while (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:261:12 + --> $DIR/disallowed-positions.rs:265:12 | LL | while (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -627,7 +627,7 @@ LL | while (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:264:12 + --> $DIR/disallowed-positions.rs:268:12 | LL | while (let 0 = 0,) {} | ^^^^^^^^^ @@ -635,7 +635,7 @@ LL | while (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:268:16 + --> $DIR/disallowed-positions.rs:272:16 | LL | while (let 0 = 0).await {} | ^^^^^^^^^ @@ -643,7 +643,7 @@ LL | while (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:15 + --> $DIR/disallowed-positions.rs:276:15 | LL | while (|| let 0 = 0) {} | ^^^ @@ -651,7 +651,7 @@ LL | while (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:275:12 + --> $DIR/disallowed-positions.rs:279:12 | LL | while (let 0 = 0)() {} | ^^^^^^^^^ @@ -659,7 +659,7 @@ LL | while (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:292:6 + --> $DIR/disallowed-positions.rs:296:6 | LL | &let 0 = 0; | ^^^ @@ -667,7 +667,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:295:6 + --> $DIR/disallowed-positions.rs:299:6 | LL | !let 0 = 0; | ^^^ @@ -675,7 +675,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:297:6 + --> $DIR/disallowed-positions.rs:301:6 | LL | *let 0 = 0; | ^^^ @@ -683,7 +683,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:299:6 + --> $DIR/disallowed-positions.rs:303:6 | LL | -let 0 = 0; | ^^^ @@ -691,7 +691,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:301:13 + --> $DIR/disallowed-positions.rs:305:13 | LL | let _ = let _ = 3; | ^^^ @@ -699,7 +699,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:309:6 + --> $DIR/disallowed-positions.rs:313:6 | LL | (let 0 = 0)?; | ^^^ @@ -707,7 +707,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:312:13 + --> $DIR/disallowed-positions.rs:316:13 | LL | true || let 0 = 0; | ^^^ @@ -715,7 +715,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:314:14 + --> $DIR/disallowed-positions.rs:318:14 | LL | (true || let 0 = 0); | ^^^ @@ -723,7 +723,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:316:22 + --> $DIR/disallowed-positions.rs:320:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -731,7 +731,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:320:9 + --> $DIR/disallowed-positions.rs:324:9 | LL | x = let 0 = 0; | ^^^ @@ -739,7 +739,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:323:12 + --> $DIR/disallowed-positions.rs:327:12 | LL | true..(let 0 = 0); | ^^^ @@ -747,7 +747,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:325:8 + --> $DIR/disallowed-positions.rs:329:8 | LL | ..(let 0 = 0); | ^^^ @@ -755,7 +755,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:327:6 + --> $DIR/disallowed-positions.rs:331:6 | LL | (let 0 = 0)..; | ^^^ @@ -763,7 +763,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:6 + --> $DIR/disallowed-positions.rs:334:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -771,7 +771,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:6 + --> $DIR/disallowed-positions.rs:338:6 | LL | (let true = let true = true); | ^^^ @@ -779,7 +779,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:17 + --> $DIR/disallowed-positions.rs:338:17 | LL | (let true = let true = true); | ^^^ @@ -787,7 +787,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:340:25 + --> $DIR/disallowed-positions.rs:344:25 | LL | let x = true && let y = 1; | ^^^ @@ -795,7 +795,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:346:19 + --> $DIR/disallowed-positions.rs:350:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -803,7 +803,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:351:6 + --> $DIR/disallowed-positions.rs:355:6 | LL | &let 0 = 0 | ^^^ @@ -811,7 +811,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:362:17 + --> $DIR/disallowed-positions.rs:366:17 | LL | true && let 1 = 1 | ^^^ @@ -819,7 +819,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:367:17 + --> $DIR/disallowed-positions.rs:371:17 | LL | true && let 1 = 1 | ^^^ @@ -827,7 +827,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:372:17 + --> $DIR/disallowed-positions.rs:376:17 | LL | true && let 1 = 1 | ^^^ @@ -835,7 +835,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:383:17 + --> $DIR/disallowed-positions.rs:387:17 | LL | true && let 1 = 1 | ^^^ @@ -843,7 +843,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:383:9 + --> $DIR/disallowed-positions.rs:387:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -854,124 +854,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:393:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:393:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:401:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:401:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:400:9 + --> $DIR/disallowed-positions.rs:404:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:400:9 + --> $DIR/disallowed-positions.rs:404:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:400:32 + --> $DIR/disallowed-positions.rs:404:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:400:32 + --> $DIR/disallowed-positions.rs:404:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:408:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:408:9 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:408:31 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:408:31 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^ - -error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:412:9 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { - | ^^^^^^^^^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:9 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:412:31 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains --> $DIR/disallowed-positions.rs:412:31 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:416:9 | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:416:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:416:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:416:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:420:9 + | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:420:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:436:22 + --> $DIR/disallowed-positions.rs:440:22 | LL | let x = (true && let y = 1); | ^^^ @@ -979,7 +979,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:441:20 + --> $DIR/disallowed-positions.rs:445:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -995,15 +995,51 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:93:16 + --> $DIR/disallowed-positions.rs:91:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:91:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:95:16 | LL | use_expr!((let 0 = 1)); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:95:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:95:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:130:8 + --> $DIR/disallowed-positions.rs:134:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -1012,7 +1048,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:139:12 + --> $DIR/disallowed-positions.rs:143:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1023,7 +1059,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:142:12 + --> $DIR/disallowed-positions.rs:146:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1034,7 +1070,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:148:12 + --> $DIR/disallowed-positions.rs:152:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1045,7 +1081,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:154:12 + --> $DIR/disallowed-positions.rs:158:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1056,7 +1092,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:110:20 + --> $DIR/disallowed-positions.rs:114:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1064,7 +1100,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:221:11 + --> $DIR/disallowed-positions.rs:225:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -1073,7 +1109,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:230:15 + --> $DIR/disallowed-positions.rs:234:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1084,7 +1120,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:233:15 + --> $DIR/disallowed-positions.rs:237:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1095,7 +1131,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:239:15 + --> $DIR/disallowed-positions.rs:243:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1106,7 +1142,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:245:15 + --> $DIR/disallowed-positions.rs:249:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1117,7 +1153,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:201:23 + --> $DIR/disallowed-positions.rs:205:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1125,7 +1161,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:330:10 + --> $DIR/disallowed-positions.rs:334:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1136,14 +1172,14 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:305:17 + --> $DIR/disallowed-positions.rs:309:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 121 previous errors +error: aborting due to 125 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr index ad16a0f8ed81..bab50c22c030 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr @@ -233,7 +233,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:99:9 + --> $DIR/disallowed-positions.rs:103:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:102:9 + --> $DIR/disallowed-positions.rs:106:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:104:9 + --> $DIR/disallowed-positions.rs:108:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:106:9 + --> $DIR/disallowed-positions.rs:110:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:114:9 + --> $DIR/disallowed-positions.rs:118:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:117:16 + --> $DIR/disallowed-positions.rs:121:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:117:13 + --> $DIR/disallowed-positions.rs:121:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:119:17 + --> $DIR/disallowed-positions.rs:123:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:121:25 + --> $DIR/disallowed-positions.rs:125:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:123:25 + --> $DIR/disallowed-positions.rs:127:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:127:12 + --> $DIR/disallowed-positions.rs:131:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:130:15 + --> $DIR/disallowed-positions.rs:134:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:133:11 + --> $DIR/disallowed-positions.rs:137:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:135:9 + --> $DIR/disallowed-positions.rs:139:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:139:8 + --> $DIR/disallowed-positions.rs:143:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:142:8 + --> $DIR/disallowed-positions.rs:146:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:148:8 + --> $DIR/disallowed-positions.rs:152:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:154:8 + --> $DIR/disallowed-positions.rs:158:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:158:19 + --> $DIR/disallowed-positions.rs:162:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:161:15 + --> $DIR/disallowed-positions.rs:165:15 | LL | if return let 0 = 0 {} | ^^^ @@ -390,7 +390,7 @@ LL | if return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:164:21 + --> $DIR/disallowed-positions.rs:168:21 | LL | loop { if break let 0 = 0 {} } | ^^^ @@ -398,7 +398,7 @@ LL | loop { if break let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:167:15 + --> $DIR/disallowed-positions.rs:171:15 | LL | if (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -406,7 +406,7 @@ LL | if (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:170:9 + --> $DIR/disallowed-positions.rs:174:9 | LL | if (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -414,7 +414,7 @@ LL | if (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:173:9 + --> $DIR/disallowed-positions.rs:177:9 | LL | if (let 0 = 0,) {} | ^^^^^^^^^ @@ -422,7 +422,7 @@ LL | if (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:177:13 + --> $DIR/disallowed-positions.rs:181:13 | LL | if (let 0 = 0).await {} | ^^^^^^^^^ @@ -430,7 +430,7 @@ LL | if (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:12 + --> $DIR/disallowed-positions.rs:185:12 | LL | if (|| let 0 = 0) {} | ^^^ @@ -438,7 +438,7 @@ LL | if (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:184:9 + --> $DIR/disallowed-positions.rs:188:9 | LL | if (let 0 = 0)() {} | ^^^^^^^^^ @@ -446,7 +446,7 @@ LL | if (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:190:12 + --> $DIR/disallowed-positions.rs:194:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -454,7 +454,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:193:12 + --> $DIR/disallowed-positions.rs:197:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -462,7 +462,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:195:12 + --> $DIR/disallowed-positions.rs:199:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -470,7 +470,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:12 + --> $DIR/disallowed-positions.rs:201:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -478,7 +478,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:205:12 + --> $DIR/disallowed-positions.rs:209:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -486,20 +486,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:208:19 + --> $DIR/disallowed-positions.rs:212:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:208:16 + --> $DIR/disallowed-positions.rs:212:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:210:20 + --> $DIR/disallowed-positions.rs:214:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -507,7 +507,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:28 + --> $DIR/disallowed-positions.rs:216:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -515,7 +515,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:214:28 + --> $DIR/disallowed-positions.rs:218:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -523,7 +523,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:15 + --> $DIR/disallowed-positions.rs:222:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -531,7 +531,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:221:18 + --> $DIR/disallowed-positions.rs:225:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -539,7 +539,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:224:14 + --> $DIR/disallowed-positions.rs:228:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -547,7 +547,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:226:12 + --> $DIR/disallowed-positions.rs:230:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -555,7 +555,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:230:11 + --> $DIR/disallowed-positions.rs:234:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -563,7 +563,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:233:11 + --> $DIR/disallowed-positions.rs:237:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -571,7 +571,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:239:11 + --> $DIR/disallowed-positions.rs:243:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -579,7 +579,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:245:11 + --> $DIR/disallowed-positions.rs:249:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -587,7 +587,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:249:22 + --> $DIR/disallowed-positions.rs:253:22 | LL | while let true = let true = true {} | ^^^ @@ -595,7 +595,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:252:18 + --> $DIR/disallowed-positions.rs:256:18 | LL | while return let 0 = 0 {} | ^^^ @@ -603,7 +603,7 @@ LL | while return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:255:39 + --> $DIR/disallowed-positions.rs:259:39 | LL | 'outer: loop { while break 'outer let 0 = 0 {} } | ^^^ @@ -611,7 +611,7 @@ LL | 'outer: loop { while break 'outer let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:258:18 + --> $DIR/disallowed-positions.rs:262:18 | LL | while (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -619,7 +619,7 @@ LL | while (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:261:12 + --> $DIR/disallowed-positions.rs:265:12 | LL | while (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -627,7 +627,7 @@ LL | while (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:264:12 + --> $DIR/disallowed-positions.rs:268:12 | LL | while (let 0 = 0,) {} | ^^^^^^^^^ @@ -635,7 +635,7 @@ LL | while (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:268:16 + --> $DIR/disallowed-positions.rs:272:16 | LL | while (let 0 = 0).await {} | ^^^^^^^^^ @@ -643,7 +643,7 @@ LL | while (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:15 + --> $DIR/disallowed-positions.rs:276:15 | LL | while (|| let 0 = 0) {} | ^^^ @@ -651,7 +651,7 @@ LL | while (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:275:12 + --> $DIR/disallowed-positions.rs:279:12 | LL | while (let 0 = 0)() {} | ^^^^^^^^^ @@ -659,7 +659,7 @@ LL | while (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:292:6 + --> $DIR/disallowed-positions.rs:296:6 | LL | &let 0 = 0; | ^^^ @@ -667,7 +667,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:295:6 + --> $DIR/disallowed-positions.rs:299:6 | LL | !let 0 = 0; | ^^^ @@ -675,7 +675,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:297:6 + --> $DIR/disallowed-positions.rs:301:6 | LL | *let 0 = 0; | ^^^ @@ -683,7 +683,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:299:6 + --> $DIR/disallowed-positions.rs:303:6 | LL | -let 0 = 0; | ^^^ @@ -691,7 +691,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:301:13 + --> $DIR/disallowed-positions.rs:305:13 | LL | let _ = let _ = 3; | ^^^ @@ -699,7 +699,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:309:6 + --> $DIR/disallowed-positions.rs:313:6 | LL | (let 0 = 0)?; | ^^^ @@ -707,7 +707,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:312:13 + --> $DIR/disallowed-positions.rs:316:13 | LL | true || let 0 = 0; | ^^^ @@ -715,7 +715,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:314:14 + --> $DIR/disallowed-positions.rs:318:14 | LL | (true || let 0 = 0); | ^^^ @@ -723,7 +723,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:316:22 + --> $DIR/disallowed-positions.rs:320:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -731,7 +731,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:320:9 + --> $DIR/disallowed-positions.rs:324:9 | LL | x = let 0 = 0; | ^^^ @@ -739,7 +739,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:323:12 + --> $DIR/disallowed-positions.rs:327:12 | LL | true..(let 0 = 0); | ^^^ @@ -747,7 +747,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:325:8 + --> $DIR/disallowed-positions.rs:329:8 | LL | ..(let 0 = 0); | ^^^ @@ -755,7 +755,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:327:6 + --> $DIR/disallowed-positions.rs:331:6 | LL | (let 0 = 0)..; | ^^^ @@ -763,7 +763,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:6 + --> $DIR/disallowed-positions.rs:334:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -771,7 +771,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:6 + --> $DIR/disallowed-positions.rs:338:6 | LL | (let true = let true = true); | ^^^ @@ -779,7 +779,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:17 + --> $DIR/disallowed-positions.rs:338:17 | LL | (let true = let true = true); | ^^^ @@ -787,7 +787,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:340:25 + --> $DIR/disallowed-positions.rs:344:25 | LL | let x = true && let y = 1; | ^^^ @@ -795,7 +795,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:346:19 + --> $DIR/disallowed-positions.rs:350:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -803,7 +803,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:351:6 + --> $DIR/disallowed-positions.rs:355:6 | LL | &let 0 = 0 | ^^^ @@ -811,7 +811,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:362:17 + --> $DIR/disallowed-positions.rs:366:17 | LL | true && let 1 = 1 | ^^^ @@ -819,7 +819,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:367:17 + --> $DIR/disallowed-positions.rs:371:17 | LL | true && let 1 = 1 | ^^^ @@ -827,7 +827,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:372:17 + --> $DIR/disallowed-positions.rs:376:17 | LL | true && let 1 = 1 | ^^^ @@ -835,7 +835,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:383:17 + --> $DIR/disallowed-positions.rs:387:17 | LL | true && let 1 = 1 | ^^^ @@ -843,7 +843,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:383:9 + --> $DIR/disallowed-positions.rs:387:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -854,124 +854,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:393:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:393:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:401:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:401:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:400:9 + --> $DIR/disallowed-positions.rs:404:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:400:9 + --> $DIR/disallowed-positions.rs:404:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:400:32 + --> $DIR/disallowed-positions.rs:404:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:400:32 + --> $DIR/disallowed-positions.rs:404:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:408:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:408:9 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:408:31 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:408:31 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^ - -error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:412:9 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { - | ^^^^^^^^^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:9 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:412:31 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains --> $DIR/disallowed-positions.rs:412:31 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:416:9 | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:416:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:416:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:416:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:420:9 + | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:420:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:436:22 + --> $DIR/disallowed-positions.rs:440:22 | LL | let x = (true && let y = 1); | ^^^ @@ -979,7 +979,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:441:20 + --> $DIR/disallowed-positions.rs:445:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -995,13 +995,49 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:93:16 + --> $DIR/disallowed-positions.rs:91:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:91:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:95:16 | LL | use_expr!((let 0 = 1)); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:95:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:95:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0658]: `let` expressions in this position are unstable --> $DIR/disallowed-positions.rs:49:8 | @@ -1043,7 +1079,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:404:8 + --> $DIR/disallowed-positions.rs:408:8 | LL | if let Some(a) = opt && (true && true) { | ^^^^^^^^^^^^^^^^^ @@ -1053,7 +1089,7 @@ LL | if let Some(a) = opt && (true && true) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:420:28 + --> $DIR/disallowed-positions.rs:424:28 | LL | if (true && (true)) && let Some(a) = opt { | ^^^^^^^^^^^^^^^^^ @@ -1063,7 +1099,7 @@ LL | if (true && (true)) && let Some(a) = opt { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:423:18 + --> $DIR/disallowed-positions.rs:427:18 | LL | if (true) && let Some(a) = opt { | ^^^^^^^^^^^^^^^^^ @@ -1073,7 +1109,7 @@ LL | if (true) && let Some(a) = opt { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:426:16 + --> $DIR/disallowed-positions.rs:430:16 | LL | if true && let Some(a) = opt { | ^^^^^^^^^^^^^^^^^ @@ -1083,7 +1119,7 @@ LL | if true && let Some(a) = opt { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:431:8 + --> $DIR/disallowed-positions.rs:435:8 | LL | if let true = (true && fun()) && (true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1093,7 +1129,7 @@ LL | if let true = (true && fun()) && (true) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:130:8 + --> $DIR/disallowed-positions.rs:134:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -1102,7 +1138,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:139:12 + --> $DIR/disallowed-positions.rs:143:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1113,7 +1149,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:142:12 + --> $DIR/disallowed-positions.rs:146:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1124,7 +1160,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:148:12 + --> $DIR/disallowed-positions.rs:152:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1135,7 +1171,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:154:12 + --> $DIR/disallowed-positions.rs:158:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1146,7 +1182,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:110:20 + --> $DIR/disallowed-positions.rs:114:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1154,7 +1190,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:221:11 + --> $DIR/disallowed-positions.rs:225:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -1163,7 +1199,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:230:15 + --> $DIR/disallowed-positions.rs:234:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1174,7 +1210,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:233:15 + --> $DIR/disallowed-positions.rs:237:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1185,7 +1221,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:239:15 + --> $DIR/disallowed-positions.rs:243:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1196,7 +1232,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:245:15 + --> $DIR/disallowed-positions.rs:249:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1207,7 +1243,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:201:23 + --> $DIR/disallowed-positions.rs:205:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1215,7 +1251,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:330:10 + --> $DIR/disallowed-positions.rs:334:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1226,14 +1262,14 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:305:17 + --> $DIR/disallowed-positions.rs:309:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 130 previous errors +error: aborting due to 134 previous errors Some errors have detailed explanations: E0277, E0308, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr index 2d5fd1144add..943956feb4e0 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr @@ -233,7 +233,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:99:9 + --> $DIR/disallowed-positions.rs:103:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:102:9 + --> $DIR/disallowed-positions.rs:106:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:104:9 + --> $DIR/disallowed-positions.rs:108:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:106:9 + --> $DIR/disallowed-positions.rs:110:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:114:9 + --> $DIR/disallowed-positions.rs:118:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:117:16 + --> $DIR/disallowed-positions.rs:121:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:117:13 + --> $DIR/disallowed-positions.rs:121:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:119:17 + --> $DIR/disallowed-positions.rs:123:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:121:25 + --> $DIR/disallowed-positions.rs:125:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:123:25 + --> $DIR/disallowed-positions.rs:127:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:127:12 + --> $DIR/disallowed-positions.rs:131:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:130:15 + --> $DIR/disallowed-positions.rs:134:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:133:11 + --> $DIR/disallowed-positions.rs:137:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:135:9 + --> $DIR/disallowed-positions.rs:139:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:139:8 + --> $DIR/disallowed-positions.rs:143:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:142:8 + --> $DIR/disallowed-positions.rs:146:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:148:8 + --> $DIR/disallowed-positions.rs:152:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:154:8 + --> $DIR/disallowed-positions.rs:158:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:158:19 + --> $DIR/disallowed-positions.rs:162:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:161:15 + --> $DIR/disallowed-positions.rs:165:15 | LL | if return let 0 = 0 {} | ^^^ @@ -390,7 +390,7 @@ LL | if return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:164:21 + --> $DIR/disallowed-positions.rs:168:21 | LL | loop { if break let 0 = 0 {} } | ^^^ @@ -398,7 +398,7 @@ LL | loop { if break let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:167:15 + --> $DIR/disallowed-positions.rs:171:15 | LL | if (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -406,7 +406,7 @@ LL | if (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:170:9 + --> $DIR/disallowed-positions.rs:174:9 | LL | if (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -414,7 +414,7 @@ LL | if (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:173:9 + --> $DIR/disallowed-positions.rs:177:9 | LL | if (let 0 = 0,) {} | ^^^^^^^^^ @@ -422,7 +422,7 @@ LL | if (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:177:13 + --> $DIR/disallowed-positions.rs:181:13 | LL | if (let 0 = 0).await {} | ^^^^^^^^^ @@ -430,7 +430,7 @@ LL | if (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:12 + --> $DIR/disallowed-positions.rs:185:12 | LL | if (|| let 0 = 0) {} | ^^^ @@ -438,7 +438,7 @@ LL | if (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:184:9 + --> $DIR/disallowed-positions.rs:188:9 | LL | if (let 0 = 0)() {} | ^^^^^^^^^ @@ -446,7 +446,7 @@ LL | if (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:190:12 + --> $DIR/disallowed-positions.rs:194:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -454,7 +454,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:193:12 + --> $DIR/disallowed-positions.rs:197:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -462,7 +462,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:195:12 + --> $DIR/disallowed-positions.rs:199:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -470,7 +470,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:12 + --> $DIR/disallowed-positions.rs:201:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -478,7 +478,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:205:12 + --> $DIR/disallowed-positions.rs:209:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -486,20 +486,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:208:19 + --> $DIR/disallowed-positions.rs:212:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:208:16 + --> $DIR/disallowed-positions.rs:212:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:210:20 + --> $DIR/disallowed-positions.rs:214:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -507,7 +507,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:28 + --> $DIR/disallowed-positions.rs:216:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -515,7 +515,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:214:28 + --> $DIR/disallowed-positions.rs:218:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -523,7 +523,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:15 + --> $DIR/disallowed-positions.rs:222:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -531,7 +531,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:221:18 + --> $DIR/disallowed-positions.rs:225:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -539,7 +539,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:224:14 + --> $DIR/disallowed-positions.rs:228:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -547,7 +547,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:226:12 + --> $DIR/disallowed-positions.rs:230:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -555,7 +555,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:230:11 + --> $DIR/disallowed-positions.rs:234:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -563,7 +563,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:233:11 + --> $DIR/disallowed-positions.rs:237:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -571,7 +571,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:239:11 + --> $DIR/disallowed-positions.rs:243:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -579,7 +579,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:245:11 + --> $DIR/disallowed-positions.rs:249:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -587,7 +587,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:249:22 + --> $DIR/disallowed-positions.rs:253:22 | LL | while let true = let true = true {} | ^^^ @@ -595,7 +595,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:252:18 + --> $DIR/disallowed-positions.rs:256:18 | LL | while return let 0 = 0 {} | ^^^ @@ -603,7 +603,7 @@ LL | while return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:255:39 + --> $DIR/disallowed-positions.rs:259:39 | LL | 'outer: loop { while break 'outer let 0 = 0 {} } | ^^^ @@ -611,7 +611,7 @@ LL | 'outer: loop { while break 'outer let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:258:18 + --> $DIR/disallowed-positions.rs:262:18 | LL | while (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -619,7 +619,7 @@ LL | while (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:261:12 + --> $DIR/disallowed-positions.rs:265:12 | LL | while (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -627,7 +627,7 @@ LL | while (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:264:12 + --> $DIR/disallowed-positions.rs:268:12 | LL | while (let 0 = 0,) {} | ^^^^^^^^^ @@ -635,7 +635,7 @@ LL | while (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:268:16 + --> $DIR/disallowed-positions.rs:272:16 | LL | while (let 0 = 0).await {} | ^^^^^^^^^ @@ -643,7 +643,7 @@ LL | while (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:15 + --> $DIR/disallowed-positions.rs:276:15 | LL | while (|| let 0 = 0) {} | ^^^ @@ -651,7 +651,7 @@ LL | while (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:275:12 + --> $DIR/disallowed-positions.rs:279:12 | LL | while (let 0 = 0)() {} | ^^^^^^^^^ @@ -659,7 +659,7 @@ LL | while (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:292:6 + --> $DIR/disallowed-positions.rs:296:6 | LL | &let 0 = 0; | ^^^ @@ -667,7 +667,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:295:6 + --> $DIR/disallowed-positions.rs:299:6 | LL | !let 0 = 0; | ^^^ @@ -675,7 +675,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:297:6 + --> $DIR/disallowed-positions.rs:301:6 | LL | *let 0 = 0; | ^^^ @@ -683,7 +683,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:299:6 + --> $DIR/disallowed-positions.rs:303:6 | LL | -let 0 = 0; | ^^^ @@ -691,7 +691,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:301:13 + --> $DIR/disallowed-positions.rs:305:13 | LL | let _ = let _ = 3; | ^^^ @@ -699,7 +699,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:309:6 + --> $DIR/disallowed-positions.rs:313:6 | LL | (let 0 = 0)?; | ^^^ @@ -707,7 +707,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:312:13 + --> $DIR/disallowed-positions.rs:316:13 | LL | true || let 0 = 0; | ^^^ @@ -715,7 +715,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:314:14 + --> $DIR/disallowed-positions.rs:318:14 | LL | (true || let 0 = 0); | ^^^ @@ -723,7 +723,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:316:22 + --> $DIR/disallowed-positions.rs:320:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -731,7 +731,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:320:9 + --> $DIR/disallowed-positions.rs:324:9 | LL | x = let 0 = 0; | ^^^ @@ -739,7 +739,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:323:12 + --> $DIR/disallowed-positions.rs:327:12 | LL | true..(let 0 = 0); | ^^^ @@ -747,7 +747,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:325:8 + --> $DIR/disallowed-positions.rs:329:8 | LL | ..(let 0 = 0); | ^^^ @@ -755,7 +755,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:327:6 + --> $DIR/disallowed-positions.rs:331:6 | LL | (let 0 = 0)..; | ^^^ @@ -763,7 +763,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:6 + --> $DIR/disallowed-positions.rs:334:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -771,7 +771,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:6 + --> $DIR/disallowed-positions.rs:338:6 | LL | (let true = let true = true); | ^^^ @@ -779,7 +779,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:17 + --> $DIR/disallowed-positions.rs:338:17 | LL | (let true = let true = true); | ^^^ @@ -787,7 +787,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:340:25 + --> $DIR/disallowed-positions.rs:344:25 | LL | let x = true && let y = 1; | ^^^ @@ -795,7 +795,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:346:19 + --> $DIR/disallowed-positions.rs:350:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -803,7 +803,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:351:6 + --> $DIR/disallowed-positions.rs:355:6 | LL | &let 0 = 0 | ^^^ @@ -811,7 +811,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:362:17 + --> $DIR/disallowed-positions.rs:366:17 | LL | true && let 1 = 1 | ^^^ @@ -819,7 +819,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:367:17 + --> $DIR/disallowed-positions.rs:371:17 | LL | true && let 1 = 1 | ^^^ @@ -827,7 +827,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:372:17 + --> $DIR/disallowed-positions.rs:376:17 | LL | true && let 1 = 1 | ^^^ @@ -835,7 +835,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:383:17 + --> $DIR/disallowed-positions.rs:387:17 | LL | true && let 1 = 1 | ^^^ @@ -843,7 +843,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:383:9 + --> $DIR/disallowed-positions.rs:387:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -854,124 +854,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:393:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:393:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:401:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:401:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:400:9 + --> $DIR/disallowed-positions.rs:404:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:400:9 + --> $DIR/disallowed-positions.rs:404:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:400:32 + --> $DIR/disallowed-positions.rs:404:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:400:32 + --> $DIR/disallowed-positions.rs:404:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:408:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:408:9 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:408:31 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:408:31 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - | ^^^^^^^^^^^^^^^ - -error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:412:9 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { - | ^^^^^^^^^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:9 - | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:412:31 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains --> $DIR/disallowed-positions.rs:412:31 | -LL | if (let Some(a) = opt && (let Some(b) = a)) && true { +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement --> $DIR/disallowed-positions.rs:416:9 | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:416:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:416:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:416:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:420:9 + | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:420:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:436:22 + --> $DIR/disallowed-positions.rs:440:22 | LL | let x = (true && let y = 1); | ^^^ @@ -979,7 +979,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:441:20 + --> $DIR/disallowed-positions.rs:445:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs index 8eb8d617d581..99f99c2be72d 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -90,8 +90,12 @@ fn _macros() { } use_expr!((let 0 = 1 && 0 == 0)); //[feature,no_feature]~^ ERROR expected expression, found `let` statement + //[feature,no_feature]~| ERROR expected expression, found `let` statement + //[feature,no_feature]~| ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); //[feature,no_feature]~^ ERROR expected expression, found `let` statement + //[feature,no_feature]~| ERROR expected expression, found `let` statement + //[feature,no_feature]~| ERROR expected expression, found `let` statement } #[cfg(not(nothing))] From d59b17c5cdbf345d0088d90fc03faf2501a39757 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 26 Mar 2025 15:54:14 +1100 Subject: [PATCH 519/546] Remove `Token::uninterpolated_span`. In favour of the similar method on `Parser`, which works on things other than identifiers and lifetimes. --- compiler/rustc_ast/src/token.rs | 27 +++++-------------- compiler/rustc_parse/src/parser/expr.rs | 14 +++++----- compiler/rustc_parse/src/parser/item.rs | 10 +++---- compiler/rustc_parse/src/parser/mod.rs | 35 +++++++++++++++++++------ compiler/rustc_parse/src/parser/ty.rs | 6 ++--- 5 files changed, 48 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 2081777fff35..d57a369eebf2 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -448,8 +448,9 @@ pub enum TokenKind { /// Identifier token. /// Do not forget about `NtIdent` when you want to match on identifiers. - /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to - /// treat regular and interpolated identifiers in the same way. + /// It's recommended to use `Token::{ident,uninterpolate}` and + /// `Parser::token_uninterpolated_span` to treat regular and interpolated + /// identifiers in the same way. Ident(Symbol, IdentIsRaw), /// This identifier (and its span) is the identifier passed to the /// declarative macro. The span in the surrounding `Token` is the span of @@ -458,8 +459,9 @@ pub enum TokenKind { /// Lifetime identifier token. /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. - /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to - /// treat regular and interpolated lifetime identifiers in the same way. + /// It's recommended to use `Token::{ident,uninterpolate}` and + /// `Parser::token_uninterpolated_span` to treat regular and interpolated + /// identifiers in the same way. Lifetime(Symbol, IdentIsRaw), /// This identifier (and its span) is the lifetime passed to the /// declarative macro. The span in the surrounding `Token` is the span of @@ -585,23 +587,6 @@ impl Token { Token::new(Ident(ident.name, ident.is_raw_guess().into()), ident.span) } - /// For interpolated tokens, returns a span of the fragment to which the interpolated - /// token refers. For all other tokens this is just a regular span. - /// It is particularly important to use this for identifiers and lifetimes - /// for which spans affect name resolution and edition checks. - /// Note that keywords are also identifiers, so they should use this - /// if they keep spans or perform edition checks. - // - // Note: `Parser::uninterpolated_token_span` may give better information - // than this method does. - pub fn uninterpolated_span(&self) -> Span { - match self.kind { - NtIdent(ident, _) | NtLifetime(ident, _) => ident.span, - Interpolated(ref nt) => nt.use_span(), - _ => self.span, - } - } - pub fn is_range_separator(&self) -> bool { [DotDot, DotDotDot, DotDotEq].contains(&self.kind) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 424fee968e1d..1c2df3ffcd10 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1318,7 +1318,7 @@ impl<'a> Parser<'a> { /// Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { - if self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)) { + if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)) { return Ok(self.mk_await_expr(self_arg, lo)); } @@ -1509,9 +1509,9 @@ impl<'a> Parser<'a> { this.parse_expr_let(restrictions) } else if this.eat_keyword(exp!(Underscore)) { Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore)) - } else if this.token.uninterpolated_span().at_least_rust_2018() { + } else if this.token_uninterpolated_span().at_least_rust_2018() { // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly. - if this.token.uninterpolated_span().at_least_rust_2024() + if this.token_uninterpolated_span().at_least_rust_2024() // check for `gen {}` and `gen move {}` // or `async gen {}` and `async gen move {}` && (this.is_gen_block(kw::Gen, 0) @@ -2186,7 +2186,7 @@ impl<'a> Parser<'a> { fn parse_opt_meta_item_lit(&mut self) -> Option { self.recover_after_dot(); let span = self.token.span; - let uninterpolated_span = self.uninterpolated_token_span(); + let uninterpolated_span = self.token_uninterpolated_span(); self.eat_token_lit().map(|token_lit| { match MetaItemLit::from_token_lit(token_lit, span) { Ok(lit) => lit, @@ -2390,7 +2390,7 @@ impl<'a> Parser<'a> { let movability = if self.eat_keyword(exp!(Static)) { Movability::Static } else { Movability::Movable }; - let coroutine_kind = if self.token.uninterpolated_span().at_least_rust_2018() { + let coroutine_kind = if self.token_uninterpolated_span().at_least_rust_2018() { self.parse_coroutine_kind(Case::Sensitive) } else { None @@ -2939,7 +2939,7 @@ impl<'a> Parser<'a> { /// Parses `for await? in ` (`for` token already eaten). fn parse_expr_for(&mut self, opt_label: Option