From 38d5ee3be32cb7050d913a622f5374588bd0fb16 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sat, 19 Sep 2026 16:43:55 +0000 Subject: [PATCH 01/15] autodiff: fix sysroot candidates in libEnzyme not found error --- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 59 +++++++++---------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index c5741f544614c..68e5ed3d37741 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -90,6 +90,7 @@ pub(crate) use self::Enzyme_AD::*; pub(crate) mod Enzyme_AD { use std::ffi::{c_char, c_void}; + use std::path::PathBuf; use std::sync::{Mutex, MutexGuard, OnceLock}; use rustc_session::config::{Sysroot, host_tuple}; @@ -433,38 +434,36 @@ pub(crate) mod Enzyme_AD { }) } - fn get_enzyme_path(sysroot: &Sysroot) -> Result { + fn get_enzyme_path(sysroot: &Sysroot) -> Result { let llvm_version_major = llvm::LLVMRustVersionMajor(); + let mut searched = Vec::new(); - let path_buf = sysroot - .all_paths() - .map(|sysroot_path| { - filesearch::make_target_lib_path(sysroot_path, host_tuple()) - .join("lib") - .with_file_name(format!("libEnzyme-{llvm_version_major}")) - .with_extension(std::env::consts::DLL_EXTENSION) - }) - .find(|f| f.exists()) - .ok_or_else(|| { - let candidates = sysroot - .all_paths() - .map(|p| p.join("lib").display().to_string()) - .collect::>() - .join("\n* "); - EnzymeLibraryError::NotFound { - err: format!( - "failed to find a `libEnzyme-{llvm_version_major}` folder \ - in the sysroot candidates:\n* {candidates}" - ), - } - })?; - - Ok(path_buf - .to_str() - .ok_or_else(|| EnzymeLibraryError::LoadFailed { - err: format!("invalid UTF-8 in path: {}", path_buf.display()), - })? - .to_string()) + for p in sysroot.all_paths() { + let libdir = filesearch::make_target_lib_path(p, host_tuple()); + + let enzyme_path = libdir + .join(format!("libEnzyme-{llvm_version_major}")) + .with_extension(std::env::consts::DLL_EXTENSION); + + if enzyme_path.exists() { + return Ok(enzyme_path); + } + + searched.push(libdir); + } + + Err(EnzymeLibraryError::NotFound { + err: format!( + "failed to find a `libEnzyme-{llvm_version_major}.{}` \ + in the sysroot candidates:\n* {}", + std::env::consts::DLL_EXTENSION, + searched + .iter() + .map(|p| p.display().to_string()) + .collect::>() + .join("\n* ") + ), + }) } } } From 483372d915e41f9a7b174bfe184d0a42bd6cf266 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 14 Sep 2026 12:01:39 +0200 Subject: [PATCH 02/15] Split PassMode::IndirectUnsized out of PassMode::Indirect This prevents nonsensical combinations like unsized+on_stack and forces all users to explicitly handle the difference between sized and unsized arguments. In a couple of places unsized arguments were handled incorrectly if they would ever manage to reach that code. --- compiler/rustc_abi/src/lib.rs | 4 +- .../src/abi/pass_mode.rs | 15 +-- .../src/abi/returning.rs | 17 ++- compiler/rustc_codegen_gcc/src/abi.rs | 24 +--- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 6 +- compiler/rustc_codegen_llvm/src/abi.rs | 64 +++------ compiler/rustc_codegen_llvm/src/builder.rs | 3 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 3 + compiler/rustc_codegen_llvm/src/mono_item.rs | 1 + compiler/rustc_codegen_ssa/src/mir/block.rs | 26 ++-- compiler/rustc_codegen_ssa/src/mir/mod.rs | 5 +- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 1 + .../src/mono_checks/abi_check.rs | 4 +- compiler/rustc_public/src/abi.rs | 13 +- .../src/unstable/convert/stable/abi.rs | 13 +- compiler/rustc_target/src/callconv/mod.rs | 89 +++++-------- compiler/rustc_target/src/callconv/nvptx64.rs | 2 +- compiler/rustc_target/src/callconv/x86.rs | 5 +- compiler/rustc_target/src/callconv/xtensa.rs | 3 +- compiler/rustc_ty_utils/src/abi.rs | 10 +- tests/ui-fulldeps/rustc_public/check_abi.rs | 15 +-- tests/ui/abi/c-zst.powerpc-linux.stderr | 1 - tests/ui/abi/c-zst.s390x-linux.stderr | 1 - tests/ui/abi/c-zst.sparc-linux.stderr | 1 - tests/ui/abi/c-zst.sparc-none.stderr | 1 - tests/ui/abi/c-zst.sparc64-linux.stderr | 1 - .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 1 - tests/ui/abi/compatibility.rs | 16 ++- tests/ui/abi/debug.generic.stderr | 122 +++++++++++++++--- tests/ui/abi/debug.loongarch64.stderr | 122 +++++++++++++++--- tests/ui/abi/debug.riscv64.stderr | 122 +++++++++++++++--- tests/ui/abi/debug.rs | 8 +- tests/ui/abi/pass-indirectly-attr.stderr | 1 - .../pass-by-value-abi.aarch64.stderr | 1 - .../pass-by-value-abi.x86_64.stderr | 3 - 35 files changed, 475 insertions(+), 249 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 56cfbf138af00..55c24ad67715a 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2416,8 +2416,8 @@ impl LayoutData { /// Checks if these two `Layout` are equal enough to be considered "the same for all function /// call ABIs". Note however that real ABIs depend on more details that are not reflected in the /// `Layout`; the `PassMode` need to be compared as well. Also note that we assume - /// aggregates are passed via `PassMode::Indirect` or `PassMode::Cast`; more strict - /// checks would otherwise be required. + /// aggregates are passed via `PassMode::Indirect`, `PassMode::IndirectUnsized` or + /// `PassMode::Cast`; more strict checks would otherwise be required. pub fn eq_abi(&self, other: &Self) -> bool { // The one thing that we are not capturing here is that for unsized types, the metadata must // also have the same ABI, and moreover that the same metadata leads to the same size. The diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 48ffc43c5cfa1..9a6854399dde6 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -126,7 +126,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { assert_eq!(pad_i32_count, 0, "padding support not yet implemented"); cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect() } - PassMode::Indirect { attrs, meta_attrs: None, address_space: _, mode } => { + PassMode::Indirect { attrs, address_space: _, mode } => { assert!( mode != IndirectMode::AmdgpuKernelArg, "unsupported amdgpu kernel argument" @@ -143,8 +143,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { smallvec![apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)] } } - PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), address_space: _, mode } => { - assert!(mode == IndirectMode::Pointer); + PassMode::IndirectUnsized { attrs, meta_attrs } => { smallvec![ apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs), @@ -188,7 +187,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { None, cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(), ), - PassMode::Indirect { attrs, meta_attrs: None, address_space: _, mode } => { + PassMode::Indirect { attrs, address_space: _, mode } => { assert!(mode == IndirectMode::Pointer); ( Some(apply_attrs_to_abi_param( @@ -198,7 +197,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { vec![], ) } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { unreachable!("unsized return value") } } @@ -268,7 +267,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>( smallvec![a, b] } PassMode::Cast { ref cast, .. } => to_casted_value(fx, arg, cast), - PassMode::Indirect { .. } => { + PassMode::Indirect { .. } | PassMode::IndirectUnsized { .. } => { if is_owned { match arg.force_stack(fx) { (ptr, None) => smallvec![ptr.get_addr(fx)], @@ -328,7 +327,7 @@ pub(super) fn cvalue_for_param<'tcx>( PassMode::Cast { ref cast, .. } => { from_casted_value(fx, &block_params, arg_abi.layout, cast) } - PassMode::Indirect { attrs, meta_attrs: None, address_space: _, mode: _ } => { + PassMode::Indirect { attrs, address_space: _, mode: _ } => { assert_eq!(block_params.len(), 1, "{:?}", block_params); if let Some(pointee_align) = attrs.pointee_align && pointee_align < arg_abi.layout.align.abi @@ -346,7 +345,7 @@ pub(super) fn cvalue_for_param<'tcx>( CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout) } } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { assert_eq!(block_params.len(), 2, "{:?}", block_params); CValue::by_ref_unsized(Pointer::new(block_params[0]), block_params[1], arg_abi.layout) } diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index 7f4ee9435b506..e2b028e1be4a8 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -17,12 +17,12 @@ pub(super) fn codegen_return_param<'tcx>( let is_ssa = ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.ret.layout.ty); (super::make_local_place(fx, RETURN_PLACE, fx.fn_abi.ret.layout, is_ssa), smallvec![]) } - PassMode::Indirect { attrs: _, meta_attrs: None, address_space: _, mode: _ } => { + PassMode::Indirect { attrs: _, address_space: _, mode: _ } => { let ret_param = block_params_iter.next().unwrap(); assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type); (CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.ret.layout), smallvec![ret_param]) } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { unreachable!("unsized return value") } }; @@ -50,7 +50,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( ) { let (ret_temp_place, return_ptr) = match ret_arg_abi.mode { PassMode::Ignore => (None, None), - PassMode::Indirect { attrs: _, meta_attrs: None, address_space: _, mode: _ } => { + PassMode::Indirect { attrs: _, address_space: _, mode: _ } => { if let Some(ret_ptr) = ret_place.try_to_ptr() { // This is an optimization to prevent unnecessary copies of the return value when // the return place is already a memory place as opposed to a register. @@ -61,7 +61,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( (Some(place), Some(place.to_ptr().get_addr(fx))) } } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { unreachable!("unsized return value") } PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None), @@ -86,14 +86,14 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); ret_place.write_cvalue(fx, result); } - PassMode::Indirect { attrs: _, meta_attrs: None, address_space: _, mode: _ } => { + PassMode::Indirect { attrs: _, address_space: _, mode: _ } => { if let Some(ret_temp_place) = ret_temp_place { // If ret_temp_place is None, it is not necessary to copy the return value. let ret_temp_value = ret_temp_place.to_cvalue(fx); ret_place.write_cvalue(fx, ret_temp_value); } } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { unreachable!("unsized return value") } } @@ -102,11 +102,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( /// Codegen a return instruction with the right return value(s) if any. pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) { match fx.fn_abi.ret.mode { - PassMode::Ignore - | PassMode::Indirect { attrs: _, meta_attrs: None, address_space: _, mode: _ } => { + PassMode::Ignore | PassMode::Indirect { attrs: _, address_space: _, mode: _ } => { fx.bcx.ins().return_(&[]); } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { unreachable!("unsized return value") } PassMode::Direct(_) => { diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 5b88cebb4f174..fff25128260c6 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -131,6 +131,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { argument_tys.push(cx.type_ptr_to(self.ret.layout.gcc_type(cx))); cx.type_void() } + PassMode::IndirectUnsized { .. } => bug!("unsized returns are not supported"), }; #[cfg(feature = "master")] let mut non_null_args = Vec::new(); @@ -189,12 +190,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { let ty = cast.gcc_type(cx); apply_attrs(ty, &cast.attrs, argument_tys.len()) } - PassMode::Indirect { - attrs: _, - meta_attrs: None, - address_space: _, - mode: IndirectMode::OnStack, - } => { + PassMode::Indirect { attrs: _, address_space: _, mode: IndirectMode::OnStack } => { let x86_interrupt_first_arg = { #[cfg(feature = "master")] { @@ -223,7 +219,6 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } PassMode::Indirect { attrs: _, - meta_attrs: None, address_space: _, mode: IndirectMode::AmdgpuKernelArg, } => { @@ -232,21 +227,10 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Direct(attrs) => { apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs, argument_tys.len()) } - PassMode::Indirect { - attrs, - meta_attrs: None, - address_space: _, - mode: IndirectMode::Pointer, - } => { + PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::Pointer } => { apply_attrs(cx.type_ptr_to(arg.layout.gcc_type(cx)), &attrs, argument_tys.len()) } - PassMode::Indirect { - attrs, - meta_attrs: Some(meta_attrs), - address_space: _, - mode, - } => { - assert!(mode == IndirectMode::Pointer); + PassMode::IndirectUnsized { attrs, meta_attrs } => { // Construct the type of a (wide) pointer to `ty`, and pass its two fields. // Any two ABI-compatible unsized types have the same metadata type and // moreover the same metadata value leads to the same dynamic size and diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 4d2590ac81e41..c271461b26ba2 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -841,12 +841,10 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); } - PassMode::Indirect { meta_attrs: Some(_), .. } => { + PassMode::IndirectUnsized { .. } => { bug!("unsized `ArgAbi` cannot be stored"); } - PassMode::Direct(_) - | PassMode::Indirect { meta_attrs: None, .. } - | PassMode::Cast { .. } => { + PassMode::Direct(_) | PassMode::Indirect { .. } | PassMode::Cast { .. } => { let next_arg = next(); self.store(bx, next_arg, dst); } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index e16f34483a0c5..84e868c58ac46 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -243,12 +243,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { match &self.mode { PassMode::Ignore => {} // Sized indirect arguments - PassMode::Indirect { attrs, meta_attrs: None, address_space: _, mode: _ } => { + PassMode::Indirect { attrs, address_space: _, mode: _ } => { let align = attrs.pointee_align.unwrap_or(self.layout.align.abi); OperandValue::Ref(PlaceValue::new_sized(val, align)).store(bx, dst); } // Unsized indirect arguments cannot be stored - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { bug!("unsized `ArgAbi` cannot be stored"); } PassMode::Cast { cast, pad_i32_count: _ } => { @@ -304,11 +304,11 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { bug!("unsized `ArgAbi` cannot be stored"); } PassMode::Direct(_) - | PassMode::Indirect { attrs: _, meta_attrs: None, address_space: _, mode: _ } + | PassMode::Indirect { attrs: _, address_space: _, mode: _ } | PassMode::Cast { .. } => { let next_arg = next(); self.store(bx, next_arg, dst); @@ -378,6 +378,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { llargument_tys.push(ty); cx.type_void() } + PassMode::IndirectUnsized { .. } => bug!("unsized returns are not supported"), }; for arg in args { @@ -400,7 +401,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { // Construct the type of a (wide) pointer to `ty`, and pass its two fields. // Any two ABI-compatible unsized types have the same metadata type and // moreover the same metadata value leads to the same dynamic size and @@ -411,7 +412,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } - PassMode::Indirect { attrs: _, meta_attrs: None, address_space, mode: _ } => { + PassMode::Indirect { attrs: _, address_space, mode: _ } => { if let Some(address_space) = address_space { cx.type_ptr_ext(*address_space) } else { @@ -507,7 +508,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { apply_range_attr(llvm::AttributePlace::ReturnValue, scalar); } } - PassMode::Indirect { attrs, meta_attrs: _, address_space: _, mode } => { + PassMode::Indirect { attrs, address_space: _, mode } => { assert!(*mode == IndirectMode::Pointer); let i = apply(attrs); let sret = llvm::CreateStructRetAttr( @@ -526,6 +527,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); } } + PassMode::IndirectUnsized { .. } => bug!("unsized returns are not supported"), PassMode::Cast { cast, pad_i32_count: _ } => { cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); } @@ -534,12 +536,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { for arg in self.args.iter() { match &arg.mode { PassMode::Ignore => {} - PassMode::Indirect { - attrs, - meta_attrs: None, - address_space: _, - mode: IndirectMode::OnStack, - } => { + PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::OnStack } => { let i = apply(attrs); let byval = llvm::CreateByValAttr( cx.llcx, @@ -549,7 +546,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } PassMode::Indirect { attrs, - meta_attrs: None, address_space: _, mode: IndirectMode::AmdgpuKernelArg, } => { @@ -566,12 +562,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { apply_range_attr(llvm::AttributePlace::Argument(i), scalar); } } - PassMode::Indirect { - attrs, - meta_attrs: None, - address_space: _, - mode: IndirectMode::Pointer, - } => { + PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::Pointer } => { let i = apply(attrs); if cx.sess().opts.optimize != config::OptLevel::No { attributes::apply_to_llfn( @@ -581,13 +572,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); } } - PassMode::Indirect { - attrs, - meta_attrs: Some(meta_attrs), - address_space: _, - mode, - } => { - assert!(*mode == IndirectMode::Pointer); + PassMode::IndirectUnsized { attrs, meta_attrs } => { apply(attrs); apply(meta_attrs); } @@ -665,7 +650,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Direct(attrs) => { attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite); } - PassMode::Indirect { attrs, meta_attrs: _, address_space: _, mode } => { + PassMode::Indirect { attrs, address_space: _, mode } => { assert!(*mode == IndirectMode::Pointer); let i = apply(bx.cx, attrs); let sret = llvm::CreateStructRetAttr( @@ -674,6 +659,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]); } + PassMode::IndirectUnsized { .. } => bug!("unsized returns are not supported"), PassMode::Cast { cast, pad_i32_count: _ } => { cast.attrs.apply_attrs_to_callsite( llvm::AttributePlace::ReturnValue, @@ -686,12 +672,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { for arg in self.args.iter() { match &arg.mode { PassMode::Ignore => {} - PassMode::Indirect { - attrs, - meta_attrs: None, - address_space: _, - mode: IndirectMode::OnStack, - } => { + PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::OnStack } => { let i = apply(bx.cx, attrs); let byval = llvm::CreateByValAttr( bx.cx.llcx, @@ -705,7 +686,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } PassMode::Indirect { attrs, - meta_attrs: None, address_space: _, mode: IndirectMode::AmdgpuKernelArg, } => { @@ -721,20 +701,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); } PassMode::Direct(attrs) - | PassMode::Indirect { - attrs, - meta_attrs: None, - address_space: _, - mode: IndirectMode::Pointer, - } => { + | PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::Pointer } => { apply(bx.cx, attrs); } - PassMode::Indirect { - attrs, - meta_attrs: Some(meta_attrs), - address_space: _, - mode: _, - } => { + PassMode::IndirectUnsized { attrs, meta_attrs } => { apply(bx.cx, attrs); apply(bx.cx, meta_attrs); } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index abc71f450a515..b677fb4ccdee9 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -24,7 +24,7 @@ use rustc_middle::ty::layout::{ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_sanitizers::{cfi, kcfi}; use rustc_session::config::OptLevel; -use rustc_span::Span; +use rustc_span::{Span, bug}; use rustc_target::callconv::{FnAbi, PassMode}; use rustc_target::spec::{Arch, HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; @@ -1555,6 +1555,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { match &fn_abi.ret.mode { PassMode::Ignore | PassMode::Indirect { .. } => self.ret_void(), PassMode::Direct(_) | PassMode::Pair { .. } | PassMode::Cast { .. } => self.ret(call), + PassMode::IndirectUnsized { .. } => bug!("unsized returns are not supported"), } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 454347a5e041e..2fc06f9c0860f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2043,6 +2043,9 @@ fn get_args_from_tuple<'ll, 'tcx>( result.push(field.val.llval); tuple_index += 1; } + PassMode::IndirectUnsized { .. } => { + bug!("autodiff/offload args must not be unsized"); + } } } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index a25624550e3ad..946197c1ec663 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -222,6 +222,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { PassMode::Direct(_) | PassMode::Pair { .. } | PassMode::Cast { .. } => { start_bx.ret(call) } + PassMode::IndirectUnsized { .. } => bug!("unsized returns are not supported"), } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index f99009a0f4243..916b827f8bf4a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -644,6 +644,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi) } + PassMode::IndirectUnsized { .. } => bug!("unsized returns are not supported"), }; bx.ret(llval); } @@ -1285,6 +1286,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Copy the arguments that use `PassMode::Indirect { mode: IndirectMode::Pointer , ..}` // to temporary stack allocations. See the comment above. for (i, arg) in first_args.iter().enumerate() { + if matches!(fn_abi.args[i].mode, PassMode::IndirectUnsized { .. }) { + bug!("extern \"tail\" arguments must not be unsized"); + } + if !matches!( fn_abi.args[i].mode, PassMode::Indirect { mode: IndirectMode::Pointer, .. } @@ -1981,16 +1986,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => bug!("codegen_argument: {:?} invalid for pair argument", op), }, - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { - match op.val { - Ref(PlaceValue { llval: a, llextra: Some(b), .. }) => { - llargs.push(a); - llargs.push(b); - return; - } - _ => bug!("codegen_argument: {:?} invalid for unsized indirect argument", op), + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => match op.val { + Ref(PlaceValue { llval: a, llextra: Some(b), .. }) => { + llargs.push(a); + llargs.push(b); + return; } - } + _ => bug!("codegen_argument: {:?} invalid for unsized indirect argument", op), + }, _ => {} } @@ -2017,7 +2020,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (scratch.val.llval, scratch.val.align, true) } PassMode::Direct(_) => (op.immediate(), arg.layout.align.abi, false), - PassMode::Ignore | PassMode::Pair(..) => unreachable!("handled above"), + PassMode::Ignore | PassMode::Pair(..) | PassMode::IndirectUnsized { .. } => { + unreachable!("handled above") + } }, Ref(op_place_val) => match arg.mode { PassMode::Indirect { attrs, mode, .. } => { @@ -2044,6 +2049,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (op_place_val.llval, op_place_val.align, true) } } + PassMode::IndirectUnsized { .. } => unreachable!("handled above"), _ => (op_place_val.llval, op_place_val.align, true), }, ZeroSized => match arg.mode { diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index aefa8356536dc..4f332f1f7b34e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -336,6 +336,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let size = cast.size(&start_bx).max(layout.size); return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout)); } + PassMode::IndirectUnsized { .. } => bug!("unsized returns are not supported"), _ => {} }; } @@ -561,7 +562,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( match arg.mode { // Sized indirect arguments - PassMode::Indirect { attrs, meta_attrs: None, address_space: _, mode } => { + PassMode::Indirect { attrs, address_space: _, mode } => { // Don't copy an indirect argument to an alloca, the caller already put it // in a temporary alloca and gave it up. // AmdgpuKernelArg/byref arguments must not be modified, so always create a @@ -586,7 +587,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } // Unsized indirect arguments - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } => { + PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { // As the storage for the indirect argument lives during // the whole function call, we just copy the wide pointer. let llarg = bx.get_param(llarg_idx); diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 3162463d222ee..7dcb0774a9056 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -497,6 +497,7 @@ fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_t signature.push_str(wrapped_wasm_type); } PassMode::Indirect { .. } => signature.push_str(ptr_type), + PassMode::IndirectUnsized { .. } => bug!("unsized argument to naked asm"), } } diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 8fc069d76e9f5..bfd4caa068ac5 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -24,7 +24,9 @@ enum UsesVectorRegisters { /// scalable vector registers or no vector registers. fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters { match mode { - PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No, + PassMode::Ignore | PassMode::Indirect { .. } | PassMode::IndirectUnsized { .. } => { + UsesVectorRegisters::No + } PassMode::Cast { pad_i32_count: _, cast } if cast.prefix.iter().any(|x| matches!(x.kind, RegKind::Vector { .. })) || matches!(cast.rest.unit.kind, RegKind::Vector { .. }) => diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 72387fce19797..76790340ec1a0 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -86,14 +86,17 @@ pub enum PassMode { Cast { pad_i32_count: u8, cast: CastTarget }, /// Pass the argument indirectly via a pointer. /// + /// The caller places the value in memory and depending on mode passes a + /// pointer to it, stores it at a fixed stack offset or stores it at a + /// fixed location in a different address space. + Indirect { attrs: ArgAttributes, address_space: Option, mode: IndirectMode }, + /// Pass the unsized argument indirectly via a hidden pointer. + /// /// The caller places the value in memory and passes a pointer to it. - Indirect { + IndirectUnsized { attrs: ArgAttributes, /// Attributes for the metadata pointer (vtable or length) of unsized arguments. - /// Only present for unsized types (e.g., `dyn Trait`, `[T]`). - meta_attrs: Option, - address_space: Option, - mode: IndirectMode, + meta_attrs: ArgAttributes, }, } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 1ac0b706ed091..8d8e33eb674b1 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -188,12 +188,15 @@ impl<'tcx> Stable<'tcx> for callconv::PassMode { callconv::PassMode::Cast { pad_i32_count, cast } => { PassMode::Cast { pad_i32_count: *pad_i32_count, cast: cast.stable(tables, cx) } } - callconv::PassMode::Indirect { attrs, meta_attrs, address_space, mode } => { - PassMode::Indirect { + callconv::PassMode::Indirect { attrs, address_space, mode } => PassMode::Indirect { + attrs: attrs.stable(tables, cx), + address_space: address_space.stable(tables, cx), + mode: mode.stable(tables, cx), + }, + callconv::PassMode::IndirectUnsized { attrs, meta_attrs } => { + PassMode::IndirectUnsized { attrs: attrs.stable(tables, cx), - meta_attrs: meta_attrs.map(|a| a.stable(tables, cx)), - address_space: address_space.stable(tables, cx), - mode: mode.stable(tables, cx), + meta_attrs: meta_attrs.stable(tables, cx), } } } diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index edc23b6c50b45..332db35d04649 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -79,20 +79,16 @@ pub enum PassMode { Cast { pad_i32_count: u8, cast: Box }, /// Pass the argument indirectly via a hidden pointer. /// - /// The `meta_attrs` value, if any, is for the metadata (vtable or length) of an unsized - /// argument. (This is the only mode that supports unsized arguments.) - /// /// `address_space` specifies if the pointer is in a special address space or the default one. /// /// `mode` can be a special way to pass an argument indirectly. - /// `OnStack` and `AmdgpuKernelArg` cannot be used for unsized arguments, i.e., when - /// `meta_attrs` is `Some`. - Indirect { - attrs: ArgAttributes, - meta_attrs: Option, - address_space: Option, - mode: IndirectMode, - }, + Indirect { attrs: ArgAttributes, address_space: Option, mode: IndirectMode }, + + /// Like `Indirect`, but for unsized parameters. + /// + /// The `meta_attrs` value, is for the metadata (vtable or length) of an unsized argument. + /// (This is the only mode that supports unsized arguments.) `on_stack` is always false. + IndirectUnsized { attrs: ArgAttributes, meta_attrs: ArgAttributes }, } impl PassMode { @@ -109,23 +105,13 @@ impl PassMode { PassMode::Cast { cast: c2, pad_i32_count: pad2 }, ) => c1.eq_abi(c2) && pad1 == pad2, ( - PassMode::Indirect { attrs: a1, meta_attrs: None, address_space: as1, mode: m1 }, - PassMode::Indirect { attrs: a2, meta_attrs: None, address_space: as2, mode: m2 }, + PassMode::Indirect { attrs: a1, address_space: as1, mode: m1 }, + PassMode::Indirect { attrs: a2, address_space: as2, mode: m2 }, ) => a1.eq_abi(a2) && as1 == as2 && m1 == m2, ( - PassMode::Indirect { - attrs: a1, - meta_attrs: Some(e1), - address_space: as1, - mode: m1, - }, - PassMode::Indirect { - attrs: a2, - meta_attrs: Some(e2), - address_space: as2, - mode: m2, - }, - ) => a1.eq_abi(a2) && as1 == as2 && e1.eq_abi(e2) && m1 == m2, + PassMode::IndirectUnsized { attrs: a1, meta_attrs: e1 }, + PassMode::IndirectUnsized { attrs: a2, meta_attrs: e2 }, + ) => a1.eq_abi(a2) && e1.eq_abi(e2), _ => false, } } @@ -452,9 +438,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> { attrs.pointee_size = layout.size; attrs.pointee_align = Some(layout.align.abi); - let meta_attrs = layout.is_unsized().then_some(ArgAttributes::new()); - - PassMode::Indirect { attrs, meta_attrs, address_space: None, mode: IndirectMode::Pointer } + if layout.is_unsized() { + PassMode::IndirectUnsized { attrs, meta_attrs: ArgAttributes::new() } + } else { + PassMode::Indirect { attrs, address_space: None, mode: IndirectMode::Pointer } + } } /// Pass this argument indirectly, by passing a (thin or wide) pointer to the argument instead. @@ -465,12 +453,8 @@ impl<'a, Ty> ArgAbi<'a, Ty> { PassMode::Direct(_) | PassMode::Pair(_, _) => { self.mode = Self::indirect_pass_mode(&self.layout); } - PassMode::Indirect { - attrs: _, - meta_attrs: _, - address_space: _, - mode: IndirectMode::Pointer, - } => { + PassMode::Indirect { attrs: _, address_space: _, mode: IndirectMode::Pointer } + | PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { // already indirect } _ => panic!("Tried to make {:?} indirect", self.mode), @@ -498,12 +482,8 @@ impl<'a, Ty> ArgAbi<'a, Ty> { PassMode::Ignore => { self.mode = Self::indirect_pass_mode(&self.layout); } - PassMode::Indirect { - attrs: _, - meta_attrs: _, - address_space: _, - mode: IndirectMode::Pointer, - } => { + PassMode::Indirect { attrs: _, address_space: _, mode: IndirectMode::Pointer } + | PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => { // already indirect } _ => panic!("Tried to make {:?} indirect (expected `PassMode::Ignore`)", self.mode), @@ -530,7 +510,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { assert!(!self.layout.is_unsized(), "used byval ABI for unsized layout"); self.make_indirect(); match self.mode { - PassMode::Indirect { ref mut attrs, meta_attrs: _, address_space: _, ref mut mode } => { + PassMode::Indirect { ref mut attrs, address_space: _, ref mut mode } => { *mode = IndirectMode::OnStack; // Some platforms, like 32-bit x86, change the alignment of the type when passing @@ -553,7 +533,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { assert!(!self.layout.is_unsized(), "used amdgpu kernel arg ABI for unsized layout"); self.make_indirect(); match self.mode { - PassMode::Indirect { attrs: _, meta_attrs: _, ref mut address_space, ref mut mode } => { + PassMode::Indirect { attrs: _, ref mut address_space, ref mut mode } => { *mode = IndirectMode::AmdgpuKernelArg; *address_space = addrspace; } @@ -610,21 +590,15 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } pub fn is_indirect(&self) -> bool { - matches!(self.mode, PassMode::Indirect { .. }) + matches!(self.mode, PassMode::Indirect { .. } | PassMode::IndirectUnsized { .. }) } pub fn is_sized_indirect(&self) -> bool { - matches!( - self.mode, - PassMode::Indirect { attrs: _, meta_attrs: None, address_space: _, mode: _ } - ) + matches!(self.mode, PassMode::Indirect { attrs: _, address_space: _, mode: _ }) } pub fn is_unsized_indirect(&self) -> bool { - matches!( - self.mode, - PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } - ) + matches!(self.mode, PassMode::IndirectUnsized { attrs: _, meta_attrs: _ }) } pub fn is_ignore(&self) -> bool { @@ -925,8 +899,11 @@ impl<'a, Ty> FnAbi<'a, Ty> { BackendRepr::Memory { .. } => { // Compute `Aggregate` ABI. - let is_indirect_not_on_stack = - matches!(arg.mode, PassMode::Indirect { mode: IndirectMode::Pointer, .. }); + let is_indirect_not_on_stack = matches!( + arg.mode, + PassMode::Indirect { mode: IndirectMode::Pointer, .. } + | PassMode::IndirectUnsized { .. } + ); assert!(is_indirect_not_on_stack); let size = arg.layout.size; @@ -1037,7 +1014,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(ArgAbi<'_, usize>, 64); - static_assert_size!(FnAbi<'_, usize>, 88); + static_assert_size!(ArgAbi<'_, usize>, 56); + static_assert_size!(FnAbi<'_, usize>, 80); // tidy-alphabetical-end } diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs index 3919b7a69a78b..32ed6c0342e2d 100644 --- a/compiler/rustc_target/src/callconv/nvptx64.rs +++ b/compiler/rustc_target/src/callconv/nvptx64.rs @@ -58,7 +58,7 @@ where match arg.mode { super::PassMode::Ignore | super::PassMode::Direct(_) => return, super::PassMode::Pair(_, _) => {} - super::PassMode::Cast { .. } => unreachable!(), + super::PassMode::Cast { .. } | super::PassMode::IndirectUnsized { .. } => unreachable!(), super::PassMode::Indirect { .. } => {} } diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 3476f41e3bc75..78a5a22620aec 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -200,13 +200,12 @@ pub(crate) fn fill_inregs<'a, Ty, C>( for arg in fn_abi.args.iter_mut() { let attrs = match arg.mode { - PassMode::Ignore - | PassMode::Indirect { attrs: _, meta_attrs: None, address_space: _, mode: _ } => { + PassMode::Ignore | PassMode::Indirect { attrs: _, address_space: _, mode: _ } => { continue; } PassMode::Direct(ref mut attrs) => attrs, PassMode::Pair(..) - | PassMode::Indirect { attrs: _, meta_attrs: Some(_), address_space: _, mode: _ } + | PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } | PassMode::Cast { .. } => { unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index 49005adeb33c0..f3c74cec804bf 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -29,9 +29,10 @@ where classify_arg_ty(cx, arg, &mut arg_gprs_left, true); // Ret args cannot be passed via stack, we lower to indirect and let the backend handle the invisible reference match arg.mode { - super::PassMode::Indirect { attrs: _, meta_attrs: _, address_space: _, ref mut mode } => { + super::PassMode::Indirect { attrs: _, address_space: _, ref mut mode } => { *mode = IndirectMode::Pointer; } + super::PassMode::IndirectUnsized { .. } => panic!("unsized returns are not supported"), _ => {} } } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 448167ff90874..0f7771cb78b0b 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -500,7 +500,7 @@ fn fn_abi_sanity_check<'tcx>( // `Cast` means "transmute to `CastType`"; that only makes sense for sized types. assert!(arg.layout.is_sized()); } - PassMode::Indirect { meta_attrs: None, attrs, .. } => { + PassMode::Indirect { attrs, .. } => { // No metadata, must be sized. // Conceptually, unsized arguments must be copied around, which requires dynamically // determining their size, which we cannot do without metadata. Consult @@ -509,9 +509,11 @@ fn fn_abi_sanity_check<'tcx>( // Indirect returns are arguments from an ABI perspective. fn_arg_attrs_sanity_check(attrs, false); } - PassMode::Indirect { meta_attrs: Some(meta_attrs), attrs, address_space: _, mode } => { - // With metadata. Must be unsized and not on the stack. - assert!(arg.layout.is_unsized() && *mode == IndirectMode::Pointer); + PassMode::IndirectUnsized { attrs, meta_attrs } => { + // With metadata. Must be unsized. + assert!(arg.layout.is_unsized()); + // And must not be a return value + assert!(!is_ret); // Also, must not be `extern` type. let tail = tcx.struct_tail_for_codegen(arg.layout.ty, cx.typing_env); if matches!(tail.kind(), ty::Foreign(..)) { diff --git a/tests/ui-fulldeps/rustc_public/check_abi.rs b/tests/ui-fulldeps/rustc_public/check_abi.rs index 92d6f28f8fd8c..6c99265c468ac 100644 --- a/tests/ui-fulldeps/rustc_public/check_abi.rs +++ b/tests/ui-fulldeps/rustc_public/check_abi.rs @@ -14,6 +14,12 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_public; +use std::assert_matches; +use std::collections::HashSet; +use std::convert::TryFrom; +use std::io::Write; +use std::ops::ControlFlow; + use rustc_public::abi::{ ArgAbi, ArgExtension, CallConvention, FieldsShape, IndirectMode, IntegerLength, PassMode, Primitive, Scalar, ValueRepr, VariantsShape, @@ -23,11 +29,6 @@ use rustc_public::mir::mono::Instance; use rustc_public::target::MachineInfo; use rustc_public::ty::{AdtDef, RigidTy, Ty, TyKind}; use rustc_public::{CrateDef, CrateItem, CrateItems, ItemKind}; -use std::assert_matches; -use std::collections::HashSet; -use std::convert::TryFrom; -use std::io::Write; -use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; @@ -127,13 +128,11 @@ fn check_primitive(abi: &ArgAbi) { /// Check the return value: `Result`. fn check_result(abi: &ArgAbi) { assert!(abi.ty.kind().is_enum()); - let PassMode::Indirect { ref attrs, ref meta_attrs, address_space: _, mode } = abi.mode else { + let PassMode::Indirect { ref attrs, address_space: _, mode } = abi.mode else { panic!("Expected PassMode::Indirect for Result, got: {:?}", abi.mode); }; // Indirect arguments have a pointee alignment (the pointer must be aligned). assert!(attrs.pointee_align().is_some()); - // Result is a sized type, so no metadata pointer. - assert!(meta_attrs.is_none()); assert!(mode == IndirectMode::Pointer); let layout = abi.layout.shape(); assert!(layout.is_sized()); diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index e5cad2199491b..0c7a6b664526d 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -34,7 +34,6 @@ error: fn_abi_of(pass_zst) = FnAbi { Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index e5cad2199491b..0c7a6b664526d 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -34,7 +34,6 @@ error: fn_abi_of(pass_zst) = FnAbi { Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, diff --git a/tests/ui/abi/c-zst.sparc-linux.stderr b/tests/ui/abi/c-zst.sparc-linux.stderr index e5cad2199491b..0c7a6b664526d 100644 --- a/tests/ui/abi/c-zst.sparc-linux.stderr +++ b/tests/ui/abi/c-zst.sparc-linux.stderr @@ -34,7 +34,6 @@ error: fn_abi_of(pass_zst) = FnAbi { Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, diff --git a/tests/ui/abi/c-zst.sparc-none.stderr b/tests/ui/abi/c-zst.sparc-none.stderr index e5cad2199491b..0c7a6b664526d 100644 --- a/tests/ui/abi/c-zst.sparc-none.stderr +++ b/tests/ui/abi/c-zst.sparc-none.stderr @@ -34,7 +34,6 @@ error: fn_abi_of(pass_zst) = FnAbi { Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index e5cad2199491b..0c7a6b664526d 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -34,7 +34,6 @@ error: fn_abi_of(pass_zst) = FnAbi { Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index e5cad2199491b..0c7a6b664526d 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -34,7 +34,6 @@ error: fn_abi_of(pass_zst) = FnAbi { Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index c0a124208b21e..666910789dfb7 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -167,6 +167,18 @@ macro_rules! test_abi_compatible { type TestC = (extern "C" fn($t1) -> $t1, extern "C" fn($t2) -> $t2); } }; + ($name:ident, $t1:ty, $t2:ty, unsized) => { + mod $name { + use super::*; + // Declaring a `type` doesn't even check well-formedness, so we also declare a function. + fn check_wf(_x: $t1, _y: $t2) {} + // Test argument only in case of unsized types, `Rust` and `C` ABIs. + #[rustc_abi(assert_eq)] + type TestRust = (fn($t1), fn($t2)); + #[rustc_abi(assert_eq)] + type TestC = (extern "C" fn($t1), extern "C" fn($t2)); + } + }; } struct Zst; @@ -296,8 +308,8 @@ macro_rules! test_transparent_unsized { ($name:ident, $t:ty) => { mod $name { use super::*; - test_abi_compatible!(wrap1, $t, TransparentWrapper1<$t>); - test_abi_compatible!(wrap2, $t, TransparentWrapper2<$t>); + test_abi_compatible!(wrap1, $t, TransparentWrapper1<$t>, unsized); + test_abi_compatible!(wrap2, $t, TransparentWrapper2<$t>, unsized); } }; } diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index 1793674fa462a..fd72327d42fd7 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -1,5 +1,5 @@ error: the `rustc_abi` attribute cannot be used on constants - --> $DIR/debug.rs:42:3 + --> $DIR/debug.rs:48:3 | LL | #[rustc_abi(debug)] | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[rustc_abi(debug)] = help: the `rustc_abi` attribute can be applied to functions and type aliases error: the `rustc_abi` attribute cannot be used on associated consts - --> $DIR/debug.rs:46:7 + --> $DIR/debug.rs:52:7 | LL | #[rustc_abi(debug)] | ^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[rustc_abi(debug)] = help: the `rustc_abi` attribute can be applied to functions and type aliases error[E0539]: malformed `rustc_abi` attribute input - --> $DIR/debug.rs:74:3 + --> $DIR/debug.rs:80:3 | LL | #[rustc_abi("assert_eq")] | ^^^^^^^^^------------- @@ -112,6 +112,98 @@ error: fn_abi_of(test) = FnAbi { LL | fn test(_x: u8) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^ +error: fn_abi_of(test_unsized) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: [u8], + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: false, + }, + fields: Array { + stride: Size(1 bytes), + count: 0, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: IndirectUnsized { + attrs: ArgAttributes { + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: Some( + Align(1 bytes), + ), + }, + meta_attrs: ArgAttributes { + regular: , + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: bool, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + u8 is 0..=1, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: u8, + valid_range: 0..=1, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:37:1 + | +LL | fn test_unsized(_x: [u8]) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: fn_abi_of(TestFnPtr) = FnAbi { args: [ ArgAbi { @@ -188,7 +280,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:37:1 + --> $DIR/debug.rs:43:1 | LL | type TestFnPtr = fn(bool) -> u8; | ^^^^^^^^^^^^^^ @@ -259,13 +351,13 @@ error: fn_abi_of(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:40:1 + --> $DIR/debug.rs:46:1 | LL | fn test_generic(_x: *const T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `rustc_abi` attribute can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:43:1 + --> $DIR/debug.rs:49:1 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -403,7 +495,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:59:1 + --> $DIR/debug.rs:65:1 | LL | type TestAbiNe = (fn(u8), fn(u32)); | ^^^^^^^^^^^^^^ @@ -445,7 +537,6 @@ error: ABIs are not compatible Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, @@ -519,7 +610,6 @@ error: ABIs are not compatible Align(4 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, @@ -557,7 +647,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:62:1 + --> $DIR/debug.rs:68:1 | LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); | ^^^^^^^^^^^^^^^^^^^^ @@ -695,7 +785,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:65:1 + --> $DIR/debug.rs:71:1 | LL | type TestAbiNeFloat = (fn(f32), fn(u32)); | ^^^^^^^^^^^^^^^^^^^ @@ -833,13 +923,13 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:69:1 + --> $DIR/debug.rs:75:1 | LL | type TestAbiNeSign = (fn(i32), fn(u32)); | ^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/debug.rs:72:46 + --> $DIR/debug.rs:78:46 | LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -848,7 +938,7 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); = note: only the last element of a tuple may have a dynamically sized type error: the `rustc_abi` attribute can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:47:5 + --> $DIR/debug.rs:53:5 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -927,12 +1017,12 @@ error: fn_abi_of(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:52:5 + --> $DIR/debug.rs:58:5 | LL | fn assoc_test(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors Some errors have detailed explanations: E0277, E0539. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr index 29ec7846101f1..15d76f6e32078 100644 --- a/tests/ui/abi/debug.loongarch64.stderr +++ b/tests/ui/abi/debug.loongarch64.stderr @@ -1,5 +1,5 @@ error: the `rustc_abi` attribute cannot be used on constants - --> $DIR/debug.rs:42:3 + --> $DIR/debug.rs:48:3 | LL | #[rustc_abi(debug)] | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[rustc_abi(debug)] = help: the `rustc_abi` attribute can be applied to functions and type aliases error: the `rustc_abi` attribute cannot be used on associated consts - --> $DIR/debug.rs:46:7 + --> $DIR/debug.rs:52:7 | LL | #[rustc_abi(debug)] | ^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[rustc_abi(debug)] = help: the `rustc_abi` attribute can be applied to functions and type aliases error[E0539]: malformed `rustc_abi` attribute input - --> $DIR/debug.rs:74:3 + --> $DIR/debug.rs:80:3 | LL | #[rustc_abi("assert_eq")] | ^^^^^^^^^------------- @@ -112,6 +112,98 @@ error: fn_abi_of(test) = FnAbi { LL | fn test(_x: u8) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^ +error: fn_abi_of(test_unsized) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: [u8], + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: false, + }, + fields: Array { + stride: Size(1 bytes), + count: 0, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: IndirectUnsized { + attrs: ArgAttributes { + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: Some( + Align(1 bytes), + ), + }, + meta_attrs: ArgAttributes { + regular: , + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: bool, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + u8 is 0..=1, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: u8, + valid_range: 0..=1, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:37:1 + | +LL | fn test_unsized(_x: [u8]) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: fn_abi_of(TestFnPtr) = FnAbi { args: [ ArgAbi { @@ -188,7 +280,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:37:1 + --> $DIR/debug.rs:43:1 | LL | type TestFnPtr = fn(bool) -> u8; | ^^^^^^^^^^^^^^ @@ -259,13 +351,13 @@ error: fn_abi_of(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:40:1 + --> $DIR/debug.rs:46:1 | LL | fn test_generic(_x: *const T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `rustc_abi` attribute can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:43:1 + --> $DIR/debug.rs:49:1 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -403,7 +495,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:59:1 + --> $DIR/debug.rs:65:1 | LL | type TestAbiNe = (fn(u8), fn(u32)); | ^^^^^^^^^^^^^^ @@ -445,7 +537,6 @@ error: ABIs are not compatible Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, @@ -519,7 +610,6 @@ error: ABIs are not compatible Align(4 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, @@ -557,7 +647,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:62:1 + --> $DIR/debug.rs:68:1 | LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); | ^^^^^^^^^^^^^^^^^^^^ @@ -695,7 +785,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:65:1 + --> $DIR/debug.rs:71:1 | LL | type TestAbiNeFloat = (fn(f32), fn(u32)); | ^^^^^^^^^^^^^^^^^^^ @@ -833,13 +923,13 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:69:1 + --> $DIR/debug.rs:75:1 | LL | type TestAbiNeSign = (fn(i32), fn(u32)); | ^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/debug.rs:72:46 + --> $DIR/debug.rs:78:46 | LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -848,7 +938,7 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); = note: only the last element of a tuple may have a dynamically sized type error: the `rustc_abi` attribute can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:47:5 + --> $DIR/debug.rs:53:5 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -927,12 +1017,12 @@ error: fn_abi_of(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:52:5 + --> $DIR/debug.rs:58:5 | LL | fn assoc_test(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors Some errors have detailed explanations: E0277, E0539. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index 29ec7846101f1..15d76f6e32078 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -1,5 +1,5 @@ error: the `rustc_abi` attribute cannot be used on constants - --> $DIR/debug.rs:42:3 + --> $DIR/debug.rs:48:3 | LL | #[rustc_abi(debug)] | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[rustc_abi(debug)] = help: the `rustc_abi` attribute can be applied to functions and type aliases error: the `rustc_abi` attribute cannot be used on associated consts - --> $DIR/debug.rs:46:7 + --> $DIR/debug.rs:52:7 | LL | #[rustc_abi(debug)] | ^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[rustc_abi(debug)] = help: the `rustc_abi` attribute can be applied to functions and type aliases error[E0539]: malformed `rustc_abi` attribute input - --> $DIR/debug.rs:74:3 + --> $DIR/debug.rs:80:3 | LL | #[rustc_abi("assert_eq")] | ^^^^^^^^^------------- @@ -112,6 +112,98 @@ error: fn_abi_of(test) = FnAbi { LL | fn test(_x: u8) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^ +error: fn_abi_of(test_unsized) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: [u8], + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: false, + }, + fields: Array { + stride: Size(1 bytes), + count: 0, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: IndirectUnsized { + attrs: ArgAttributes { + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: Some( + Align(1 bytes), + ), + }, + meta_attrs: ArgAttributes { + regular: , + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: bool, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + u8 is 0..=1, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: u8, + valid_range: 0..=1, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:37:1 + | +LL | fn test_unsized(_x: [u8]) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: fn_abi_of(TestFnPtr) = FnAbi { args: [ ArgAbi { @@ -188,7 +280,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:37:1 + --> $DIR/debug.rs:43:1 | LL | type TestFnPtr = fn(bool) -> u8; | ^^^^^^^^^^^^^^ @@ -259,13 +351,13 @@ error: fn_abi_of(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:40:1 + --> $DIR/debug.rs:46:1 | LL | fn test_generic(_x: *const T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `rustc_abi` attribute can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:43:1 + --> $DIR/debug.rs:49:1 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -403,7 +495,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:59:1 + --> $DIR/debug.rs:65:1 | LL | type TestAbiNe = (fn(u8), fn(u32)); | ^^^^^^^^^^^^^^ @@ -445,7 +537,6 @@ error: ABIs are not compatible Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, @@ -519,7 +610,6 @@ error: ABIs are not compatible Align(4 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, @@ -557,7 +647,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:62:1 + --> $DIR/debug.rs:68:1 | LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); | ^^^^^^^^^^^^^^^^^^^^ @@ -695,7 +785,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:65:1 + --> $DIR/debug.rs:71:1 | LL | type TestAbiNeFloat = (fn(f32), fn(u32)); | ^^^^^^^^^^^^^^^^^^^ @@ -833,13 +923,13 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:69:1 + --> $DIR/debug.rs:75:1 | LL | type TestAbiNeSign = (fn(i32), fn(u32)); | ^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/debug.rs:72:46 + --> $DIR/debug.rs:78:46 | LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -848,7 +938,7 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); = note: only the last element of a tuple may have a dynamically sized type error: the `rustc_abi` attribute can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:47:5 + --> $DIR/debug.rs:53:5 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -927,12 +1017,12 @@ error: fn_abi_of(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:52:5 + --> $DIR/debug.rs:58:5 | LL | fn assoc_test(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors Some errors have detailed explanations: E0277, E0539. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 68228979d6900..8b897492e7865 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -16,7 +16,7 @@ //@ [generic] ignore-riscv64 //@ [generic] ignore-loongarch64 //@ ignore-backends: gcc -#![feature(rustc_attrs)] +#![feature(rustc_attrs, unsized_fn_params)] #![crate_type = "lib"] #![feature(no_core)] #![no_std] @@ -33,6 +33,12 @@ fn test(_x: u8) -> bool { true } +#[rustc_abi(debug)] +fn test_unsized(_x: [u8]) -> bool { + //~^ ERROR: fn_abi + true +} + #[rustc_abi(debug)] type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr index 5821e6279bb85..76d07c553a1a0 100644 --- a/tests/ui/abi/pass-indirectly-attr.stderr +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -47,7 +47,6 @@ error: fn_abi_of(extern_c) = FnAbi { Align(1 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, diff --git a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr index c9e77ac941901..59d4e18e4cd7c 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr @@ -34,7 +34,6 @@ error: fn_abi_of(take_va_list) = FnAbi { Align(8 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, diff --git a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr index 04320a5312361..b7e29098d6fe6 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr @@ -34,7 +34,6 @@ error: fn_abi_of(take_va_list) = FnAbi { Align(8 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, @@ -113,7 +112,6 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi { Align(8 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, @@ -194,7 +192,6 @@ error: fn_abi_of(take_va_list_win64) = FnAbi { Align(8 bytes), ), }, - meta_attrs: None, address_space: None, mode: Pointer, }, From 314a75b0251d7efd12bc6897fbe16661d9983755 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 16 Sep 2026 14:50:31 +0200 Subject: [PATCH 03/15] `TrivialTypeTraversalImpls!`: also impl `GenericTypeVisitable` When `TypeVisitable` is implemented but `GenericTypeVisitable` isn't, the lint (which we'll add soon) recommends adding `#[derive(GenericTypeVisitable)]`. However, this suggestion is incorrect for types whose impls ought to be trivial. There, the problem occurs because the type was added to `TrivialTypeTraversalImpls!` in `macros.rs`, which added the `TypeVisitable` impl, but wasn't added to `trivial_impls!` in `generic_visit.rs`, such that the `GenericTypeVisitable` impl wasn't added. Imo, the root cause of this problem is that we have two separate macros for adding trivial impls. So this commit merges them into one, by making `TrivialTypeTraversalImpls!` add a `GenericTypeVisitable` impl as well. RE: `Variance`: its `GenericTypeVisitable` impl is now provided by `TrivialTypeTraversalImpls!`, making the derive unnecessary. RE: `rustc_hash::FxBuildHasher`: its `GenericTypeVisitable` impl ended up being removed, because `TypeVisitable` can't be implemented due to it not implemnting `Debug`. This shouldn't be a problem however, as `{Generic,}TypeVisitable` should always be implemented in pairs anyway. I confirmed this by removing the impl from `ra-ap-rustc_type_ir` and `cargo check`-ing r-a. --- compiler/rustc_type_ir/src/generic_visit.rs | 47 --------------------- compiler/rustc_type_ir/src/lib.rs | 3 +- compiler/rustc_type_ir/src/macros.rs | 23 +++++++++- 3 files changed, 23 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_type_ir/src/generic_visit.rs b/compiler/rustc_type_ir/src/generic_visit.rs index 2444990749411..9910c84b42d26 100644 --- a/compiler/rustc_type_ir/src/generic_visit.rs +++ b/compiler/rustc_type_ir/src/generic_visit.rs @@ -172,57 +172,10 @@ unsafe impl, S: GenericTypeVisitable> GenericTy } } -macro_rules! trivial_impls { - ( $($ty:ty),* $(,)? ) => { - $( - unsafe impl - GenericTypeVisitable for $ty - { - fn generic_visit_with(&self, _visitor: &mut V) {} - } - )* - }; -} - unsafe impl GenericTypeVisitable for std::marker::PhantomData { fn generic_visit_with(&self, _visitor: &mut V) {} } -trivial_impls!( - (), - rustc_ast_ir::Mutability, - bool, - i8, - i16, - i32, - i64, - i128, - isize, - u8, - u16, - u32, - u64, - u128, - usize, - crate::ClausePolarity, - crate::BoundConstness, - crate::DebruijnIndex, - crate::solve::Certainty, - crate::UniverseIndex, - crate::BoundVar, - crate::InferTy, - crate::IntTy, - crate::UintTy, - crate::FloatTy, - crate::InferConst, - crate::RegionVid, - rustc_hash::FxBuildHasher, - crate::TypeFlags, - crate::solve::GoalSource, - crate::solve::VisibleForLeakCheck, - rustc_abi::ExternAbi, -); - // SAFETY: `FnSigKind` is a packed representation, therefore visiting its fields doesn't make sense unsafe impl GenericTypeVisitable for crate::FnSigKind { fn generic_visit_with(&self, _visitor: &mut V) {} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index b7fa0c77e44ee..38b717b2cadb4 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -105,7 +105,6 @@ pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy}; -use rustc_type_ir_macros::GenericTypeVisitable; #[cfg(feature = "nightly")] pub use serialize::*; pub use sty::*; @@ -251,7 +250,7 @@ pub fn debug_bound_var( } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, GenericTypeVisitable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(Decodable, Encodable, StableHash))] #[cfg_attr(feature = "nightly", rustc_pass_by_value)] pub enum Variance { diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 3741c80d0eb14..096f43f81e608 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -31,6 +31,12 @@ macro_rules! TrivialTypeTraversalImpls { ::output() } } + + // NOTE: this deliberately avoids adding an `I: Interner` generic, because that would + // allow creating a trivial impl for arena-allocating types, which would be incorrect. + unsafe impl $crate::GenericTypeVisitable for $ty { + fn generic_visit_with(&self, _visitor: &mut V) {} + } )+ }; } @@ -44,21 +50,36 @@ macro_rules! TrivialTypeTraversalImpls { TrivialTypeTraversalImpls! { (), bool, - usize, + i8, + i16, + i32, + i64, + i128, + isize, u8, u16, u32, u64, + usize, // tidy-alphabetical-start crate::BoundConstness, + crate::BoundVar, crate::ClausePolarity, crate::DebruijnIndex, + crate::FloatTy, + crate::InferConst, + crate::InferTy, + crate::IntTy, + crate::RegionVid, + crate::TypeFlags, + crate::UintTy, crate::UniverseIndex, crate::Variance, crate::solve::BuiltinImplSource, crate::solve::Certainty, crate::solve::GoalSource, crate::solve::VisibleForLeakCheck, + rustc_abi::ExternAbi, rustc_ast_ir::Mutability, // tidy-alphabetical-end } From e3940510fa39613b20be1ccfea0d00a0cad07303 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 30 Sep 2026 13:11:01 +0200 Subject: [PATCH 04/15] dogfood: add missing `GenericTypeVisitable` impls The missing impl for arrays was (indirectly) highlighted by the test suite, the rest -- by the `#[deny]` --- compiler/rustc_type_ir/src/generic_visit.rs | 6 ++++++ compiler/rustc_type_ir/src/unnormalized.rs | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_type_ir/src/generic_visit.rs b/compiler/rustc_type_ir/src/generic_visit.rs index 9910c84b42d26..e2663a61421f1 100644 --- a/compiler/rustc_type_ir/src/generic_visit.rs +++ b/compiler/rustc_type_ir/src/generic_visit.rs @@ -116,6 +116,12 @@ unsafe impl> GenericTypeVisitable for [T] { } } +unsafe impl, const N: usize> GenericTypeVisitable for [T; N] { + fn generic_visit_with(&self, visitor: &mut V) { + self.iter().for_each(|it| it.generic_visit_with(visitor)); + } +} + unsafe impl, Ix: Idx> GenericTypeVisitable for IndexVec { fn generic_visit_with(&self, visitor: &mut V) { self.iter().for_each(|it| it.generic_visit_with(visitor)); diff --git a/compiler/rustc_type_ir/src/unnormalized.rs b/compiler/rustc_type_ir/src/unnormalized.rs index 17a8e0e75fa78..3b03d64cd57a3 100644 --- a/compiler/rustc_type_ir/src/unnormalized.rs +++ b/compiler/rustc_type_ir/src/unnormalized.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::StableHash_NoContext; -use rustc_type_ir_macros::TypeVisitable_Generic; +use rustc_type_ir_macros::{GenericTypeVisitable, TypeVisitable_Generic}; use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder}; use crate::inherent::*; @@ -30,7 +30,7 @@ use crate::{ /// [here]: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/Eager.20normalization.2C.20ahoy.21/with/582996293 #[derive_where(Clone, Copy, PartialOrd, PartialEq, Eq, Hash, Debug; T)] #[cfg_attr(feature = "nightly", derive(StableHash_NoContext))] -#[derive(TypeVisitable_Generic)] +#[derive(TypeVisitable_Generic, GenericTypeVisitable)] pub struct Unnormalized { value: T, #[type_visitable(ignore)] From 4ba952a8d69aaf4e9835e30ff5c7e13f73224845 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 Oct 2026 20:21:53 +0200 Subject: [PATCH 05/15] Fix more `incoherent_impl` linking --- src/librustdoc/html/format.rs | 10 +++++--- .../rustdoc-html/jump-to-def/link-to-alloc.rs | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 tests/rustdoc-html/jump-to-def/link-to-alloc.rs diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7f0c4132456ad..464977d762488 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -17,7 +17,7 @@ use rustc_attr_ir::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, MacroKinds}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE, ModId}; use rustc_metadata::creader::CStore; use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_span::symbol::kw; @@ -436,7 +436,6 @@ fn transitive_reexport_path_inner( def_id: DefId, callers: &mut Vec, ) -> Option> { - use rustc_hir::def_id::ModId; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; if let Some(cnum) = def_id.as_crate_root() { @@ -644,7 +643,12 @@ fn url_parts( relative_to: &[Symbol], jump_to_def_path_depth: Option, ) -> Result<(UrlPartsBuilder, bool), HrefError> { - match cache.extern_locations[&def_id.krate] { + let location = if def_id.krate == LOCAL_CRATE { + &ExternalLocation::Local + } else { + &cache.extern_locations[&def_id.krate] + }; + match *location { ExternalLocation::Remote { ref url, is_absolute } => { let depth = jump_to_def_path_depth.unwrap_or(relative_to.len()); let mut builder = remote_url_prefix(url, is_absolute, depth); diff --git a/tests/rustdoc-html/jump-to-def/link-to-alloc.rs b/tests/rustdoc-html/jump-to-def/link-to-alloc.rs new file mode 100644 index 0000000000000..38d3caaa24b74 --- /dev/null +++ b/tests/rustdoc-html/jump-to-def/link-to-alloc.rs @@ -0,0 +1,24 @@ +// This test ensures that we're linking to `alloc` for the `Error::new` method as +// it is defined in `alloc`. The path between `core` (`core::io::error::Error`) and `alloc` +// (`alloc::io::Error`) is different though, so this test ensures that we generate the +// correct one (and also that we link to `std` rather than `alloc`). + +#![crate_name = "foo"] + +// Needed for the `alloc` imports. +extern crate alloc; + +//@ compile-flags: -Zunstable-options --generate-link-to-definition + +//@ has 'src/foo/link-to-alloc.rs.html' + +use alloc::io; + +pub fn foo() -> Option { + //@ has - '//a[@href="{{channel}}/core/io/error/struct.Error.html"]' 'Error' + //@ has - '//a[@href="{{channel}}/std/io/struct.Error.html#method.new"]' 'new' + // This check is just to show that we also link to `core` when relevant. + //@ has - '//a[@href="{{channel}}/core/io/error/enum.ErrorKind.html#variant.InvalidInput"]' \ + // 'InvalidInput' + Some(io::Error::new(io::ErrorKind::InvalidInput, "blob")) +} From 9a6d547f7ecfd6cb9482125e6c8a977a34d9c397 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 6 Oct 2026 19:13:19 -0400 Subject: [PATCH 06/15] Update Enzyme submodule --- src/tools/enzyme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/enzyme b/src/tools/enzyme index fa6e20ebd80f0..ede97b5c7b8d1 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit fa6e20ebd80f0e28219abaf174d95baf1513ce92 +Subproject commit ede97b5c7b8d1ddacd5383601798a67aaac2077c From 48156cc3c9c112d9e5ea43ea09e583430cc00613 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 7 Oct 2026 02:50:09 -0700 Subject: [PATCH 07/15] Store loop hints as `UnrollAttr` rather than `AttributeKind` This will make it easier to move them in a subsequent commit, since `UnrollAttr` implements `PartialEq`. If, in the future, we add more kinds of loop hints, this can become a small enum wrapping only those attr types. --- compiler/rustc_codegen_llvm/src/builder.rs | 9 +++------ compiler/rustc_codegen_ssa/src/mir/block.rs | 4 ++-- compiler/rustc_codegen_ssa/src/traits/builder.rs | 4 ++-- compiler/rustc_middle/src/mir/terminator.rs | 4 ++-- compiler/rustc_middle/src/thir.rs | 4 ++-- compiler/rustc_middle/src/ty/structural_impls.rs | 1 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 8 +++----- 7 files changed, 15 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index b7c930502978e..d259fe83565fa 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -8,7 +8,7 @@ pub(crate) mod gpu_offload; use libc::{c_char, c_uint}; use rustc_abi::{self as abi, Align, CanonAbi, Size, WrappingRange}; -use rustc_attr_ir::{AttributeKind, UnrollAttr}; +use rustc_attr_ir::UnrollAttr; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; @@ -340,16 +340,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - fn br_with_attrs(&mut self, dest: &'ll BasicBlock, loop_hint_attrs: &[AttributeKind]) { + fn br_with_attrs(&mut self, dest: &'ll BasicBlock, loop_hint_attrs: &[UnrollAttr]) { unsafe { let val = llvm::LLVMBuildBr(self.llbuilder, dest); let mut nodes = Vec::new(); - for loop_hint_attr in loop_hint_attrs { - let AttributeKind::Unroll(unroll) = loop_hint_attr else { - continue; - }; + for unroll in loop_hint_attrs { // UnrollAttr::Count needs a second operand, the provided count, but the other // unroll hints do not. let md_node = if let UnrollAttr::Count(count) = unroll { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 9db1dd700e95e..232af2bbe8815 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -7,7 +7,7 @@ use rustc_abi::{ }; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_attr_ir::AttributeKind; +use rustc_attr_ir::UnrollAttr; use rustc_attr_ir::lang_items::LangItem; use rustc_data_structures::packed::Pu128; use rustc_lint_defs::builtin::TAIL_CALL_TRACK_CALLER; @@ -140,7 +140,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { bx: &mut Bx, target: mir::BasicBlock, mergeable_succ: bool, - loop_hint_attrs: &[AttributeKind], + loop_hint_attrs: &[UnrollAttr], ) -> MergingSucc { let (needs_landing_pad, is_cleanupret) = self.llbb_characteristics(fx, target); if mergeable_succ && !needs_landing_pad && !is_cleanupret { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 59e1f6e9d0098..3c0c01d07cccc 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -3,7 +3,7 @@ use std::ops::Deref; use rustc_abi::{Align, Scalar, Size, WrappingRange}; use rustc_ast::expand::typetree::{FncTree, TypeTree}; -use rustc_attr_ir::AttributeKind; +use rustc_attr_ir::UnrollAttr; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; @@ -94,7 +94,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn ret_void(&mut self); fn ret(&mut self, v: Self::Value); fn br(&mut self, dest: Self::BasicBlock); - fn br_with_attrs(&mut self, dest: Self::BasicBlock, _loop_hint_attrs: &[AttributeKind]) { + fn br_with_attrs(&mut self, dest: Self::BasicBlock, _loop_hint_attrs: &[UnrollAttr]) { self.br(dest) } fn cond_br( diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 540a49aece678..15d6c8f03bc70 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -3,7 +3,7 @@ use std::slice; use rustc_ast::InlineAsmOptions; -use rustc_attr_ir::AttributeKind; +use rustc_attr_ir::UnrollAttr; use rustc_attr_ir::lang_items::LangItem; use rustc_data_structures::packed::Pu128; use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; @@ -419,7 +419,7 @@ impl fmt::Display for AssertKind { pub struct Terminator<'tcx> { pub source_info: SourceInfo, pub kind: TerminatorKind<'tcx>, - pub loop_hint_attrs: ThinVec, + pub loop_hint_attrs: ThinVec, } impl<'tcx> Terminator<'tcx> { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index a3e5168e4f1e9..1205c5813a679 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -15,7 +15,7 @@ use std::sync::Arc; use rustc_abi::{FieldIdx, Integer, Size, VariantIdx}; use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece, Mutability}; -use rustc_attr_ir::AttributeKind; +use rustc_attr_ir::UnrollAttr; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; @@ -62,7 +62,7 @@ macro_rules! thir_with_elements { #[derive(Debug, StableHash, Clone)] pub struct Thir<'tcx> { pub body_type: BodyTy<'tcx>, - pub loop_hint_attrs: FxIndexMap>, + pub loop_hint_attrs: FxIndexMap>, $( pub $name: IndexVec<$id, $value>, )* diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 3710a159b3fdd..300c70e04ede6 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -218,6 +218,7 @@ TrivialTypeTraversalImpls! { rustc_ast::InlineAsmOptions, rustc_ast::InlineAsmTemplatePiece, rustc_attr_ir::AttributeKind, + rustc_attr_ir::UnrollAttr, rustc_hir::CoroutineKind, rustc_hir::HirId, rustc_hir::MatchSource, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 16e92ae2c51e4..e38e9293ba196 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -2,7 +2,7 @@ use itertools::Itertools; use rustc_abi::{FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use rustc_ast::UnsafeBinderCastKind; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::{AttributeKind, HasAttrs, find_attr}; +use rustc_attr_ir::{AttributeKind, HasAttrs, UnrollAttr, find_attr}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::HirId; @@ -57,13 +57,11 @@ impl<'tcx> SplattedFunc<'tcx> { } } -fn filter_loop_hint_attrs(id: HirId, tcx: TyCtxt<'_>) -> ThinVec { +fn filter_loop_hint_attrs(id: HirId, tcx: TyCtxt<'_>) -> ThinVec { HasAttrs::get_attrs(id, &tcx) .into_iter() .filter_map(|attr| match attr { - rustc_attr_ir::Attribute::Parsed(attrkind @ AttributeKind::Unroll(_)) => { - Some(attrkind.clone()) - } + rustc_attr_ir::Attribute::Parsed(AttributeKind::Unroll(unroll)) => Some(unroll.clone()), _ => None, }) .collect() From 6545abe3199bc18e29ea4137d9127af0e58289b5 Mon Sep 17 00:00:00 2001 From: tmiasko Date: Wed, 7 Oct 2026 11:45:59 +0000 Subject: [PATCH 08/15] Use BasicBlock::start_location and Location::START --- compiler/rustc_borrowck/src/polonius/constraints.rs | 3 +-- compiler/rustc_borrowck/src/polonius/legacy/mod.rs | 7 +++---- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_const_eval/src/interpret/eval_context.rs | 4 ++-- compiler/rustc_middle/src/mir/mod.rs | 1 + compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_mir_dataflow/src/framework/cursor.rs | 2 +- compiler/rustc_mir_transform/src/coroutine/mod.rs | 2 +- compiler/rustc_mir_transform/src/elaborate_drops.rs | 2 +- compiler/rustc_mir_transform/src/liveness.rs | 2 +- compiler/rustc_mir_transform/src/ssa_range_prop.rs | 6 +++--- compiler/rustc_mir_transform/src/validate.rs | 4 ++-- 12 files changed, 18 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/constraints.rs b/compiler/rustc_borrowck/src/polonius/constraints.rs index d445d2e8ef96d..2879f0caea572 100644 --- a/compiler/rustc_borrowck/src/polonius/constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/constraints.rs @@ -178,8 +178,7 @@ impl LocalizedConstraintGraph { // Inter-block edges, from the block's terminator to each successor block's // entry point. for successor_block in body[location.block].terminator().successors() { - let next_location = - Location { block: successor_block, statement_index: 0 }; + let next_location = successor_block.start_location(); let next_point = location_map.point_from_location(next_location); if liveness.is_live_at(next_point) { successor_found(LocalizedNode { diff --git a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs index 1aae724266c6f..93a618b838ddb 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs @@ -6,7 +6,7 @@ use std::iter; use either::Either; -use rustc_middle::mir::{Body, Local, LocalKind, Location, START_BLOCK}; +use rustc_middle::mir::{Body, Local, LocalKind, Location}; use rustc_middle::ty::{GenericArg, TyCtxt}; use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData}; use tracing::debug; @@ -80,8 +80,7 @@ fn emit_move_facts( } } - let fn_entry_start = - location_table.start_index(Location { block: START_BLOCK, statement_index: 0 }); + let fn_entry_start = location_table.start_index(Location::START); // initialized_at for init in move_data.inits.iter() { @@ -101,7 +100,7 @@ fn emit_move_facts( // The initialization happened in (or rather, when arriving at) // the successors, but not in the unwind block. - let first_statement = Location { block: successor, statement_index: 0 }; + let first_statement = successor.start_location(); facts .path_assigned_at_base .push((init.path, location_table.start_index(first_statement))); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index ab0d786c6f264..d4d650d2a3ed1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -592,7 +592,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } for (block, block_data) in body.basic_blocks.iter_enumerated() { - let mut location = Location { block, statement_index: 0 }; + let mut location = block.start_location(); for stmt in &block_data.statements { self.visit_statement(stmt, location); location.statement_index += 1; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index a74b323c395e6..94b73a830503e 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -522,7 +522,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Jump to the given block. #[inline] pub fn go_to_block(&mut self, target: mir::BasicBlock) { - self.frame_mut().loc = Left(mir::Location { block: target, statement_index: 0 }); + self.frame_mut().loc = Left(target.start_location()); } /// *Return* to the given `target` basic block. @@ -549,7 +549,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[cold] // usually we have normal returns, not unwinding pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> { self.frame_mut().loc = match target { - mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }), + mir::UnwindAction::Cleanup(block) => Left(block.start_location()), mir::UnwindAction::Continue => Right(self.frame_mut().body.span), mir::UnwindAction::Unreachable => { throw_ub_format!("unwinding past a stack frame that does not allow unwinding"); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 19a6d2a31c4e3..6f266fc62b63e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1303,6 +1303,7 @@ rustc_index::newtype_index! { } impl BasicBlock { + #[inline] pub fn start_location(self) -> Location { Location { block: self, statement_index: 0 } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index ae30093b1cda7..daf47f991f488 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -793,7 +793,7 @@ impl<'a, 'tcx> MirWriter<'a, 'tcx> { writeln!(w, "{INDENT}{block:?}{cleanup_text}: {{")?; // List of statements in the middle. - let mut current_location = Location { block, statement_index: 0 }; + let mut current_location = block.start_location(); for statement in &data.statements { (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?; diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 63b2adceb524c..17a13ef2f2edd 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -134,7 +134,7 @@ where if A::Direction::IS_FORWARD { self.seek_to_block_entry(block) } else { - self.seek_after(Location { block, statement_index: 0 }, Effect::Primary) + self.seek_after(block.start_location(), Effect::Primary) } } diff --git a/compiler/rustc_mir_transform/src/coroutine/mod.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs index 1e63dca78adbb..9ea1e27dca943 100644 --- a/compiler/rustc_mir_transform/src/coroutine/mod.rs +++ b/compiler/rustc_mir_transform/src/coroutine/mod.rs @@ -394,7 +394,7 @@ impl<'tcx> TransformVisitor<'tcx> { visitor.visit_body(body); for suspension in &mut self.suspension_points { let ctxt = PlaceContext::MutatingUse(MutatingUseContext::Yield); - let location = Location { block: START_BLOCK, statement_index: 0 }; + let location = Location::START; visitor.visit_place(&mut suspension.resume_arg, ctxt, location); } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index a19ae86542d25..8ae63c5c3b0c4 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -443,7 +443,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { { assert!(!self.patch.is_term_patched(bb)); - let loc = Location { block: tgt, statement_index: 0 }; + let loc = tgt.start_location(); let path = self.move_data().rev_lookup.find(destination.as_ref()); on_lookup_result_bits(self.move_data(), path, |child| { self.set_drop_flag(loc, child, DropFlagState::Present) diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 7725daa276cc6..442bd9d26bbd0 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -434,7 +434,7 @@ fn find_self_assignments<'tcx>( statement_index: bb_data.statements.len(), }); // Target block - self_assign.insert(Location { block: *target, statement_index: 0 }); + self_assign.insert(target.start_location()); } } // Straight self-assignment. diff --git a/compiler/rustc_mir_transform/src/ssa_range_prop.rs b/compiler/rustc_mir_transform/src/ssa_range_prop.rs index f3f34ce11fe1a..e6df6bbd9fb4e 100644 --- a/compiler/rustc_mir_transform/src/ssa_range_prop.rs +++ b/compiler/rustc_mir_transform/src/ssa_range_prop.rs @@ -159,7 +159,7 @@ impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { if let Some(place) = cond.place() && self.is_ssa(place) => { - let successor = Location { block: *target, statement_index: 0 }; + let successor = target.start_location(); if location.strictly_dominates(successor, &self.dominators) // Don't propagate range information from built-in overflow checks, // this MIR might be lowered without them! @@ -186,7 +186,7 @@ impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { // FIXME: For multiple targets, the range can be the union of their values. continue; } - let successor = Location { block: target, statement_index: 0 }; + let successor = target.start_location(); if self.unique_predecessors.contains(successor.block) { assert_ne!(location.block, successor.block); let range = WrappingRange { start: val, end: val }; @@ -196,7 +196,7 @@ impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { // FIXME: The range for the otherwise target be extend to more types. // For instance, `val` is within the range [4, 1) at the otherwise target of `matches!(val, 1 | 2 | 3)`. - let otherwise = Location { block: targets.otherwise(), statement_index: 0 }; + let otherwise = targets.otherwise().start_location(); if place.ty(self.local_decls, self.tcx).ty.is_bool() && let [val] = targets.all_values() && self.unique_predecessors.contains(otherwise.block) diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 28a508bde9eca..48978d851d0ee 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -209,7 +209,7 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { } Some(e) if *e == s => (), Some(e) => self.fail( - Location { block: bb, statement_index: 0 }, + bb.start_location(), format!( "Cleanup control flow violation: The blocks dominated by {:?} have edges to both {:?} and {:?}", bb, @@ -231,7 +231,7 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { let no_cycle = stack.insert(parent); if !no_cycle { self.fail( - Location { block: bb, statement_index: 0 }, + bb.start_location(), format!( "Cleanup control flow violation: Cycle involving edge {bb:?} -> {parent:?}", ), From 6321136154f87bc21a27f840c43e601d01d9f7f0 Mon Sep 17 00:00:00 2001 From: June Pyle Date: Tue, 6 Oct 2026 18:34:07 -0700 Subject: [PATCH 09/15] Fix debug assert failure in `note_obligation_cause_code_inner` and convert crash test to regression test --- .../src/error_reporting/traits/suggestions.rs | 6 +++-- tests/crashes/139381.rs | 13 ---------- .../note-obligation-cause-ice-139381.rs | 26 +++++++++++++++++++ .../note-obligation-cause-ice-139381.stderr | 25 ++++++++++++++++++ 4 files changed, 55 insertions(+), 15 deletions(-) delete mode 100644 tests/crashes/139381.rs create mode 100644 tests/ui/higher-ranked/note-obligation-cause-ice-139381.rs create mode 100644 tests/ui/higher-ranked/note-obligation-cause-ice-139381.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 76755eb481db7..5a69d4c8df384 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4974,8 +4974,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .as_ref() .and_then(|typeck| typeck.node_type_opt(expr.hir_id)) && let Some(pred) = predicate.as_clause() - && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() - && self.can_eq(param_env, pred.self_ty(), expr_ty) + && let Some(pred) = pred.as_trait_clause() + && self + .infcx + .enter_forall(pred, |pred| self.can_eq(param_env, pred.self_ty(), expr_ty)) { (expr_ty, expr) } else { diff --git a/tests/crashes/139381.rs b/tests/crashes/139381.rs deleted file mode 100644 index 6757b584e82a1..0000000000000 --- a/tests/crashes/139381.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #139381 -//@ needs-rustc-debug-assertions -trait A<'a> { - type Assoc: ?Sized; -} - -impl<'a> A<'a> for () { - type Assoc = &'a (); -} - -fn hello() -> impl for<'a> A<'a, Assoc: Into + 'static + Copy> { - () -} diff --git a/tests/ui/higher-ranked/note-obligation-cause-ice-139381.rs b/tests/ui/higher-ranked/note-obligation-cause-ice-139381.rs new file mode 100644 index 0000000000000..1de781d8f0aaa --- /dev/null +++ b/tests/ui/higher-ranked/note-obligation-cause-ice-139381.rs @@ -0,0 +1,26 @@ +//! regression test for a failed debug assertion that was caused by improper +//! handling of bound clauses in `note_obligation_cause_code_inner`. +//! See https://github.com/rust-lang/rust/issues/139381#event-32605696260. + +//@ check-fail +//@ needs-rustc-debug-assertions + +trait A<'a> { + type Assoc: ?Sized; +} + +impl<'a> A<'a> for () { + type Assoc = &'a (); +} + +fn hello() -> impl for<'a> A<'a, Assoc: Into + 'static + Copy> { + //~^ ERROR not satisfied + //~| NOTE not implemented for `u8` + //~| NOTE in this expansion of desugaring + //~| NOTE in this expansion of desugaring + //~| NOTE required for `&'a ()` to implement `for<'a> Into` + //~| NOTE in this expansion of desugaring + () +} + +fn main() {} diff --git a/tests/ui/higher-ranked/note-obligation-cause-ice-139381.stderr b/tests/ui/higher-ranked/note-obligation-cause-ice-139381.stderr new file mode 100644 index 0000000000000..462dcaf8a3eee --- /dev/null +++ b/tests/ui/higher-ranked/note-obligation-cause-ice-139381.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `for<'a> u8: From<&'a ()>` is not satisfied + --> $DIR/note-obligation-cause-ice-139381.rs:16:15 + | +LL | fn hello() -> impl for<'a> A<'a, Assoc: Into + 'static + Copy> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> From<&'a ()>` is not implemented for `u8` + | +help: `u8` implements trait `From` + --> $SRC_DIR/core/src/convert/num.rs:LL:COL + | + = note: `From` + ::: $SRC_DIR/core/src/convert/num.rs:LL:COL + | + = note: in this macro invocation + --> $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL + | + = note: `From` + ::: $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL + | + = note: in this macro invocation + = note: required for `&'a ()` to implement `for<'a> Into` + = note: this error originates in the macro `impl_from_bool` which comes from the expansion of the macro `into_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 0d7fdb5483fa1c588e85ba9f7d31704ad5734179 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Wed, 7 Oct 2026 10:35:50 -0400 Subject: [PATCH 10/15] Update Enzyme submodule again --- src/tools/enzyme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/enzyme b/src/tools/enzyme index ede97b5c7b8d1..10beef3564f95 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit ede97b5c7b8d1ddacd5383601798a67aaac2077c +Subproject commit 10beef3564f953d9eb4c2b0b60fa7dc002d6174a From 23fa0f40cfb20085b53f83e63db98974c57471a1 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 13 Sep 2026 12:23:10 +0800 Subject: [PATCH 11/15] codegen: tell LLVM that the discriminant is a power of two We should not disable the pattern in MatchBranchSimplification. The two forms exhaustive match and cast are equivalent, but the cast is better represented in MIR: no branches, only one statement. AFAIK, LLVM does not handle multiple disjoint intervals well. As an workaround, the patch emits `assume(ctpop(val) == 1)` to tell LLVM that the discriminant is a power of two. --- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 6 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 11 ++-- compiler/rustc_codegen_ssa/src/mir/operand.rs | 24 ++++++- .../rustc_codegen_ssa/src/traits/intrinsic.rs | 2 + .../enum/enum-discriminant-power-of-two.rs | 65 +++++++++++++++++++ 5 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 tests/codegen-llvm/enum/enum-discriminant-power-of-two.rs diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 06713016cedbe..9da753058af8b 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -365,7 +365,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc sym::cttz_nonzero => { self.count_trailing_zeroes_nonzero(width, args[0].immediate()) } - sym::ctpop => self.pop_count(args[0].immediate()), + sym::ctpop => self.ctpop(args[0].immediate()), sym::bswap => { if width == 8 { args[0].immediate() // byte swap a u8/i8 is just a no-op @@ -682,6 +682,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc cond } + fn ctpop(&mut self, val: Self::Value) -> Self::Value { + self.pop_count(val) + } + fn type_checked_load( &mut self, _vtable: Self::Value, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index f3740ed7504fe..8d4321faa9505 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -513,11 +513,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.call_intrinsic(llvm_name, &[llty], &[args[0].immediate(), y]); self.intcast(ret, result_layout.llvm_type(self), false) } - sym::ctpop => { - let ret = - self.call_intrinsic("llvm.ctpop", &[llty], &[args[0].immediate()]); - self.intcast(ret, result_layout.llvm_type(self), false) - } + sym::ctpop => self.ctpop(args[0].immediate()), sym::bswap => { if width == 8 { args[0].immediate() // byte swap a u8/i8 is just a no-op @@ -1060,6 +1056,11 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } + fn ctpop(&mut self, val: Self::Value) -> Self::Value { + let ret = self.call_intrinsic("llvm.ctpop", &[self.val_ty(val)], &[val]); + self.intcast(ret, self.type_i32(), false) + } + fn type_checked_load( &mut self, llvtable: &'ll Value, diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index c1a1b2db6fa9d..0ad967c5fb14c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -472,7 +472,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { return bx.cx().const_poison(cast_to); } - let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { + let (tag_scalar, tag_encoding, tag_field, variants) = match self.layout.variants { Variants::Empty => unreachable!("we already handled uninhabited types"), Variants::Single { index } => { let discr_val = @@ -488,8 +488,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { }; return bx.cx().const_uint_big(cast_to, discr_val); } - Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { - (tag, tag_encoding, tag_field) + Variants::Multiple { tag, ref tag_encoding, tag_field, ref variants } => { + (tag, tag_encoding, tag_field, variants) } }; @@ -517,6 +517,24 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { Primitive::Int(_, signed) => !tag_scalar.is_bool() && signed, _ => false, }; + if bx.cx().sess().opts.optimize != OptLevel::No { + let vals: Vec = variants + .iter_enumerated() + .filter_map(|(idx, layout)| { + (!layout.is_uninhabited()).then(|| { + self.layout.ty.discriminant_for_variant(bx.tcx(), idx).unwrap().val + }) + }) + .collect(); + // Recording all possible discriminant values using `assume(v == c1 || v == c2 || v == c3)` may introduce + // additional compile-time overhead, but we can use `assume(ctpop(v) == 1)` when all possible values are known to be powers of two. + if vals.iter().all(|val| val.is_power_of_two()) { + let one = bx.cx().const_i32(1); + let ctpop = bx.ctpop(tag_imm); + let is_one = bx.icmp(IntPredicate::IntEQ, ctpop, one); + bx.assume(is_one); + } + } bx.intcast(tag_imm, cast_to, signed) } TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 47144834b5072..f7eaafbeb1ef6 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -41,6 +41,8 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; + /// Returns the number of bits set. The return type must be `u32`. + fn ctpop(&mut self, val: Self::Value) -> Self::Value; /// Trait method used to load a function while testing if it is associated with a type /// identifier. fn type_checked_load( diff --git a/tests/codegen-llvm/enum/enum-discriminant-power-of-two.rs b/tests/codegen-llvm/enum/enum-discriminant-power-of-two.rs new file mode 100644 index 0000000000000..5a207bf43858e --- /dev/null +++ b/tests/codegen-llvm/enum/enum-discriminant-power-of-two.rs @@ -0,0 +1,65 @@ +//! Check that LLVM can recognize that all discriminants are powers of two. +//! +//! Regression test for . +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled + +#![crate_type = "lib"] + +#[derive(Clone, Copy)] +#[repr(u8)] +pub enum Vsew { + E8 = 8, + E16 = 16, + E32 = 32, + E64 = 64, +} + +#[unsafe(no_mangle)] +pub fn is_power_of_two_match(sew: Vsew) -> u8 { + // CHECK-LABEL: define{{.*}} i8 @is_power_of_two_match(i8{{.*}} %sew) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = {{.*}}call{{.*}} i8 @llvm.ctpop.i8(i8 %sew) + // CHECK-NEXT: %1 = icmp eq i8 %0, 1 + // CHECK-NEXT: call void @llvm.assume(i1 %1) + // CHECK-NEXT: ret i8 %sew + let res: u8 = match sew { + Vsew::E8 => 8, + Vsew::E16 => 16, + Vsew::E32 => 32, + Vsew::E64 => 64, + }; + assert!(res.is_power_of_two()); + res +} + +#[unsafe(no_mangle)] +pub fn is_power_of_two_cast(sew: Vsew) -> u8 { + // CHECK-LABEL: define{{.*}} i8 @is_power_of_two_cast(i8{{.*}} %sew) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = {{.*}}call{{.*}} i8 @llvm.ctpop.i8(i8 %sew) + // CHECK-NEXT: %1 = icmp eq i8 %0, 1 + // CHECK-NEXT: call void @llvm.assume(i1 %1) + // CHECK-NEXT: ret i8 %sew + let res = sew as u8; + assert!(res.is_power_of_two()); + res +} + +impl Vsew { + #[inline(always)] + pub const fn bits_width(self) -> u8 { + match self { + Self::E8 => 8, + Self::E16 => 16, + Self::E32 => 32, + Self::E64 => 64, + } + } +} + +#[unsafe(no_mangle)] +pub fn vlmax(sew: Vsew) -> u32 { + // CHECK-LABEL: define{{.*}} i32 @vlmax(i8 {{.*}}%sew) + // CHECK-NOT: udiv + 512 / u32::from(sew.bits_width()) +} From 6396944cef79faa287f69cd321e756f76c0ee921 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Oct 2026 17:44:08 +0200 Subject: [PATCH 12/15] relax_elf_relocations is x86-only --- compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++-- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 4 ++-- compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 2 +- compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs | 2 -- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index a95f259545982..824234b58f290 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -207,7 +207,7 @@ pub(crate) fn target_machine_factory( let emit_stack_size_section = sess.opts.unstable_opts.emit_stack_sizes; let verbose_asm = sess.opts.unstable_opts.verbose_asm; - let relax_elf_relocations = + let relax_x86_elf_relocations = sess.opts.unstable_opts.relax_elf_relocations.unwrap_or(sess.target.relax_elf_relocations); let use_init_array = @@ -276,7 +276,7 @@ pub(crate) fn target_machine_factory( singlethread, verbose_asm, emit_stack_size_section, - relax_elf_relocations, + relax_x86_elf_relocations, use_init_array, &split_dwarf_file, &output_obj_file, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 3873701ae09ac..da40bddc6ba81 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -350,7 +350,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( LLVMRustCodeGenOptLevel RustOptLevel, LLVMRustFloatABI RustFloatABIType, bool FunctionSections, bool DataSections, bool UniqueSectionNames, bool TrapUnreachable, bool Singlethread, bool VerboseAsm, - bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray, + bool EmitStackSizeSection, bool X86RelaxRelocations, bool UseInitArray, const char *SplitDwarfFile, const char *OutputObjFile, LLVMRustCompressionKind DebugInfoCompression, bool UseEmulatedTls, bool UseWasmEH, uint64_t LargeDataThreshold) { @@ -390,7 +390,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( // compression kind that is known to be supported by this build of LLVM, via // `LLVMRustLLVMHasZlibCompression` and `LLVMRustLLVMHasZstdCompression`. Options.MCOptions.CompressDebugSections = fromRust(DebugInfoCompression); - Options.MCOptions.X86RelaxRelocations = RelaxELFRelocations; + Options.MCOptions.X86RelaxRelocations = X86RelaxRelocations; Options.UseInitArray = UseInitArray; Options.EmulatedTLS = UseEmulatedTls; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9a3e74c28348d..a29309c71e879 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2823,7 +2823,7 @@ options! { \"C\", \"cdecl\", and \"stdcall\" fn.\ It is UNSOUND to link together crates that use different values for this flag!"), relax_elf_relocations: Option = (None, parse_opt_bool, [TRACKED], - "whether ELF relocations can be relaxed"), + "whether ELF relocations can be relaxed (x86 only)"), remap_cwd_prefix: Option = (None, parse_opt_pathbuf, [TRACKED], "remap paths under the current working directory to this path prefix"), remark_dir: Option = (None, parse_opt_pathbuf, [UNTRACKED], diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index b5196599eb120..fb5472e0e8e28 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2541,7 +2541,7 @@ pub struct TargetOptions { /// rustc and not forwarded to LLVM. pub rustc_abi: Option, - /// Whether or not RelaxElfRelocation flag will be passed to the linker + /// Whether or not X86RelaxRelocations flag will be passed to LLVM (x86 only). pub relax_elf_relocations: bool, /// Additional arguments to pass to LLVM, similar to the `-C llvm-args` codegen option. diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs b/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs index 41c8b3b206395..f9c92c1703bdf 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_sony_ps3.rs @@ -85,8 +85,6 @@ pub(crate) fn target() -> Target { // This limits us to 64KB of ToC, but yields smaller binaries and less assembly. // Only becomes a problem for binaries with thousands of dependencies. code_model: Some(CodeModel::Small), - // Prevents LLVM from emitting modern linker relaxation relocations. - relax_elf_relocations: false, // CellOS main executables (`EBOOT.ELF`) **must be static executables** (ET_EXEC). relocation_model: RelocModel::Static, From 7870b6018b7ad6229373fc1e53b7616b19cc1e7a Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 7 Oct 2026 17:20:34 +0200 Subject: [PATCH 13/15] disable next-solver with higher-ranked-assumptions --- compiler/rustc_ast_passes/src/diagnostics.rs | 9 +++++++++ compiler/rustc_ast_passes/src/feature_gate.rs | 15 +++++++++++++-- compiler/rustc_middle/src/ty/context.rs | 1 + compiler/rustc_traits/src/coroutine_witnesses.rs | 2 +- ...er-ranked-auto-trait-1.assumptions_next.stderr | 10 ++++++++++ ...gher-ranked-auto-trait-1.no_assumptions.stderr | 12 ++++++------ .../higher-ranked-auto-trait-1.rs | 8 +++++++- 7 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.assumptions_next.stderr diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs index a3cffab3fc4dc..bb006b32ac73e 100644 --- a/compiler/rustc_ast_passes/src/diagnostics.rs +++ b/compiler/rustc_ast_passes/src/diagnostics.rs @@ -49,6 +49,15 @@ pub(crate) struct NextSolverDisabledForGenericConstExprs { pub span: Span, } +#[derive(Diagnostic)] +#[diag("`-Zhigher-ranked-assumptions` is not supported with the next-generation trait solver")] +#[note("the feature flag will be superseded by `-Zassumptions-on-binders`")] +#[note("`-Znext-solver=globally` is currently enabled by default for testing")] +#[note("reverted the setting to `-Znext-solver=coherence` for this crate")] +#[note("the currently stable trait solver will be used for this crate")] +#[note("see issues #160895 for more information")] +pub(crate) struct NextSolverDisabledForHigherRankedAssumptions; + #[derive(Diagnostic)] #[diag("functions in {$in_impl -> [true] trait impls diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1176d6e1398f0..5feebcc0b8bdf 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -411,6 +411,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { check_incompatible_features(sess, features); check_dependent_features(sess, features); warn_next_solver_and_gce(sess, features); + warn_next_solver_and_higher_ranked_assumptions(sess); check_features_requiring_new_solver(sess, features); let mut visitor = PostExpansionVisitor { sess, features }; @@ -703,8 +704,8 @@ fn warn_next_solver_and_gce(sess: &Session, features: &Features) { return; } - // Warn people who uses GCE and -Znext-solver=globally - // that their trait solver was downgraded to -Znext-solver=no + // Warn people who use GCE and -Znext-solver=globally + // that their trait solver was downgraded to -Znext-solver=coherence if let Some(gce_span) = features .enabled_lang_features() .iter() @@ -716,6 +717,16 @@ fn warn_next_solver_and_gce(sess: &Session, features: &Features) { } } +fn warn_next_solver_and_higher_ranked_assumptions(sess: &Session) { + // Warn people who use -Zhigher-ranked-assumptions and -Znext-solver=globally + // that their trait solver was downgraded to -Znext-solver=coherence + if sess.opts.unstable_opts.next_solver == NextSolverConfig::Globally + && sess.opts.unstable_opts.higher_ranked_assumptions + { + sess.dcx().emit_warn(diagnostics::NextSolverDisabledForHigherRankedAssumptions); + } +} + fn check_features_requiring_new_solver(sess: &Session, features: &Features) { if sess.opts.unstable_opts.next_solver == NextSolverConfig::Globally { return; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aa7fe0872f20c..fdc706f4b043b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2818,6 +2818,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn next_trait_solver_globally(self) -> bool { self.sess.opts.unstable_opts.next_solver == NextSolverConfig::Globally + && !self.sess.opts.unstable_opts.higher_ranked_assumptions && !self.features().generic_const_exprs() } diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 624db7747d1f0..2a6087003cb75 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -54,7 +54,7 @@ fn compute_assumptions<'tcx>( def_id: DefId, bound_tys: &'tcx ty::List>, ) -> &'tcx ty::List> { - if tcx.next_trait_solver_globally() || !tcx.sess.opts.unstable_opts.higher_ranked_assumptions { + if !tcx.sess.opts.unstable_opts.higher_ranked_assumptions { return &ty::List::empty(); } diff --git a/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.assumptions_next.stderr b/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.assumptions_next.stderr new file mode 100644 index 0000000000000..c2078fdefafa6 --- /dev/null +++ b/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.assumptions_next.stderr @@ -0,0 +1,10 @@ +warning: `-Zhigher-ranked-assumptions` is not supported with the next-generation trait solver + | + = note: the feature flag will be superseded by `-Zassumptions-on-binders` + = note: `-Znext-solver=globally` is currently enabled by default for testing + = note: reverted the setting to `-Znext-solver=coherence` for this crate + = note: the currently stable trait solver will be used for this crate + = note: see issues #160895 for more information + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.no_assumptions.stderr b/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.no_assumptions.stderr index b298a3bf2153a..b2c56bf95156c 100644 --- a/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.no_assumptions.stderr +++ b/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.no_assumptions.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/higher-ranked-auto-trait-1.rs:37:5 + --> $DIR/higher-ranked-auto-trait-1.rs:43:5 | LL | / async { LL | | let _y = &(); @@ -10,13 +10,13 @@ LL | | drop(_x); LL | | } | |_____^ one type is more general than the other | - = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` - found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` + = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:46:19: 46:29}` + found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:46:19: 46:29}` = note: no two async blocks, even if identical, have the same type = help: consider pinning your async block and casting it to a trait object error[E0308]: mismatched types - --> $DIR/higher-ranked-auto-trait-1.rs:37:5 + --> $DIR/higher-ranked-auto-trait-1.rs:43:5 | LL | / async { LL | | let _y = &(); @@ -27,8 +27,8 @@ LL | | drop(_x); LL | | } | |_____^ one type is more general than the other | - = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` - found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` + = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:46:19: 46:29}` + found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:46:19: 46:29}` = note: no two async blocks, even if identical, have the same type = help: consider pinning your async block and casting it to a trait object = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.rs b/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.rs index 740f7e2924545..902085a7f159f 100644 --- a/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.rs +++ b/tests/ui/async-await/witness-auto-trait/higher-ranked-auto-trait-1.rs @@ -1,10 +1,16 @@ // Repro for . //@ edition: 2021 -//@ revisions: assumptions no_assumptions +//@ revisions: assumptions no_assumptions assumptions_next //@[assumptions] compile-flags: -Zhigher-ranked-assumptions +//@[assumptions_next] compile-flags: -Zhigher-ranked-assumptions -Znext-solver //@[assumptions] check-pass +//@[assumptions_next] check-pass //@[no_assumptions] known-bug: #110338 +// We're using this test to just check the way -Zhigher-ranked-assumptions +// interacts with the next-generation trait solver. +//[assumptions_next]~? WARN `-Zhigher-ranked-assumptions` is not supported with the next-generation trait solver + use std::future::Future; use std::marker::PhantomData; From ec45ecffeee8ba13e42a7f45b6cdad3155ebd146 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 7 Oct 2026 02:59:30 -0700 Subject: [PATCH 14/15] Move `loop_hint_attrs` from `Terminator` into `TerminatorKind::Goto` Only the `Goto` variant uses `loop_hint_attrs`, so other variants shouldn't pay the cost. This shrinks `Terminator` and thus `BasicBlockData` by 8 bytes, and also simplifies many users of `Terminator`. Every byte saved from `BasicBlockData` makes a big difference in max-rss. For aws-sdk-ec2 full check, this saves 34.1 MiB (~0.62% of its peak RSS) Add a `TerminatorKind::goto` helper function for convenient construction with a target and no hints. With that helper available, most of this commit is simple, straightforward, mechanical translations of construction or pattern matching. The only notable changes are: - `compiler/rustc_codegen_ssa/src/mir/block.rs` actually uses the moved hints. - `compiler/rustc_middle/src/mir/mod.rs` updates the size assertions. - `compiler/rustc_mir_build/src/builder/cfg.rs` adds/updates helpers. - `compiler/rustc_mir_build/src/builder/expr/into.rs` has the one place that creates a `Goto` with non-empty hints. --- compiler/rustc_borrowck/src/lib.rs | 2 +- .../src/polonius/legacy/loan_invalidations.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- .../rustc_const_eval/src/interpret/step.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 4 +- compiler/rustc_middle/src/mir/syntax.rs | 4 +- compiler/rustc_middle/src/mir/terminator.rs | 15 +++-- compiler/rustc_middle/src/mir/visit.rs | 2 +- compiler/rustc_mir_build/src/builder/cfg.rs | 17 +++++- .../src/builder/custom/parse.rs | 2 - .../src/builder/custom/parse/instruction.rs | 2 +- .../rustc_mir_build/src/builder/expr/into.rs | 19 ++++-- compiler/rustc_mir_build/src/builder/scope.rs | 16 ++--- .../rustc_mir_dataflow/src/framework/tests.rs | 3 +- .../src/move_paths/builder.rs | 2 +- .../src/add_call_guards.rs | 7 +-- .../src/add_moves_for_packed_drops.rs | 7 +-- .../rustc_mir_transform/src/check_enums.rs | 8 +-- .../rustc_mir_transform/src/check_pointers.rs | 2 - .../src/cleanup_post_borrowck.rs | 2 +- .../rustc_mir_transform/src/coroutine/drop.rs | 3 +- .../rustc_mir_transform/src/coroutine/mod.rs | 49 +++------------ .../rustc_mir_transform/src/coverage/graph.rs | 2 +- .../rustc_mir_transform/src/coverage/tests.rs | 8 +-- .../src/early_otherwise_branch.rs | 3 - .../rustc_mir_transform/src/elaborate_drop.rs | 61 ++++++------------- .../src/elaborate_drops.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 13 ++-- .../rustc_mir_transform/src/instsimplify.rs | 8 +-- .../rustc_mir_transform/src/jump_threading.rs | 2 +- .../src/lint_and_remove_uninhabited.rs | 2 +- compiler/rustc_mir_transform/src/liveness.rs | 4 +- .../src/lower_intrinsics.rs | 26 ++++---- .../src/lower_slice_len.rs | 2 +- .../src/multiple_return_terminators.rs | 2 +- compiler/rustc_mir_transform/src/patch.rs | 5 -- .../rustc_mir_transform/src/promote_consts.rs | 9 +-- .../src/remove_uninit_drops.rs | 2 +- .../src/remove_unneeded_drops.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 51 ++++------------ .../src/shim/async_destructor_ctor.rs | 17 +----- compiler/rustc_mir_transform/src/simplify.rs | 8 +-- .../src/simplify_branches.rs | 4 +- .../src/tail_copy_to_move.rs | 2 +- .../src/unreachable_prop.rs | 6 +- compiler/rustc_mir_transform/src/validate.rs | 2 +- .../src/unstable/convert/stable/mir.rs | 2 +- 50 files changed, 161 insertions(+), 264 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c2233fa495a47..96fc9b2e37651 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -978,7 +978,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, } } - TerminatorKind::Goto { target: _ } + TerminatorKind::Goto { target: _, loop_hint_attrs: _ } | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Unreachable | TerminatorKind::UnwindResume diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index e4d1419b11d83..e10701e1a1b1c 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { } } } - TerminatorKind::Goto { target: _ } + TerminatorKind::Goto { target: _, loop_hint_attrs: _ } | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index ab0d786c6f264..1dc4b29fb5187 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2082,7 +2082,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn check_iscleanup(&mut self, block_data: &BasicBlockData<'tcx>) { let is_cleanup = block_data.is_cleanup; match block_data.terminator().kind { - TerminatorKind::Goto { target } => { + TerminatorKind::Goto { target, .. } => { self.assert_iscleanup(block_data, target, is_cleanup) } TerminatorKind::SwitchInt { ref targets, .. } => { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e752189130290..a6d5e4c6a6423 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -343,7 +343,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { crate::PrintOnPanic(|| format!("terminator {:?}", bb_data.terminator().kind)); match &bb_data.terminator().kind { - TerminatorKind::Goto { target } => { + TerminatorKind::Goto { target, loop_hint_attrs: _ } => { if let TerminatorKind::Return = fx.mir[*target].terminator().kind { let mut can_immediately_return = true; for stmt in &fx.mir[*target].statements { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 232af2bbe8815..2516a8d55ff8c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1676,8 +1676,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { MergingSucc::False } - mir::TerminatorKind::Goto { target } => { - helper.funclet_br(self, bx, target, mergeable_succ(), &terminator.loop_hint_attrs) + mir::TerminatorKind::Goto { target, ref loop_hint_attrs } => { + helper.funclet_br(self, bx, target, mergeable_succ(), loop_hint_attrs) } mir::TerminatorKind::SwitchInt { ref discr, ref targets } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index aefa8356536dc..433210d6c1d7f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -437,7 +437,7 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ))), )); - bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block }; + bb.terminator_mut().kind = mir::TerminatorKind::goto(destination_block); } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index e9f1d06187cd6..b647cc624bc04 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -532,7 +532,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.return_from_current_stack_frame(/* unwinding */ false)? } - Goto { target } => self.go_to_block(target), + Goto { target, loop_hint_attrs: _ } => self.go_to_block(target), SwitchInt { ref discr, ref targets } => { let discr = self.read_immediate(&self.eval_operand(discr, None)?)?; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 19a6d2a31c4e3..7dabc71e41b25 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1732,11 +1732,11 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(BasicBlockData<'_>, 144); + static_assert_size!(BasicBlockData<'_>, 136); static_assert_size!(LocalDecl<'_>, 40); static_assert_size!(SourceScopeData<'_>, 64); static_assert_size!(Statement<'_>, 40); - static_assert_size!(Terminator<'_>, 104); + static_assert_size!(Terminator<'_>, 96); static_assert_size!(VarDebugInfo<'_>, 88); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 6bb0190cd70b8..487c2c43da7d5 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -5,6 +5,7 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, Mutability}; +use rustc_attr_ir::UnrollAttr; use rustc_data_structures::packed::Pu128; use rustc_hir::CoroutineKind; use rustc_hir::def_id::DefId; @@ -14,6 +15,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::{Span, Spanned, Symbol}; use rustc_target::asm::InlineAsmRegOrRegClass; use smallvec::SmallVec; +use thin_vec::ThinVec; use super::{BasicBlock, Const, Local, UserTypeProjection}; use crate::mir::coverage::CoverageKind; @@ -683,7 +685,7 @@ pub enum InlineAsmMacro { #[derive(Clone, TyEncodable, TyDecodable, StableHash, PartialEq, TypeFoldable, TypeVisitable)] pub enum TerminatorKind<'tcx> { /// Block has one successor; we continue execution there. - Goto { target: BasicBlock }, + Goto { target: BasicBlock, loop_hint_attrs: ThinVec }, /// Switches based on the computed value. /// diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 15d6c8f03bc70..c4e6a3089ae9b 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -3,7 +3,6 @@ use std::slice; use rustc_ast::InlineAsmOptions; -use rustc_attr_ir::UnrollAttr; use rustc_attr_ir::lang_items::LangItem; use rustc_data_structures::packed::Pu128; use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; @@ -419,7 +418,6 @@ impl fmt::Display for AssertKind { pub struct Terminator<'tcx> { pub source_info: SourceInfo, pub kind: TerminatorKind<'tcx>, - pub loop_hint_attrs: ThinVec, } impl<'tcx> Terminator<'tcx> { @@ -479,6 +477,11 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) } } + + #[inline] + pub fn goto(target: BasicBlock) -> TerminatorKind<'tcx> { + TerminatorKind::Goto { target, loop_hint_attrs: ThinVec::new() } + } } pub use helper::*; @@ -527,7 +530,7 @@ mod helper { mk_successors(slice::from_ref(t), Some(u), None) } // single successor - Goto { target: ref t } + Goto { target: ref t, .. } | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. } | Call { target: Some(ref t), unwind: _, .. } | Yield { resume: ref t, drop: None, .. } @@ -590,7 +593,7 @@ mod helper { f(u) } } - Goto { target } => { + Goto { target, .. } => { f(target); } UnwindResume @@ -675,7 +678,7 @@ impl<'tcx> TerminatorKind<'tcx> { #[inline] pub fn as_goto(&self) -> Option { match self { - TerminatorKind::Goto { target } => Some(*target), + TerminatorKind::Goto { target, loop_hint_attrs: _ } => Some(*target), _ => None, } } @@ -745,7 +748,7 @@ impl<'tcx> TerminatorKind<'tcx> { | CoroutineDrop | Unreachable => TerminatorEdges::None, - Goto { target } => TerminatorEdges::Single(target), + Goto { target, loop_hint_attrs: _ } => TerminatorEdges::Single(target), // FIXME: Maybe we need also TerminatorEdges::Trio for async drop // (target + unwind + dropline) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 1b45378c86c0a..2bbe41bdad09f 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -518,7 +518,7 @@ macro_rules! make_mir_visitor { terminator: &$($mutability)? Terminator<'tcx>, location: Location ) { - let Terminator { source_info, kind, loop_hint_attrs: _ } = terminator; + let Terminator { source_info, kind } = terminator; self.visit_source_info(source_info); match kind { diff --git a/compiler/rustc_mir_build/src/builder/cfg.rs b/compiler/rustc_mir_build/src/builder/cfg.rs index a8e68963ec724..020858d427712 100644 --- a/compiler/rustc_mir_build/src/builder/cfg.rs +++ b/compiler/rustc_mir_build/src/builder/cfg.rs @@ -1,5 +1,6 @@ //! Routines for manipulating the control-flow graph. +use rustc_attr_ir::UnrollAttr; use rustc_data_structures::thin_vec::ThinVec; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; @@ -120,8 +121,7 @@ impl<'tcx> CFG<'tcx> { block, self.block_data(block) ); - self.block_data_mut(block).terminator = - Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }); + self.block_data_mut(block).terminator = Some(Terminator { source_info, kind }); self.block_data_mut(block).terminator.as_mut().unwrap() } @@ -132,6 +132,17 @@ impl<'tcx> CFG<'tcx> { source_info: SourceInfo, target: BasicBlock, ) -> &mut Terminator<'tcx> { - self.terminate(origin, source_info, TerminatorKind::Goto { target }) + self.goto_with_hints(origin, source_info, target, ThinVec::new()) + } + + #[inline(always)] + pub(crate) fn goto_with_hints( + &mut self, + origin: BasicBlock, + source_info: SourceInfo, + target: BasicBlock, + loop_hint_attrs: ThinVec, + ) -> &mut Terminator<'tcx> { + self.terminate(origin, source_info, TerminatorKind::Goto { target, loop_hint_attrs }) } } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index 73ffbec6685cc..b227923292779 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::thin_vec::ThinVec; use rustc_index::IndexSlice; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -319,7 +318,6 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { data.terminator = Some(Terminator { source_info: SourceInfo { span, scope: self.source_scope }, kind: terminator, - loop_hint_attrs: ThinVec::new(), }); Ok(data) diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 5454a7bef67a7..3241e2b17ece5 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -47,7 +47,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { Ok(TerminatorKind::Return) }, @call(mir_goto, args) => { - Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } ) + Ok(TerminatorKind::goto(self.parse_block(args[0])?)) }, @call(mir_unreachable, _args) => { Ok(TerminatorKind::Unreachable) diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 6ca12032362be..167bedfc2101e 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -4,6 +4,7 @@ use rustc_abi::FieldIdx; use rustc_ast::{AsmMacro, InlineAsmOptions}; use rustc_attr_ir::lang_items::LangItem; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -237,10 +238,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Execute the body, branching back to the test. let body_block_end = this.expr_into_dest(tmp, body_block, body).into_block(); - let goto = this.cfg.goto(body_block_end, source_info, loop_block); - if let Some(attrs) = this.thir.loop_hint_attrs.get(&expr_id) { - goto.loop_hint_attrs = attrs.clone(); - } + let loop_hint_attrs = this + .thir + .loop_hint_attrs + .get(&expr_id) + .map(|attrs| attrs.clone()) + .unwrap_or_else(|| ThinVec::new()); + this.cfg.goto_with_hints( + body_block_end, + source_info, + loop_block, + loop_hint_attrs, + ); // Loops are only exited by `break` expressions. None @@ -772,7 +781,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.terminate( target, source_info, - TerminatorKind::Goto { target: destination_block }, + TerminatorKind::goto(destination_block), ); mir::InlineAsmOperand::Label { target_index } diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 4b3c224a84357..79505dd6f03fc 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -447,7 +447,7 @@ impl DropTree { // use `DUMMY_SP`. let source_info = SourceInfo { span: DUMMY_SP, ..drop_node.data.source_info }; - let terminator = TerminatorKind::Goto { target }; + let terminator = TerminatorKind::goto(target); cfg.terminate(block, source_info, terminator); } } @@ -467,7 +467,7 @@ impl DropTree { // use `DUMMY_SP`. let source_info = SourceInfo { span: DUMMY_SP, ..drop_node.data.source_info }; - let terminator = TerminatorKind::Goto { target }; + let terminator = TerminatorKind::goto(target); cfg.terminate(block, source_info, terminator); } } @@ -569,12 +569,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate( normal_block.into_block(), source_info, - TerminatorKind::Goto { target }, + TerminatorKind::goto(target), ); self.cfg.terminate( exit_block.into_block(), source_info, - TerminatorKind::Goto { target }, + TerminatorKind::goto(target), ); target.unit() } @@ -622,12 +622,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate( normal_block.into_block(), source_info, - TerminatorKind::Goto { target }, + TerminatorKind::goto(target), ); self.cfg.terminate( exit_block.into_block(), source_info, - TerminatorKind::Goto { target }, + TerminatorKind::goto(target), ); target.unit() } @@ -2117,7 +2117,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for ExitScopes { // (The dummy is added by `break_scope` and `break_from_if_then_scope`.) let term = cfg.block_data_mut(from).terminator_mut(); if let TerminatorKind::UnwindResume = term.kind { - term.kind = TerminatorKind::Goto { target: to }; + term.kind = TerminatorKind::goto(to); } else { span_bug!(term.source_info.span, "unexpected dummy terminator kind: {:?}", term.kind); } @@ -2158,7 +2158,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind { TerminatorKind::Drop { unwind, .. } => { if let UnwindAction::Cleanup(unwind) = *unwind { let source_info = term.source_info; - cfg.terminate(unwind, source_info, TerminatorKind::Goto { target: to }); + cfg.terminate(unwind, source_info, TerminatorKind::goto(to)); } else { *unwind = UnwindAction::Cleanup(to); } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 9646caab241d9..bfdf96a48f401 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -2,7 +2,6 @@ use std::marker::PhantomData; -use rustc_data_structures::thin_vec::ThinVec; use rustc_index::IndexVec; use rustc_middle::ty; use rustc_span::DUMMY_SP; @@ -22,7 +21,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { blocks.push(mir::BasicBlockData::new_stmts( std::iter::repeat(&nop).cloned().take(n).collect(), - Some(mir::Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }), + Some(mir::Terminator { source_info, kind }), false, )) }; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 3c1c631285f96..26628a05188d7 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -449,7 +449,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { fn gather_terminator(&mut self, term: &Terminator<'tcx>) { debug!("gather_terminator({:?}, {:?})", self.loc, term); match term.kind { - TerminatorKind::Goto { target: _ } + TerminatorKind::Goto { target: _, .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => {} // In some sense returning moves the return place into the current diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index 01fd042864019..17e99f506e0f2 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -15,7 +15,6 @@ //! //! NOTE: Simplify CFG will happily undo most of the work this pass does. -use rustc_data_structures::thin_vec::ThinVec; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; @@ -89,11 +88,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards { let cur_len = body.basic_blocks.len(); let mut new_block = |source_info: SourceInfo, is_cleanup: bool, target: BasicBlock| { let block = BasicBlockData::new( - Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target }, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::goto(target) }), is_cleanup, ); let idx = cur_len + new_blocks.len(); diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index e0c07619efbc6..41c63d4857df8 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::thin_vec::ThinVec; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use tracing::debug; @@ -95,11 +94,7 @@ fn add_move_for_packed_drop<'tcx>( let storage_dead_block = patch.new_block(BasicBlockData::new_stmts( vec![Statement::new(source_info, StatementKind::StorageDead(temp))], - Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target }, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::goto(target) }), is_cleanup, )); diff --git a/compiler/rustc_mir_transform/src/check_enums.rs b/compiler/rustc_mir_transform/src/check_enums.rs index 8d2178a07c5c6..260028c570461 100644 --- a/compiler/rustc_mir_transform/src/check_enums.rs +++ b/compiler/rustc_mir_transform/src/check_enums.rs @@ -1,6 +1,5 @@ use rustc_abi::{Scalar, Size, TagEncoding, Variants, WrappingRange}; use rustc_attr_ir::lang_items::LangItem; -use rustc_data_structures::thin_vec::ThinVec; use rustc_index::IndexVec; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; @@ -63,8 +62,7 @@ impl<'tcx> crate::MirPass<'tcx> for CheckEnums { ); basic_blocks[block].terminator = Some(Terminator { source_info, - kind: TerminatorKind::Goto { target: new_block }, - loop_hint_attrs: ThinVec::new(), + kind: TerminatorKind::goto(new_block), }); } EnumCheckType::Direct { source_op, discr, op_size, valid_discrs } => { @@ -395,7 +393,6 @@ fn insert_direct_enum_check<'tcx>( invalid_discr_block, ), }, - loop_hint_attrs: ThinVec::new(), }); // Abort in case of an invalid enum discriminant. @@ -415,7 +412,6 @@ fn insert_direct_enum_check<'tcx>( // make a failing UB check turn into much worse UB when we start unwinding. unwind: UnwindAction::Unreachable, }, - loop_hint_attrs: ThinVec::new(), }); } @@ -461,7 +457,6 @@ fn insert_uninhabited_enum_check<'tcx>( // make a failing UB check turn into much worse UB when we start unwinding. unwind: UnwindAction::Unreachable, }, - loop_hint_attrs: ThinVec::new(), }); } @@ -539,6 +534,5 @@ fn insert_niche_check<'tcx>( // make a failing UB check turn into much worse UB when we start unwinding. unwind: UnwindAction::Unreachable, }, - loop_hint_attrs: ThinVec::new(), }); } diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index fb6379a25af95..25336280926fe 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -1,5 +1,4 @@ use rustc_attr_ir::lang_items::LangItem; -use rustc_data_structures::thin_vec::ThinVec; use rustc_index::IndexVec; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -117,7 +116,6 @@ pub(crate) fn check_pointers<'tcx, F>( // worse UB when we start unwinding. unwind: UnwindAction::Unreachable, }, - loop_hint_attrs: ThinVec::new(), }); } } diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 31d9d124ab846..6b7054302e77a 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -66,7 +66,7 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck { TerminatorKind::FalseEdge { real_target, .. } | TerminatorKind::FalseUnwind { real_target, .. } => { invalidate_cfg = true; - terminator.kind = TerminatorKind::Goto { target: real_target }; + terminator.kind = TerminatorKind::goto(real_target); } _ => {} } diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 44ea6aef0e02d..aea2992bbce21 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -375,8 +375,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( replace: false, drop: None, }; - body.basic_blocks_mut()[call_bb].terminator = - Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }); + body.basic_blocks_mut()[call_bb].terminator = Some(Terminator { source_info, kind }); // Run derefer to fix Derefs that are not in the first place deref_finder(tcx, &mut body, false); diff --git a/compiler/rustc_mir_transform/src/coroutine/mod.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs index 1e63dca78adbb..ba75c8934272d 100644 --- a/compiler/rustc_mir_transform/src/coroutine/mod.rs +++ b/compiler/rustc_mir_transform/src/coroutine/mod.rs @@ -64,7 +64,6 @@ pub(super) use layout::mir_coroutine_witnesses; use layout::{CoroutineSavedLocals, compute_layout, locals_live_across_suspend_points}; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_attr_ir::lang_items::LangItem; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind}; use rustc_index::bit_set::{BitMatrix, DenseBitSet}; use rustc_index::{Idx, IndexVec, indexvec}; @@ -253,11 +252,7 @@ impl<'tcx> TransformVisitor<'tcx> { body.basic_blocks_mut().push(BasicBlockData::new_stmts( statements, - Some(Terminator { - source_info, - kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::Return }), false, )); @@ -698,7 +693,7 @@ fn eliminate_get_context_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { terminator.source_info, StatementKind::Assign(Box::new((*destination, arg))), ); - terminator.kind = TerminatorKind::Goto { target: target.unwrap() }; + terminator.kind = TerminatorKind::goto(target.unwrap()); bb_data.statements.push(assign); } } @@ -741,19 +736,13 @@ fn insert_switch<'tcx>( } let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), targets: switch_targets }; - body.basic_blocks_mut()[START_BLOCK].terminator = Some(Terminator { - source_info: SourceInfo::outermost(body.span), - kind: switch, - loop_hint_attrs: ThinVec::new(), - }); + body.basic_blocks_mut()[START_BLOCK].terminator = + Some(Terminator { source_info: SourceInfo::outermost(body.span), kind: switch }); } fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock { let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().push(BasicBlockData::new( - Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }), - false, - )) + body.basic_blocks_mut().push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) } fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> { @@ -776,11 +765,7 @@ fn insert_poll_ready_block<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ba let source_info = SourceInfo::outermost(body.span); body.basic_blocks_mut().push(BasicBlockData::new_stmts( [return_poll_ready_assign(tcx, source_info)].to_vec(), - Some(Terminator { - source_info, - kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::Return }), false, )) } @@ -835,12 +820,7 @@ fn generate_poison_block_and_redirect_unwinds_there<'tcx>( let source_info = SourceInfo::outermost(body.span); let poison_block = body.basic_blocks_mut().push(BasicBlockData::new_stmts( vec![transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info)], - Some(Terminator { - source_info, - kind: TerminatorKind::UnwindResume, - - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }), true, )); @@ -851,12 +831,8 @@ fn generate_poison_block_and_redirect_unwinds_there<'tcx>( // An existing `Resume` terminator is redirected to jump to our dedicated // "poisoning block" above. if idx != poison_block { - *block.terminator_mut() = Terminator { - source_info, - kind: TerminatorKind::Goto { target: poison_block }, - - loop_hint_attrs: ThinVec::new(), - }; + *block.terminator_mut() = + Terminator { source_info, kind: TerminatorKind::goto(poison_block) }; } } else if !block.is_cleanup // Any terminators that *can* unwind but don't have an unwind target set are also @@ -1019,12 +995,7 @@ fn create_cases<'tcx>( // Then jump to the real target let block = body.basic_blocks_mut().push(BasicBlockData::new_stmts( statements, - Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target }, - - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::goto(target) }), false, )); diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index dcc7c5b91d76a..2a5eae62f80ec 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -381,7 +381,7 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera | Drop { target, .. } | FalseEdge { real_target: target, .. } | FalseUnwind { real_target: target, .. } - | Goto { target } => slice::from_ref(target), + | Goto { target, .. } => slice::from_ref(target), // A call terminator can normally be chained, except when it has no // successor because it is known to diverge. diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index e9876310f112f..9fcd2a3028f84 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -26,7 +26,6 @@ use itertools::Itertools; use rustc_data_structures::graph::{DirectedGraph, Successors}; -use rustc_data_structures::thin_vec::ThinVec; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::*; use rustc_middle::ty; @@ -73,7 +72,6 @@ impl<'tcx> MockBlocks<'tcx> { Some(Terminator { source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)), kind, - loop_hint_attrs: ThinVec::new(), }), false, )) @@ -86,7 +84,7 @@ impl<'tcx> MockBlocks<'tcx> { | TerminatorKind::Drop { ref mut target, .. } | TerminatorKind::FalseEdge { real_target: ref mut target, .. } | TerminatorKind::FalseUnwind { real_target: ref mut target, .. } - | TerminatorKind::Goto { ref mut target } + | TerminatorKind::Goto { ref mut target, .. } | TerminatorKind::Yield { resume: ref mut target, .. } => *target = to_block, ref invalid => bug!("Invalid from_block: {:?}", invalid), } @@ -145,7 +143,7 @@ impl<'tcx> MockBlocks<'tcx> { } fn goto(&mut self, some_from_block: Option) -> BasicBlock { - self.add_block_from(some_from_block, TerminatorKind::Goto { target: TEMP_BLOCK }) + self.add_block_from(some_from_block, TerminatorKind::goto(TEMP_BLOCK)) } fn switchint(&mut self, some_from_block: Option) -> BasicBlock { @@ -182,7 +180,7 @@ fn debug_basic_blocks(mir_body: &Body<'_>) -> String { | TerminatorKind::Drop { target, .. } | TerminatorKind::FalseEdge { real_target: target, .. } | TerminatorKind::FalseUnwind { real_target: target, .. } - | TerminatorKind::Goto { target } + | TerminatorKind::Goto { target, .. } | TerminatorKind::Yield { resume: target, .. } => { format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), target) } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index b1ac4d33445b0..6a34f0167354b 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -1,6 +1,5 @@ use std::fmt::Debug; -use rustc_data_structures::thin_vec::ThinVec; use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; use tracing::trace; @@ -175,7 +174,6 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { discr: parent_op, targets: eq_targets, }, - loop_hint_attrs: ThinVec::new(), }), bbs[parent].is_cleanup, ); @@ -230,7 +228,6 @@ fn evaluate_candidate<'tcx>( let Terminator { kind: TerminatorKind::SwitchInt { targets: child_targets, discr: child_discr }, source_info, - loop_hint_attrs: _, } = bbs[child].terminator() else { return None; diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 9b81f55ab1145..db8d5d6fd23b9 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -3,7 +3,6 @@ use std::{fmt, iter, mem}; use itertools::Itertools; use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_attr_ir::lang_items::LangItem; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::{CoroutineDesugaring, CoroutineKind}; use rustc_index::Idx; use rustc_middle::mir::*; @@ -263,20 +262,20 @@ where let succ_with_dead = self.new_block_with_statements( unwind, vec![self.storage_dead(fut)], - TerminatorKind::Goto { target: succ }, + TerminatorKind::goto(succ), ); let dropline_with_dead = dropline.map(|target| { self.new_block_with_statements( unwind, vec![self.storage_dead(fut)], - TerminatorKind::Goto { target }, + TerminatorKind::goto(target), ) }); let unwind_with_dead = unwind.map(|target| { self.new_block_with_statements( Unwind::InCleanup, vec![self.storage_dead(fut)], - TerminatorKind::Goto { target }, + TerminatorKind::goto(target), ) }); @@ -322,12 +321,8 @@ where dropline_with_dead.unwrap_or(succ_with_dead), unwind_with_dead, ); - self.elaborator - .patch() - .patch_terminator(drop_resume_bb, TerminatorKind::Goto { target: panic_bb }); - self.elaborator - .patch() - .patch_terminator(drop_drop_bb, TerminatorKind::Goto { target: drop_pin_bb }); + self.elaborator.patch().patch_terminator(drop_resume_bb, TerminatorKind::goto(panic_bb)); + self.elaborator.patch().patch_terminator(drop_drop_bb, TerminatorKind::goto(drop_pin_bb)); // If we are in the regular code path, `dropline_with_dead` is `Some`. // @@ -344,12 +339,8 @@ where succ_with_dead, unwind_with_dead, ); - self.elaborator - .patch() - .patch_terminator(resume_bb, TerminatorKind::Goto { target: pin_bb }); - self.elaborator - .patch() - .patch_terminator(drop_bb, TerminatorKind::Goto { target: drop_pin_bb }); + self.elaborator.patch().patch_terminator(resume_bb, TerminatorKind::goto(pin_bb)); + self.elaborator.patch().patch_terminator(drop_bb, TerminatorKind::goto(drop_pin_bb)); pin_bb } else { // We were already in the drop line, so return the loop we created for it. @@ -654,9 +645,7 @@ where self.dropline, false, ); - self.elaborator - .patch() - .patch_terminator(bb, TerminatorKind::Goto { target: async_drop_bb }); + self.elaborator.patch().patch_terminator(bb, TerminatorKind::goto(async_drop_bb)); } else { self.elaborator.patch().patch_terminator( bb, @@ -745,24 +734,18 @@ where fn elaborate_drop(&mut self, bb: BasicBlock) { match self.elaborator.drop_style(self.path, DropFlagMode::Deep) { DropStyle::Dead => { - self.elaborator - .patch() - .patch_terminator(bb, TerminatorKind::Goto { target: self.succ }); + self.elaborator.patch().patch_terminator(bb, TerminatorKind::goto(self.succ)); } DropStyle::Static => { self.build_drop(bb); } DropStyle::Conditional => { let drop_bb = self.complete_drop(self.succ, self.unwind); - self.elaborator - .patch() - .patch_terminator(bb, TerminatorKind::Goto { target: drop_bb }); + self.elaborator.patch().patch_terminator(bb, TerminatorKind::goto(drop_bb)); } DropStyle::Open => { let drop_bb = self.open_drop(); - self.elaborator - .patch() - .patch_terminator(bb, TerminatorKind::Goto { target: drop_bb }); + self.elaborator.patch().patch_terminator(bb, TerminatorKind::goto(drop_bb)); } } } @@ -1023,7 +1006,7 @@ where Place::from(ptr_local), Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty), )], - TerminatorKind::Goto { target: do_drop_bb }, + TerminatorKind::goto(do_drop_bb), ) } @@ -1335,7 +1318,7 @@ where self.build_async_drop(place, ety, loop_block, unwind, dropline, false); self.elaborator .patch() - .patch_terminator(drop_block, TerminatorKind::Goto { target: async_drop_bb }); + .patch_terminator(drop_block, TerminatorKind::goto(async_drop_bb)); } else { self.elaborator.patch().patch_terminator( drop_block, @@ -1449,7 +1432,7 @@ where ), ), ], - TerminatorKind::Goto { target: slice_block }, + TerminatorKind::goto(slice_block), ) } @@ -1491,7 +1474,7 @@ where ), self.assign(cur.into(), Rvalue::Use(zero, WithRetag::Yes)), ], - TerminatorKind::Goto { target: loop_block }, + TerminatorKind::goto(loop_block), ); // FIXME(#34708): handle partially-dropped array/slice elements. @@ -1577,7 +1560,7 @@ where if statements.is_empty() { return succ; } - self.new_block_with_statements(unwind, statements, TerminatorKind::Goto { target: succ }) + self.new_block_with_statements(unwind, statements, TerminatorKind::goto(succ)) } #[instrument(level = "debug", skip(self), ret)] @@ -1641,11 +1624,7 @@ where #[instrument(level = "trace", skip(self), ret)] fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock { self.elaborator.patch().new_block(BasicBlockData::new( - Some(Terminator { - source_info: self.source_info, - kind: k, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info: self.source_info, kind: k }), unwind.is_cleanup(), )) } @@ -1659,11 +1638,7 @@ where ) -> BasicBlock { self.elaborator.patch().new_block(BasicBlockData::new_stmts( statements, - Some(Terminator { - source_info: self.source_info, - kind: k, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info: self.source_info, kind: k }), unwind.is_cleanup(), )) } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index a19ae86542d25..3c4e1d698804a 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -352,7 +352,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { .ty .needs_drop(self.tcx, self.typing_env()) { - self.patch.patch_terminator(bb, TerminatorKind::Goto { target }); + self.patch.patch_terminator(bb, TerminatorKind::goto(target)); continue; } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 38021f4b76a4d..367e16daa8232 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -6,7 +6,6 @@ use std::{debug_assert_matches, iter}; use rustc_abi::{ExternAbi, FieldIdx}; use rustc_attr_ir::lang_items::LangItem; use rustc_attr_ir::{InlineAttr, OptimizeAttr}; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_index::Idx; @@ -871,8 +870,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( let data = BasicBlockData::new( Some(Terminator { source_info: terminator.source_info, - kind: TerminatorKind::Goto { target: block }, - loop_hint_attrs: ThinVec::new(), + kind: TerminatorKind::goto(block), }), caller_body[block].is_cleanup, ); @@ -999,8 +997,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( caller_body[callsite.block].terminator = Some(Terminator { source_info: callsite.source_info, - kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) }, - loop_hint_attrs: ThinVec::new(), + kind: TerminatorKind::goto(integrator.map_block(START_BLOCK)), }); // Copy required constants from the callee_body into the caller_body. Although we are only @@ -1285,7 +1282,7 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { match terminator.kind { TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => bug!(), - TerminatorKind::Goto { ref mut target } => { + TerminatorKind::Goto { ref mut target, .. } => { *target = self.map_block(*target); } TerminatorKind::SwitchInt { ref mut targets, .. } => { @@ -1313,14 +1310,14 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { } TerminatorKind::Return => { terminator.kind = if let Some(tgt) = self.return_block { - TerminatorKind::Goto { target: tgt } + TerminatorKind::goto(tgt) } else { TerminatorKind::Unreachable } } TerminatorKind::UnwindResume => { terminator.kind = match self.cleanup_block { - UnwindAction::Cleanup(tgt) => TerminatorKind::Goto { target: tgt }, + UnwindAction::Cleanup(tgt) => TerminatorKind::goto(tgt), UnwindAction::Continue => TerminatorKind::UnwindResume, UnwindAction::Unreachable => TerminatorKind::Unreachable, UnwindAction::Terminate(reason) => TerminatorKind::UnwindTerminate(reason), diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index e02e29a2e23e0..eaedb7c9aca3d 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -256,7 +256,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { ), ))), )); - terminator.kind = TerminatorKind::Goto { target: *destination_block }; + terminator.kind = TerminatorKind::goto(*destination_block); } /// Simplify `size_of_val` and `align_of_val` if we don't actually need @@ -314,7 +314,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { Rvalue::Use(const_op, WithRetag::Yes), ))), )); - terminator.kind = TerminatorKind::Goto { target: *destination_block }; + terminator.kind = TerminatorKind::goto(*destination_block); } } @@ -371,7 +371,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { Rvalue::BinaryOp(BinOp::Eq, Box::new((lhs_op, rhs_op))), ))), )); - terminator.kind = TerminatorKind::Goto { target: *destination_block }; + terminator.kind = TerminatorKind::goto(*destination_block); } } @@ -421,7 +421,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } Some(false) => { // If we know the assert does not panic, turn the call into a Goto - terminator.kind = TerminatorKind::Goto { target: target_block }; + terminator.kind = TerminatorKind::goto(target_block); } } } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 05616da42505b..ef92a373d5a46 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -1049,7 +1049,7 @@ impl<'a, 'tcx> OpportunitySet<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn apply_goto(&mut self, bb: BasicBlock, target: BasicBlock) { - self.basic_blocks[bb].terminator_mut().kind = TerminatorKind::Goto { target }; + self.basic_blocks[bb].terminator_mut().kind = TerminatorKind::goto(target); } #[instrument(level = "debug", skip(self), ret)] diff --git a/compiler/rustc_mir_transform/src/lint_and_remove_uninhabited.rs b/compiler/rustc_mir_transform/src/lint_and_remove_uninhabited.rs index 458be599c3fea..6e875902be506 100644 --- a/compiler/rustc_mir_transform/src/lint_and_remove_uninhabited.rs +++ b/compiler/rustc_mir_transform/src/lint_and_remove_uninhabited.rs @@ -126,7 +126,7 @@ fn find_unreachable_code_from<'tcx>( match term.kind { // The user does not care for `goto` and compiler-generated drops. If the target block is // only reachable through those terminators, continue searching there. - TerminatorKind::Goto { target } | TerminatorKind::Drop { target, .. } => { + TerminatorKind::Goto { target, .. } | TerminatorKind::Drop { target, .. } => { if &body.basic_blocks.predecessors()[target][..] == &[bb] { find_unreachable_code_from(target, body) } else { diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 7725daa276cc6..1ec81d0d73b21 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -120,7 +120,7 @@ pub(crate) fn check_liveness<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Den if let TerminatorKind::Return | TerminatorKind::UnwindResume = bbdata.terminator().kind { - bbdata.terminator_mut().kind = TerminatorKind::Goto { target: START_BLOCK }; + bbdata.terminator_mut().kind = TerminatorKind::goto(START_BLOCK); } } body = &body_mem; @@ -1418,7 +1418,7 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_, 'tcx> { match terminator.kind { TerminatorKind::Return | TerminatorKind::Yield { .. } - | TerminatorKind::Goto { target: START_BLOCK } // Inserted for the `FnMut` case. + | TerminatorKind::Goto { target: START_BLOCK, .. } // Inserted for the `FnMut` case. | TerminatorKind::Call { target: None, .. } // unwinding could be caught if self.capture_kind != CaptureKind::None => { diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index c0f906330d8af..3ee8c405a1d77 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -38,7 +38,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { Rvalue::Use(Operand::RuntimeChecks(op), WithRetag::Yes), ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::forget => { let target = target.unwrap(); @@ -56,7 +56,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { ), ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::copy_nonoverlapping => { let target = target.unwrap(); @@ -75,7 +75,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { ), )), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::assume => { let target = target.unwrap(); @@ -88,7 +88,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { arg.node, ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::wrapping_add | sym::wrapping_sub @@ -126,7 +126,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))), ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { let target = target.unwrap(); @@ -146,7 +146,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))), ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::read_via_copy => { let Ok([arg]) = take_array(args) else { @@ -177,7 +177,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { // so it must be unreachable. TerminatorKind::Unreachable } - Some(target) => TerminatorKind::Goto { target }, + Some(target) => TerminatorKind::goto(target), } } // `write_via_move` is already lowered during MIR building. @@ -198,7 +198,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { Rvalue::Discriminant(arg), ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::offset => { let target = target.unwrap(); @@ -215,7 +215,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr.node, delta.node))), ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::slice_get_unchecked => { let target = target.unwrap(); @@ -261,7 +261,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { terminator.source_info, StatementKind::Assign(Box::new((*destination, rvalue))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::transmute | sym::transmute_unchecked => { let dst_ty = destination.ty(local_decls, tcx).ty; @@ -283,7 +283,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { ))), )); if let Some(target) = *target { - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } else { terminator.kind = TerminatorKind::Unreachable; } @@ -313,7 +313,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { Rvalue::Aggregate(Box::new(kind), fields.into()), ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } sym::ptr_metadata => { let Ok([ptr]) = take_array(args) else { @@ -330,7 +330,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node), ))), )); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); } _ => {} } diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 1dfba7d6c5200..745ced538c8e7 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -57,7 +57,7 @@ fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_ite let add_statement = Statement::new(terminator.source_info, len_statement_kind); // modify terminator into simple Goto - let new_terminator_kind = TerminatorKind::Goto { target: *bb }; + let new_terminator_kind = TerminatorKind::goto(*bb); block.statements.push(add_statement); block.terminator_mut().kind = new_terminator_kind; diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs index 280a57e474237..5df08eb7ad52f 100644 --- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs +++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs @@ -25,7 +25,7 @@ impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators { } for bb in bbs { - if let TerminatorKind::Goto { target } = bb.terminator().kind + if let TerminatorKind::Goto { target, .. } = bb.terminator().kind && bbs_simple_returns.contains(target) { bb.terminator_mut().kind = TerminatorKind::Return; diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index 6a2d5101067e7..da1077707baff 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::thin_vec::ThinVec; use rustc_index::Idx; use rustc_middle::mir::*; use rustc_middle::ty::Ty; @@ -93,7 +92,6 @@ impl<'tcx> MirPatch<'tcx> { Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::UnwindResume, - loop_hint_attrs: ThinVec::new(), }), true, )); @@ -110,7 +108,6 @@ impl<'tcx> MirPatch<'tcx> { Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::Unreachable, - loop_hint_attrs: ThinVec::new(), }), true, )); @@ -127,7 +124,6 @@ impl<'tcx> MirPatch<'tcx> { Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::Unreachable, - loop_hint_attrs: ThinVec::new(), }), false, )); @@ -146,7 +142,6 @@ impl<'tcx> MirPatch<'tcx> { Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::UnwindTerminate(reason), - loop_hint_attrs: ThinVec::new(), }), true, )); diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 92c2f9a1c20e1..b490ebb3a9392 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -16,7 +16,6 @@ use std::{assert_matches, cmp, iter, mem}; use either::{Left, Right}; use rustc_const_eval::check_consts::{ConstCx, qualifs}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_index::{IndexSlice, IndexVec}; @@ -611,7 +610,7 @@ impl<'tcx> Validator<'_, 'tcx> { safe_blocks.insert(safe_block); // Let's see if we can find another safe block. safe_block = match body.basic_blocks[safe_block].terminator().kind { - TerminatorKind::Goto { target } => target, + TerminatorKind::Goto { target, .. } => target, TerminatorKind::Call { target: Some(target), .. } | TerminatorKind::Drop { target, .. } => { // This calls a function or the destructor. `target` does not get executed if @@ -757,7 +756,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Some(Terminator { source_info: SourceInfo::outermost(span), kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), }), false, )) @@ -845,8 +843,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }; Terminator { source_info: terminator.source_info, - kind: mem::replace(&mut terminator.kind, TerminatorKind::Goto { target }), - loop_hint_attrs: ThinVec::new(), + kind: mem::replace(&mut terminator.kind, TerminatorKind::goto(target)), } }; @@ -1099,7 +1096,7 @@ fn promote_candidates<'tcx>( && let Some(index) = place.as_local() { if promoted(index) { - terminator.kind = TerminatorKind::Goto { target: *target }; + terminator.kind = TerminatorKind::goto(*target); } } } diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index c5f462f714dd8..74cac4c8481f0 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -62,7 +62,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { }; // Replace block terminator with `Goto`. - block.terminator_mut().kind = TerminatorKind::Goto { target: *target }; + block.terminator_mut().kind = TerminatorKind::goto(*target); } } diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 45a5c5626f98a..04c9204aa6aa5 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -29,7 +29,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops { continue; } debug!("SUCCESS: replacing `drop` with goto({:?})", target); - terminator.kind = TerminatorKind::Goto { target }; + terminator.kind = TerminatorKind::goto(target); should_simplify = true; } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index faf7039d498b1..f1d85166653ff 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -2,7 +2,6 @@ use std::{assert_matches, fmt, iter}; use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_attr_ir::lang_items::LangItem; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::{Idx, IndexVec}; @@ -280,13 +279,10 @@ pub fn build_drop_shim<'tcx>( let return_block = BasicBlock::new(1); let mut blocks = IndexVec::with_capacity(2); let block = |blocks: &mut IndexVec<_, _>, kind| { - blocks.push(BasicBlockData::new( - Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }), - false, - )) + blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) }; if ty.is_some() { - block(&mut blocks, TerminatorKind::Goto { target: return_block }); + block(&mut blocks, TerminatorKind::goto(return_block)); } block(&mut blocks, TerminatorKind::Return); @@ -338,7 +334,6 @@ pub fn build_drop_shim<'tcx>( call_source: CallSource::Misc, fn_span: span, }, - loop_hint_attrs: ThinVec::new(), }); } else { let patch = { @@ -491,11 +486,7 @@ fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, shim: ty::ShimKind<'tcx>) -> Rvalue::ThreadLocalRef(def_id), ))), )], - Some(Terminator { - source_info, - kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::Return }), false, )]); @@ -581,7 +572,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { let source_info = self.source_info(); self.blocks.push(BasicBlockData::new_stmts( statements, - Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }), + Some(Terminator { source_info, kind }), is_cleanup, )) } @@ -704,7 +695,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { unwind = next_unwind; } // If all clones succeed then we end up here. - self.block(vec![], TerminatorKind::Goto { target }, false); + self.block(vec![], TerminatorKind::goto(target), false); unwind } @@ -712,7 +703,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { where I: IntoIterator>, { - self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); + self.block(vec![], TerminatorKind::goto(self.block_index_offset(3)), false); let unwind = self.block(vec![], TerminatorKind::UnwindResume, true); let target = self.block(vec![], TerminatorKind::Return, false); @@ -726,7 +717,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { coroutine_def_id: DefId, args: CoroutineArgs>, ) { - self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); + self.block(vec![], TerminatorKind::goto(self.block_index_offset(3)), false); let unwind = self.block(vec![], TerminatorKind::UnwindResume, true); // This will get overwritten with a switch once we know the target blocks let switch = self.block(vec![], TerminatorKind::Unreachable, false); @@ -744,7 +735,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { place: Box::new(Place::return_place()), variant_index, })], - TerminatorKind::Goto { target: clone_block }, + TerminatorKind::goto(clone_block), false, ); cases.push((index as u128, start_block)); @@ -927,7 +918,7 @@ fn build_call_shim<'tcx>( let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { blocks.push(BasicBlockData::new_stmts( statements, - Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }), + Some(Terminator { source_info, kind }), is_cleanup, )) }; @@ -1054,11 +1045,7 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { let start_block = BasicBlockData::new_stmts( vec![statement], - Some(Terminator { - source_info, - kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::Return }), false, ); @@ -1141,11 +1128,7 @@ fn build_fn_ptr_as_ptr_shim<'tcx>( let start_block = BasicBlockData::new_stmts( statements, - Some(Terminator { - source_info, - kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::Return }), false, ); let source = MirSource::from_shim(ty::ShimKind::FnPtrAsPtr(def_id, self_ty)); @@ -1180,11 +1163,7 @@ fn build_fn_ptr_from_ptr_shim<'tcx>( let start_block = BasicBlockData::new_stmts( statements, - Some(Terminator { - source_info, - kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::Return }), false, ); let source = MirSource::from_shim(ty::ShimKind::FnPtrFromPtr(def_id, self_ty)); @@ -1282,11 +1261,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>( let statements = vec![stmt]; let start_block = BasicBlockData::new_stmts( statements, - Some(Terminator { - source_info, - kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::Return }), false, ); diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index fcc28b20d25a0..7530716e8cf39 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -85,10 +85,7 @@ pub(super) fn build_async_drop_shim<'tcx>( let return_block = BasicBlock::new(1); let mut blocks = IndexVec::with_capacity(2); let block = |blocks: &mut IndexVec<_, _>, kind| { - blocks.push(BasicBlockData::new( - Some(Terminator { source_info, kind, loop_hint_attrs: ThinVec::new() }), - false, - )) + blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) }; block( &mut blocks, @@ -101,7 +98,7 @@ pub(super) fn build_async_drop_shim<'tcx>( drop: None, } } else { - TerminatorKind::Goto { target: return_block } + TerminatorKind::goto(return_block) }, ); block(&mut blocks, TerminatorKind::Return); @@ -393,8 +390,6 @@ fn build_adrop_for_adrop_shim<'tcx>( call_source: CallSource::Misc, fn_span: span, }, - - loop_hint_attrs: ThinVec::new(), }), false, )); @@ -418,17 +413,11 @@ fn build_adrop_for_adrop_shim<'tcx>( call_source: CallSource::Misc, fn_span: span, }, - - loop_hint_attrs: ThinVec::new(), }), false, )); blocks.push(BasicBlockData::new( - Some(Terminator { - source_info, - kind: TerminatorKind::Return, - loop_hint_attrs: ThinVec::new(), - }), + Some(Terminator { source_info, kind: TerminatorKind::Return }), false, )); diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 32504fc72fecd..c0281871f2a73 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -235,7 +235,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { // We can move all debuginfos to the last basic block. let mut trivial_goto_chain = true; while let Some(terminator) = self.take_terminator_if_simple_goto(current) { - let Terminator { kind: TerminatorKind::Goto { target }, .. } = terminator else { + let Terminator { kind: TerminatorKind::Goto { target, .. }, .. } = terminator else { unreachable!(); }; trivial_goto_chain &= self.pred_count[target] == 1; @@ -246,7 +246,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { *changed |= *start != last; *start = last; while let Some((current, mut terminator)) = terminators.pop() { - let Terminator { kind: TerminatorKind::Goto { ref mut target }, .. } = terminator + let Terminator { kind: TerminatorKind::Goto { ref mut target, .. }, .. } = terminator else { unreachable!(); }; @@ -284,7 +284,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { terminator: &mut Terminator<'tcx>, ) -> bool { let target = match terminator.kind { - TerminatorKind::Goto { target } if self.pred_count[target] == 1 => target, + TerminatorKind::Goto { target, .. } if self.pred_count[target] == 1 => target, _ => return false, }; @@ -325,7 +325,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { self.pred_count[first_succ] -= (count - 1) as u32; debug!("simplifying branch {:?}", terminator); - terminator.kind = TerminatorKind::Goto { target: first_succ }; + terminator.kind = TerminatorKind::goto(first_succ); true } diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 58a3f1b571e59..b25728e15eef3 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -81,14 +81,14 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { && let Some(constant) = c.const_.try_eval_bits(tcx, typing_env) => { let target = targets.target_for_value(constant); - TerminatorKind::Goto { target } + TerminatorKind::goto(target) } TerminatorKind::Assert { target, ref cond, expected, .. } if let Some(c) = try_get_const(&cond, pre_place_const.take()) && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) && constant == expected => { - TerminatorKind::Goto { target } + TerminatorKind::goto(target) } _ => continue, }; diff --git a/compiler/rustc_mir_transform/src/tail_copy_to_move.rs b/compiler/rustc_mir_transform/src/tail_copy_to_move.rs index e97844748cefb..c6a55b90d5c6e 100644 --- a/compiler/rustc_mir_transform/src/tail_copy_to_move.rs +++ b/compiler/rustc_mir_transform/src/tail_copy_to_move.rs @@ -86,7 +86,7 @@ impl<'tcx> crate::MirPass<'tcx> for TailCopyToMove { let mut first = None; for pred in predecessors[state.block].iter().copied() { let terminator = body.basic_blocks[pred].terminator(); - if let TerminatorKind::Goto { target } = terminator.kind { + if let TerminatorKind::Goto { target, .. } = terminator.kind { debug_assert_eq!(target, state.block); if first.is_none() { first = Some(pred); diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index 3e03cfe37b75e..eacc263675e15 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -30,7 +30,7 @@ impl crate::MirPass<'_> for UnreachablePropagation { TerminatorKind::Unreachable => true, // This will unconditionally run into an unreachable and is therefore unreachable // as well. - TerminatorKind::Goto { target } if unreachable_blocks.contains(target) => { + TerminatorKind::Goto { target, .. } if unreachable_blocks.contains(target) => { patch.patch_terminator(bb, TerminatorKind::Unreachable); true } @@ -132,12 +132,12 @@ pub(crate) fn remove_successors_from_switch<'tcx>( let terminator = match (num_targets, otherwise_unreachable) { // If all targets are unreachable, we can be unreachable as well. (1, true) => TerminatorKind::Unreachable, - (1, false) => TerminatorKind::Goto { target: otherwise }, + (1, false) => TerminatorKind::goto(otherwise), (2, true) => { // All targets are unreachable except one. Record the equality, and make it a goto. let (value, target) = new_targets.iter().next().unwrap(); add_assumption(BinOp::Eq, value); - TerminatorKind::Goto { target } + TerminatorKind::goto(target) } _ if num_targets == targets.all_targets().len() => { // Nothing has changed. diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 28a508bde9eca..f8afc895bb712 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -339,7 +339,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { match &terminator.kind { - TerminatorKind::Goto { target } => { + TerminatorKind::Goto { target, .. } => { self.check_edge(location, *target, EdgeKind::Normal); } TerminatorKind::SwitchInt { targets, discr: _ } => { diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index c464c310cddf4..9bf83f90e5574 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -733,7 +733,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { ) -> Self::T { use crate::mir::TerminatorKind; match self { - mir::TerminatorKind::Goto { target } => { + mir::TerminatorKind::Goto { target, .. } => { TerminatorKind::Goto { target: target.as_usize() } } mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt { From 6257fafb8ea547943a690775ec426e4b8a364fde Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 1 Aug 2026 12:31:13 +0200 Subject: [PATCH 15/15] add MISSING_GENERIC_TYPE_VISITABLE lint --- compiler/rustc_lint/src/diagnostics.rs | 11 ++ compiler/rustc_lint/src/internal.rs | 73 +++++++++- compiler/rustc_lint/src/lib.rs | 6 + compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_type_ir/src/generic_visit.rs | 1 + compiler/rustc_type_ir/src/lib.rs | 6 + compiler/rustc_type_ir/src/visit.rs | 1 + .../missing-generic-type-visitable-derive.rs | 128 ++++++++++++++++++ ...ssing-generic-type-visitable-derive.stderr | 65 +++++++++ 9 files changed, 288 insertions(+), 5 deletions(-) create mode 100644 tests/ui-fulldeps/internal-lints/missing-generic-type-visitable-derive.rs create mode 100644 tests/ui-fulldeps/internal-lints/missing-generic-type-visitable-derive.stderr diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index d9fc1703f8c03..601f1213650e1 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -3261,3 +3261,14 @@ pub(crate) enum RawBorrowViaReferenceSuggestion<'a> { #[help("consider using `&raw {$mutbl}` for a safer and more explicit raw pointer")] Spanless { mutbl: &'a str }, } + +#[derive(Diagnostic)] +#[diag("missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable`")] +#[note_once( + "`GenericTypeVisitable` is rust-analyzer's version of `TypeVisitable`; it should be implemented whenever the latter is" +)] +#[help("mark the type with `#[derive(GenericTypeVisitable)]`")] +#[help( + "or, if `GenericTypeVisitable` is derived, check whether all fields implement `GenericTypeVisitable`" +)] +pub(crate) struct MissingGenericTypeVisitableDeriveDiag; diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index b32fa2515238a..bce726311e51f 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -8,17 +8,20 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, HirId}; +use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint_defs::{declare_lint_pass, declare_tool_lint}; use rustc_middle::ty::{self, ClausePolarity, GenericArgsRef}; use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::{Span, sym}; +use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{Obligation, ObligationCause}; use crate::diagnostics::{ AttributeKindInFindAttr, BadOptAccessDiag, DefaultHashTypesDiag, - ImplicitSysrootCrateImportDiag, LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability, - QueryUntracked, RustcMustMatchExhaustivelyNotExhaustive, SpanUseEqCtxtDiag, - SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse, - TypeIrInherentUsage, TypeIrTraitUsage, + ImplicitSysrootCrateImportDiag, LintPassByHand, MissingGenericTypeVisitableDeriveDiag, + NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, + RustcMustMatchExhaustivelyNotExhaustive, SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, + TyQualified, TykindDiag, TykindKind, TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -873,3 +876,63 @@ impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively { } } } + +declare_tool_lint! { + /// The `missing_generic_type_visitable_derive` lint detects types implementing `TypeVisitable` + /// but not deriving `GenericTypeVisitable`. + /// + /// `GenericTypeVisitable` is the analog of `TypeVisitable` used by rust-analyzer, and needs to + /// be implemented whenever `TypeVisitable` is. See [`rustc_type_ir::generic_visit`] for more + /// information. + pub rustc::MISSING_GENERIC_TYPE_VISITABLE_DERIVE, + // This lint is meant to be manually enabled in selected crates (currently only `rustc_type_ir`) + Allow, + "Forbid implementing `TypeVisitable` without deriving `GenericTypeVisitable`", + report_in_external_macro: true +} + +declare_lint_pass!(MissingGenericTypeVisitableDerive => [MISSING_GENERIC_TYPE_VISITABLE_DERIVE]); + +impl<'tcx> LateLintPass<'tcx> for MissingGenericTypeVisitableDerive { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + // lint ADTs except unions, as neither trait can be implemented on the latter + if matches!(item.kind, hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..)) + && let Some(regular_id) = cx.tcx.get_diagnostic_item(sym::TypeVisitable) + && let Some(generic_id) = cx.tcx.get_diagnostic_item(sym::GenericTypeVisitable) + && let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env()) + && let self_ty = { + let self_id = item.owner_id.to_def_id(); + let args = infcx.fresh_args_for_item(DUMMY_SP, self_id); + cx.tcx.type_of(self_id).instantiate(cx.tcx, args).skip_norm_wip() + } + // check whether `Self: TypeVisitable` holds for some `I`.. + && { + let predicate = + ty::TraitRef::new(cx.tcx, regular_id, [self_ty, infcx.next_ty_var(DUMMY_SP)]); + let obligation = + Obligation::new(cx.tcx, ObligationCause::dummy(), param_env, predicate); + + // NOTE: I initially went with `predicate_must_hold_modulo_regions` (which is what's + // used by Clippy's [`implements_trait`](https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.implements_trait.html), + // but that returned `false` more often than I'd hoped, and so I went with the + // next-most strict function. + infcx.predicate_may_hold(&obligation) + } + // ..while `Self: GenericTypeVisitable` doesn't + && { + let predicate = + ty::TraitRef::new(cx.tcx, generic_id, [self_ty, infcx.next_ty_var(DUMMY_SP)]); + let obligation = + Obligation::new(cx.tcx, ObligationCause::dummy(), param_env, predicate); + + !infcx.predicate_may_hold(&obligation) + } + { + cx.emit_span_lint( + MISSING_GENERIC_TYPE_VISITABLE_DERIVE, + item.span, + MissingGenericTypeVisitableDeriveDiag, + ); + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index deea9e1bbc13c..bf716b099f856 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -298,6 +298,7 @@ late_lint_methods!( BadOptAccess: BadOptAccess, DefaultHashTypes: DefaultHashTypes, DisallowedPassByRef: DisallowedPassByRef, + MissingGenericTypeVisitableDerive: MissingGenericTypeVisitableDerive, QueryStability: QueryStability, RustcMustMatchExhaustively: RustcMustMatchExhaustively, SpanUseEqCtxt: SpanUseEqCtxt, @@ -769,6 +770,11 @@ fn register_internals(store: &mut LintStore) { // // Late pass: RustcMustMatchExhaustively LintId::of(RUSTC_MUST_MATCH_EXHAUSTIVELY), + // Late pass: MissingGenericTypeVisitableDerive + // Note: this one is not included so that it doesn't become effectively warn-by-default + // (since `rustc::internal` is warn-by-default). Instead, it's enabled manually in + // each relevant crate. + // LintId::of(MISSING_GENERIC_TYPE_VISITABLE_DERIVE), ], ); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3debf3248ff80..eb8fd764d5e67 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -237,6 +237,7 @@ symbols! { From, FromIterator, FromResidual, + GenericTypeVisitable, GlobalAlloc, Hash, HashMap, @@ -358,6 +359,7 @@ symbols! { TyCtxt, TyKind, Type, + TypeVisitable, Union, Unresolved, Unsafe, diff --git a/compiler/rustc_type_ir/src/generic_visit.rs b/compiler/rustc_type_ir/src/generic_visit.rs index e2663a61421f1..5fc5ab39f6eb1 100644 --- a/compiler/rustc_type_ir/src/generic_visit.rs +++ b/compiler/rustc_type_ir/src/generic_visit.rs @@ -26,6 +26,7 @@ use crate::Interner; /// /// Therefore, it is advised to instead derive this using the derive /// macro located in `rustc_macros`. +#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "GenericTypeVisitable")] pub unsafe trait GenericTypeVisitable { fn generic_visit_with(&self, visitor: &mut V); } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 38b717b2cadb4..0be6a2c4152dc 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -27,6 +27,12 @@ #![allow(rustc::usage_of_type_ir_traits)] #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(associated_type_defaults, rustc_attrs, negative_impls))] +// NOTE: the outer `cfg_attr` is only there so that r-a doesn't see the nightly-only `bootstrap` +// in the inner `cfg_attr`. When the latter is removed, the former can be removed as well. +#![cfg_attr( + feature = "nightly", + cfg_attr(not(bootstrap), deny(rustc::missing_generic_type_visitable_derive)) +)] // tidy-alphabetical-end extern crate self as rustc_type_ir; diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 008b6aeb239ee..396c8c17a2952 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -59,6 +59,7 @@ use crate::{self as ty, Const, Interner, PredicateProxy, Region, TypeFlags}; /// /// To implement this conveniently, use the derive macro located in /// `rustc_macros`. +#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "TypeVisitable")] pub trait TypeVisitable: fmt::Debug { /// The entry point for visiting. To visit a value `t` with a visitor `v` /// call: `t.visit_with(v)`. diff --git a/tests/ui-fulldeps/internal-lints/missing-generic-type-visitable-derive.rs b/tests/ui-fulldeps/internal-lints/missing-generic-type-visitable-derive.rs new file mode 100644 index 0000000000000..02c0a6ae5b370 --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/missing-generic-type-visitable-derive.rs @@ -0,0 +1,128 @@ +//@ compile-flags: -Z unstable-options + +#![crate_type = "lib"] +#![feature(rustc_private)] +#![deny(rustc::missing_generic_type_visitable_derive)] + +extern crate rustc_type_ir; +extern crate rustc_type_ir_macros; + +use rustc_type_ir::{GenericTypeVisitable, TypeVisitable}; +use rustc_type_ir::{Interner, TypeVisitor, VisitorResult}; +use rustc_type_ir_macros::{GenericTypeVisitable, TypeVisitable_Generic}; +use std::{fmt::Debug, hash::Hash}; + +// Should lint: `TypeVisitable` is implemented, but `GenericTypeVisitable` isn't + +#[derive(Debug, TypeVisitable_Generic)] +struct DerivesRegular; +//~^ ERROR missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + +#[derive(Debug)] +struct ImplsRegular; +//~^ ERROR missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + +impl TypeVisitable for ImplsRegular { + fn visit_with>(&self, _f: &mut F) -> F::Result { + F::Result::output() + } +} + +// Same but with an enum + +#[derive(Debug, TypeVisitable_Generic)] +enum EnumDerivesRegular {} +//~^ ERROR missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + +// Same but the type is generic, over the interner + +#[derive(TypeVisitable_Generic)] +struct GenericOverIDerivesRegular(I::Clause); +//~^ ERROR missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + +// manually hand-rolled `#[derive_where(Debug; I: Interner)]` +impl std::fmt::Debug for GenericOverIDerivesRegular { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + todo!() + } +} + +// Same but the type is generic, over an unrelated type + +#[derive(TypeVisitable_Generic)] +struct GenericOverTDerivesRegular([T; 67]); +//~^ ERROR missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + +// manually hand-rolled `#[derive(Debug)]`, to avoid the spurious bound on `T` +impl Debug for GenericOverTDerivesRegular { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + todo!() + } +} + +// Should not lint: both traits are implemented + +#[derive(Debug, TypeVisitable_Generic, GenericTypeVisitable)] +struct DerivesBoth; + +#[derive(Debug, GenericTypeVisitable)] +struct ImplsAndDerives; + +impl TypeVisitable for ImplsAndDerives { + fn visit_with>(&self, _f: &mut F) -> F::Result { + F::Result::output() + } +} + +#[derive(Debug, TypeVisitable_Generic)] +struct DerivesAndImpls; + +unsafe impl GenericTypeVisitable for DerivesAndImpls { + fn generic_visit_with(&self, _visitor: &mut V) {} +} + +#[derive(Debug)] +struct ImplsBoth; + +impl TypeVisitable for ImplsBoth { + fn visit_with>(&self, _f: &mut F) -> F::Result { + F::Result::output() + } +} + +unsafe impl GenericTypeVisitable for ImplsBoth { + fn generic_visit_with(&self, _visitor: &mut V) {} +} + +// Should not lint: `TypeVisitable` isn't implemented, so `GenericTypeVisitable` doesn't need to be +// either + +struct ImplsNone; + +// Should not lint: `GenericTypeVisitable` is implemented but `TypeVisitable` isn't -- weird, but +// okay for the purposes of this lint + +#[derive(GenericTypeVisitable)] +struct DerivesGeneric; + +struct ImplsGeneric; + +unsafe impl GenericTypeVisitable for ImplsGeneric { + fn generic_visit_with(&self, _visitor: &mut V) {} +} + +// FIXME(ada4a): this will currently lint, and suggest adding a derive, even though ther's already +// one present. The actual problem is that the item has a _field_ that doesn't implement the trait, +// which makes the impl generated by the derive on this item unusable due to unsatisfied bounds. +// +// There are two ways of solving this: +// - in the lint, emit a different suggestion -- namely, to add a derive to the problematic field's +// type -- if we see that the linted type already has a derive. +// - change the derive to add _assertions_ that the bound holds for each field type, and not just +// trait bounds on the impl. +#[derive(Debug)] +#[derive(TypeVisitable_Generic, GenericTypeVisitable)] +struct FieldDoesntImplGeneric { + //~^ ERROR missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + field: ImplsRegular, +} diff --git a/tests/ui-fulldeps/internal-lints/missing-generic-type-visitable-derive.stderr b/tests/ui-fulldeps/internal-lints/missing-generic-type-visitable-derive.stderr new file mode 100644 index 0000000000000..91b6094f0a11a --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/missing-generic-type-visitable-derive.stderr @@ -0,0 +1,65 @@ +error: missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + --> $DIR/missing-generic-type-visitable-derive.rs:18:1 + | +LL | struct DerivesRegular; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `GenericTypeVisitable` is rust-analyzer's version of `TypeVisitable`; it should be implemented whenever the latter is + = help: mark the type with `#[derive(GenericTypeVisitable)]` + = help: or, if `GenericTypeVisitable` is derived, check whether all fields implement `GenericTypeVisitable` +note: the lint level is defined here + --> $DIR/missing-generic-type-visitable-derive.rs:5:9 + | +LL | #![deny(rustc::missing_generic_type_visitable_derive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + --> $DIR/missing-generic-type-visitable-derive.rs:22:1 + | +LL | struct ImplsRegular; + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the type with `#[derive(GenericTypeVisitable)]` + = help: or, if `GenericTypeVisitable` is derived, check whether all fields implement `GenericTypeVisitable` + +error: missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + --> $DIR/missing-generic-type-visitable-derive.rs:34:1 + | +LL | enum EnumDerivesRegular {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the type with `#[derive(GenericTypeVisitable)]` + = help: or, if `GenericTypeVisitable` is derived, check whether all fields implement `GenericTypeVisitable` + +error: missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + --> $DIR/missing-generic-type-visitable-derive.rs:40:1 + | +LL | struct GenericOverIDerivesRegular(I::Clause); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the type with `#[derive(GenericTypeVisitable)]` + = help: or, if `GenericTypeVisitable` is derived, check whether all fields implement `GenericTypeVisitable` + +error: missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + --> $DIR/missing-generic-type-visitable-derive.rs:53:1 + | +LL | struct GenericOverTDerivesRegular([T; 67]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the type with `#[derive(GenericTypeVisitable)]` + = help: or, if `GenericTypeVisitable` is derived, check whether all fields implement `GenericTypeVisitable` + +error: missing `#[derive(GenericTypeVisitable)]` on a type which implements `TypeVisitable` + --> $DIR/missing-generic-type-visitable-derive.rs:125:1 + | +LL | / struct FieldDoesntImplGeneric { +LL | | +LL | | field: ImplsRegular, +LL | | } + | |_^ + | + = help: mark the type with `#[derive(GenericTypeVisitable)]` + = help: or, if `GenericTypeVisitable` is derived, check whether all fields implement `GenericTypeVisitable` + +error: aborting due to 6 previous errors +