From efcae7d31d30ba8d8c806fbb8dea634e78d7b969 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Jul 2025 22:38:57 +0200 Subject: [PATCH 01/23] properly use caller-side panic location for some GenericArgs methods --- compiler/rustc_middle/src/ty/generic_args.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7d34d8df3f3b9..a5fd4d7a262c5 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -536,21 +536,28 @@ impl<'tcx> GenericArgs<'tcx> { #[inline] #[track_caller] pub fn type_at(&self, i: usize) -> Ty<'tcx> { - self[i].as_type().unwrap_or_else(|| bug!("expected type for param #{} in {:?}", i, self)) + self[i].as_type().unwrap_or_else( + #[track_caller] + || bug!("expected type for param #{} in {:?}", i, self), + ) } #[inline] #[track_caller] pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { - self[i] - .as_region() - .unwrap_or_else(|| bug!("expected region for param #{} in {:?}", i, self)) + self[i].as_region().unwrap_or_else( + #[track_caller] + || bug!("expected region for param #{} in {:?}", i, self), + ) } #[inline] #[track_caller] pub fn const_at(&self, i: usize) -> ty::Const<'tcx> { - self[i].as_const().unwrap_or_else(|| bug!("expected const for param #{} in {:?}", i, self)) + self[i].as_const().unwrap_or_else( + #[track_caller] + || bug!("expected const for param #{} in {:?}", i, self), + ) } #[inline] From de1b999ff6c981475e4491ea2fff1851655587e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Jul 2025 23:23:40 +0200 Subject: [PATCH 02/23] atomicrmw on pointers: move integer-pointer cast hacks into backend --- .../src/intrinsics/mod.rs | 24 ++--- compiler/rustc_codegen_gcc/src/builder.rs | 7 +- compiler/rustc_codegen_llvm/src/builder.rs | 14 ++- compiler/rustc_codegen_ssa/messages.ftl | 2 + compiler/rustc_codegen_ssa/src/errors.rs | 8 ++ .../rustc_codegen_ssa/src/mir/intrinsic.rs | 82 +++++++++++++---- .../rustc_codegen_ssa/src/traits/builder.rs | 3 + .../rustc_hir_analysis/src/check/intrinsic.rs | 12 +-- library/core/src/intrinsics/mod.rs | 30 +++---- library/core/src/sync/atomic.rs | 89 ++++++++++--------- src/tools/miri/src/intrinsics/atomic.rs | 19 ++-- src/tools/miri/src/operator.rs | 8 +- tests/codegen-llvm/atomicptr.rs | 6 +- .../atomic-lock-free/atomic_lock_free.rs | 39 +++++--- tests/ui/intrinsics/intrinsic-atomics.rs | 12 +-- tests/ui/intrinsics/non-integer-atomic.rs | 32 +++---- tests/ui/intrinsics/non-integer-atomic.stderr | 32 +++---- 17 files changed, 243 insertions(+), 176 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 4ff5773a06cb2..ed40901ac9b8b 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -969,7 +969,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = amount.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -982,7 +982,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_xsub => { @@ -991,7 +991,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = amount.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1004,7 +1004,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_and => { @@ -1013,7 +1013,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1025,7 +1025,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::And, ptr, src); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_or => { @@ -1034,7 +1034,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1046,7 +1046,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Or, ptr, src); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_xor => { @@ -1055,7 +1055,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1067,7 +1067,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Xor, ptr, src); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_nand => { @@ -1076,7 +1076,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1088,7 +1088,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Nand, ptr, src); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_max => { diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index a4ec4bf8deac4..032f5d0a622d8 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1656,6 +1656,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, + ret_ptr: bool, ) -> RValue<'gcc> { let size = get_maybe_pointer_size(src); let name = match op { @@ -1683,6 +1684,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let atomic_function = self.context.get_builtin_function(name); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + // FIXME: If `ret_ptr` is true and `src` is an integer, we should really tell GCC + // that this is a pointer operation that needs to preserve provenance -- but like LLVM, + // GCC does not currently seems to support that. let void_ptr_type = self.context.new_type::<*mut ()>(); let volatile_void_ptr_type = void_ptr_type.make_volatile(); let dst = self.context.new_cast(self.location, dst, volatile_void_ptr_type); @@ -1690,7 +1694,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let new_src_type = atomic_function.get_param(1).to_rvalue().get_type(); let src = self.context.new_bitcast(self.location, src, new_src_type); let res = self.context.new_call(self.location, atomic_function, &[dst, src, order]); - self.context.new_cast(self.location, res, src.get_type()) + let res_type = if ret_ptr { void_ptr_type } else { src.get_type() }; + self.context.new_cast(self.location, res, res_type) } fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 0ade9edb0d2ea..51593f3f065f4 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1326,15 +1326,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, op: rustc_codegen_ssa::common::AtomicRmwBinOp, dst: &'ll Value, - mut src: &'ll Value, + src: &'ll Value, order: rustc_middle::ty::AtomicOrdering, + ret_ptr: bool, ) -> &'ll Value { - // The only RMW operation that LLVM supports on pointers is compare-exchange. - let requires_cast_to_int = self.val_ty(src) == self.type_ptr() - && op != rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicXchg; - if requires_cast_to_int { - src = self.ptrtoint(src, self.type_isize()); - } + // FIXME: If `ret_ptr` is true and `src` is not a pointer, we *should* tell LLVM that the + // LHS is a pointer and the operation should be provenance-preserving, but LLVM does not + // currently support that (https://github.com/llvm/llvm-project/issues/120837). let mut res = unsafe { llvm::LLVMBuildAtomicRMW( self.llbuilder, @@ -1345,7 +1343,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { llvm::False, // SingleThreaded ) }; - if requires_cast_to_int { + if ret_ptr && self.val_ty(res) != self.type_ptr() { res = self.inttoptr(res, self.type_ptr()); } res diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index c7bd6ffd1f27c..42310a8b8c77b 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -97,6 +97,8 @@ codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` +codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer or pointer type, found `{$ty}` + codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 9040915b6af34..751e7c8a6cb1e 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -764,6 +764,14 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, + #[diag(codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type, code = E0511)] + BasicIntegerOrPtrType { + #[primary_span] + span: Span, + name: Symbol, + ty: Ty<'tcx>, + }, + #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = E0511)] BasicFloatType { #[primary_span] diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index fc95f62b4a43d..3c667b8e88203 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -92,6 +92,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let invalid_monomorphization_int_type = |ty| { bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); }; + let invalid_monomorphization_int_or_ptr_type = |ty| { + bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerOrPtrType { + span, + name, + ty, + }); + }; let parse_atomic_ordering = |ord: ty::Value<'tcx>| { let discr = ord.valtree.unwrap_branch()[0].unwrap_leaf(); @@ -351,7 +358,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::atomic_load => { let ty = fn_args.type_at(0); if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { - invalid_monomorphization_int_type(ty); + invalid_monomorphization_int_or_ptr_type(ty); return Ok(()); } let ordering = fn_args.const_at(1).to_value(); @@ -367,7 +374,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::atomic_store => { let ty = fn_args.type_at(0); if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { - invalid_monomorphization_int_type(ty); + invalid_monomorphization_int_or_ptr_type(ty); return Ok(()); } let ordering = fn_args.const_at(1).to_value(); @@ -377,10 +384,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.atomic_store(val, ptr, parse_atomic_ordering(ordering), size); return Ok(()); } + // These are all AtomicRMW ops sym::atomic_cxchg | sym::atomic_cxchgweak => { let ty = fn_args.type_at(0); if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { - invalid_monomorphization_int_type(ty); + invalid_monomorphization_int_or_ptr_type(ty); return Ok(()); } let succ_ordering = fn_args.const_at(1).to_value(); @@ -407,7 +415,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return Ok(()); } - // These are all AtomicRMW ops sym::atomic_max | sym::atomic_min => { let atom_op = if name == sym::atomic_max { AtomicRmwBinOp::AtomicMax @@ -420,7 +427,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ordering = fn_args.const_at(1).to_value(); let ptr = args[0].immediate(); let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + bx.atomic_rmw( + atom_op, + ptr, + val, + parse_atomic_ordering(ordering), + /* ret_ptr */ false, + ) } else { invalid_monomorphization_int_type(ty); return Ok(()); @@ -438,21 +451,44 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ordering = fn_args.const_at(1).to_value(); let ptr = args[0].immediate(); let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + bx.atomic_rmw( + atom_op, + ptr, + val, + parse_atomic_ordering(ordering), + /* ret_ptr */ false, + ) } else { invalid_monomorphization_int_type(ty); return Ok(()); } } - sym::atomic_xchg - | sym::atomic_xadd + sym::atomic_xchg => { + let ty = fn_args.type_at(0); + let ordering = fn_args.const_at(1).to_value(); + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { + let ptr = args[0].immediate(); + let val = args[1].immediate(); + let atomic_op = AtomicRmwBinOp::AtomicXchg; + bx.atomic_rmw( + atomic_op, + ptr, + val, + parse_atomic_ordering(ordering), + /* ret_ptr */ ty.is_raw_ptr(), + ) + } else { + invalid_monomorphization_int_or_ptr_type(ty); + return Ok(()); + } + } + sym::atomic_xadd | sym::atomic_xsub | sym::atomic_and | sym::atomic_nand | sym::atomic_or | sym::atomic_xor => { let atom_op = match name { - sym::atomic_xchg => AtomicRmwBinOp::AtomicXchg, sym::atomic_xadd => AtomicRmwBinOp::AtomicAdd, sym::atomic_xsub => AtomicRmwBinOp::AtomicSub, sym::atomic_and => AtomicRmwBinOp::AtomicAnd, @@ -462,14 +498,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => unreachable!(), }; - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { - let ordering = fn_args.const_at(1).to_value(); - let ptr = args[0].immediate(); - let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + // The type of the in-memory data. + let ty_mem = fn_args.type_at(0); + // The type of the 2nd operand, given by-value. + let ty_op = fn_args.type_at(1); + + let ordering = fn_args.const_at(2).to_value(); + // We require either both arguments to have the same integer type, or the first to + // be a pointer and the second to be `usize`. + if (int_type_width_signed(ty_mem, bx.tcx()).is_some() && ty_op == ty_mem) + || (ty_mem.is_raw_ptr() && ty_op == bx.tcx().types.usize) + { + let ptr = args[0].immediate(); // of type "pointer to `ty_mem`" + let val = args[1].immediate(); // of type `ty_op` + bx.atomic_rmw( + atom_op, + ptr, + val, + parse_atomic_ordering(ordering), + /* ret_ptr */ ty_mem.is_raw_ptr(), + ) } else { - invalid_monomorphization_int_type(ty); + invalid_monomorphization_int_or_ptr_type(ty_mem); return Ok(()); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 979456a6ba70f..fc17b30d65723 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -548,12 +548,15 @@ pub trait BuilderMethods<'a, 'tcx>: failure_order: AtomicOrdering, weak: bool, ) -> (Self::Value, Self::Value); + /// `ret_ptr` indicates whether the return type (which is also the type `dst` points to) + /// is a pointer or the same type as `src`. fn atomic_rmw( &mut self, op: AtomicRmwBinOp, dst: Self::Value, src: Self::Value, order: AtomicOrdering, + ret_ptr: bool, ) -> Self::Value; fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope); fn set_invariant_load(&mut self, load: Self::Value); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 6e5fe3823ab51..4441dd6ebd66a 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -652,16 +652,16 @@ pub(crate) fn check_intrinsic_type( sym::atomic_store => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit), sym::atomic_xchg - | sym::atomic_xadd - | sym::atomic_xsub - | sym::atomic_and - | sym::atomic_nand - | sym::atomic_or - | sym::atomic_xor | sym::atomic_max | sym::atomic_min | sym::atomic_umax | sym::atomic_umin => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), + sym::atomic_xadd + | sym::atomic_xsub + | sym::atomic_and + | sym::atomic_nand + | sym::atomic_or + | sym::atomic_xor => (2, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(1)], param(0)), sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit), other => { diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 106cc725fee2c..9bf695e30258a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -150,69 +150,63 @@ pub unsafe fn atomic_xchg(dst: *mut T, src: /// Adds to the current value, returning the previous value. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. +/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method. For example, [`AtomicIsize::fetch_add`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_xadd(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_xadd(dst: *mut T, src: U) -> T; /// Subtract from the current value, returning the previous value. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. +/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method. For example, [`AtomicIsize::fetch_sub`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_xsub(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_xsub(dst: *mut T, src: U) -> T; /// Bitwise and with the current value, returning the previous value. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. +/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method. For example, [`AtomicBool::fetch_and`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_and(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_and(dst: *mut T, src: U) -> T; /// Bitwise nand with the current value, returning the previous value. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. +/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method. For example, [`AtomicBool::fetch_nand`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_nand(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_nand(dst: *mut T, src: U) -> T; /// Bitwise or with the current value, returning the previous value. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. +/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method. For example, [`AtomicBool::fetch_or`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_or(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_or(dst: *mut T, src: U) -> T; /// Bitwise xor with the current value, returning the previous value. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. +/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method. For example, [`AtomicBool::fetch_xor`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_xor(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_xor(dst: *mut T, src: U) -> T; /// Maximum with the current value using a signed comparison. /// `T` must be a signed integer type. diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 546f3d91a8099..bf07b18f3e739 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -2291,7 +2291,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_add(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } + unsafe { atomic_add(self.p.get(), val, order).cast() } } /// Offsets the pointer's address by subtracting `val` *bytes*, returning the @@ -2316,9 +2316,10 @@ impl AtomicPtr { /// #![feature(strict_provenance_atomic_ptr)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// - /// let atom = AtomicPtr::::new(core::ptr::without_provenance_mut(1)); - /// assert_eq!(atom.fetch_byte_sub(1, Ordering::Relaxed).addr(), 1); - /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 0); + /// let mut arr = [0i64, 1]; + /// let atom = AtomicPtr::::new(&raw mut arr[1]); + /// assert_eq!(atom.fetch_byte_sub(8, Ordering::Relaxed).addr(), (&raw const arr[1]).addr()); + /// assert_eq!(atom.load(Ordering::Relaxed).addr(), (&raw const arr[0]).addr()); /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] @@ -2326,7 +2327,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_sub(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } + unsafe { atomic_sub(self.p.get(), val, order).cast() } } /// Performs a bitwise "or" operation on the address of the current pointer, @@ -2377,7 +2378,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_or(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } + unsafe { atomic_or(self.p.get(), val, order).cast() } } /// Performs a bitwise "and" operation on the address of the current @@ -2427,7 +2428,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_and(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } + unsafe { atomic_and(self.p.get(), val, order).cast() } } /// Performs a bitwise "xor" operation on the address of the current @@ -2475,7 +2476,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_xor(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } + unsafe { atomic_xor(self.p.get(), val, order).cast() } } /// Returns a mutable pointer to the underlying pointer. @@ -3975,15 +3976,15 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { +unsafe fn atomic_add(dst: *mut T, val: U, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_add`. unsafe { match order { - Relaxed => intrinsics::atomic_xadd::(dst, val), - Acquire => intrinsics::atomic_xadd::(dst, val), - Release => intrinsics::atomic_xadd::(dst, val), - AcqRel => intrinsics::atomic_xadd::(dst, val), - SeqCst => intrinsics::atomic_xadd::(dst, val), + Relaxed => intrinsics::atomic_xadd::(dst, val), + Acquire => intrinsics::atomic_xadd::(dst, val), + Release => intrinsics::atomic_xadd::(dst, val), + AcqRel => intrinsics::atomic_xadd::(dst, val), + SeqCst => intrinsics::atomic_xadd::(dst, val), } } } @@ -3992,15 +3993,15 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { +unsafe fn atomic_sub(dst: *mut T, val: U, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_sub`. unsafe { match order { - Relaxed => intrinsics::atomic_xsub::(dst, val), - Acquire => intrinsics::atomic_xsub::(dst, val), - Release => intrinsics::atomic_xsub::(dst, val), - AcqRel => intrinsics::atomic_xsub::(dst, val), - SeqCst => intrinsics::atomic_xsub::(dst, val), + Relaxed => intrinsics::atomic_xsub::(dst, val), + Acquire => intrinsics::atomic_xsub::(dst, val), + Release => intrinsics::atomic_xsub::(dst, val), + AcqRel => intrinsics::atomic_xsub::(dst, val), + SeqCst => intrinsics::atomic_xsub::(dst, val), } } } @@ -4141,15 +4142,15 @@ unsafe fn atomic_compare_exchange_weak( #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { +unsafe fn atomic_and(dst: *mut T, val: U, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_and` unsafe { match order { - Relaxed => intrinsics::atomic_and::(dst, val), - Acquire => intrinsics::atomic_and::(dst, val), - Release => intrinsics::atomic_and::(dst, val), - AcqRel => intrinsics::atomic_and::(dst, val), - SeqCst => intrinsics::atomic_and::(dst, val), + Relaxed => intrinsics::atomic_and::(dst, val), + Acquire => intrinsics::atomic_and::(dst, val), + Release => intrinsics::atomic_and::(dst, val), + AcqRel => intrinsics::atomic_and::(dst, val), + SeqCst => intrinsics::atomic_and::(dst, val), } } } @@ -4157,15 +4158,15 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { +unsafe fn atomic_nand(dst: *mut T, val: U, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_nand` unsafe { match order { - Relaxed => intrinsics::atomic_nand::(dst, val), - Acquire => intrinsics::atomic_nand::(dst, val), - Release => intrinsics::atomic_nand::(dst, val), - AcqRel => intrinsics::atomic_nand::(dst, val), - SeqCst => intrinsics::atomic_nand::(dst, val), + Relaxed => intrinsics::atomic_nand::(dst, val), + Acquire => intrinsics::atomic_nand::(dst, val), + Release => intrinsics::atomic_nand::(dst, val), + AcqRel => intrinsics::atomic_nand::(dst, val), + SeqCst => intrinsics::atomic_nand::(dst, val), } } } @@ -4173,15 +4174,15 @@ unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { +unsafe fn atomic_or(dst: *mut T, val: U, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_or` unsafe { match order { - SeqCst => intrinsics::atomic_or::(dst, val), - Acquire => intrinsics::atomic_or::(dst, val), - Release => intrinsics::atomic_or::(dst, val), - AcqRel => intrinsics::atomic_or::(dst, val), - Relaxed => intrinsics::atomic_or::(dst, val), + SeqCst => intrinsics::atomic_or::(dst, val), + Acquire => intrinsics::atomic_or::(dst, val), + Release => intrinsics::atomic_or::(dst, val), + AcqRel => intrinsics::atomic_or::(dst, val), + Relaxed => intrinsics::atomic_or::(dst, val), } } } @@ -4189,15 +4190,15 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { +unsafe fn atomic_xor(dst: *mut T, val: U, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_xor` unsafe { match order { - SeqCst => intrinsics::atomic_xor::(dst, val), - Acquire => intrinsics::atomic_xor::(dst, val), - Release => intrinsics::atomic_xor::(dst, val), - AcqRel => intrinsics::atomic_xor::(dst, val), - Relaxed => intrinsics::atomic_xor::(dst, val), + SeqCst => intrinsics::atomic_xor::(dst, val), + Acquire => intrinsics::atomic_xor::(dst, val), + Release => intrinsics::atomic_xor::(dst, val), + AcqRel => intrinsics::atomic_xor::(dst, val), + Relaxed => intrinsics::atomic_xor::(dst, val), } } } diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index 0a59a707a101c..341a00a30aec3 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -105,27 +105,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "or" => { - let ord = get_ord_at(1); + let ord = get_ord_at(2); this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord))?; } "xor" => { - let ord = get_ord_at(1); + let ord = get_ord_at(2); this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord))?; } "and" => { - let ord = get_ord_at(1); + let ord = get_ord_at(2); this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord))?; } "nand" => { - let ord = get_ord_at(1); + let ord = get_ord_at(2); this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord))?; } "xadd" => { - let ord = get_ord_at(1); + let ord = get_ord_at(2); this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord))?; } "xsub" => { - let ord = get_ord_at(1); + let ord = get_ord_at(2); this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord))?; } "min" => { @@ -231,15 +231,14 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let place = this.deref_pointer(place)?; let rhs = this.read_immediate(rhs)?; - if !place.layout.ty.is_integral() && !place.layout.ty.is_raw_ptr() { + if !(place.layout.ty.is_integral() || place.layout.ty.is_raw_ptr()) + || !(rhs.layout.ty.is_integral() || rhs.layout.ty.is_raw_ptr()) + { span_bug!( this.cur_span(), "atomic arithmetic operations only work on integer and raw pointer types", ); } - if rhs.layout.ty != place.layout.ty { - span_bug!(this.cur_span(), "atomic arithmetic operation type mismatch"); - } let old = match atomic_op { AtomicOp::Min => diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 73d671121f653..3c3f2c2853588 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -50,17 +50,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Some more operations are possible with atomics. - // The return value always has the provenance of the *left* operand. + // The RHS must be `usize`. Add | Sub | BitOr | BitAnd | BitXor => { assert!(left.layout.ty.is_raw_ptr()); - assert!(right.layout.ty.is_raw_ptr()); + assert_eq!(right.layout.ty, this.tcx.types.usize); let ptr = left.to_scalar().to_pointer(this)?; // We do the actual operation with usize-typed scalars. let left = ImmTy::from_uint(ptr.addr().bytes(), this.machine.layouts.usize); - let right = ImmTy::from_uint( - right.to_scalar().to_target_usize(this)?, - this.machine.layouts.usize, - ); let result = this.binary_op(bin_op, &left, &right)?; // Construct a new pointer with the provenance of `ptr` (the LHS). let result_ptr = Pointer::new( diff --git a/tests/codegen-llvm/atomicptr.rs b/tests/codegen-llvm/atomicptr.rs index 4819af40ca2d2..ce6c4aa0d2b8e 100644 --- a/tests/codegen-llvm/atomicptr.rs +++ b/tests/codegen-llvm/atomicptr.rs @@ -1,5 +1,5 @@ // LLVM does not support some atomic RMW operations on pointers, so inside codegen we lower those -// to integer atomics, surrounded by casts to and from integer type. +// to integer atomics, followed by an inttoptr cast. // This test ensures that we do the round-trip correctly for AtomicPtr::fetch_byte_add, and also // ensures that we do not have such a round-trip for AtomicPtr::swap, because LLVM supports pointer // arguments to `atomicrmw xchg`. @@ -20,8 +20,8 @@ pub fn helper(_: usize) {} // CHECK-LABEL: @atomicptr_fetch_byte_add #[no_mangle] pub fn atomicptr_fetch_byte_add(a: &AtomicPtr, v: usize) -> *mut u8 { - // CHECK: %[[INTPTR:.*]] = ptrtoint ptr %{{.*}} to [[USIZE]] - // CHECK-NEXT: %[[RET:.*]] = atomicrmw add ptr %{{.*}}, [[USIZE]] %[[INTPTR]] + // CHECK: llvm.lifetime.start + // CHECK-NEXT: %[[RET:.*]] = atomicrmw add ptr %{{.*}}, [[USIZE]] %v // CHECK-NEXT: inttoptr [[USIZE]] %[[RET]] to ptr a.fetch_byte_add(v, Relaxed) } diff --git a/tests/run-make/atomic-lock-free/atomic_lock_free.rs b/tests/run-make/atomic-lock-free/atomic_lock_free.rs index f5c3b360ee815..92ffd111ce8b7 100644 --- a/tests/run-make/atomic-lock-free/atomic_lock_free.rs +++ b/tests/run-make/atomic-lock-free/atomic_lock_free.rs @@ -14,7 +14,7 @@ pub enum AtomicOrdering { } #[rustc_intrinsic] -unsafe fn atomic_xadd(dst: *mut T, src: T) -> T; +unsafe fn atomic_xadd(dst: *mut T, src: U) -> T; #[lang = "pointee_sized"] pub trait PointeeSized {} @@ -35,51 +35,62 @@ impl Copy for *mut T {} impl ConstParamTy for AtomicOrdering {} #[cfg(target_has_atomic = "8")] +#[unsafe(no_mangle)] // let's make sure we actually generate a symbol to check pub unsafe fn atomic_u8(x: *mut u8) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1u8); } #[cfg(target_has_atomic = "8")] +#[unsafe(no_mangle)] pub unsafe fn atomic_i8(x: *mut i8) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1i8); } #[cfg(target_has_atomic = "16")] +#[unsafe(no_mangle)] pub unsafe fn atomic_u16(x: *mut u16) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1u16); } #[cfg(target_has_atomic = "16")] +#[unsafe(no_mangle)] pub unsafe fn atomic_i16(x: *mut i16) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1i16); } #[cfg(target_has_atomic = "32")] +#[unsafe(no_mangle)] pub unsafe fn atomic_u32(x: *mut u32) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1u32); } #[cfg(target_has_atomic = "32")] +#[unsafe(no_mangle)] pub unsafe fn atomic_i32(x: *mut i32) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1i32); } #[cfg(target_has_atomic = "64")] +#[unsafe(no_mangle)] pub unsafe fn atomic_u64(x: *mut u64) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1u64); } #[cfg(target_has_atomic = "64")] +#[unsafe(no_mangle)] pub unsafe fn atomic_i64(x: *mut i64) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1i64); } #[cfg(target_has_atomic = "128")] +#[unsafe(no_mangle)] pub unsafe fn atomic_u128(x: *mut u128) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1u128); } #[cfg(target_has_atomic = "128")] +#[unsafe(no_mangle)] pub unsafe fn atomic_i128(x: *mut i128) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1i128); } #[cfg(target_has_atomic = "ptr")] +#[unsafe(no_mangle)] pub unsafe fn atomic_usize(x: *mut usize) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1usize); } #[cfg(target_has_atomic = "ptr")] +#[unsafe(no_mangle)] pub unsafe fn atomic_isize(x: *mut isize) { - atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, _, { AtomicOrdering::SeqCst }>(x, 1isize); } diff --git a/tests/ui/intrinsics/intrinsic-atomics.rs b/tests/ui/intrinsics/intrinsic-atomics.rs index 2275aafff8330..c19948137db01 100644 --- a/tests/ui/intrinsics/intrinsic-atomics.rs +++ b/tests/ui/intrinsics/intrinsic-atomics.rs @@ -33,14 +33,14 @@ pub fn main() { assert_eq!(rusti::atomic_xchg::<_, { Release }>(&mut *x, 0), 1); assert_eq!(*x, 0); - assert_eq!(rusti::atomic_xadd::<_, { SeqCst }>(&mut *x, 1), 0); - assert_eq!(rusti::atomic_xadd::<_, { Acquire }>(&mut *x, 1), 1); - assert_eq!(rusti::atomic_xadd::<_, { Release }>(&mut *x, 1), 2); + assert_eq!(rusti::atomic_xadd::<_, _, { SeqCst }>(&mut *x, 1), 0); + assert_eq!(rusti::atomic_xadd::<_, _, { Acquire }>(&mut *x, 1), 1); + assert_eq!(rusti::atomic_xadd::<_, _, { Release }>(&mut *x, 1), 2); assert_eq!(*x, 3); - assert_eq!(rusti::atomic_xsub::<_, { SeqCst }>(&mut *x, 1), 3); - assert_eq!(rusti::atomic_xsub::<_, { Acquire }>(&mut *x, 1), 2); - assert_eq!(rusti::atomic_xsub::<_, { Release }>(&mut *x, 1), 1); + assert_eq!(rusti::atomic_xsub::<_, _, { SeqCst }>(&mut *x, 1), 3); + assert_eq!(rusti::atomic_xsub::<_, _, { Acquire }>(&mut *x, 1), 2); + assert_eq!(rusti::atomic_xsub::<_, _, { Release }>(&mut *x, 1), 1); assert_eq!(*x, 0); loop { diff --git a/tests/ui/intrinsics/non-integer-atomic.rs b/tests/ui/intrinsics/non-integer-atomic.rs index 853c163710fcf..30f713f12412d 100644 --- a/tests/ui/intrinsics/non-integer-atomic.rs +++ b/tests/ui/intrinsics/non-integer-atomic.rs @@ -13,80 +13,80 @@ pub type Quux = [u8; 100]; pub unsafe fn test_bool_load(p: &mut bool, v: bool) { intrinsics::atomic_load::<_, { SeqCst }>(p); - //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `bool` + //~^ ERROR `atomic_load` intrinsic: expected basic integer or pointer type, found `bool` } pub unsafe fn test_bool_store(p: &mut bool, v: bool) { intrinsics::atomic_store::<_, { SeqCst }>(p, v); - //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `bool` + //~^ ERROR `atomic_store` intrinsic: expected basic integer or pointer type, found `bool` } pub unsafe fn test_bool_xchg(p: &mut bool, v: bool) { intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `bool` + //~^ ERROR `atomic_xchg` intrinsic: expected basic integer or pointer type, found `bool` } pub unsafe fn test_bool_cxchg(p: &mut bool, v: bool) { intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); - //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `bool` + //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `bool` } pub unsafe fn test_Foo_load(p: &mut Foo, v: Foo) { intrinsics::atomic_load::<_, { SeqCst }>(p); - //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `Foo` + //~^ ERROR `atomic_load` intrinsic: expected basic integer or pointer type, found `Foo` } pub unsafe fn test_Foo_store(p: &mut Foo, v: Foo) { intrinsics::atomic_store::<_, { SeqCst }>(p, v); - //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `Foo` + //~^ ERROR `atomic_store` intrinsic: expected basic integer or pointer type, found `Foo` } pub unsafe fn test_Foo_xchg(p: &mut Foo, v: Foo) { intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `Foo` + //~^ ERROR `atomic_xchg` intrinsic: expected basic integer or pointer type, found `Foo` } pub unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) { intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); - //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `Foo` + //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `Foo` } pub unsafe fn test_Bar_load(p: &mut Bar, v: Bar) { intrinsics::atomic_load::<_, { SeqCst }>(p); - //~^ ERROR expected basic integer type, found `&dyn Fn()` + //~^ ERROR expected basic integer or pointer type, found `&dyn Fn()` } pub unsafe fn test_Bar_store(p: &mut Bar, v: Bar) { intrinsics::atomic_store::<_, { SeqCst }>(p, v); - //~^ ERROR expected basic integer type, found `&dyn Fn()` + //~^ ERROR expected basic integer or pointer type, found `&dyn Fn()` } pub unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) { intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - //~^ ERROR expected basic integer type, found `&dyn Fn()` + //~^ ERROR expected basic integer or pointer type, found `&dyn Fn()` } pub unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) { intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); - //~^ ERROR expected basic integer type, found `&dyn Fn()` + //~^ ERROR expected basic integer or pointer type, found `&dyn Fn()` } pub unsafe fn test_Quux_load(p: &mut Quux, v: Quux) { intrinsics::atomic_load::<_, { SeqCst }>(p); - //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `[u8; 100]` + //~^ ERROR `atomic_load` intrinsic: expected basic integer or pointer type, found `[u8; 100]` } pub unsafe fn test_Quux_store(p: &mut Quux, v: Quux) { intrinsics::atomic_store::<_, { SeqCst }>(p, v); - //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `[u8; 100]` + //~^ ERROR `atomic_store` intrinsic: expected basic integer or pointer type, found `[u8; 100]` } pub unsafe fn test_Quux_xchg(p: &mut Quux, v: Quux) { intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `[u8; 100]` + //~^ ERROR `atomic_xchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` } pub unsafe fn test_Quux_cxchg(p: &mut Quux, v: Quux) { intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); - //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `[u8; 100]` + //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` } diff --git a/tests/ui/intrinsics/non-integer-atomic.stderr b/tests/ui/intrinsics/non-integer-atomic.stderr index e539d99b8aebd..b96ee7ba84688 100644 --- a/tests/ui/intrinsics/non-integer-atomic.stderr +++ b/tests/ui/intrinsics/non-integer-atomic.stderr @@ -1,94 +1,94 @@ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `bool` --> $DIR/non-integer-atomic.rs:15:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `bool` --> $DIR/non-integer-atomic.rs:20:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `bool` --> $DIR/non-integer-atomic.rs:25:5 | LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `bool` --> $DIR/non-integer-atomic.rs:30:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `Foo` --> $DIR/non-integer-atomic.rs:35:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `Foo` --> $DIR/non-integer-atomic.rs:40:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `Foo` --> $DIR/non-integer-atomic.rs:45:5 | LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `Foo` --> $DIR/non-integer-atomic.rs:50:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:55:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:60:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:65:5 | LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:70:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:75:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:80:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:85:5 | LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:90:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); From 6bf3cbe39e09f4d9187a0b1f6a7bd45101f7aad8 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 28 Jul 2025 00:01:28 +0300 Subject: [PATCH 03/23] In rustc_pattern_analysis, put `true` witnesses before `false` witnesses In rustc it doesn't really matter what the order of the witnesses is, but I'm planning to use the witnesses for implementing the "add missing match arms" assist in rust-analyzer, and there `true` before `false` is the natural order (like `Some` before `None`), and also what the current assist does. The current order doesn't seem to be intentional; the code was created when bool ctors became their own thing, not just int ctors, but for integer, 0 before 1 is indeed the natural order. --- compiler/rustc_pattern_analysis/src/constructor.rs | 10 +++++----- .../rustc_pattern_analysis/tests/exhaustiveness.rs | 3 +++ .../deref-patterns/usefulness/non-exhaustive.rs | 2 +- .../deref-patterns/usefulness/non-exhaustive.stderr | 6 +++--- tests/ui/pattern/usefulness/unions.rs | 2 +- tests/ui/pattern/usefulness/unions.stderr | 4 ++-- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 9a9e0db964c96..12f653a13371d 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -1130,16 +1130,16 @@ impl ConstructorSet { seen_false = true; } } - if seen_false { - present.push(Bool(false)); - } else { - missing.push(Bool(false)); - } if seen_true { present.push(Bool(true)); } else { missing.push(Bool(true)); } + if seen_false { + present.push(Bool(false)); + } else { + missing.push(Bool(false)); + } } ConstructorSet::Integers { range_1, range_2 } => { let seen_ranges: Vec<_> = diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs index 14ca0d057f06e..4ad64f81560af 100644 --- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs +++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs @@ -176,6 +176,9 @@ fn test_witnesses() { ), vec!["Enum::Variant1(_)", "Enum::Variant2(_)", "_"], ); + + // Assert we put `true` before `false`. + assert_witnesses(AllOfThem, Ty::Bool, Vec::new(), vec!["true", "false"]); } #[test] diff --git a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs index 704cae8bdbc4b..bab6308223e50 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs +++ b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs @@ -15,7 +15,7 @@ fn main() { } match Box::new((true, Box::new(false))) { - //~^ ERROR non-exhaustive patterns: `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered + //~^ ERROR non-exhaustive patterns: `deref!((true, deref!(true)))` and `deref!((false, deref!(false)))` not covered (true, false) => {} (false, true) => {} } diff --git a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr index 55fa84bafde26..a1abd5f0e3f4b 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr +++ b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr @@ -28,11 +28,11 @@ LL ~ true => {}, LL + deref!(deref!(false)) => todo!() | -error[E0004]: non-exhaustive patterns: `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered +error[E0004]: non-exhaustive patterns: `deref!((true, deref!(true)))` and `deref!((false, deref!(false)))` not covered --> $DIR/non-exhaustive.rs:17:11 | LL | match Box::new((true, Box::new(false))) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `deref!((true, deref!(true)))` and `deref!((false, deref!(false)))` not covered | note: `Box<(bool, Box)>` defined here --> $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -40,7 +40,7 @@ note: `Box<(bool, Box)>` defined here help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ (false, true) => {}, -LL + deref!((false, deref!(false))) | deref!((true, deref!(true))) => todo!() +LL + deref!((true, deref!(true))) | deref!((false, deref!(false))) => todo!() | error[E0004]: non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered diff --git a/tests/ui/pattern/usefulness/unions.rs b/tests/ui/pattern/usefulness/unions.rs index 80a7f36a09a26..3de79c6f84953 100644 --- a/tests/ui/pattern/usefulness/unions.rs +++ b/tests/ui/pattern/usefulness/unions.rs @@ -26,7 +26,7 @@ fn main() { } // Our approach can report duplicate witnesses sometimes. match (x, true) { - //~^ ERROR non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered + //~^ ERROR non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: true }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered (U8AsBool { b: true }, true) => {} (U8AsBool { b: false }, true) => {} (U8AsBool { n: 1.. }, true) => {} diff --git a/tests/ui/pattern/usefulness/unions.stderr b/tests/ui/pattern/usefulness/unions.stderr index 4b397dc25db8b..98fb6a33ae41a 100644 --- a/tests/ui/pattern/usefulness/unions.stderr +++ b/tests/ui/pattern/usefulness/unions.stderr @@ -16,11 +16,11 @@ LL ~ U8AsBool { n: 1.. } => {}, LL + U8AsBool { n: 0_u8 } | U8AsBool { b: false } => todo!() | -error[E0004]: non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered +error[E0004]: non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: true }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered --> $DIR/unions.rs:28:15 | LL | match (x, true) { - | ^^^^^^^^^ patterns `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered + | ^^^^^^^^^ patterns `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: true }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered | = note: the matched value is of type `(U8AsBool, bool)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms From fc463540deaeaac68d55b17c18cc2ca0d4a2343b Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 1 Aug 2025 10:39:25 +0200 Subject: [PATCH 04/23] more strongly dissuade use of `skip_binder` --- compiler/rustc_type_ir/src/binder.rs | 60 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index a7b915c48455b..09ef798211f0b 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -15,13 +15,12 @@ use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use crate::{self as ty, Interner}; -/// Binder is a binder for higher-ranked lifetimes or types. It is part of the +/// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` -/// (which would be represented by the type `PolyTraitRef == -/// Binder`). Note that when we instantiate, -/// erase, or otherwise "discharge" these bound vars, we change the -/// type from `Binder` to just `T` (see -/// e.g., `liberate_late_bound_regions`). +/// (which would be represented by the type `PolyTraitRef == Binder`). +/// +/// See +/// for more details. /// /// `Decodable` and `Encodable` are implemented for `Binder` using the `impl_binder_encode_decode!` macro. #[derive_where(Clone; I: Interner, T: Clone)] @@ -154,22 +153,19 @@ impl> TypeSuperVisitable for Binder { } impl Binder { - /// Skips the binder and returns the "bound" value. This is a - /// risky thing to do because it's easy to get confused about - /// De Bruijn indices and the like. It is usually better to - /// discharge the binder using `no_bound_vars` or - /// `instantiate_bound_regions` or something like - /// that. `skip_binder` is only valid when you are either - /// extracting data that has nothing to do with bound vars, you - /// are doing some sort of test that does not involve bound - /// regions, or you are being very careful about your depth - /// accounting. + /// Returns the value contained inside of this `for<'a>`. Accessing generic args + /// in the returned value is generally incorrect. + /// + /// Please read + /// before using this function. It is usually better to discharge the binder using + /// `no_bound_vars` or `instantiate_bound_regions` or something like that. /// - /// Some examples where `skip_binder` is reasonable: + /// `skip_binder` is only valid when you are either extracting data that does not reference + /// any generic arguments, e.g. a `DefId`, or when you're making sure you only pass the + /// value to things which can handle escaping bound vars. /// - /// - extracting the `DefId` from a PolyTraitRef; - /// - comparing the self type of a PolyTraitRef to see if it is equal to - /// a type parameter `X`, since the type `X` does not reference any regions + /// See existing uses of `.skip_binder()` in `rustc_trait_selection::traits::select` + /// or `rustc_next_trait_solver` for examples. pub fn skip_binder(self) -> T { self.value } @@ -336,12 +332,11 @@ impl TypeVisitor for ValidateBoundVars { } } -/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo(T)` +/// Similar to [`Binder`] except that it tracks early bound generics, i.e. `struct Foo(T)` /// needs `T` instantiated immediately. This type primarily exists to avoid forgetting to call /// `instantiate`. /// -/// If you don't have anything to `instantiate`, you may be looking for -/// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder). +/// See for more details. #[derive_where(Clone; I: Interner, T: Clone)] #[derive_where(Copy; I: Interner, T: Copy)] #[derive_where(PartialEq; I: Interner, T: PartialEq)] @@ -404,17 +399,22 @@ impl EarlyBinder { EarlyBinder { value, _tcx: PhantomData } } - /// Skips the binder and returns the "bound" value. - /// This can be used to extract data that does not depend on generic parameters - /// (e.g., getting the `DefId` of the inner value or getting the number of - /// arguments of an `FnSig`). Otherwise, consider using - /// [`instantiate_identity`](EarlyBinder::instantiate_identity). + /// Skips the binder and returns the "bound" value. Accessing generic args + /// in the returned value is generally incorrect. + /// + /// Please read + /// before using this function. + /// + /// Only use this to extract data that does not depend on generic parameters, e.g. + /// to get the `DefId` of the inner value or the number of arguments ofan `FnSig`, + /// or while making sure to only pass the value to functions which are explicitly + /// set up to handle these uninstantiated generic parameters. /// /// To skip the binder on `x: &EarlyBinder` to obtain `&T`, leverage /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`. /// - /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is - /// the analogous operation on [`super::Binder`]. + /// See also [`Binder::skip_binder`](Binder::skip_binder), which is + /// the analogous operation on [`Binder`]. pub fn skip_binder(self) -> T { self.value } From cdb299c0d8463d7e66b680e93c8d0d7258fc7643 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 6 Aug 2025 08:57:14 +0000 Subject: [PATCH 05/23] Enable f16 and f128 on targets that were fixed in LLVM21 LLVM21 fixed the new float types on a number of targets: * SystemZ gained f16 support https://github.com/llvm/llvm-project/pull/109164 * Hexagon now uses soft f16 to avoid recursion bugs https://github.com/llvm/llvm-project/pull/130977 * Mips now correctly handles f128 (actually since LLVM20) https://github.com/llvm/llvm-project/pull/117525 * f128 is now correctly aligned when passing the stack on x86 https://github.com/llvm/llvm-project/pull/138092 Thus, enable the types on relevant targets for LLVM > 21.0.0. NVPTX also gained handling of f128 as a storage type, but it lacks support for basic math operations so is still disabled here. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 24 +++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 53899da183a3a..d66a9dd614cff 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -371,24 +371,25 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { let target_abi = sess.target.options.abi.as_ref(); let target_pointer_width = sess.target.pointer_width; let version = get_version(); + let lt_20_1_1 = version < (20, 1, 1); + let lt_21_0_0 = version < (21, 0, 0); cfg.has_reliable_f16 = match (target_arch, target_os) { - // Selection failure - ("s390x", _) => false, - // LLVM crash without neon (now fixed) + // LLVM crash without neon (fixed in llvm20) ("aarch64", _) - if !cfg.target_features.iter().any(|f| f.as_str() == "neon") - && version < (20, 1, 1) => + if !cfg.target_features.iter().any(|f| f.as_str() == "neon") && lt_20_1_1 => { false } // Unsupported ("arm64ec", _) => false, + // Selection failure (fixed in llvm21) + ("s390x", _) if lt_21_0_0 => false, // MinGW ABI bugs ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion ("csky", _) => false, - ("hexagon", _) => false, + ("hexagon", _) if lt_21_0_0 => false, // (fixed in llvm21) ("powerpc" | "powerpc64", _) => false, ("sparc" | "sparc64", _) => false, ("wasm32" | "wasm64", _) => false, @@ -401,9 +402,10 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { cfg.has_reliable_f128 = match (target_arch, target_os) { // Unsupported ("arm64ec", _) => false, - // Selection bug - ("mips64" | "mips64r6", _) => false, - // Selection bug + // Selection bug (fixed in llvm20) + ("mips64" | "mips64r6", _) if lt_20_1_1 => false, + // Selection bug . This issue is closed + // but basic math still does not work. ("nvptx64", _) => false, // Unsupported https://github.com/llvm/llvm-project/issues/121122 ("amdgpu", _) => false, @@ -413,8 +415,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { // ABI unsupported ("sparc", _) => false, // Stack alignment bug . NB: tests may - // not fail if our compiler-builtins is linked. - ("x86", _) => false, + // not fail if our compiler-builtins is linked. (fixed in llvm21) + ("x86", _) if lt_21_0_0 => false, // MinGW ABI bugs ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // There are no known problems on other platforms, so the only requirement is that symbols From 99196657fcb5c1e20c13e76166c7f52d35584e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 16 Jul 2025 19:45:07 +0000 Subject: [PATCH 06/23] Use `tcx.short_string()` in more diagnostics `TyCtxt::short_string` ensures that user visible type paths aren't overwhelming on the terminal output, and properly saves the long name to disk as a side-channel. We already use these throughout the compiler and have been using them as needed when users find cases where the output is verbose. This is a proactive search of some cases to use `short_string`. We add support for shortening the path of "trait path only". Every manual use of `short_string` is a bright marker that that error should be using structured diagnostics instead (as they have proper handling of long types without the maintainer having to think abou tthem). When we don't actually print out a shortened type we don't need the "use `--verbose`" note. On E0599 show type identity to avoid expanding the receiver's generic parameters. Unify wording on `long_ty_path` everywhere. --- compiler/rustc_errors/src/diagnostic.rs | 5 + .../src/hir_ty_lowering/mod.rs | 5 +- compiler/rustc_hir_typeck/messages.ftl | 4 +- compiler/rustc_hir_typeck/src/errors.rs | 8 +- .../rustc_hir_typeck/src/method/suggest.rs | 125 ++++++++---------- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_trait_selection/messages.ftl | 2 - .../src/error_reporting/infer/mod.rs | 15 ++- .../error_reporting/infer/need_type_info.rs | 32 ++--- .../src/error_reporting/traits/ambiguity.rs | 57 ++++---- .../traits/fulfillment_errors.rs | 119 +++++++++++------ .../traits/on_unimplemented.rs | 4 +- .../src/error_reporting/traits/suggestions.rs | 67 ++++++---- compiler/rustc_trait_selection/src/errors.rs | 11 -- .../rustc_confusables_std_cases.stderr | 6 +- tests/ui/codegen/overflow-during-mono.rs | 3 +- tests/ui/codegen/overflow-during-mono.stderr | 10 +- .../issue-18343.stderr | 2 +- .../issue-2392.stderr | 12 +- ...y_owner_parent_found_in_diagnostics.stderr | 2 +- .../dropck_no_diverge_on_nonregular_1.rs | 1 + .../dropck_no_diverge_on_nonregular_1.stderr | 6 +- .../never-type-fallback-breaking.e2024.stderr | 8 +- tests/ui/error-codes/E0275.rs | 1 + tests/ui/error-codes/E0275.stderr | 8 +- .../trait-bounds/hrtb-doesnt-borrow-self-2.rs | 2 + .../hrtb-doesnt-borrow-self-2.stderr | 16 ++- .../auto-trait-leakage/auto-trait-leak2.rs | 1 + .../auto-trait-leak2.stderr | 16 +-- ...et-binding-without-sufficient-type-info.rs | 1 + ...inding-without-sufficient-type-info.stderr | 6 +- .../interior-mutability.rs | 1 + .../interior-mutability.stderr | 4 +- tests/ui/issues/issue-41880.stderr | 2 +- .../methods/call_method_unknown_referent.rs | 2 +- .../call_method_unknown_referent.stderr | 2 +- tests/ui/methods/inherent-bound-in-probe.rs | 1 + .../ui/methods/inherent-bound-in-probe.stderr | 12 +- ...ethod-not-found-generic-arg-elision.stderr | 8 +- .../methods/probe-error-on-infinite-deref.rs | 1 + .../probe-error-on-infinite-deref.stderr | 8 +- tests/ui/methods/untrimmed-path-type.stderr | 2 +- .../defaulted-never-note.fallback.stderr | 2 +- tests/ui/never_type/defaulted-never-note.rs | 2 +- ...diverging-fallback-no-leak.fallback.stderr | 2 +- tests/ui/recursion/issue-23122-2.rs | 1 + tests/ui/recursion/issue-23122-2.stderr | 8 +- ...ssue-38591-non-regular-dropck-recursion.rs | 1 + ...-38591-non-regular-dropck-recursion.stderr | 6 +- tests/ui/recursion/issue-83150.rs | 2 +- tests/ui/recursion/issue-83150.stderr | 6 +- ...itrary_self_type_infinite_recursion.stderr | 2 +- ..._types_not_allow_call_with_no_deref.stderr | 4 +- ...arbitrary_self_types_pin_needing_borrow.rs | 2 +- ...trary_self_types_pin_needing_borrow.stderr | 2 +- tests/ui/simd/libm_no_std_cant_float.stderr | 12 +- tests/ui/suggestions/enum-method-probe.fixed | 12 +- tests/ui/suggestions/enum-method-probe.rs | 12 +- tests/ui/suggestions/enum-method-probe.stderr | 12 +- tests/ui/suggestions/field-has-method.rs | 2 +- tests/ui/suggestions/field-has-method.stderr | 2 +- tests/ui/suggestions/inner_type.fixed | 10 +- tests/ui/suggestions/inner_type.rs | 10 +- tests/ui/suggestions/inner_type.stderr | 10 +- tests/ui/suggestions/inner_type2.rs | 4 +- tests/ui/suggestions/inner_type2.stderr | 4 +- .../traits/issue-91949-hangs-on-recursion.rs | 2 +- .../issue-91949-hangs-on-recursion.stderr | 4 +- 68 files changed, 397 insertions(+), 339 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 96c7ba6ed27b9..5a5563c7bb2c8 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1382,6 +1382,11 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { &mut self.long_ty_path } + pub fn with_long_ty_path(mut self, long_ty_path: Option) -> Self { + self.long_ty_path = long_ty_path; + self + } + /// Most `emit_producing_guarantee` functions use this as a starting point. fn emit_producing_nothing(mut self) { let diag = self.take_diag(); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 7e2bfa9f920c7..1675aecd2b84f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1135,9 +1135,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } } else { + let trait_ = + tcx.short_string(bound.print_only_trait_path(), err.long_ty_path()); err.note(format!( - "associated {assoc_kind_str} `{assoc_ident}` could derive from `{}`", - bound.print_only_trait_path(), + "associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`", )); } } diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index bac4d70103c3d..1ed0756fdd6a7 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -159,7 +159,7 @@ hir_typeck_lossy_provenance_ptr2int = .suggestion = use `.addr()` to obtain the address of a pointer .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead -hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` +hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty}` hir_typeck_naked_asm_outside_naked_fn = the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` @@ -184,7 +184,7 @@ hir_typeck_never_type_fallback_flowing_into_unsafe_path = never type fallback af hir_typeck_never_type_fallback_flowing_into_unsafe_union_field = never type fallback affects this union access .help = specify the type explicitly -hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> +hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty}`{$trait_missing_method -> [true] {""} *[other] {" "}in the current scope } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index a8bb6956f1016..d15d092b7d3da 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -200,11 +200,11 @@ pub(crate) enum ExplicitDestructorCallSugg { #[derive(Diagnostic)] #[diag(hir_typeck_missing_parentheses_in_range, code = E0689)] -pub(crate) struct MissingParenthesesInRange { +pub(crate) struct MissingParenthesesInRange<'tcx> { #[primary_span] #[label(hir_typeck_missing_parentheses_in_range)] pub span: Span, - pub ty_str: String, + pub ty: Ty<'tcx>, pub method_name: String, #[subdiagnostic] pub add_missing_parentheses: Option, @@ -828,13 +828,13 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> { #[derive(Diagnostic)] #[diag(hir_typeck_no_associated_item, code = E0599)] -pub(crate) struct NoAssociatedItem { +pub(crate) struct NoAssociatedItem<'tcx> { #[primary_span] pub span: Span, pub item_kind: &'static str, pub item_ident: Ident, pub ty_prefix: Cow<'static, str>, - pub ty_str: String, + pub ty: Ty<'tcx>, pub trait_missing_method: bool, } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0c0cc752b01ae..7848d9323c513 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -376,16 +376,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> { - let mut file = None; + fn suggest_missing_writer( + &self, + rcvr_ty: Ty<'tcx>, + rcvr_expr: &hir::Expr<'tcx>, + mut long_ty_path: Option, + ) -> Diag<'_> { let mut err = struct_span_code_err!( self.dcx(), rcvr_expr.span, E0599, "cannot write into `{}`", - self.tcx.short_string(rcvr_ty, &mut file), + self.tcx.short_string(rcvr_ty, &mut long_ty_path), ); - *err.long_ty_path() = file; + *err.long_ty_path() = long_ty_path; err.span_note( rcvr_expr.span, "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method", @@ -403,7 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, self_source: SelfSource<'tcx>, method_name: Ident, - ty_str_reported: &str, + ty: Ty<'tcx>, err: &mut Diag<'_>, ) { #[derive(Debug)] @@ -478,7 +482,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If the shadowed binding has an itializer expression, - // use the initializer expression'ty to try to find the method again. + // use the initializer expression's ty to try to find the method again. // For example like: `let mut x = Vec::new();`, // `Vec::new()` is the itializer expression. if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id) @@ -566,17 +570,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut span = MultiSpan::from_span(sugg_let.span); span.push_span_label(sugg_let.span, format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here")); + + let ty = self.tcx.short_string(ty, err.long_ty_path()); span.push_span_label( self.tcx.hir_span(recv_id), - format!( - "earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`" - ), + format!("earlier `{rcvr_name}` shadowed here with type `{ty}`"), ); err.span_note( span, format!( "there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \ - that has method `{method_name}` available" + that has method `{method_name}` available" ), ); } @@ -602,15 +606,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); let mut ty_file = None; - let (ty_str, short_ty_str) = - if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { - (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string())) - } else { - ( - tcx.short_string(rcvr_ty, &mut ty_file), - with_forced_trimmed_paths!(rcvr_ty.to_string()), - ) - }; let is_method = mode == Mode::MethodCall; let unsatisfied_predicates = &no_match_data.unsatisfied_predicates; let similar_candidate = no_match_data.similar_candidate; @@ -629,15 +624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We could pass the file for long types into these two, but it isn't strictly necessary // given how targeted they are. - if let Err(guar) = self.report_failed_method_call_on_range_end( - tcx, - rcvr_ty, - source, - span, - item_ident, - &short_ty_str, - &mut ty_file, - ) { + if let Err(guar) = + self.report_failed_method_call_on_range_end(tcx, rcvr_ty, source, span, item_ident) + { return guar; } if let Err(guar) = self.report_failed_method_call_on_numerical_infer_var( @@ -647,44 +636,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, item_kind, item_ident, - &short_ty_str, &mut ty_file, ) { return guar; } span = item_ident.span; - // Don't show generic arguments when the method can't be found in any implementation (#81576). - let mut ty_str_reported = ty_str.clone(); - if let ty::Adt(_, generics) = rcvr_ty.kind() { - if generics.len() > 0 { - let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors(); - let candidate_found = autoderef.any(|(ty, _)| { - if let ty::Adt(adt_def, _) = ty.kind() { - self.tcx - .inherent_impls(adt_def.did()) - .into_iter() - .any(|def_id| self.associated_value(*def_id, item_ident).is_some()) - } else { - false - } - }); - let has_deref = autoderef.step_count() > 0; - if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() { - if let Some((path_string, _)) = ty_str.split_once('<') { - ty_str_reported = path_string.to_string(); - } - } - } - } - let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| { tcx.is_diagnostic_item(sym::write_macro, def_id) || tcx.is_diagnostic_item(sym::writeln_macro, def_id) }) && item_ident.name == sym::write_fmt; let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source { - self.suggest_missing_writer(rcvr_ty, rcvr_expr) + self.suggest_missing_writer(rcvr_ty, rcvr_expr, ty_file) } else { + // Don't show expanded generic arguments when the method can't be found in any + // implementation (#81576). + let mut ty = rcvr_ty; + if let ty::Adt(def, generics) = rcvr_ty.kind() { + if generics.len() > 0 { + let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors(); + let candidate_found = autoderef.any(|(ty, _)| { + if let ty::Adt(adt_def, _) = ty.kind() { + self.tcx + .inherent_impls(adt_def.did()) + .into_iter() + .any(|def_id| self.associated_value(*def_id, item_ident).is_some()) + } else { + false + } + }); + let has_deref = autoderef.step_count() > 0; + if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() { + ty = self.tcx.at(span).type_of(def.did()).instantiate_identity(); + } + } + } + let mut err = self.dcx().create_err(NoAssociatedItem { span, item_kind, @@ -695,16 +682,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { rcvr_ty.prefix_string(self.tcx) }, - ty_str: ty_str_reported.clone(), + ty, trait_missing_method, }); if is_method { self.suggest_use_shadowed_binding_with_method( - source, - item_ident, - &ty_str_reported, - &mut err, + source, item_ident, rcvr_ty, &mut err, ); } @@ -734,6 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err }; + if tcx.sess.source_map().is_multiline(sugg_span) { err.span_label(sugg_span.with_hi(span.lo()), ""); } @@ -750,6 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if tcx.ty_is_opaque_future(rcvr_ty) && item_ident.name == sym::poll { + let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path()); err.help(format!( "method `poll` found on `Pin<&mut {ty_str}>`, \ see documentation for `std::pin::Pin`" @@ -1339,7 +1325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let OnUnimplementedNote { message, label, notes, .. } = self .err_ctxt() - .on_unimplemented_note(trait_ref, &obligation, &mut ty_file); + .on_unimplemented_note(trait_ref, &obligation, err.long_ty_path()); (message, label, notes) }) .unwrap() @@ -1347,6 +1333,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, None, Vec::new()) }; let primary_message = primary_message.unwrap_or_else(|| { + let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path()); format!( "the {item_kind} `{item_ident}` exists for {actual_prefix} `{ty_str}`, \ but its trait bounds were not satisfied" @@ -1409,6 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut find_candidate_for_method = false; let mut label_span_not_found = |err: &mut Diag<'_>| { + let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path()); if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); let is_string_or_ref_str = match rcvr_ty.kind() { @@ -2520,8 +2508,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: SelfSource<'tcx>, span: Span, item_name: Ident, - ty_str: &str, - long_ty_path: &mut Option, ) -> Result<(), ErrorGuaranteed> { if let SelfSource::MethodCall(expr) = source { for (_, parent) in tcx.hir_parent_iter(expr.hir_id).take(5) { @@ -2583,18 +2569,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if pick.is_ok() { let range_span = parent_expr.span.with_hi(expr.span.hi()); - let mut err = self.dcx().create_err(errors::MissingParenthesesInRange { + return Err(self.dcx().emit_err(errors::MissingParenthesesInRange { span, - ty_str: ty_str.to_string(), + ty: actual, method_name: item_name.as_str().to_string(), add_missing_parentheses: Some(errors::AddMissingParenthesesInRange { func_name: item_name.name.as_str().to_string(), left: range_span.shrink_to_lo(), right: range_span.shrink_to_hi(), }), - }); - *err.long_ty_path() = long_ty_path.take(); - return Err(err.emit()); + })); } } } @@ -2610,7 +2594,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, item_kind: &str, item_name: Ident, - ty_str: &str, long_ty_path: &mut Option, ) -> Result<(), ErrorGuaranteed> { let found_candidate = all_traits(self.tcx) @@ -2643,14 +2626,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !actual.has_concrete_skeleton() && let SelfSource::MethodCall(expr) = source { + let ty_str = self.tcx.short_string(actual, long_ty_path); let mut err = struct_span_code_err!( self.dcx(), span, E0689, - "can't call {} `{}` on ambiguous numeric type `{}`", - item_kind, - item_name, - ty_str + "can't call {item_kind} `{item_name}` on ambiguous numeric type `{ty_str}`" ); *err.long_ty_path() = long_ty_path.take(); let concrete_type = if actual.is_integral() { "i32" } else { "f32" }; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b381d62be47e6..67244e767cbe8 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2987,7 +2987,7 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> { } } -#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)] pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>); impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> { diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 8232da4df43ec..fcb250250871e 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -171,8 +171,6 @@ trait_selection_fps_remove_ref = consider removing the reference trait_selection_fps_use_ref = consider using a reference trait_selection_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime -trait_selection_full_type_written = the full type name has been written to '{$path}' - trait_selection_ignored_diagnostic_option = `{$option_name}` is ignored due to previous definition of `{$option_name}` .other_label = `{$option_name}` is first declared here .label = `{$option_name}` is already declared here diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index ed8229154a9bf..1c890821b1d0a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1930,7 +1930,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, - path: &mut Option, + long_ty_path: &mut Option, ) -> Vec { let mut suggestions = Vec::new(); let span = trace.cause.span; @@ -2009,7 +2009,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) | ObligationCauseCode::BlockTailExpression(.., source)) = code && let hir::MatchSource::TryDesugar(_) = source - && let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path) + && let Some((expected_ty, found_ty)) = + self.values_str(trace.values, &trace.cause, long_ty_path) { suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), @@ -2139,11 +2140,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, values: ValuePairs<'tcx>, cause: &ObligationCause<'tcx>, - file: &mut Option, + long_ty_path: &mut Option, ) -> Option<(DiagStyledString, DiagStyledString)> { match values { ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), - ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file), + ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, long_ty_path), ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), @@ -2183,7 +2184,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn expected_found_str_term( &self, exp_found: ty::error::ExpectedFound>, - path: &mut Option, + long_ty_path: &mut Option, ) -> Option<(DiagStyledString, DiagStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { @@ -2200,11 +2201,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let exp_s = exp.content(); let fnd_s = fnd.content(); if exp_s.len() > len { - let exp_s = self.tcx.short_string(expected, path); + let exp_s = self.tcx.short_string(expected, long_ty_path); exp = DiagStyledString::highlighted(exp_s); } if fnd_s.len() > len { - let fnd_s = self.tcx.short_string(found, path); + let fnd_s = self.tcx.short_string(found, long_ty_path); fnd = DiagStyledString::highlighted(fnd_s); } (exp, fnd) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 966f117a1bf91..ec2287ed5161d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -436,8 +436,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: false, - path: Default::default(), }), TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { span, @@ -447,8 +445,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: false, - path: Default::default(), }), TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { span, @@ -458,8 +454,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: false, - path: Default::default(), }), } } @@ -496,7 +490,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; - let (source_kind, name, path) = kind.ty_localized_msg(self); + let (source_kind, name, long_ty_path) = kind.ty_localized_msg(self); let failure_span = if should_label_span && !failure_span.overlaps(span) { Some(failure_span) } else { @@ -628,7 +622,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } } - match error_code { + let mut err = match error_code { TypeAnnotationNeeded::E0282 => self.dcx().create_err(AnnotationRequired { span, source_kind, @@ -637,8 +631,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.is_some(), - path: path.unwrap_or_default(), }), TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { span, @@ -648,8 +640,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.is_some(), - path: path.unwrap_or_default(), }), TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { span, @@ -659,10 +649,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.is_some(), - path: path.unwrap_or_default(), }), - } + }; + *err.long_ty_path() = long_ty_path; + err } } @@ -726,22 +716,24 @@ impl<'tcx> InferSource<'tcx> { impl<'tcx> InferSourceKind<'tcx> { fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String, Option) { - let mut path = None; + let mut long_ty_path = None; match *self { InferSourceKind::LetBinding { ty, .. } | InferSourceKind::ClosureArg { ty, .. } | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { - ("closure", closure_as_fn_str(infcx, ty), path) + ("closure", closure_as_fn_str(infcx, ty), long_ty_path) } else if !ty.is_ty_or_numeric_infer() { - ("normal", infcx.tcx.short_string(ty, &mut path), path) + ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path) } else { - ("other", String::new(), path) + ("other", String::new(), long_ty_path) } } // FIXME: We should be able to add some additional info here. InferSourceKind::GenericArg { .. } - | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new(), path), + | InferSourceKind::FullyQualifiedMethodCall { .. } => { + ("other", String::new(), long_ty_path) + } } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index cdf1402252aa0..af912227ce4e4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -169,7 +169,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; - let mut file = None; + let mut long_ty_path = None; debug!(?predicate, obligation.cause.code = ?obligation.cause.code()); @@ -211,19 +211,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.tcx.as_lang_item(trait_pred.def_id()), Some(LangItem::Sized | LangItem::MetaSized) ) { - match self.tainted_by_errors() { - None => { - let err = self.emit_inference_failure_err( + return match self.tainted_by_errors() { + None => self + .emit_inference_failure_err( obligation.cause.body_id, span, trait_pred.self_ty().skip_binder().into(), TypeAnnotationNeeded::E0282, false, - ); - return err.emit(); - } - Some(e) => return e, - } + ) + .emit(), + Some(e) => e, + }; } // Typically, this ambiguity should only happen if @@ -260,8 +259,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, E0283, "type annotations needed: cannot satisfy `{}`", - self.tcx.short_string(predicate, &mut file), + self.tcx.short_string(predicate, &mut long_ty_path), ) + .with_long_ty_path(long_ty_path) }; let mut ambiguities = compute_applicable_impls_for_diagnostics( @@ -307,7 +307,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.cancel(); return e; } - let pred = self.tcx.short_string(predicate, &mut file); + let pred = self.tcx.short_string(predicate, &mut err.long_ty_path()); err.note(format!("cannot satisfy `{pred}`")); let impl_candidates = self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap()); @@ -512,6 +512,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true, ) } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { if let Err(e) = predicate.error_reported() { return e; @@ -536,7 +537,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .filter_map(ty::GenericArg::as_term) .chain([data.term]) .find(|g| g.has_non_region_infer()); - let predicate = self.tcx.short_string(predicate, &mut file); + let predicate = self.tcx.short_string(predicate, &mut long_ty_path); if let Some(term) = term { self.emit_inference_failure_err( obligation.cause.body_id, @@ -546,6 +547,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true, ) .with_note(format!("cannot satisfy `{predicate}`")) + .with_long_ty_path(long_ty_path) } else { // If we can't find a generic parameter, just print a generic error struct_span_code_err!( @@ -555,6 +557,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) + .with_long_ty_path(long_ty_path) } } @@ -568,17 +571,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let term = data.walk().filter_map(ty::GenericArg::as_term).find(|term| term.is_infer()); if let Some(term) = term { - let err = self.emit_inference_failure_err( + self.emit_inference_failure_err( obligation.cause.body_id, span, term, TypeAnnotationNeeded::E0284, true, - ); - err + ) } else { // If we can't find a generic parameter, just print a generic error - let predicate = self.tcx.short_string(predicate, &mut file); + let predicate = self.tcx.short_string(predicate, &mut long_ty_path); struct_span_code_err!( self.dcx(), span, @@ -586,6 +588,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) + .with_long_ty_path(long_ty_path) } } @@ -597,13 +600,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { TypeAnnotationNeeded::E0284, true, ), + ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) if term.is_infer() => { if let Some(e) = self.tainted_by_errors() { return e; } - let alias = self.tcx.short_string(alias, &mut file); + let alias = self.tcx.short_string(alias, &mut long_ty_path); struct_span_code_err!( self.dcx(), span, @@ -611,37 +615,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "type annotations needed: cannot normalize `{alias}`", ) .with_span_label(span, format!("cannot normalize `{alias}`")) + .with_long_ty_path(long_ty_path) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => { if let Some(e) = self.tainted_by_errors() { return e; } - let mut err; - if self.tcx.features().staged_api() { - err = self.dcx().struct_span_err( + self.dcx().struct_span_err( span, format!("unstable feature `{sym}` is used without being enabled."), - ); - - err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")); + ).with_help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")) } else { - err = feature_err_unstable_feature_bound( + feature_err_unstable_feature_bound( &self.tcx.sess, sym, span, format!("use of unstable library feature `{sym}`"), - ); + ) } - err } _ => { if let Some(e) = self.tainted_by_errors() { return e; } - let predicate = self.tcx.short_string(predicate, &mut file); + let predicate = self.tcx.short_string(predicate, &mut long_ty_path); struct_span_code_err!( self.dcx(), span, @@ -649,9 +650,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) + .with_long_ty_path(long_ty_path) } }; - *err.long_ty_path() = file; self.note_obligation_cause(&mut err, obligation); err.emit() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index a9e346a5cdb01..62859329de356 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -208,16 +208,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { performs a conversion on the error value \ using the `From` trait"; let (message, notes, append_const_msg) = if is_try_conversion { + let ty = self.tcx.short_string( + main_trait_predicate.skip_binder().self_ty(), + &mut long_ty_file, + ); // We have a `-> Result<_, E1>` and `gives_E2()?`. ( - Some(format!( - "`?` couldn't convert the error to `{}`", - main_trait_predicate.skip_binder().self_ty(), - )), + Some(format!("`?` couldn't convert the error to `{ty}`")), vec![question_mark_message.to_owned()], Some(AppendConstMessage::Default), ) } else if is_question_mark { + let main_trait_predicate = + self.tcx.short_string(main_trait_predicate, &mut long_ty_file); // Similar to the case above, but in this case the conversion is for a // trait object: `-> Result<_, Box` and `gives_E()?` when // `E: Error` isn't met. @@ -233,7 +236,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (message, notes, append_const_msg) }; - let err_msg = self.get_standard_error_message( + let default_err_msg = || self.get_standard_error_message( main_trait_predicate, message, None, @@ -258,7 +261,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } GetSafeTransmuteErrorAndReason::Default => { - (err_msg, None) + (default_err_msg(), None) } GetSafeTransmuteErrorAndReason::Error { err_msg, @@ -266,7 +269,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } => (err_msg, safe_transmute_explanation), } } else { - (err_msg, None) + (default_err_msg(), None) }; let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); @@ -279,15 +282,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some(ret_span) = self.return_type_span(&obligation) { if is_try_conversion { + let ty = self.tcx.short_string( + main_trait_predicate.skip_binder().self_ty(), + err.long_ty_path(), + ); err.span_label( ret_span, - format!( - "expected `{}` because of this", - main_trait_predicate.skip_binder().self_ty() - ), + format!("expected `{ty}` because of this"), ); } else if is_question_mark { - err.span_label(ret_span, format!("required `{main_trait_predicate}` because of this")); + let main_trait_predicate = + self.tcx.short_string(main_trait_predicate, err.long_ty_path()); + err.span_label( + ret_span, + format!("required `{main_trait_predicate}` because of this"), + ); } } @@ -303,6 +312,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &obligation, leaf_trait_predicate, pre_message, + err.long_ty_path(), ); self.check_for_binding_assigned_block_without_tail_expression( @@ -414,11 +424,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else { vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))] }; + let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path()); + let ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path()); err.multipart_suggestion( format!( - "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", - cand.print_trait_sugared(), - cand.self_ty(), + "the trait `{trait_}` is implemented for fn pointer \ + `{ty}`, try casting using `as`", ), suggestion, Applicability::MaybeIncorrect, @@ -522,7 +533,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { \ for more information)", ); - err.help("did you intend to use the type `()` here instead?"); + err.help("you might have intended to use the type `()` here instead"); } } @@ -722,10 +733,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty } => { + let expected_ty_str = self.tcx.short_string(expected_ty, &mut long_ty_file); + let ct_str = self.tcx.short_string(ct, &mut long_ty_file); let mut diag = self.dcx().struct_span_err( span, - format!("the constant `{ct}` is not of type `{expected_ty}`"), + format!("the constant `{ct_str}` is not of type `{expected_ty_str}`"), ); + diag.long_ty_path = long_ty_file; self.note_type_err( &mut diag, @@ -1118,9 +1132,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .must_apply_modulo_regions() { if !suggested { + let err_ty = self.tcx.short_string(err_ty, err.long_ty_path()); err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); } } else { + let err_ty = self.tcx.short_string(err_ty, err.long_ty_path()); err.span_label( span, format!( @@ -1156,12 +1172,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } (ty::Adt(def, _), None) if def.did().is_local() => { + let trait_path = self.tcx.short_string( + trait_pred.skip_binder().trait_ref.print_only_trait_path(), + err.long_ty_path(), + ); err.span_note( self.tcx.def_span(def.did()), - format!( - "`{self_ty}` needs to implement `{}`", - trait_pred.skip_binder().trait_ref.print_only_trait_path(), - ), + format!("`{self_ty}` needs to implement `{trait_path}`"), ); } (ty::Adt(def, _), Some(ty)) if def.did().is_local() => { @@ -1195,13 +1212,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { bug!() }; + let mut file = None; + let ty_str = self.tcx.short_string(ty, &mut file); let mut diag = match ty.kind() { ty::Float(_) => { struct_span_code_err!( self.dcx(), span, E0741, - "`{ty}` is forbidden as the type of a const generic parameter", + "`{ty_str}` is forbidden as the type of a const generic parameter", ) } ty::FnPtr(..) => { @@ -1226,7 +1245,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.dcx(), span, E0741, - "`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter", + "`{ty_str}` must implement `ConstParamTy` to be used as the type of a const generic parameter", ); // Only suggest derive if this isn't a derived obligation, // and the struct is local. @@ -1258,21 +1277,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.dcx(), span, E0741, - "`{ty}` can't be used as a const parameter type", + "`{ty_str}` can't be used as a const parameter type", ) } }; + diag.long_ty_path = file; let mut code = obligation.cause.code(); let mut pred = obligation.predicate.as_trait_clause(); while let Some((next_code, next_pred)) = code.parent_with_predicate() { if let Some(pred) = pred { self.enter_forall(pred, |pred| { - diag.note(format!( - "`{}` must implement `{}`, but it does not", - pred.self_ty(), - pred.print_modifiers_and_trait_path() - )); + let ty = self.tcx.short_string(pred.self_ty(), diag.long_ty_path()); + let trait_path = self + .tcx + .short_string(pred.print_modifiers_and_trait_path(), diag.long_ty_path()); + diag.note(format!("`{ty}` must implement `{trait_path}`, but it does not")); }) } code = next_code; @@ -1584,7 +1604,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { projection_term: ty::AliasTerm<'tcx>, normalized_ty: ty::Term<'tcx>, expected_ty: ty::Term<'tcx>, - file: &mut Option, + long_ty_path: &mut Option, ) -> Option<(String, Span, Option)> { let trait_def_id = projection_term.trait_def_id(self.tcx); let self_ty = projection_term.self_ty(); @@ -1624,17 +1644,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let item = match self_ty.kind() { ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), - _ => self.tcx.short_string(self_ty, file), + _ => self.tcx.short_string(self_ty, long_ty_path), }; + let expected_ty = self.tcx.short_string(expected_ty, long_ty_path); + let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path); Some((format!( "expected `{item}` to return `{expected_ty}`, but it returns `{normalized_ty}`", ), span, closure_span)) } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) { + let self_ty = self.tcx.short_string(self_ty, long_ty_path); + let expected_ty = self.tcx.short_string(expected_ty, long_ty_path); + let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path); Some((format!( "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \ resolves to `{normalized_ty}`" ), span, None)) } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { + let self_ty = self.tcx.short_string(self_ty, long_ty_path); + let expected_ty = self.tcx.short_string(expected_ty, long_ty_path); + let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path); Some((format!( "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \ yields `{normalized_ty}`" @@ -2097,12 +2125,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let [TypeError::Sorts(exp_found)] = &terrs[..] { let exp_found = self.resolve_vars_if_possible(*exp_found); + let expected = + self.tcx.short_string(exp_found.expected, err.long_ty_path()); + let found = self.tcx.short_string(exp_found.found, err.long_ty_path()); err.highlighted_help(vec![ StringPart::normal("for that trait implementation, "), StringPart::normal("expected `"), - StringPart::highlighted(exp_found.expected.to_string()), + StringPart::highlighted(expected), StringPart::normal("`, found `"), - StringPart::highlighted(exp_found.found.to_string()), + StringPart::highlighted(found), StringPart::normal("`"), ]); self.suggest_function_pointers_impl(None, &exp_found, err); @@ -2135,11 +2166,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (ty::FnPtr(..), _) => (" implemented for fn pointer `", ""), _ => (" implemented for `", ""), }; + let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path()); + let self_ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path()); err.highlighted_help(vec![ - StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), + StringPart::normal(format!("the trait `{trait_}` ",)), StringPart::highlighted("is"), StringPart::normal(desc), - StringPart::highlighted(cand.self_ty().to_string()), + StringPart::highlighted(self_ty), StringPart::normal("`"), StringPart::normal(mention_castable), ]); @@ -2159,9 +2192,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .into_iter() .map(|c| { if all_traits_equal { - format!("\n {}", c.self_ty()) + format!("\n {}", self.tcx.short_string(c.self_ty(), err.long_ty_path())) } else { - format!("\n `{}` implements `{}`", c.self_ty(), c.print_only_trait_path()) + format!( + "\n `{}` implements `{}`", + self.tcx.short_string(c.self_ty(), err.long_ty_path()), + self.tcx.short_string(c.print_only_trait_path(), err.long_ty_path()), + ) } }) .collect(); @@ -2477,7 +2514,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { predicate_constness: Option, append_const_msg: Option, post_message: String, - long_ty_file: &mut Option, + long_ty_path: &mut Option, ) -> String { message .and_then(|cannot_do_this| { @@ -2503,7 +2540,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "the trait bound `{}` is not satisfied{post_message}", self.tcx.short_string( trait_predicate.print_with_bound_constness(predicate_constness), - long_ty_file, + long_ty_path, ), ) }) @@ -2608,8 +2645,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { dst_min_align, } => { format!( - "the minimum alignment of `{src}` ({src_min_align}) should \ - be greater than that of `{dst}` ({dst_min_align})" + "the minimum alignment of `{src}` ({src_min_align}) should be \ + greater than that of `{dst}` ({dst_min_align})" ) } rustc_transmute::Reason::DstIsMoreUnique => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 5765dfd891d4f..bb5c6469f34b4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -99,7 +99,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, trait_pred: ty::PolyTraitPredicate<'tcx>, obligation: &PredicateObligation<'tcx>, - long_ty_file: &mut Option, + long_ty_path: &mut Option, ) -> OnUnimplementedNote { if trait_pred.polarity() != ty::PredicatePolarity::Positive { return OnUnimplementedNote::default(); @@ -281,7 +281,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type() { - self.tcx.short_string(ty, long_ty_file) + self.tcx.short_string(ty, long_ty_path) } else { trait_pred.trait_ref.args[param.index as usize].to_string() } 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 718cff6d135bd..374e1f679302d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3,6 +3,7 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; +use std::path::PathBuf; use itertools::{EitherOrBoth, Itertools}; use rustc_abi::ExternAbi; @@ -1369,6 +1370,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let self_ty_str = self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path()); + let trait_path = self + .tcx + .short_string(old_pred.print_modifiers_and_trait_path(), err.long_ty_path()); + if has_custom_message { err.note(msg); } else { @@ -1376,10 +1381,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } err.span_label( span, - format!( - "the trait `{}` is not implemented for `{self_ty_str}`", - old_pred.print_modifiers_and_trait_path() - ), + format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"), ); }; @@ -3333,17 +3335,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { tcx.async_fn_trait_kind_from_def_id(data.parent_trait_pred.def_id()).is_some(); if !is_upvar_tys_infer_tuple && !is_builtin_async_fn_trait { - let ty_str = tcx.short_string(ty, err.long_ty_path()); - let msg = format!("required because it appears within the type `{ty_str}`"); + let mut msg = || { + let ty_str = tcx.short_string(ty, err.long_ty_path()); + format!("required because it appears within the type `{ty_str}`") + }; match ty.kind() { - ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { - Some(ident) => { - err.span_note(ident.span, msg); - } - None => { - err.note(msg); + ty::Adt(def, _) => { + let msg = msg(); + match tcx.opt_item_ident(def.did()) { + Some(ident) => { + err.span_note(ident.span, msg); + } + None => { + err.note(msg); + } } - }, + } ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { // If the previous type is async fn, this is the future generated by the body of an async function. // Avoid printing it twice (it was already printed in the `ty::Coroutine` arm below). @@ -3363,6 +3370,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { // See comment above; skip printing twice. } else { + let msg = msg(); err.span_note(tcx.def_span(def_id), msg); } } @@ -3392,6 +3400,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"); } _ => { + let msg = msg(); err.note(msg); } }; @@ -3441,7 +3450,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let self_ty_str = tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); - let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); + let trait_name = tcx.short_string( + parent_trait_pred.print_modifiers_and_trait_path(), + err.long_ty_path(), + ); let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; match tcx.hir_get_if_local(data.impl_or_alias_def_id) { @@ -3539,10 +3551,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { parent_trait_pred.skip_binder().self_ty(), err.long_ty_path(), ); - err.note(format!( - "required for `{self_ty}` to implement `{}`", - parent_trait_pred.print_modifiers_and_trait_path() - )); + let trait_path = tcx.short_string( + parent_trait_pred.print_modifiers_and_trait_path(), + err.long_ty_path(), + ); + err.note(format!("required for `{self_ty}` to implement `{trait_path}`")); } // #74711: avoid a stack overflow ensure_sufficient_stack(|| { @@ -3558,15 +3571,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }); } ObligationCauseCode::ImplDerivedHost(ref data) => { - let self_ty = - self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty()); - let msg = format!( - "required for `{self_ty}` to implement `{} {}`", - data.derived.parent_host_pred.skip_binder().constness, + let self_ty = tcx.short_string( + self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty()), + err.long_ty_path(), + ); + let trait_path = tcx.short_string( data.derived .parent_host_pred .map_bound(|pred| pred.trait_ref) .print_only_trait_path(), + err.long_ty_path(), + ); + let msg = format!( + "required for `{self_ty}` to implement `{} {trait_path}`", + data.derived.parent_host_pred.skip_binder().constness, ); match tcx.hir_get_if_local(data.impl_def_id) { Some(Node::Item(hir::Item { @@ -5351,6 +5369,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( obligation: &PredicateObligation<'tcx>, trait_predicate: ty::PolyTraitPredicate<'tcx>, pre_message: String, + long_ty_path: &mut Option, ) -> String { if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { "consider using `()`, or a `Result`".to_owned() @@ -5369,7 +5388,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( format!( "{pre_message}the trait `{}` is not implemented for{desc} `{}`", trait_predicate.print_modifiers_and_trait_path(), - tcx.short_string(trait_predicate.self_ty().skip_binder(), &mut None), + tcx.short_string(trait_predicate.self_ty().skip_binder(), long_ty_path), ) } else { // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7901d52dffb61..af241099c0149 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use rustc_ast::Path; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; @@ -224,9 +222,6 @@ pub struct AnnotationRequired<'a> { pub infer_subdiags: Vec>, #[subdiagnostic] pub multi_suggestions: Vec>, - #[note(trait_selection_full_type_written)] - pub was_written: bool, - pub path: PathBuf, } // Copy of `AnnotationRequired` for E0283 @@ -245,9 +240,6 @@ pub struct AmbiguousImpl<'a> { pub infer_subdiags: Vec>, #[subdiagnostic] pub multi_suggestions: Vec>, - #[note(trait_selection_full_type_written)] - pub was_written: bool, - pub path: PathBuf, } // Copy of `AnnotationRequired` for E0284 @@ -266,9 +258,6 @@ pub struct AmbiguousReturn<'a> { pub infer_subdiags: Vec>, #[subdiagnostic] pub multi_suggestions: Vec>, - #[note(trait_selection_full_type_written)] - pub was_written: bool, - pub path: PathBuf, } // Used when a better one isn't available diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr index f2d9ebe2c0eae..771c0c6dfe98e 100644 --- a/tests/ui/attributes/rustc_confusables_std_cases.stderr +++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `push` found for struct `BTreeSet` in the current scope +error[E0599]: no method named `push` found for struct `BTreeSet` in the current scope --> $DIR/rustc_confusables_std_cases.rs:6:7 | LL | x.push(1); @@ -22,7 +22,7 @@ LL - x.push_back(1); LL + x.push(1); | -error[E0599]: no method named `push` found for struct `VecDeque` in the current scope +error[E0599]: no method named `push` found for struct `VecDeque` in the current scope --> $DIR/rustc_confusables_std_cases.rs:12:7 | LL | x.push(1); @@ -35,7 +35,7 @@ LL | let mut x = Vec::new(); | ^^^^^ `x` of type `Vec<_>` that has method `push` defined earlier here ... LL | let mut x = VecDeque::new(); - | ----- earlier `x` shadowed here with type `VecDeque` + | ----- earlier `x` shadowed here with type `VecDeque<_>` help: you might have meant to use `push_back` | LL | x.push_back(1); diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index a9045840173e7..3aafe05ba0537 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,5 +1,6 @@ -//~ ERROR overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: FnMut(&'a _)` +//~ ERROR overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:14:41: 14:44}: FnMut(&'a _)` //@ build-fail +//@ compile-flags: -Zwrite-long-types-to-disk=yes #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index 74d98fde285bb..1559de757e7ba 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,10 +1,12 @@ -error[E0275]: overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: FnMut(&'a _)` +error[E0275]: overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:14:41: 14:44}: FnMut(&'a _)` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`) - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` + = note: required for `Filter, {closure@overflow-during-mono.rs:14:41}>` to implement `Iterator` = note: 31 redundant requirements hidden - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator` + = note: required for `Filter, ...>, ...>, ...>, ...>` to implement `Iterator` + = note: required for `Filter, ...>, ...>, ...>, ...>` to implement `IntoIterator` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/overflow-during-mono.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/confuse-field-and-method/issue-18343.stderr b/tests/ui/confuse-field-and-method/issue-18343.stderr index e50c971d837b8..9517617fe34cc 100644 --- a/tests/ui/confuse-field-and-method/issue-18343.stderr +++ b/tests/ui/confuse-field-and-method/issue-18343.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `closure` found for struct `Obj` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-18343.rs:7:7 | LL | struct Obj where F: FnMut() -> u32 { diff --git a/tests/ui/confuse-field-and-method/issue-2392.stderr b/tests/ui/confuse-field-and-method/issue-2392.stderr index 77930de44a770..e1ad24df80f70 100644 --- a/tests/ui/confuse-field-and-method/issue-2392.stderr +++ b/tests/ui/confuse-field-and-method/issue-2392.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `closure` found for struct `Obj` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:36:15 | LL | struct Obj where F: FnOnce() -> u32 { @@ -12,7 +12,7 @@ help: to call the closure stored in `closure`, surround the field access with pa LL | (o_closure.closure)(); | + + -error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope +error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:38:15 | LL | struct Obj where F: FnOnce() -> u32 { @@ -23,7 +23,7 @@ LL | o_closure.not_closure(); | | | field, not a method -error[E0599]: no method named `closure` found for struct `Obj` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:42:12 | LL | struct Obj where F: FnOnce() -> u32 { @@ -65,7 +65,7 @@ help: to call the trait object stored in `boxed_closure`, surround the field acc LL | (boxed_closure.boxed_closure)(); | + + -error[E0599]: no method named `closure` found for struct `Obj` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:53:12 | LL | struct Obj where F: FnOnce() -> u32 { @@ -79,7 +79,7 @@ help: to call the function stored in `closure`, surround the field access with p LL | (w.wrap.closure)(); | + + -error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope +error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:55:12 | LL | struct Obj where F: FnOnce() -> u32 { @@ -90,7 +90,7 @@ LL | w.wrap.not_closure(); | | | field, not a method -error[E0599]: no method named `closure` found for struct `Obj` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:58:24 | LL | struct Obj where F: FnOnce() -> u32 { diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr index 61e2a8f64dd52..b0bfc72065878 100644 --- a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr +++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr @@ -43,7 +43,7 @@ help: consider introducing lifetime `'a` here LL | impl<'a> Trait for Z { | ++++ -error[E0599]: no function or associated item named `new` found for struct `InvariantRef` in the current scope +error[E0599]: no function or associated item named `new` found for struct `InvariantRef<'a, T>` in the current scope --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41 | LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); diff --git a/tests/ui/dropck/dropck_no_diverge_on_nonregular_1.rs b/tests/ui/dropck/dropck_no_diverge_on_nonregular_1.rs index 17b76b6c8321a..2bb82a2ebf207 100644 --- a/tests/ui/dropck/dropck_no_diverge_on_nonregular_1.rs +++ b/tests/ui/dropck/dropck_no_diverge_on_nonregular_1.rs @@ -1,5 +1,6 @@ // Issue 22443: Reject code using non-regular types that would // otherwise cause dropck to loop infinitely. +//@ compile-flags: -Zwrite-long-types-to-disk=yes use std::marker::PhantomData; diff --git a/tests/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/tests/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr index 9360f4a98e9b9..330a40d925bb1 100644 --- a/tests/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr +++ b/tests/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr @@ -1,10 +1,12 @@ error[E0320]: overflow while adding drop-check rules for `FingerTree` - --> $DIR/dropck_no_diverge_on_nonregular_1.rs:24:9 + --> $DIR/dropck_no_diverge_on_nonregular_1.rs:25:9 | LL | let ft = | ^^ | - = note: overflowed on `FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: overflowed on `FingerTree>>>>>>>>>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/dropck_no_diverge_on_nonregular_1.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr index 2daf00f7804ff..f0d4de364fbd0 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr @@ -5,7 +5,7 @@ LL | true => Default::default(), | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` | = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) - = help: did you intend to use the type `()` here instead? + = help: you might have intended to use the type `()` here instead error[E0277]: the trait bound `!: Default` is not satisfied --> $DIR/never-type-fallback-breaking.rs:37:5 @@ -14,7 +14,7 @@ LL | deserialize()?; | ^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` | = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) - = help: did you intend to use the type `()` here instead? + = help: you might have intended to use the type `()` here instead note: required by a bound in `deserialize` --> $DIR/never-type-fallback-breaking.rs:33:23 | @@ -51,7 +51,7 @@ LL | takes_apit(|| Default::default())?; | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` | = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) - = help: did you intend to use the type `()` here instead? + = help: you might have intended to use the type `()` here instead error[E0277]: the trait bound `!: Default` is not satisfied --> $DIR/never-type-fallback-breaking.rs:76:17 @@ -62,7 +62,7 @@ LL | takes_apit2(mk()?); | required by a bound introduced by this call | = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) - = help: did you intend to use the type `()` here instead? + = help: you might have intended to use the type `()` here instead note: required by a bound in `takes_apit2` --> $DIR/never-type-fallback-breaking.rs:71:25 | diff --git a/tests/ui/error-codes/E0275.rs b/tests/ui/error-codes/E0275.rs index 28a9676f03e39..98d4a3c01b9a2 100644 --- a/tests/ui/error-codes/E0275.rs +++ b/tests/ui/error-codes/E0275.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zwrite-long-types-to-disk=yes trait Foo {} struct Bar(T); diff --git a/tests/ui/error-codes/E0275.stderr b/tests/ui/error-codes/E0275.stderr index 3b31c87320ae9..755404c1e1698 100644 --- a/tests/ui/error-codes/E0275.stderr +++ b/tests/ui/error-codes/E0275.stderr @@ -1,17 +1,19 @@ error[E0275]: overflow evaluating the requirement `Bar>>>>>>: Foo` - --> $DIR/E0275.rs:5:33 + --> $DIR/E0275.rs:6:33 | LL | impl Foo for T where Bar: Foo {} | ^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`E0275`) -note: required for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` to implement `Foo` - --> $DIR/E0275.rs:5:9 +note: required for `Bar>>>>>>>>>>>>` to implement `Foo` + --> $DIR/E0275.rs:6:9 | LL | impl Foo for T where Bar: Foo {} | ^^^ ^ --- unsatisfied trait bound introduced here = note: 126 redundant requirements hidden = note: required for `Bar` to implement `Foo` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/E0275.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs index d8a1f3fa69e4b..d2793afdd0646 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs @@ -6,6 +6,8 @@ // This tests double-checks that we do not allow such behavior to leak // through again. +//@ compile-flags: -Zwrite-long-types-to-disk=yes + pub trait Stream { type Item; fn next(self) -> Option; diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr index 23b979e2ef0bb..91e65b2b07318 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr @@ -1,5 +1,5 @@ -error[E0599]: the method `countx` exists for struct `Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:109:30: 109:37}>`, but its trait bounds were not satisfied - --> $DIR/hrtb-doesnt-borrow-self-2.rs:110:24 +error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@...}>`, but its trait bounds were not satisfied + --> $DIR/hrtb-doesnt-borrow-self-2.rs:112:24 | LL | pub struct Filter { | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` @@ -8,19 +8,21 @@ LL | let count = filter.countx(); | ^^^^^^ method cannot be called due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: - `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:109:30: 109:37}>: Stream` - `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:109:30: 109:37}>: Stream` - `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:109:30: 109:37}>: Stream` - --> $DIR/hrtb-doesnt-borrow-self-2.rs:96:50 + `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + --> $DIR/hrtb-doesnt-borrow-self-2.rs:98:50 | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here = help: items from traits can only be used if the trait is implemented and in scope note: `StreamExt` defines an item `countx`, perhaps you need to implement it - --> $DIR/hrtb-doesnt-borrow-self-2.rs:64:1 + --> $DIR/hrtb-doesnt-borrow-self-2.rs:66:1 | LL | pub trait StreamExt | ^^^^^^^^^^^^^^^^^^^ + = note: the full name for the type has been written to '$TEST_BUILD_DIR/hrtb-doesnt-borrow-self-2.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs index 09450089adaa8..ead81bf337469 100644 --- a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs +++ b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zwrite-long-types-to-disk=yes use std::cell::Cell; use std::rc::Rc; diff --git a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr index 52fa28145d664..ba76d9ba2b8fc 100644 --- a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr +++ b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr @@ -1,5 +1,5 @@ error[E0277]: `Rc>` cannot be sent between threads safely - --> $DIR/auto-trait-leak2.rs:20:10 + --> $DIR/auto-trait-leak2.rs:21:10 | LL | fn before() -> impl Fn(i32) { | ------------ within this `impl Fn(i32)` @@ -11,23 +11,23 @@ LL | send(before()); | = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc>` note: required because it's used within this closure - --> $DIR/auto-trait-leak2.rs:10:5 + --> $DIR/auto-trait-leak2.rs:11:5 | LL | move |x| p.set(x) | ^^^^^^^^ note: required because it appears within the type `impl Fn(i32)` - --> $DIR/auto-trait-leak2.rs:5:16 + --> $DIR/auto-trait-leak2.rs:6:16 | LL | fn before() -> impl Fn(i32) { | ^^^^^^^^^^^^ note: required by a bound in `send` - --> $DIR/auto-trait-leak2.rs:13:12 + --> $DIR/auto-trait-leak2.rs:14:12 | LL | fn send(_: T) {} | ^^^^ required by this bound in `send` error[E0277]: `Rc>` cannot be sent between threads safely - --> $DIR/auto-trait-leak2.rs:25:10 + --> $DIR/auto-trait-leak2.rs:26:10 | LL | send(after()); | ---- ^^^^^^^ `Rc>` cannot be sent between threads safely @@ -39,17 +39,17 @@ LL | fn after() -> impl Fn(i32) { | = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc>` note: required because it's used within this closure - --> $DIR/auto-trait-leak2.rs:38:5 + --> $DIR/auto-trait-leak2.rs:39:5 | LL | move |x| p.set(x) | ^^^^^^^^ note: required because it appears within the type `impl Fn(i32)` - --> $DIR/auto-trait-leak2.rs:33:15 + --> $DIR/auto-trait-leak2.rs:34:15 | LL | fn after() -> impl Fn(i32) { | ^^^^^^^^^^^^ note: required by a bound in `send` - --> $DIR/auto-trait-leak2.rs:13:12 + --> $DIR/auto-trait-leak2.rs:14:12 | LL | fn send(_: T) {} | ^^^^ required by this bound in `send` diff --git a/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.rs b/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.rs index 4fd15eea9e0f1..f1353f1805d8f 100644 --- a/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.rs +++ b/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zwrite-long-types-to-disk=yes type A = (i32, i32, i32, i32); type B = (A, A, A, A); type C = (B, B, B, B); diff --git a/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.stderr b/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.stderr index 65fe2ffcb7f16..5c4a1a7582931 100644 --- a/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.stderr +++ b/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.stderr @@ -1,9 +1,11 @@ -error[E0282]: type annotations needed for `Result<_, ((((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32))), (((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32))), (((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32))), (((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32))))>` - --> $DIR/really-long-type-in-let-binding-without-sufficient-type-info.rs:7:9 +error[E0282]: type annotations needed for `Result<_, (((..., ..., ..., ...), ..., ..., ...), ..., ..., ...)>` + --> $DIR/really-long-type-in-let-binding-without-sufficient-type-info.rs:8:9 | LL | let y = Err(x); | ^ ------ type must be known at this point | + = note: the full name for the type has been written to '$TEST_BUILD_DIR/really-long-type-in-let-binding-without-sufficient-type-info.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console help: consider giving `y` an explicit type, where the type for type parameter `T` is specified | LL | let y: Result = Err(x); diff --git a/tests/ui/interior-mutability/interior-mutability.rs b/tests/ui/interior-mutability/interior-mutability.rs index c704acc22af6b..7e4fe76852d76 100644 --- a/tests/ui/interior-mutability/interior-mutability.rs +++ b/tests/ui/interior-mutability/interior-mutability.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zwrite-long-types-to-disk=yes use std::cell::Cell; use std::panic::catch_unwind; fn main() { diff --git a/tests/ui/interior-mutability/interior-mutability.stderr b/tests/ui/interior-mutability/interior-mutability.stderr index cfc64445bf3be..5a959d14c8a91 100644 --- a/tests/ui/interior-mutability/interior-mutability.stderr +++ b/tests/ui/interior-mutability/interior-mutability.stderr @@ -1,5 +1,5 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary - --> $DIR/interior-mutability.rs:5:18 + --> $DIR/interior-mutability.rs:6:18 | LL | catch_unwind(|| { x.set(23); }); | ------------ ^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary @@ -11,7 +11,7 @@ note: required because it appears within the type `Cell` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `&Cell` to implement `UnwindSafe` note: required because it's used within this closure - --> $DIR/interior-mutability.rs:5:18 + --> $DIR/interior-mutability.rs:6:18 | LL | catch_unwind(|| { x.set(23); }); | ^^ diff --git a/tests/ui/issues/issue-41880.stderr b/tests/ui/issues/issue-41880.stderr index 1936c0aebd40d..2f1ebee7ca5a3 100644 --- a/tests/ui/issues/issue-41880.stderr +++ b/tests/ui/issues/issue-41880.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `iter` found for struct `Iterate` in the current scope +error[E0599]: no method named `iter` found for struct `Iterate` in the current scope --> $DIR/issue-41880.rs:27:24 | LL | pub struct Iterate { diff --git a/tests/ui/methods/call_method_unknown_referent.rs b/tests/ui/methods/call_method_unknown_referent.rs index b01e2d80f7f80..b26ecc74175b6 100644 --- a/tests/ui/methods/call_method_unknown_referent.rs +++ b/tests/ui/methods/call_method_unknown_referent.rs @@ -44,5 +44,5 @@ fn main() { // our resolution logic needs to be able to call methods such as foo() // on the outer type even if the inner type is ambiguous. let _c = (ptr as SmartPtr<_>).read(); - //~^ ERROR no method named `read` found for struct `SmartPtr` + //~^ ERROR no method named `read` found for struct `SmartPtr` } diff --git a/tests/ui/methods/call_method_unknown_referent.stderr b/tests/ui/methods/call_method_unknown_referent.stderr index 748b02b52b577..5d6974a00c695 100644 --- a/tests/ui/methods/call_method_unknown_referent.stderr +++ b/tests/ui/methods/call_method_unknown_referent.stderr @@ -10,7 +10,7 @@ error[E0282]: type annotations needed LL | let _b = (rc as std::rc::Rc<_>).read(); | ^^^^ cannot infer type -error[E0599]: no method named `read` found for struct `SmartPtr` in the current scope +error[E0599]: no method named `read` found for struct `SmartPtr` in the current scope --> $DIR/call_method_unknown_referent.rs:46:35 | LL | struct SmartPtr(T); diff --git a/tests/ui/methods/inherent-bound-in-probe.rs b/tests/ui/methods/inherent-bound-in-probe.rs index 4add93e808d22..39b4ba983e442 100644 --- a/tests/ui/methods/inherent-bound-in-probe.rs +++ b/tests/ui/methods/inherent-bound-in-probe.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zwrite-long-types-to-disk=yes // Fixes #110131 // // The issue is that we were constructing an `ImplDerived` cause code for the diff --git a/tests/ui/methods/inherent-bound-in-probe.stderr b/tests/ui/methods/inherent-bound-in-probe.stderr index 77aed390c9ace..b7751ca471436 100644 --- a/tests/ui/methods/inherent-bound-in-probe.stderr +++ b/tests/ui/methods/inherent-bound-in-probe.stderr @@ -1,5 +1,5 @@ error[E0277]: `Helper<'a, T>` is not an iterator - --> $DIR/inherent-bound-in-probe.rs:38:21 + --> $DIR/inherent-bound-in-probe.rs:39:21 | LL | type IntoIter = Helper<'a, T>; | ^^^^^^^^^^^^^ `Helper<'a, T>` is not an iterator @@ -9,14 +9,14 @@ note: required by a bound in `std::iter::IntoIterator::IntoIter` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL error[E0275]: overflow evaluating the requirement `&_: IntoIterator` - --> $DIR/inherent-bound-in-probe.rs:42:9 + --> $DIR/inherent-bound-in-probe.rs:43:9 | LL | Helper::new(&self.0) | ^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_bound_in_probe`) note: required for `&BitReaderWrapper<_>` to implement `IntoIterator` - --> $DIR/inherent-bound-in-probe.rs:32:13 + --> $DIR/inherent-bound-in-probe.rs:33:13 | LL | impl<'a, T> IntoIterator for &'a BitReaderWrapper | ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,15 +24,17 @@ LL | where LL | &'a T: IntoIterator, | ------------- unsatisfied trait bound introduced here = note: 126 redundant requirements hidden - = note: required for `&BitReaderWrapper>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` to implement `IntoIterator` + = note: required for `&BitReaderWrapper>>` to implement `IntoIterator` note: required by a bound in `Helper` - --> $DIR/inherent-bound-in-probe.rs:16:12 + --> $DIR/inherent-bound-in-probe.rs:17:12 | LL | struct Helper<'a, T> | ------ required by a bound in this struct LL | where LL | &'a T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Helper` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/inherent-bound-in-probe.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 2 previous errors diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.stderr b/tests/ui/methods/method-not-found-generic-arg-elision.stderr index 8429c3aebac2f..75fabc27b0f7d 100644 --- a/tests/ui/methods/method-not-found-generic-arg-elision.stderr +++ b/tests/ui/methods/method-not-found-generic-arg-elision.stderr @@ -10,7 +10,7 @@ LL | let d = point_i32.distance(); = note: the method was found for - `Point` -error[E0599]: no method named `other` found for struct `Point` in the current scope +error[E0599]: no method named `other` found for struct `Point` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:84:23 | LL | struct Point { @@ -19,7 +19,7 @@ LL | struct Point { LL | let d = point_i32.other(); | ^^^^^ method not found in `Point` -error[E0599]: no method named `extend` found for struct `Map` in the current scope +error[E0599]: no method named `extend` found for struct `Map` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:87:67 | LL | v.iter().map(Box::new(|x| x * x) as Box i32>).extend(std::iter::once(100)); @@ -41,7 +41,7 @@ LL | wrapper.method(); - `Wrapper` and 2 more types -error[E0599]: no method named `other` found for struct `Wrapper` in the current scope +error[E0599]: no method named `other` found for struct `Wrapper` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:92:13 | LL | struct Wrapper(T); @@ -64,7 +64,7 @@ LL | wrapper.method(); - `Wrapper2<'a, i32, C>` - `Wrapper2<'a, i8, C>` -error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope +error[E0599]: no method named `other` found for struct `Wrapper2<'a, T, C>` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:98:13 | LL | struct Wrapper2<'a, T, const C: usize> { diff --git a/tests/ui/methods/probe-error-on-infinite-deref.rs b/tests/ui/methods/probe-error-on-infinite-deref.rs index 85c1c0c09c13e..196d026438be8 100644 --- a/tests/ui/methods/probe-error-on-infinite-deref.rs +++ b/tests/ui/methods/probe-error-on-infinite-deref.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zwrite-long-types-to-disk=yes use std::ops::Deref; // Make sure that method probe error reporting doesn't get too tangled up diff --git a/tests/ui/methods/probe-error-on-infinite-deref.stderr b/tests/ui/methods/probe-error-on-infinite-deref.stderr index 57a9ca2eaa80f..6148b00116302 100644 --- a/tests/ui/methods/probe-error-on-infinite-deref.stderr +++ b/tests/ui/methods/probe-error-on-infinite-deref.stderr @@ -1,13 +1,15 @@ -error[E0055]: reached the recursion limit while auto-dereferencing `Wrap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/probe-error-on-infinite-deref.rs:13:13 +error[E0055]: reached the recursion limit while auto-dereferencing `Wrap>>>>>>>>>>` + --> $DIR/probe-error-on-infinite-deref.rs:14:13 | LL | Wrap(1).lmao(); | ^^^^ deref recursion limit reached | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`probe_error_on_infinite_deref`) + = note: the full name for the type has been written to '$TEST_BUILD_DIR/probe-error-on-infinite-deref.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error[E0599]: no method named `lmao` found for struct `Wrap<{integer}>` in the current scope - --> $DIR/probe-error-on-infinite-deref.rs:13:13 + --> $DIR/probe-error-on-infinite-deref.rs:14:13 | LL | struct Wrap(T); | -------------- method `lmao` not found for this struct diff --git a/tests/ui/methods/untrimmed-path-type.stderr b/tests/ui/methods/untrimmed-path-type.stderr index 1f3101ff4e78f..ee07e2daa1e1d 100644 --- a/tests/ui/methods/untrimmed-path-type.stderr +++ b/tests/ui/methods/untrimmed-path-type.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `unknown` found for enum `Result` in the current scope +error[E0599]: no method named `unknown` found for enum `Result` in the current scope --> $DIR/untrimmed-path-type.rs:5:11 | LL | meow().unknown(); diff --git a/tests/ui/never_type/defaulted-never-note.fallback.stderr b/tests/ui/never_type/defaulted-never-note.fallback.stderr index fe9a924f64a0f..7526a399bf177 100644 --- a/tests/ui/never_type/defaulted-never-note.fallback.stderr +++ b/tests/ui/never_type/defaulted-never-note.fallback.stderr @@ -8,7 +8,7 @@ LL | foo(_x); | = help: the trait `ImplementedForUnitButNotNever` is implemented for `()` = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) - = help: did you intend to use the type `()` here instead? + = help: you might have intended to use the type `()` here instead note: required by a bound in `foo` --> $DIR/defaulted-never-note.rs:25:11 | diff --git a/tests/ui/never_type/defaulted-never-note.rs b/tests/ui/never_type/defaulted-never-note.rs index badb5d4c51d83..71f0d9fa5bb5f 100644 --- a/tests/ui/never_type/defaulted-never-note.rs +++ b/tests/ui/never_type/defaulted-never-note.rs @@ -35,7 +35,7 @@ fn smeg() { //[fallback]~| HELP trait `ImplementedForUnitButNotNever` is implemented for `()` //[fallback]~| NOTE this error might have been caused //[fallback]~| NOTE required by a bound introduced by this call - //[fallback]~| HELP did you intend + //[fallback]~| HELP you might have intended to use the type `()` } fn main() { diff --git a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr index c5463814475c7..610c687194b76 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr +++ b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr @@ -10,7 +10,7 @@ LL | unconstrained_arg(return); () i32 = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) - = help: did you intend to use the type `()` here instead? + = help: you might have intended to use the type `()` here instead note: required by a bound in `unconstrained_arg` --> $DIR/diverging-fallback-no-leak.rs:12:25 | diff --git a/tests/ui/recursion/issue-23122-2.rs b/tests/ui/recursion/issue-23122-2.rs index 95e1f60d8b029..d4f13e9fa5587 100644 --- a/tests/ui/recursion/issue-23122-2.rs +++ b/tests/ui/recursion/issue-23122-2.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zwrite-long-types-to-disk=yes trait Next { type Next: Next; } diff --git a/tests/ui/recursion/issue-23122-2.stderr b/tests/ui/recursion/issue-23122-2.stderr index c5774cc188829..de402d65e6d6a 100644 --- a/tests/ui/recursion/issue-23122-2.stderr +++ b/tests/ui/recursion/issue-23122-2.stderr @@ -1,17 +1,19 @@ error[E0275]: overflow evaluating the requirement `<<<<<<<... as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized` - --> $DIR/issue-23122-2.rs:10:17 + --> $DIR/issue-23122-2.rs:11:17 | LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`) -note: required for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` to implement `Next` - --> $DIR/issue-23122-2.rs:9:15 +note: required for `GetNext<<<<... as Next>::Next as Next>::Next as Next>::Next>` to implement `Next` + --> $DIR/issue-23122-2.rs:10:15 | LL | impl Next for GetNext { | - ^^^^ ^^^^^^^^^^ | | | unsatisfied trait bound introduced here + = note: the full name for the type has been written to '$TEST_BUILD_DIR/issue-23122-2.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/recursion/issue-38591-non-regular-dropck-recursion.rs b/tests/ui/recursion/issue-38591-non-regular-dropck-recursion.rs index 7b7b1a9580bdc..c219a920bb4f1 100644 --- a/tests/ui/recursion/issue-38591-non-regular-dropck-recursion.rs +++ b/tests/ui/recursion/issue-38591-non-regular-dropck-recursion.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zwrite-long-types-to-disk=yes // `S` is infinitely recursing so it's not possible to generate a finite // drop impl. // diff --git a/tests/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/tests/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index 409f63b91b64d..cf3bc4578a727 100644 --- a/tests/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/tests/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,10 +1,12 @@ error[E0320]: overflow while adding drop-check rules for `S` - --> $DIR/issue-38591-non-regular-dropck-recursion.rs:11:6 + --> $DIR/issue-38591-non-regular-dropck-recursion.rs:12:6 | LL | fn f(x: S) {} | ^ | - = note: overflowed on `S` + = note: overflowed on `S` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/issue-38591-non-regular-dropck-recursion.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/recursion/issue-83150.rs b/tests/ui/recursion/issue-83150.rs index b720c168187b8..9194ce1ab17a8 100644 --- a/tests/ui/recursion/issue-83150.rs +++ b/tests/ui/recursion/issue-83150.rs @@ -1,6 +1,6 @@ //~ ERROR overflow evaluating the requirement `Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:12:24: 12:27}>: Iterator` //@ build-fail -//@ compile-flags: -Copt-level=0 +//@ compile-flags: -Copt-level=0 -Zwrite-long-types-to-disk=yes fn main() { let mut iter = 0u8..1; diff --git a/tests/ui/recursion/issue-83150.stderr b/tests/ui/recursion/issue-83150.stderr index 600922f1e57a7..a245b001badef 100644 --- a/tests/ui/recursion/issue-83150.stderr +++ b/tests/ui/recursion/issue-83150.stderr @@ -13,9 +13,11 @@ LL | func(&mut iter.map(|x| x + 1)) error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:12:24: 12:27}>: Iterator` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) - = note: required for `&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:12:24: 12:27}>` to implement `Iterator` + = note: required for `&mut Map<&mut Range, {closure@issue-83150.rs:12:24}>` to implement `Iterator` = note: 65 redundant requirements hidden - = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>, {closure@$DIR/issue-83150.rs:12:24: 12:27}>` to implement `Iterator` + = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut ..., ...>, ...>, ...>, ...>` to implement `Iterator` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/issue-83150.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/self/arbitrary_self_type_infinite_recursion.stderr b/tests/ui/self/arbitrary_self_type_infinite_recursion.stderr index 5e652efb36454..2dadc5c2d33bb 100644 --- a/tests/ui/self/arbitrary_self_type_infinite_recursion.stderr +++ b/tests/ui/self/arbitrary_self_type_infinite_recursion.stderr @@ -32,7 +32,7 @@ LL | p.method(); | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`arbitrary_self_type_infinite_recursion`) -error[E0599]: no method named `method` found for struct `MySmartPtr` in the current scope +error[E0599]: no method named `method` found for struct `MySmartPtr` in the current scope --> $DIR/arbitrary_self_type_infinite_recursion.rs:21:5 | LL | struct MySmartPtr(T); diff --git a/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.stderr b/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.stderr index a30cf605829f8..5d7f614209391 100644 --- a/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.stderr +++ b/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `frobnicate_ref` found for struct `CppRef` in the current scope +error[E0599]: no method named `frobnicate_ref` found for struct `CppRef` in the current scope --> $DIR/arbitrary_self_types_not_allow_call_with_no_deref.rs:29:17 | LL | struct CppRef(T); @@ -16,7 +16,7 @@ help: there is a method `frobnicate_cpp_ref` with a similar name LL | foo_cpp_ref.frobnicate_cpp_ref(); | ++++ -error[E0599]: no method named `frobnicate_self` found for struct `CppRef` in the current scope +error[E0599]: no method named `frobnicate_self` found for struct `CppRef` in the current scope --> $DIR/arbitrary_self_types_not_allow_call_with_no_deref.rs:32:17 | LL | struct CppRef(T); diff --git a/tests/ui/self/arbitrary_self_types_pin_needing_borrow.rs b/tests/ui/self/arbitrary_self_types_pin_needing_borrow.rs index d877dbe60754d..288458902782a 100644 --- a/tests/ui/self/arbitrary_self_types_pin_needing_borrow.rs +++ b/tests/ui/self/arbitrary_self_types_pin_needing_borrow.rs @@ -9,5 +9,5 @@ impl S { fn main() { Pin::new(S).x(); //~^ ERROR the trait bound `S: Deref` is not satisfied - //~| ERROR no method named `x` found for struct `Pin` in the current scope + //~| ERROR no method named `x` found for struct `Pin` in the current scope } diff --git a/tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr b/tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr index 1811cd6753ffe..df226a9366a3c 100644 --- a/tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr @@ -15,7 +15,7 @@ LL | Pin::new(&S).x(); LL | Pin::new(&mut S).x(); | ++++ -error[E0599]: no method named `x` found for struct `Pin` in the current scope +error[E0599]: no method named `x` found for struct `Pin` in the current scope --> $DIR/arbitrary_self_types_pin_needing_borrow.rs:10:17 | LL | Pin::new(S).x(); diff --git a/tests/ui/simd/libm_no_std_cant_float.stderr b/tests/ui/simd/libm_no_std_cant_float.stderr index 97e0b7efe2abc..cc9aefaad5ef3 100644 --- a/tests/ui/simd/libm_no_std_cant_float.stderr +++ b/tests/ui/simd/libm_no_std_cant_float.stderr @@ -1,34 +1,34 @@ -error[E0599]: no method named `ceil` found for struct `Simd` in the current scope +error[E0599]: no method named `ceil` found for struct `Simd` in the current scope --> $DIR/libm_no_std_cant_float.rs:15:17 | LL | let _xc = x.ceil(); | ^^^^ method not found in `Simd` -error[E0599]: no method named `floor` found for struct `Simd` in the current scope +error[E0599]: no method named `floor` found for struct `Simd` in the current scope --> $DIR/libm_no_std_cant_float.rs:16:17 | LL | let _xf = x.floor(); | ^^^^^ method not found in `Simd` -error[E0599]: no method named `round` found for struct `Simd` in the current scope +error[E0599]: no method named `round` found for struct `Simd` in the current scope --> $DIR/libm_no_std_cant_float.rs:17:17 | LL | let _xr = x.round(); | ^^^^^ method not found in `Simd` -error[E0599]: no method named `trunc` found for struct `Simd` in the current scope +error[E0599]: no method named `trunc` found for struct `Simd` in the current scope --> $DIR/libm_no_std_cant_float.rs:18:17 | LL | let _xt = x.trunc(); | ^^^^^ method not found in `Simd` -error[E0599]: no method named `mul_add` found for struct `Simd` in the current scope +error[E0599]: no method named `mul_add` found for struct `Simd` in the current scope --> $DIR/libm_no_std_cant_float.rs:19:19 | LL | let _xfma = x.mul_add(x, x); | ^^^^^^^ method not found in `Simd` -error[E0599]: no method named `sqrt` found for struct `Simd` in the current scope +error[E0599]: no method named `sqrt` found for struct `Simd` in the current scope --> $DIR/libm_no_std_cant_float.rs:20:20 | LL | let _xsqrt = x.sqrt(); diff --git a/tests/ui/suggestions/enum-method-probe.fixed b/tests/ui/suggestions/enum-method-probe.fixed index b7fd6f112d586..1ce6a943c5bba 100644 --- a/tests/ui/suggestions/enum-method-probe.fixed +++ b/tests/ui/suggestions/enum-method-probe.fixed @@ -14,7 +14,7 @@ impl Foo { fn test_result_in_result() -> Result<(), ()> { let res: Result<_, ()> = Ok(Foo); res?.get(); - //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~^ ERROR no method named `get` found for enum `Result` in the current scope //~| HELP use the `?` operator Ok(()) } @@ -22,7 +22,7 @@ fn test_result_in_result() -> Result<(), ()> { async fn async_test_result_in_result() -> Result<(), ()> { let res: Result<_, ()> = Ok(Foo); res?.get(); - //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~^ ERROR no method named `get` found for enum `Result` in the current scope //~| HELP use the `?` operator Ok(()) } @@ -30,21 +30,21 @@ async fn async_test_result_in_result() -> Result<(), ()> { fn test_result_in_unit_return() { let res: Result<_, ()> = Ok(Foo); res.expect("REASON").get(); - //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~^ ERROR no method named `get` found for enum `Result` in the current scope //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` } async fn async_test_result_in_unit_return() { let res: Result<_, ()> = Ok(Foo); res.expect("REASON").get(); - //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~^ ERROR no method named `get` found for enum `Result` in the current scope //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` } fn test_option_in_option() -> Option<()> { let res: Option<_> = Some(Foo); res?.get(); - //~^ ERROR no method named `get` found for enum `Option` in the current scope + //~^ ERROR no method named `get` found for enum `Option` in the current scope //~| HELP use the `?` operator Some(()) } @@ -52,7 +52,7 @@ fn test_option_in_option() -> Option<()> { fn test_option_in_unit_return() { let res: Option<_> = Some(Foo); res.expect("REASON").get(); - //~^ ERROR no method named `get` found for enum `Option` in the current scope + //~^ ERROR no method named `get` found for enum `Option` in the current scope //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` } diff --git a/tests/ui/suggestions/enum-method-probe.rs b/tests/ui/suggestions/enum-method-probe.rs index cbb819b7c8c09..dd3addbd0a3fb 100644 --- a/tests/ui/suggestions/enum-method-probe.rs +++ b/tests/ui/suggestions/enum-method-probe.rs @@ -14,7 +14,7 @@ impl Foo { fn test_result_in_result() -> Result<(), ()> { let res: Result<_, ()> = Ok(Foo); res.get(); - //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~^ ERROR no method named `get` found for enum `Result` in the current scope //~| HELP use the `?` operator Ok(()) } @@ -22,7 +22,7 @@ fn test_result_in_result() -> Result<(), ()> { async fn async_test_result_in_result() -> Result<(), ()> { let res: Result<_, ()> = Ok(Foo); res.get(); - //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~^ ERROR no method named `get` found for enum `Result` in the current scope //~| HELP use the `?` operator Ok(()) } @@ -30,21 +30,21 @@ async fn async_test_result_in_result() -> Result<(), ()> { fn test_result_in_unit_return() { let res: Result<_, ()> = Ok(Foo); res.get(); - //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~^ ERROR no method named `get` found for enum `Result` in the current scope //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` } async fn async_test_result_in_unit_return() { let res: Result<_, ()> = Ok(Foo); res.get(); - //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~^ ERROR no method named `get` found for enum `Result` in the current scope //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` } fn test_option_in_option() -> Option<()> { let res: Option<_> = Some(Foo); res.get(); - //~^ ERROR no method named `get` found for enum `Option` in the current scope + //~^ ERROR no method named `get` found for enum `Option` in the current scope //~| HELP use the `?` operator Some(()) } @@ -52,7 +52,7 @@ fn test_option_in_option() -> Option<()> { fn test_option_in_unit_return() { let res: Option<_> = Some(Foo); res.get(); - //~^ ERROR no method named `get` found for enum `Option` in the current scope + //~^ ERROR no method named `get` found for enum `Option` in the current scope //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` } diff --git a/tests/ui/suggestions/enum-method-probe.stderr b/tests/ui/suggestions/enum-method-probe.stderr index e66973d9d954b..5aa0fc44c7b50 100644 --- a/tests/ui/suggestions/enum-method-probe.stderr +++ b/tests/ui/suggestions/enum-method-probe.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `get` found for enum `Result` in the current scope +error[E0599]: no method named `get` found for enum `Result` in the current scope --> $DIR/enum-method-probe.rs:24:9 | LL | res.get(); @@ -14,7 +14,7 @@ help: use the `?` operator to extract the `Foo` value, propagating a `Result::Er LL | res?.get(); | + -error[E0599]: no method named `get` found for enum `Result` in the current scope +error[E0599]: no method named `get` found for enum `Result` in the current scope --> $DIR/enum-method-probe.rs:39:9 | LL | res.get(); @@ -30,7 +30,7 @@ help: consider using `Result::expect` to unwrap the `Foo` value, panicking if th LL | res.expect("REASON").get(); | +++++++++++++++++ -error[E0599]: no method named `get` found for enum `Result` in the current scope +error[E0599]: no method named `get` found for enum `Result` in the current scope --> $DIR/enum-method-probe.rs:16:9 | LL | res.get(); @@ -46,7 +46,7 @@ help: use the `?` operator to extract the `Foo` value, propagating a `Result::Er LL | res?.get(); | + -error[E0599]: no method named `get` found for enum `Result` in the current scope +error[E0599]: no method named `get` found for enum `Result` in the current scope --> $DIR/enum-method-probe.rs:32:9 | LL | res.get(); @@ -62,7 +62,7 @@ help: consider using `Result::expect` to unwrap the `Foo` value, panicking if th LL | res.expect("REASON").get(); | +++++++++++++++++ -error[E0599]: no method named `get` found for enum `Option` in the current scope +error[E0599]: no method named `get` found for enum `Option` in the current scope --> $DIR/enum-method-probe.rs:46:9 | LL | res.get(); @@ -78,7 +78,7 @@ help: use the `?` operator to extract the `Foo` value, propagating an `Option::N LL | res?.get(); | + -error[E0599]: no method named `get` found for enum `Option` in the current scope +error[E0599]: no method named `get` found for enum `Option` in the current scope --> $DIR/enum-method-probe.rs:54:9 | LL | res.get(); diff --git a/tests/ui/suggestions/field-has-method.rs b/tests/ui/suggestions/field-has-method.rs index d28b6ba546c4a..6e584d7833879 100644 --- a/tests/ui/suggestions/field-has-method.rs +++ b/tests/ui/suggestions/field-has-method.rs @@ -17,7 +17,7 @@ struct InferOk { fn foo(i: InferOk) { let k = i.kind(); - //~^ ERROR no method named `kind` found for struct `InferOk` in the current scope + //~^ ERROR no method named `kind` found for struct `InferOk` in the current scope } fn main() {} diff --git a/tests/ui/suggestions/field-has-method.stderr b/tests/ui/suggestions/field-has-method.stderr index daff2db64189a..adcb723e4f126 100644 --- a/tests/ui/suggestions/field-has-method.stderr +++ b/tests/ui/suggestions/field-has-method.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `kind` found for struct `InferOk` in the current scope +error[E0599]: no method named `kind` found for struct `InferOk` in the current scope --> $DIR/field-has-method.rs:19:15 | LL | struct InferOk { diff --git a/tests/ui/suggestions/inner_type.fixed b/tests/ui/suggestions/inner_type.fixed index 175a2a02acdf8..8174f8e204e5c 100644 --- a/tests/ui/suggestions/inner_type.fixed +++ b/tests/ui/suggestions/inner_type.fixed @@ -15,26 +15,26 @@ fn main() { let other_item = std::cell::RefCell::new(Struct { p: 42_u32 }); other_item.borrow().method(); - //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] //~| HELP use `.borrow()` to borrow the `Struct`, panicking if a mutable borrow exists other_item.borrow_mut().some_mutable_method(); - //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] + //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] //~| HELP .borrow_mut()` to mutably borrow the `Struct`, panicking if any borrows exist let another_item = std::sync::Mutex::new(Struct { p: 42_u32 }); another_item.lock().unwrap().method(); - //~^ ERROR no method named `method` found for struct `std::sync::Mutex` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `std::sync::Mutex` in the current scope [E0599] //~| HELP use `.lock().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired let another_item = std::sync::RwLock::new(Struct { p: 42_u32 }); another_item.read().unwrap().method(); - //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599] //~| HELP use `.read().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired another_item.write().unwrap().some_mutable_method(); - //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] + //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] //~| HELP use `.write().unwrap()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired } diff --git a/tests/ui/suggestions/inner_type.rs b/tests/ui/suggestions/inner_type.rs index ab021414f56ce..e4eaf07ca8b7a 100644 --- a/tests/ui/suggestions/inner_type.rs +++ b/tests/ui/suggestions/inner_type.rs @@ -15,26 +15,26 @@ fn main() { let other_item = std::cell::RefCell::new(Struct { p: 42_u32 }); other_item.method(); - //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] //~| HELP use `.borrow()` to borrow the `Struct`, panicking if a mutable borrow exists other_item.some_mutable_method(); - //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] + //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] //~| HELP .borrow_mut()` to mutably borrow the `Struct`, panicking if any borrows exist let another_item = std::sync::Mutex::new(Struct { p: 42_u32 }); another_item.method(); - //~^ ERROR no method named `method` found for struct `std::sync::Mutex` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `std::sync::Mutex` in the current scope [E0599] //~| HELP use `.lock().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired let another_item = std::sync::RwLock::new(Struct { p: 42_u32 }); another_item.method(); - //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599] //~| HELP use `.read().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired another_item.some_mutable_method(); - //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] + //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] //~| HELP use `.write().unwrap()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired } diff --git a/tests/ui/suggestions/inner_type.stderr b/tests/ui/suggestions/inner_type.stderr index 67ebb5789b70c..017ddb5ad6dee 100644 --- a/tests/ui/suggestions/inner_type.stderr +++ b/tests/ui/suggestions/inner_type.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `method` found for struct `RefCell` in the current scope +error[E0599]: no method named `method` found for struct `RefCell` in the current scope --> $DIR/inner_type.rs:17:16 | LL | other_item.method(); @@ -14,7 +14,7 @@ help: use `.borrow()` to borrow the `Struct`, panicking if a mutable borrow LL | other_item.borrow().method(); | +++++++++ -error[E0599]: no method named `some_mutable_method` found for struct `RefCell` in the current scope +error[E0599]: no method named `some_mutable_method` found for struct `RefCell` in the current scope --> $DIR/inner_type.rs:21:16 | LL | other_item.some_mutable_method(); @@ -30,7 +30,7 @@ help: use `.borrow_mut()` to mutably borrow the `Struct`, panicking if any LL | other_item.borrow_mut().some_mutable_method(); | +++++++++++++ -error[E0599]: no method named `method` found for struct `std::sync::Mutex` in the current scope +error[E0599]: no method named `method` found for struct `std::sync::Mutex` in the current scope --> $DIR/inner_type.rs:27:18 | LL | another_item.method(); @@ -46,7 +46,7 @@ help: use `.lock().unwrap()` to borrow the `Struct`, blocking the current t LL | another_item.lock().unwrap().method(); | ++++++++++++++++ -error[E0599]: no method named `method` found for struct `RwLock` in the current scope +error[E0599]: no method named `method` found for struct `RwLock` in the current scope --> $DIR/inner_type.rs:33:18 | LL | another_item.method(); @@ -62,7 +62,7 @@ help: use `.read().unwrap()` to borrow the `Struct`, blocking the current t LL | another_item.read().unwrap().method(); | ++++++++++++++++ -error[E0599]: no method named `some_mutable_method` found for struct `RwLock` in the current scope +error[E0599]: no method named `some_mutable_method` found for struct `RwLock` in the current scope --> $DIR/inner_type.rs:37:18 | LL | another_item.some_mutable_method(); diff --git a/tests/ui/suggestions/inner_type2.rs b/tests/ui/suggestions/inner_type2.rs index fac68c053eb4f..7082862f409e7 100644 --- a/tests/ui/suggestions/inner_type2.rs +++ b/tests/ui/suggestions/inner_type2.rs @@ -16,11 +16,11 @@ thread_local! { fn main() { STRUCT.method(); - //~^ ERROR no method named `method` found for struct `LocalKey` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `LocalKey` in the current scope [E0599] //~| HELP use `with` or `try_with` to access thread local storage let item = std::mem::MaybeUninit::new(Struct { p: 42_u32 }); item.method(); - //~^ ERROR no method named `method` found for union `MaybeUninit` in the current scope [E0599] + //~^ ERROR no method named `method` found for union `MaybeUninit` in the current scope [E0599] //~| HELP if this `MaybeUninit>` has been initialized, use one of the `assume_init` methods to access the inner value } diff --git a/tests/ui/suggestions/inner_type2.stderr b/tests/ui/suggestions/inner_type2.stderr index 984366123c827..e6cb2048522fd 100644 --- a/tests/ui/suggestions/inner_type2.stderr +++ b/tests/ui/suggestions/inner_type2.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `method` found for struct `LocalKey` in the current scope +error[E0599]: no method named `method` found for struct `LocalKey` in the current scope --> $DIR/inner_type2.rs:18:12 | LL | STRUCT.method(); @@ -11,7 +11,7 @@ note: the method `method` exists on the type `Struct` LL | pub fn method(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -error[E0599]: no method named `method` found for union `MaybeUninit` in the current scope +error[E0599]: no method named `method` found for union `MaybeUninit` in the current scope --> $DIR/inner_type2.rs:23:10 | LL | item.method(); diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs index 7c9ae09349aab..434cf00fc4b4b 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,6 +1,6 @@ //~ ERROR overflow evaluating the requirement ` as Iterator>::Item == ()` //@ build-fail -//@ compile-flags: -Zinline-mir=no +//@ compile-flags: -Zinline-mir=no -Zwrite-long-types-to-disk=yes // Regression test for #91949. // This hanged *forever* on 1.56, fixed by #90423. diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr index c2f09371cf7fc..a179107885ab2 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -24,7 +24,9 @@ LL | impl> Iterator for IteratorOfWrapped { | | | unsatisfied trait bound introduced here = note: 256 redundant requirements hidden - = note: required for `IteratorOfWrapped<(), Map>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>` to implement `Iterator` + = note: required for `IteratorOfWrapped<(), Map>, ...>>` to implement `Iterator` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/issue-91949-hangs-on-recursion.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error; 1 warning emitted From 26c12c746296e01c2dc13d8078b0a2f1569fcb1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 29 Jul 2025 18:39:16 +0000 Subject: [PATCH 07/23] Account for bare tuples in field searching logic When looking for the field names and types of a given type, account for tuples. This allows suggestions for incorrectly nested field accesses and field name typos to trigger as intended. Previously these suggestions only worked on `ty::Adt`, including tuple structs which are no different to tuples, so they should behave the same in suggestions. ``` error[E0599]: no method named `get_ref` found for tuple `(BufReader,)` in the current scope --> $DIR/missing-field-access.rs:11:15 | LL | let x = f.get_ref(); | ^^^^^^^ method not found in `(BufReader,)` | help: one of the expressions' fields has a method of the same name | LL | let x = f.0.get_ref(); | ++ ``` --- compiler/rustc_hir_typeck/src/expr.rs | 51 +++++++++++-------- .../rustc_hir_typeck/src/method/suggest.rs | 3 +- .../coherence/coherence-tuple-conflict.stderr | 2 + tests/ui/consts/issue-19244-1.stderr | 6 +++ tests/ui/diagnostic-width/long-E0609.stderr | 1 + .../ui/offset-of/offset-of-tuple-field.stderr | 48 +++++++++++++++++ tests/ui/parser/float-field.stderr | 6 +++ .../traits/well-formed-recursion-limit.stderr | 4 ++ tests/ui/tuple/index-invalid.stderr | 14 +++++ tests/ui/tuple/missing-field-access.rs | 17 +++++++ tests/ui/tuple/missing-field-access.stderr | 38 ++++++++++++++ .../ui/tuple/tuple-index-out-of-bounds.stderr | 6 +++ 12 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 tests/ui/tuple/missing-field-access.rs create mode 100644 tests/ui/tuple/missing-field-access.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 454ec7ddcafbe..7ec9e7a19bad6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3321,18 +3321,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { (base_ty, "") }; - for (found_fields, args) in + for found_fields in self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, expr.hir_id) { - let field_names = found_fields.iter().map(|field| field.name).collect::>(); + let field_names = found_fields.iter().map(|field| field.0.name).collect::>(); let mut candidate_fields: Vec<_> = found_fields .into_iter() .filter_map(|candidate_field| { self.check_for_nested_field_satisfying_condition_for_diag( span, - &|candidate_field, _| candidate_field.ident(self.tcx()) == field, + &|candidate_field, _| candidate_field == field, candidate_field, - args, vec![], mod_id, expr.hir_id, @@ -3396,7 +3395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_ty: Ty<'tcx>, mod_id: DefId, hir_id: HirId, - ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> { + ) -> Vec)>> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); let mut autoderef = self.autoderef(span, base_ty).silence_errors(); @@ -3422,7 +3421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { return None; } - return Some(( + return Some( fields .iter() .filter(move |field| { @@ -3431,9 +3430,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) // For compile-time reasons put a limit on number of fields we search .take(100) + .map(|field_def| { + ( + field_def.ident(self.tcx).normalize_to_macros_2_0(), + field_def.ty(self.tcx, args), + ) + }) + .collect::>(), + ); + } + ty::Tuple(types) => { + return Some( + types + .iter() + .enumerate() + // For compile-time reasons put a limit on number of fields we search + .take(100) + .map(|(i, ty)| (Ident::from_str(&i.to_string()), ty)) .collect::>(), - *args, - )); + ); } _ => None, } @@ -3446,9 +3461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn check_for_nested_field_satisfying_condition_for_diag( &self, span: Span, - matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool, - candidate_field: &ty::FieldDef, - subst: GenericArgsRef<'tcx>, + matches: &impl Fn(Ident, Ty<'tcx>) -> bool, + candidate_field: (Ident, Ty<'tcx>), mut field_path: Vec, mod_id: DefId, hir_id: HirId, @@ -3463,16 +3477,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // up to a depth of three None } else { - field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); - let field_ty = candidate_field.ty(self.tcx, subst); - if matches(candidate_field, field_ty) { + field_path.push(candidate_field.0); + let field_ty = candidate_field.1; + if matches(candidate_field.0, field_ty) { return Some(field_path); } else { - for (nested_fields, subst) in self - .get_field_candidates_considering_privacy_for_diag( - span, field_ty, mod_id, hir_id, - ) - { + for nested_fields in self.get_field_candidates_considering_privacy_for_diag( + span, field_ty, mod_id, hir_id, + ) { // recursively search fields of `candidate_field` if it's a ty::Adt for field in nested_fields { if let Some(field_path) = self @@ -3480,7 +3492,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, matches, field, - subst, field_path.clone(), mod_id, hir_id, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0c0cc752b01ae..74bfdb5ba0108 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2792,7 +2792,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { if let SelfSource::MethodCall(expr) = source { let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); - for (fields, args) in self.get_field_candidates_considering_privacy_for_diag( + for fields in self.get_field_candidates_considering_privacy_for_diag( span, actual, mod_id, @@ -2831,7 +2831,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) }, candidate_field, - args, vec![], mod_id, expr.hir_id, diff --git a/tests/ui/coherence/coherence-tuple-conflict.stderr b/tests/ui/coherence/coherence-tuple-conflict.stderr index 95f9a1a8841c8..8ce65f79aca98 100644 --- a/tests/ui/coherence/coherence-tuple-conflict.stderr +++ b/tests/ui/coherence/coherence-tuple-conflict.stderr @@ -12,6 +12,8 @@ error[E0609]: no field `dummy` on type `&(A, B)` | LL | fn get(&self) -> usize { self.dummy } | ^^^^^ unknown field + | + = note: available fields are: `0`, `1` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-19244-1.stderr b/tests/ui/consts/issue-19244-1.stderr index 9c1336402e649..7d78f954efeb7 100644 --- a/tests/ui/consts/issue-19244-1.stderr +++ b/tests/ui/consts/issue-19244-1.stderr @@ -3,6 +3,12 @@ error[E0609]: no field `1` on type `(usize,)` | LL | let a: [isize; TUP.1]; | ^ unknown field + | +help: a field with a similar name exists + | +LL - let a: [isize; TUP.1]; +LL + let a: [isize; TUP.0]; + | error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/long-E0609.stderr b/tests/ui/diagnostic-width/long-E0609.stderr index 36ef85457468e..70092ea34bc13 100644 --- a/tests/ui/diagnostic-width/long-E0609.stderr +++ b/tests/ui/diagnostic-width/long-E0609.stderr @@ -4,6 +4,7 @@ error[E0609]: no field `field` on type `(..., ..., ..., ...)` LL | x.field; | ^^^^^ unknown field | + = note: available fields are: `0`, `1`, `2`, `3` = note: the full name for the type has been written to '$TEST_BUILD_DIR/long-E0609.long-type-$LONG_TYPE_HASH.txt' = note: consider using `--verbose` to print the full type name to the console diff --git a/tests/ui/offset-of/offset-of-tuple-field.stderr b/tests/ui/offset-of/offset-of-tuple-field.stderr index 4da0d85165035..e4a5ed09e13ea 100644 --- a/tests/ui/offset-of/offset-of-tuple-field.stderr +++ b/tests/ui/offset-of/offset-of-tuple-field.stderr @@ -15,60 +15,108 @@ error[E0609]: no field `_0` on type `(u8, u8)` | LL | offset_of!((u8, u8), _0); | ^^ + | +help: a field with a similar name exists + | +LL - offset_of!((u8, u8), _0); +LL + offset_of!((u8, u8), 0); + | error[E0609]: no field `01` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:7:26 | LL | offset_of!((u8, u8), 01); | ^^ + | +help: a field with a similar name exists + | +LL - offset_of!((u8, u8), 01); +LL + offset_of!((u8, u8), 0); + | error[E0609]: no field `1e2` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:8:26 | LL | offset_of!((u8, u8), 1e2); | ^^^ + | + = note: available fields are: `0`, `1` error[E0609]: no field `1_` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:9:26 | LL | offset_of!((u8, u8), 1_u8); | ^^^^ + | +help: a field with a similar name exists + | +LL - offset_of!((u8, u8), 1_u8); +LL + offset_of!((u8, u8), 1); + | error[E0609]: no field `1e2` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:12:35 | LL | builtin # offset_of((u8, u8), 1e2); | ^^^ + | + = note: available fields are: `0`, `1` error[E0609]: no field `_0` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:13:35 | LL | builtin # offset_of((u8, u8), _0); | ^^ + | +help: a field with a similar name exists + | +LL - builtin # offset_of((u8, u8), _0); +LL + builtin # offset_of((u8, u8), 0); + | error[E0609]: no field `01` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:14:35 | LL | builtin # offset_of((u8, u8), 01); | ^^ + | +help: a field with a similar name exists + | +LL - builtin # offset_of((u8, u8), 01); +LL + builtin # offset_of((u8, u8), 0); + | error[E0609]: no field `1_` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:15:35 | LL | builtin # offset_of((u8, u8), 1_u8); | ^^^^ + | +help: a field with a similar name exists + | +LL - builtin # offset_of((u8, u8), 1_u8); +LL + builtin # offset_of((u8, u8), 1); + | error[E0609]: no field `2` on type `(u8, u16)` --> $DIR/offset-of-tuple-field.rs:18:47 | LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); | ^ + | +help: a field with a similar name exists + | +LL - offset_of!(((u8, u16), (u32, u16, u8)), 0.2); +LL + offset_of!(((u8, u16), (u32, u16, u8)), 0.0); + | error[E0609]: no field `1e2` on type `(u8, u16)` --> $DIR/offset-of-tuple-field.rs:19:47 | LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); | ^^^ + | + = note: available fields are: `0`, `1` error[E0609]: no field `0` on type `u8` --> $DIR/offset-of-tuple-field.rs:21:49 diff --git a/tests/ui/parser/float-field.stderr b/tests/ui/parser/float-field.stderr index 0cc1b0767dc74..078d16a411729 100644 --- a/tests/ui/parser/float-field.stderr +++ b/tests/ui/parser/float-field.stderr @@ -305,6 +305,8 @@ error[E0609]: no field `1e1` on type `(u8, u8)` | LL | { s.1.1e1; } | ^^^ unknown field + | + = note: available fields are: `0`, `1` error[E0609]: no field `0x1e1` on type `S` --> $DIR/float-field.rs:34:9 @@ -343,12 +345,16 @@ error[E0609]: no field `f32` on type `(u8, u8)` | LL | { s.1.f32; } | ^^^ unknown field + | + = note: available fields are: `0`, `1` error[E0609]: no field `1e1` on type `(u8, u8)` --> $DIR/float-field.rs:71:9 | LL | { s.1.1e1f32; } | ^^^^^^^^ unknown field + | + = note: available fields are: `0`, `1` error: aborting due to 57 previous errors diff --git a/tests/ui/traits/well-formed-recursion-limit.stderr b/tests/ui/traits/well-formed-recursion-limit.stderr index e0270ecabbd8d..a4c85c4fcbdf3 100644 --- a/tests/ui/traits/well-formed-recursion-limit.stderr +++ b/tests/ui/traits/well-formed-recursion-limit.stderr @@ -3,12 +3,16 @@ error[E0609]: no field `ab` on type `(Box<(dyn Fn(Option) -> Option + 'sta | LL | let (ab, ba) = (i.ab, i.ba); | ^^ unknown field + | + = note: available fields are: `0`, `1` error[E0609]: no field `ba` on type `(Box<(dyn Fn(Option) -> Option + 'static)>, Box<(dyn Fn(Option) -> Option + 'static)>)` --> $DIR/well-formed-recursion-limit.rs:12:29 | LL | let (ab, ba) = (i.ab, i.ba); | ^^ unknown field + | + = note: available fields are: `0`, `1` error[E0275]: overflow assigning `_` to `Option<_>` --> $DIR/well-formed-recursion-limit.rs:15:33 diff --git a/tests/ui/tuple/index-invalid.stderr b/tests/ui/tuple/index-invalid.stderr index ae2c275f52cd9..acc4134d1a653 100644 --- a/tests/ui/tuple/index-invalid.stderr +++ b/tests/ui/tuple/index-invalid.stderr @@ -3,18 +3,32 @@ error[E0609]: no field `1` on type `(((),),)` | LL | let _ = (((),),).1.0; | ^ unknown field + | +help: a field with a similar name exists + | +LL - let _ = (((),),).1.0; +LL + let _ = (((),),).0.0; + | error[E0609]: no field `1` on type `((),)` --> $DIR/index-invalid.rs:4:24 | LL | let _ = (((),),).0.1; | ^ unknown field + | +help: a field with a similar name exists + | +LL - let _ = (((),),).0.1; +LL + let _ = (((),),).0.0; + | error[E0609]: no field `000` on type `(((),),)` --> $DIR/index-invalid.rs:6:22 | LL | let _ = (((),),).000.000; | ^^^ unknown field + | + = note: available field is: `0` error: aborting due to 3 previous errors diff --git a/tests/ui/tuple/missing-field-access.rs b/tests/ui/tuple/missing-field-access.rs new file mode 100644 index 0000000000000..4ccd759ccd245 --- /dev/null +++ b/tests/ui/tuple/missing-field-access.rs @@ -0,0 +1,17 @@ +use std::{fs::File, io::BufReader}; + +struct F(BufReader); + +fn main() { + let f = F(BufReader::new(File::open("x").unwrap())); + let x = f.get_ref(); //~ ERROR E0599 + //~^ HELP one of the expressions' fields has a method of the same name + //~| HELP consider pinning the expression + let f = (BufReader::new(File::open("x").unwrap()), ); + let x = f.get_ref(); //~ ERROR E0599 + //~^ HELP one of the expressions' fields has a method of the same name + //~| HELP consider pinning the expression + + // FIXME(estebank): the pinning suggestion should not be included in either case. + // https://github.com/rust-lang/rust/issues/144602 +} diff --git a/tests/ui/tuple/missing-field-access.stderr b/tests/ui/tuple/missing-field-access.stderr new file mode 100644 index 0000000000000..711a8906d6276 --- /dev/null +++ b/tests/ui/tuple/missing-field-access.stderr @@ -0,0 +1,38 @@ +error[E0599]: no method named `get_ref` found for struct `F` in the current scope + --> $DIR/missing-field-access.rs:7:15 + | +LL | struct F(BufReader); + | -------- method `get_ref` not found for this struct +... +LL | let x = f.get_ref(); + | ^^^^^^^ method not found in `F` + | +help: one of the expressions' fields has a method of the same name + | +LL | let x = f.0.get_ref(); + | ++ +help: consider pinning the expression + | +LL ~ let mut pinned = std::pin::pin!(f); +LL ~ let x = pinned.as_ref().get_ref(); + | + +error[E0599]: no method named `get_ref` found for tuple `(BufReader,)` in the current scope + --> $DIR/missing-field-access.rs:11:15 + | +LL | let x = f.get_ref(); + | ^^^^^^^ method not found in `(BufReader,)` + | +help: one of the expressions' fields has a method of the same name + | +LL | let x = f.0.get_ref(); + | ++ +help: consider pinning the expression + | +LL ~ let mut pinned = std::pin::pin!(f); +LL ~ let x = pinned.as_ref().get_ref(); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/tuple/tuple-index-out-of-bounds.stderr b/tests/ui/tuple/tuple-index-out-of-bounds.stderr index 8b3c835c3e3ce..728276909096e 100644 --- a/tests/ui/tuple/tuple-index-out-of-bounds.stderr +++ b/tests/ui/tuple/tuple-index-out-of-bounds.stderr @@ -15,6 +15,12 @@ error[E0609]: no field `2` on type `({integer}, {integer})` | LL | tuple.2; | ^ unknown field + | +help: a field with a similar name exists + | +LL - tuple.2; +LL + tuple.0; + | error: aborting due to 2 previous errors From dd3b8255ca6215b5129181ceb6912aed1370bdce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 29 Jul 2025 20:14:02 +0000 Subject: [PATCH 08/23] Do not suggest pinning missing `.get_ref()` When suggesting field access which would encounter a method not found, do not suggest pinning when those methods are on `impl Pin` itself. ``` error[E0599]: no method named `get_ref` found for tuple `(BufReader,)` in the current scope --> $DIR/missing-field-access.rs:11:15 | LL | let x = f.get_ref(); | ^^^^^^^ method not found in `(BufReader,)` | help: one of the expressions' fields has a method of the same name | LL | let x = f.0.get_ref(); | ++ ``` instead of ``` error[E0599]: no method named `get_ref` found for tuple `(BufReader,)` in the current scope --> $DIR/missing-field-access.rs:11:15 | LL | let x = f.get_ref(); | ^^^^^^^ method not found in `(BufReader,)` | help: one of the expressions' fields has a method of the same name | LL | let x = f.0.get_ref(); | ++ help: consider pinning the expression | LL ~ let mut pinned = std::pin::pin!(f); LL ~ let x = pinned.as_ref().get_ref(); | ``` --- compiler/rustc_hir_typeck/src/method/suggest.rs | 9 ++++++++- tests/ui/tuple/missing-field-access.rs | 9 ++++----- tests/ui/tuple/missing-field-access.stderr | 14 ++------------ 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 74bfdb5ba0108..b368d54865c30 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3585,6 +3585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.lang_items().deref_trait(), self.tcx.lang_items().deref_mut_trait(), self.tcx.lang_items().drop_trait(), + self.tcx.lang_items().pin_type(), self.tcx.get_diagnostic_item(sym::AsRef), ]; // Try alternative arbitrary self types that could fulfill this call. @@ -3670,7 +3671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { debug!("try_alt_rcvr: pick candidate {:?}", pick); - let did = Some(pick.item.container_id(self.tcx)); + let did = pick.item.trait_container(self.tcx); // We don't want to suggest a container type when the missing // method is `.clone()` or `.deref()` otherwise we'd suggest // `Arc::new(foo).clone()`, which is far from what the user wants. @@ -3734,6 +3735,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We skip some common traits that we don't want to consider because autoderefs // would take care of them. && !skippable.contains(&Some(pick.item.container_id(self.tcx))) + && !skippable.contains(&pick.item.impl_container(self.tcx).and_then(|did| { + match self.tcx.type_of(did).instantiate_identity().kind() { + ty::Adt(def, _) => Some(def.did()), + _ => None, + } + })) // We don't want to go through derefs. && pick.autoderefs == 0 // Check that the method of the same name that was found on the new `Pin` diff --git a/tests/ui/tuple/missing-field-access.rs b/tests/ui/tuple/missing-field-access.rs index 4ccd759ccd245..b94b7cf977cde 100644 --- a/tests/ui/tuple/missing-field-access.rs +++ b/tests/ui/tuple/missing-field-access.rs @@ -1,3 +1,7 @@ +// Ensure that suggestions to search for missing intermediary field accesses are available for both +// tuple structs *and* regular tuples. +// Ensure that we do not suggest pinning the expression just because `Pin::get_ref` exists. +// https://github.com/rust-lang/rust/issues/144602 use std::{fs::File, io::BufReader}; struct F(BufReader); @@ -6,12 +10,7 @@ fn main() { let f = F(BufReader::new(File::open("x").unwrap())); let x = f.get_ref(); //~ ERROR E0599 //~^ HELP one of the expressions' fields has a method of the same name - //~| HELP consider pinning the expression let f = (BufReader::new(File::open("x").unwrap()), ); let x = f.get_ref(); //~ ERROR E0599 //~^ HELP one of the expressions' fields has a method of the same name - //~| HELP consider pinning the expression - - // FIXME(estebank): the pinning suggestion should not be included in either case. - // https://github.com/rust-lang/rust/issues/144602 } diff --git a/tests/ui/tuple/missing-field-access.stderr b/tests/ui/tuple/missing-field-access.stderr index 711a8906d6276..fd9f01f8ff6ac 100644 --- a/tests/ui/tuple/missing-field-access.stderr +++ b/tests/ui/tuple/missing-field-access.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `get_ref` found for struct `F` in the current scope - --> $DIR/missing-field-access.rs:7:15 + --> $DIR/missing-field-access.rs:11:15 | LL | struct F(BufReader); | -------- method `get_ref` not found for this struct @@ -11,14 +11,9 @@ help: one of the expressions' fields has a method of the same name | LL | let x = f.0.get_ref(); | ++ -help: consider pinning the expression - | -LL ~ let mut pinned = std::pin::pin!(f); -LL ~ let x = pinned.as_ref().get_ref(); - | error[E0599]: no method named `get_ref` found for tuple `(BufReader,)` in the current scope - --> $DIR/missing-field-access.rs:11:15 + --> $DIR/missing-field-access.rs:14:15 | LL | let x = f.get_ref(); | ^^^^^^^ method not found in `(BufReader,)` @@ -27,11 +22,6 @@ help: one of the expressions' fields has a method of the same name | LL | let x = f.0.get_ref(); | ++ -help: consider pinning the expression - | -LL ~ let mut pinned = std::pin::pin!(f); -LL ~ let x = pinned.as_ref().get_ref(); - | error: aborting due to 2 previous errors From a17e8cfe8f64ed8c14ffa44081f518b617bfbe35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 30 Jul 2025 16:21:40 +0000 Subject: [PATCH 09/23] Do not provide field typo suggestions for tuples and tuple structs --- compiler/rustc_hir_typeck/src/expr.rs | 4 ++++ tests/ui/consts/issue-19244-1.stderr | 6 +----- tests/ui/error-codes/ex-E0612.stderr | 6 +----- .../ui/offset-of/offset-of-tuple-field.stderr | 18 +++--------------- .../tuple-struct-field-naming-47073.stderr | 6 +----- tests/ui/tuple/index-invalid.stderr | 12 ++---------- .../ui/tuple/tuple-index-out-of-bounds.stderr | 12 ++---------- 7 files changed, 14 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7ec9e7a19bad6..edb497b763aea 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2745,6 +2745,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let available_field_names = self.available_field_names(variant, expr, skip_fields); if let Some(field_name) = find_best_match_for_name(&available_field_names, field.ident.name, None) + && !(field.ident.name.as_str().parse::().is_ok() + && field_name.as_str().parse::().is_ok()) { err.span_label(field.ident.span, "unknown field"); err.span_suggestion_verbose( @@ -3360,6 +3362,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } else if let Some(field_name) = find_best_match_for_name(&field_names, field.name, None) + && !(field.name.as_str().parse::().is_ok() + && field_name.as_str().parse::().is_ok()) { err.span_suggestion_verbose( field.span, diff --git a/tests/ui/consts/issue-19244-1.stderr b/tests/ui/consts/issue-19244-1.stderr index 7d78f954efeb7..98a33817b4c8a 100644 --- a/tests/ui/consts/issue-19244-1.stderr +++ b/tests/ui/consts/issue-19244-1.stderr @@ -4,11 +4,7 @@ error[E0609]: no field `1` on type `(usize,)` LL | let a: [isize; TUP.1]; | ^ unknown field | -help: a field with a similar name exists - | -LL - let a: [isize; TUP.1]; -LL + let a: [isize; TUP.0]; - | + = note: available field is: `0` error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/ex-E0612.stderr b/tests/ui/error-codes/ex-E0612.stderr index 54451d3d4526e..e6062f6061db4 100644 --- a/tests/ui/error-codes/ex-E0612.stderr +++ b/tests/ui/error-codes/ex-E0612.stderr @@ -4,11 +4,7 @@ error[E0609]: no field `1` on type `Foo` LL | y.1; | ^ unknown field | -help: a field with a similar name exists - | -LL - y.1; -LL + y.0; - | + = note: available field is: `0` error: aborting due to 1 previous error diff --git a/tests/ui/offset-of/offset-of-tuple-field.stderr b/tests/ui/offset-of/offset-of-tuple-field.stderr index e4a5ed09e13ea..01622c5fa2da6 100644 --- a/tests/ui/offset-of/offset-of-tuple-field.stderr +++ b/tests/ui/offset-of/offset-of-tuple-field.stderr @@ -28,11 +28,7 @@ error[E0609]: no field `01` on type `(u8, u8)` LL | offset_of!((u8, u8), 01); | ^^ | -help: a field with a similar name exists - | -LL - offset_of!((u8, u8), 01); -LL + offset_of!((u8, u8), 0); - | + = note: available fields are: `0`, `1` error[E0609]: no field `1e2` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:8:26 @@ -80,11 +76,7 @@ error[E0609]: no field `01` on type `(u8, u8)` LL | builtin # offset_of((u8, u8), 01); | ^^ | -help: a field with a similar name exists - | -LL - builtin # offset_of((u8, u8), 01); -LL + builtin # offset_of((u8, u8), 0); - | + = note: available fields are: `0`, `1` error[E0609]: no field `1_` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:15:35 @@ -104,11 +96,7 @@ error[E0609]: no field `2` on type `(u8, u16)` LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); | ^ | -help: a field with a similar name exists - | -LL - offset_of!(((u8, u16), (u32, u16, u8)), 0.2); -LL + offset_of!(((u8, u16), (u32, u16, u8)), 0.0); - | + = note: available fields are: `0`, `1` error[E0609]: no field `1e2` on type `(u8, u16)` --> $DIR/offset-of-tuple-field.rs:19:47 diff --git a/tests/ui/structs/tuple-struct-field-naming-47073.stderr b/tests/ui/structs/tuple-struct-field-naming-47073.stderr index efbdaeca4ea03..09ba2fb406a9e 100644 --- a/tests/ui/structs/tuple-struct-field-naming-47073.stderr +++ b/tests/ui/structs/tuple-struct-field-naming-47073.stderr @@ -4,11 +4,7 @@ error[E0609]: no field `00` on type `Verdict` LL | let _condemned = justice.00; | ^^ unknown field | -help: a field with a similar name exists - | -LL - let _condemned = justice.00; -LL + let _condemned = justice.0; - | + = note: available fields are: `0`, `1` error[E0609]: no field `001` on type `Verdict` --> $DIR/tuple-struct-field-naming-47073.rs:11:31 diff --git a/tests/ui/tuple/index-invalid.stderr b/tests/ui/tuple/index-invalid.stderr index acc4134d1a653..fee09b7947c12 100644 --- a/tests/ui/tuple/index-invalid.stderr +++ b/tests/ui/tuple/index-invalid.stderr @@ -4,11 +4,7 @@ error[E0609]: no field `1` on type `(((),),)` LL | let _ = (((),),).1.0; | ^ unknown field | -help: a field with a similar name exists - | -LL - let _ = (((),),).1.0; -LL + let _ = (((),),).0.0; - | + = note: available field is: `0` error[E0609]: no field `1` on type `((),)` --> $DIR/index-invalid.rs:4:24 @@ -16,11 +12,7 @@ error[E0609]: no field `1` on type `((),)` LL | let _ = (((),),).0.1; | ^ unknown field | -help: a field with a similar name exists - | -LL - let _ = (((),),).0.1; -LL + let _ = (((),),).0.0; - | + = note: available field is: `0` error[E0609]: no field `000` on type `(((),),)` --> $DIR/index-invalid.rs:6:22 diff --git a/tests/ui/tuple/tuple-index-out-of-bounds.stderr b/tests/ui/tuple/tuple-index-out-of-bounds.stderr index 728276909096e..2be9d5631f781 100644 --- a/tests/ui/tuple/tuple-index-out-of-bounds.stderr +++ b/tests/ui/tuple/tuple-index-out-of-bounds.stderr @@ -4,11 +4,7 @@ error[E0609]: no field `2` on type `Point` LL | origin.2; | ^ unknown field | -help: a field with a similar name exists - | -LL - origin.2; -LL + origin.0; - | + = note: available fields are: `0`, `1` error[E0609]: no field `2` on type `({integer}, {integer})` --> $DIR/tuple-index-out-of-bounds.rs:12:11 @@ -16,11 +12,7 @@ error[E0609]: no field `2` on type `({integer}, {integer})` LL | tuple.2; | ^ unknown field | -help: a field with a similar name exists - | -LL - tuple.2; -LL + tuple.0; - | + = note: available fields are: `0`, `1` error: aborting due to 2 previous errors From eace82ca42ddffbbda8e2f34444e564ea375580d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 30 Jul 2025 16:32:15 +0000 Subject: [PATCH 10/23] review comment --- compiler/rustc_hir_typeck/src/expr.rs | 56 +++++++++---------- .../rustc_hir_typeck/src/method/suggest.rs | 14 ++--- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index edb497b763aea..0498a9383663a 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3462,52 +3462,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This method is called after we have encountered a missing field error to recursively /// search for the field + #[instrument(skip(self, matches, mod_id, hir_id), level = "debug")] pub(crate) fn check_for_nested_field_satisfying_condition_for_diag( &self, span: Span, matches: &impl Fn(Ident, Ty<'tcx>) -> bool, - candidate_field: (Ident, Ty<'tcx>), + (candidate_name, candidate_ty): (Ident, Ty<'tcx>), mut field_path: Vec, mod_id: DefId, hir_id: HirId, ) -> Option> { - debug!( - "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", - span, candidate_field, field_path - ); - if field_path.len() > 3 { // For compile-time reasons and to avoid infinite recursion we only check for fields // up to a depth of three - None - } else { - field_path.push(candidate_field.0); - let field_ty = candidate_field.1; - if matches(candidate_field.0, field_ty) { - return Some(field_path); - } else { - for nested_fields in self.get_field_candidates_considering_privacy_for_diag( - span, field_ty, mod_id, hir_id, + return None; + } + field_path.push(candidate_name); + if matches(candidate_name, candidate_ty) { + return Some(field_path); + } + for nested_fields in self.get_field_candidates_considering_privacy_for_diag( + span, + candidate_ty, + mod_id, + hir_id, + ) { + // recursively search fields of `candidate_field` if it's a ty::Adt + for field in nested_fields { + if let Some(field_path) = self.check_for_nested_field_satisfying_condition_for_diag( + span, + matches, + field, + field_path.clone(), + mod_id, + hir_id, ) { - // recursively search fields of `candidate_field` if it's a ty::Adt - for field in nested_fields { - if let Some(field_path) = self - .check_for_nested_field_satisfying_condition_for_diag( - span, - matches, - field, - field_path.clone(), - mod_id, - hir_id, - ) - { - return Some(field_path); - } - } + return Some(field_path); } } - None } + None } fn check_expr_index( diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index b368d54865c30..9c5c2ae5b0ad0 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3585,7 +3585,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.lang_items().deref_trait(), self.tcx.lang_items().deref_mut_trait(), self.tcx.lang_items().drop_trait(), - self.tcx.lang_items().pin_type(), self.tcx.get_diagnostic_item(sym::AsRef), ]; // Try alternative arbitrary self types that could fulfill this call. @@ -3720,8 +3719,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !alt_rcvr_sugg // `T: !Unpin` && !unpin - // The method isn't `as_ref`, as it would provide a wrong suggestion for `Pin`. - && sym::as_ref != item_name.name // Either `Pin::as_ref` or `Pin::as_mut`. && let Some(pin_call) = pin_call // Search for `item_name` as a method accessible on `Pin`. @@ -3735,12 +3732,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We skip some common traits that we don't want to consider because autoderefs // would take care of them. && !skippable.contains(&Some(pick.item.container_id(self.tcx))) - && !skippable.contains(&pick.item.impl_container(self.tcx).and_then(|did| { - match self.tcx.type_of(did).instantiate_identity().kind() { - ty::Adt(def, _) => Some(def.did()), - _ => None, + // Do not suggest pinning when the method is directly on `Pin`. + && pick.item.impl_container(self.tcx).map_or(true, |did| { + match self.tcx.type_of(did).skip_binder().kind() { + ty::Adt(def, _) => Some(def.did()) != self.tcx.lang_items().pin_type(), + _ => true, } - })) + }) // We don't want to go through derefs. && pick.autoderefs == 0 // Check that the method of the same name that was found on the new `Pin` From d434cae18f92d8a5ef8996fb579e2c11efbaa2cb Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 1 Mar 2025 03:10:05 +0100 Subject: [PATCH 11/23] Add target_env = "macabi" and target_env = "sim" --- compiler/rustc_codegen_ssa/src/back/apple.rs | 4 +- compiler/rustc_codegen_ssa/src/back/link.rs | 8 ++-- compiler/rustc_metadata/src/native_libs.rs | 2 +- .../rustc_target/src/spec/base/apple/mod.rs | 43 +++++++++++-------- .../rustc_target/src/spec/base/apple/tests.rs | 6 ++- .../src/spec/targets/aarch64_apple_darwin.rs | 4 +- .../src/spec/targets/aarch64_apple_ios.rs | 4 +- .../spec/targets/aarch64_apple_ios_macabi.rs | 4 +- .../src/spec/targets/aarch64_apple_ios_sim.rs | 4 +- .../src/spec/targets/aarch64_apple_tvos.rs | 4 +- .../spec/targets/aarch64_apple_tvos_sim.rs | 4 +- .../spec/targets/aarch64_apple_visionos.rs | 4 +- .../targets/aarch64_apple_visionos_sim.rs | 4 +- .../src/spec/targets/aarch64_apple_watchos.rs | 4 +- .../spec/targets/aarch64_apple_watchos_sim.rs | 4 +- .../spec/targets/arm64_32_apple_watchos.rs | 4 +- .../src/spec/targets/arm64e_apple_darwin.rs | 4 +- .../src/spec/targets/arm64e_apple_ios.rs | 4 +- .../src/spec/targets/arm64e_apple_tvos.rs | 4 +- .../src/spec/targets/armv7k_apple_watchos.rs | 4 +- .../src/spec/targets/armv7s_apple_ios.rs | 4 +- .../src/spec/targets/i386_apple_ios.rs | 4 +- .../src/spec/targets/i686_apple_darwin.rs | 4 +- .../src/spec/targets/x86_64_apple_darwin.rs | 4 +- .../src/spec/targets/x86_64_apple_ios.rs | 4 +- .../spec/targets/x86_64_apple_ios_macabi.rs | 4 +- .../src/spec/targets/x86_64_apple_tvos.rs | 4 +- .../spec/targets/x86_64_apple_watchos_sim.rs | 4 +- .../src/spec/targets/x86_64h_apple_darwin.rs | 4 +- .../src/platform-support/apple-ios-macabi.md | 11 +++++ .../rustc/src/platform-support/apple-ios.md | 14 ++++++ src/tools/compiletest/src/directives/tests.rs | 7 +-- tests/ui/check-cfg/well-known-values.stderr | 2 +- 33 files changed, 112 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs index d242efaf4fd42..2f68bad1695b5 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple.rs @@ -17,7 +17,7 @@ mod tests; /// The canonical name of the desired SDK for a given target. pub(super) fn sdk_name(target: &Target) -> &'static str { - match (&*target.os, &*target.abi) { + match (&*target.os, &*target.env) { ("macos", "") => "MacOSX", ("ios", "") => "iPhoneOS", ("ios", "sim") => "iPhoneSimulator", @@ -34,7 +34,7 @@ pub(super) fn sdk_name(target: &Target) -> &'static str { } pub(super) fn macho_platform(target: &Target) -> u32 { - match (&*target.os, &*target.abi) { + match (&*target.os, &*target.env) { ("macos", _) => object::macho::PLATFORM_MACOS, ("ios", "macabi") => object::macho::PLATFORM_MACCATALYST, ("ios", "sim") => object::macho::PLATFORM_IOSSIMULATOR, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b69fbf61185d7..6e21f54587f60 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3026,7 +3026,7 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool /// We need to communicate five things to the linker on Apple/Darwin targets: /// - The architecture. /// - The operating system (and that it's an Apple platform). -/// - The environment / ABI. +/// - The environment. /// - The deployment target. /// - The SDK version. fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { @@ -3040,7 +3040,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // `sess.target.arch` (`target_arch`) is not detailed enough. let llvm_arch = sess.target.llvm_target.split_once('-').expect("LLVM target must have arch").0; let target_os = &*sess.target.os; - let target_abi = &*sess.target.abi; + let target_env = &*sess.target.env; // The architecture name to forward to the linker. // @@ -3091,14 +3091,14 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // > - visionos-simulator // > - xros-simulator // > - driverkit - let platform_name = match (target_os, target_abi) { + let platform_name = match (target_os, target_env) { (os, "") => os, ("ios", "macabi") => "mac-catalyst", ("ios", "sim") => "ios-simulator", ("tvos", "sim") => "tvos-simulator", ("watchos", "sim") => "watchos-simulator", ("visionos", "sim") => "visionos-simulator", - _ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"), + _ => bug!("invalid OS/env combination for Apple target: {target_os}, {target_env}"), }; let min_version = sess.apple_deployment_target().fmt_full().to_string(); diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 8855766ca98f8..958e314efabb4 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -83,7 +83,7 @@ pub fn walk_native_lib_search_dirs( // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks // we must have the support library stubs in the library search path (#121430). if let Some(sdk_root) = apple_sdk_root - && sess.target.llvm_target.contains("macabi") + && sess.target.env == "macabi" { f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?; f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?; diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index aa6d1ec7009e7..da9f96ce37d35 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -51,14 +51,14 @@ impl Arch { }) } - fn target_cpu(self, abi: TargetAbi) -> &'static str { + fn target_cpu(self, env: TargetEnv) -> &'static str { match self { Armv7k => "cortex-a8", Armv7s => "swift", // iOS 10 is only supported on iPhone 5 or higher. - Arm64 => match abi { - TargetAbi::Normal => "apple-a7", - TargetAbi::Simulator => "apple-a12", - TargetAbi::MacCatalyst => "apple-a12", + Arm64 => match env { + TargetEnv::Normal => "apple-a7", + TargetEnv::Simulator => "apple-a12", + TargetEnv::MacCatalyst => "apple-a12", }, Arm64e => "apple-a12", Arm64_32 => "apple-s4", @@ -83,14 +83,14 @@ impl Arch { } #[derive(Copy, Clone, PartialEq)] -pub(crate) enum TargetAbi { +pub(crate) enum TargetEnv { Normal, Simulator, MacCatalyst, } -impl TargetAbi { - fn target_abi(self) -> &'static str { +impl TargetEnv { + fn target_env(self) -> &'static str { match self { Self::Normal => "", Self::MacCatalyst => "macabi", @@ -104,13 +104,20 @@ impl TargetAbi { pub(crate) fn base( os: &'static str, arch: Arch, - abi: TargetAbi, + env: TargetEnv, ) -> (TargetOptions, StaticCow, StaticCow) { let mut opts = TargetOptions { - abi: abi.target_abi().into(), llvm_floatabi: Some(FloatAbi::Hard), os: os.into(), - cpu: arch.target_cpu(abi).into(), + env: env.target_env().into(), + // NOTE: We originally set `cfg(target_abi = "macabi")` / `cfg(target_abi = "sim")`, + // before it was discovered that those are actually environments: + // https://github.com/rust-lang/rust/issues/133331 + // + // But let's continue setting them for backwards compatibility. + // FIXME(madsmtm): Warn about using these in the future. + abi: env.target_env().into(), + cpu: arch.target_cpu(env).into(), link_env_remove: link_env_remove(os), vendor: "apple".into(), linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No), @@ -168,14 +175,14 @@ pub(crate) fn base( // All Apple x86-32 targets have SSE2. opts.rustc_abi = Some(RustcAbi::X86Sse2); } - (opts, unversioned_llvm_target(os, arch, abi), arch.target_arch()) + (opts, unversioned_llvm_target(os, arch, env), arch.target_arch()) } /// Generate part of the LLVM target triple. /// /// See `rustc_codegen_ssa::back::versioned_llvm_target` for the full triple passed to LLVM and /// Clang. -fn unversioned_llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow { +fn unversioned_llvm_target(os: &str, arch: Arch, env: TargetEnv) -> StaticCow { let arch = arch.target_name(); // Convert to the "canonical" OS name used by LLVM: // https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L236-L282 @@ -187,10 +194,10 @@ fn unversioned_llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow "xros", _ => unreachable!("tried to get LLVM target OS for non-Apple platform"), }; - let environment = match abi { - TargetAbi::Normal => "", - TargetAbi::MacCatalyst => "-macabi", - TargetAbi::Simulator => "-simulator", + let environment = match env { + TargetEnv::Normal => "", + TargetEnv::MacCatalyst => "-macabi", + TargetEnv::Simulator => "-simulator", }; format!("{arch}-apple-{os}{environment}").into() } @@ -309,7 +316,7 @@ impl OSVersion { /// This matches what LLVM does, see in part: /// pub fn minimum_deployment_target(target: &Target) -> Self { - let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.abi) { + let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.env) { ("macos", "aarch64", _) => (11, 0, 0), ("ios", "aarch64", "macabi") => (14, 0, 0), ("ios", "aarch64", "sim") => (14, 0, 0), diff --git a/compiler/rustc_target/src/spec/base/apple/tests.rs b/compiler/rustc_target/src/spec/base/apple/tests.rs index 391f347010436..bca86ce33c3d9 100644 --- a/compiler/rustc_target/src/spec/base/apple/tests.rs +++ b/compiler/rustc_target/src/spec/base/apple/tests.rs @@ -6,7 +6,7 @@ use crate::spec::targets::{ }; #[test] -fn simulator_targets_set_abi() { +fn simulator_targets_set_env() { let all_sim_targets = [ x86_64_apple_ios::target(), x86_64_apple_tvos::target(), @@ -18,7 +18,9 @@ fn simulator_targets_set_abi() { ]; for target in &all_sim_targets { - assert_eq!(target.abi, "sim") + assert_eq!(target.env, "sim"); + // Ensure backwards compat + assert_eq!(target.abi, "sim"); } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index 4dd39877715a7..e19604725559a 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("macos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("macos", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs index 769a7b6c3919e..3b522c34522b0 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index 4bb2f73e4f9fd..4d6a3103ee307 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::MacCatalyst); + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetEnv::MacCatalyst); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs index 7d04034e759b4..d366ed264820b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index ec92a40e255fb..7aef6f96e1c5f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs index 74fbe5a89ca7c..f0d17db873bf2 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs index dc595fbe7b6c1..22ce52e637f3b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs index 06ff1bfb2f071..21739ba9fdb7b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs index 2359627110729..2e88f95f1dd81 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs index bad9f6c1485c8..272dc682dc0e4 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs index 4c3a2f4374387..564ac2cd7081f 100644 --- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::Arm64_32, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64_32, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs index 326f2b16d594f..86e178a95728c 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("macos", Arch::Arm64e, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("macos", Arch::Arm64e, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs index 01c6f0b888d65..dae3f77d7ae39 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Arm64e, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("ios", Arch::Arm64e, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs index cad3650bda1a4..a99fc5dc68c94 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("tvos", Arch::Arm64e, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("tvos", Arch::Arm64e, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs index 8103d132cea81..df58559848a0c 100644 --- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::Armv7k, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("watchos", Arch::Armv7k, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs index ba9edd714612d..63259043b73d7 100644 --- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Armv7s, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("ios", Arch::Armv7s, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs index 29865fcd4c4ed..a919be765a27f 100644 --- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { // i386-apple-ios is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let (opts, llvm_target, arch) = base("ios", Arch::I386, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("ios", Arch::I386, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index d1339c57b0088..96c477d523676 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("macos", Arch::I686, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("macos", Arch::I686, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index eba595ba7dd24..53e2cb469ee82 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs index df45f430ecbfa..d74a688fa0f71 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { // x86_64-apple-ios is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index ee0c2bf31cd47..193e26f94c98b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetAbi::MacCatalyst); + let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetEnv::MacCatalyst); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs index 80ca80013f05f..e69bd17a04969 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { // x86_64-apple-tvos is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let (opts, llvm_target, arch) = base("tvos", Arch::X86_64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("tvos", Arch::X86_64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs index c503baedb8b50..9490ca6aa36c9 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::X86_64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("watchos", Arch::X86_64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index e64556c4132ab..67b5a160a89a5 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetAbi::Normal); + let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetEnv::Normal); opts.max_atomic_width = Some(128); opts.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md index d4b71dbd4f492..c6f68f7a1e812 100644 --- a/src/doc/rustc/src/platform-support/apple-ios-macabi.md +++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md @@ -56,6 +56,17 @@ Rust programs can be built for these targets by specifying `--target`, if $ rustc --target aarch64-apple-ios-macabi your-code.rs ``` +The target can be differentiated from the iOS targets with the +`target_env = "macabi"` cfg (or `target_abi = "macabi"` before Rust CURRENT_RUSTC_VERSION). + +```rust +if cfg!(target_env = "macabi") { + // Do something only on Mac Catalyst. +} +``` + +This is similar to the `TARGET_OS_MACCATALYST` define in C code. + ## Testing Mac Catalyst binaries can be run directly on macOS 10.15 Catalina or newer. diff --git a/src/doc/rustc/src/platform-support/apple-ios.md b/src/doc/rustc/src/platform-support/apple-ios.md index 64325554ab60b..586afa652262b 100644 --- a/src/doc/rustc/src/platform-support/apple-ios.md +++ b/src/doc/rustc/src/platform-support/apple-ios.md @@ -66,6 +66,20 @@ Rust programs can be built for these targets by specifying `--target`, if $ rustc --target aarch64-apple-ios your-code.rs ``` +The simulator variants can be differentiated from the variants running +on-device with the `target_env = "sim"` cfg (or `target_abi = "sim"` before +Rust CURRENT_RUSTC_VERSION). + +```rust +if cfg!(all(target_vendor = "apple", target_env = "sim")) { + // Do something on the iOS/tvOS/visionOS/watchOS Simulator. +} { + // Everything else, like Windows and non-Simulator iOS. +} +``` + +This is similar to the `TARGET_OS_SIMULATOR` define in C code. + ## Testing There is no support for running the Rust or standard library testsuite at the diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 30d8537b51a56..33a02eb29fd53 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -637,6 +637,7 @@ fn matches_env() { ("x86_64-unknown-linux-gnu", "gnu"), ("x86_64-fortanix-unknown-sgx", "sgx"), ("arm-unknown-linux-musleabi", "musl"), + ("aarch64-apple-ios-macabi", "macabi"), ]; for (target, env) in envs { let config: Config = cfg().target(target).build(); @@ -647,11 +648,7 @@ fn matches_env() { #[test] fn matches_abi() { - let abis = [ - ("aarch64-apple-ios-macabi", "macabi"), - ("x86_64-unknown-linux-gnux32", "x32"), - ("arm-unknown-linux-gnueabi", "eabi"), - ]; + let abis = [("x86_64-unknown-linux-gnux32", "x32"), ("arm-unknown-linux-gnueabi", "eabi")]; for (target, abi) in abis { let config: Config = cfg().target(target).build(); assert!(config.matches_abi(abi), "{target} {abi}"); diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index b2186f85b8ac2..18e038a442eee 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `nto80`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, `uclibc`, and `v5` + = note: expected values for `target_env` are: ``, `gnu`, `macabi`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `nto80`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, `sim`, `uclibc`, and `v5` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From 2054a0c56b063c195d316e4ff44d0c9f8ad2c012 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 28 Jul 2025 03:00:24 -0700 Subject: [PATCH 12/23] mbe: In error messages, don't assume attributes are always proc macros Now that `macro_rules` macros can define attribute rules, make sure error messages account for that. --- compiler/rustc_errors/src/emitter.rs | 2 +- .../tests/fail/alloc/alloc_error_handler_custom.stderr | 2 +- .../alloc-error-handler-bad-signature-1.stderr | 4 ++-- .../alloc-error-handler-bad-signature-2.stderr | 4 ++-- .../alloc-error-handler-bad-signature-3.stderr | 2 +- tests/ui/allocator/not-an-allocator.stderr | 8 ++++---- tests/ui/allocator/two-allocators.stderr | 2 +- tests/ui/custom_test_frameworks/mismatch.stderr | 2 +- tests/ui/proc-macro/span-from-proc-macro.stderr | 2 +- .../termination-trait-test-wrong-type.stderr | 2 +- tests/ui/test-attrs/issue-12997-2.stderr | 2 +- tests/ui/test-attrs/test-function-signature.stderr | 2 +- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 84970e7c162b2..0c839f94f7f10 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -409,7 +409,7 @@ pub trait Emitter { if !redundant_span || always_backtrace { let msg: Cow<'static, _> = match trace.kind { ExpnKind::Macro(MacroKind::Attr, _) => { - "this procedural macro expansion".into() + "this attribute macro expansion".into() } ExpnKind::Macro(MacroKind::Derive, _) => { "this derive macro expansion".into() diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr index 29c56ca81f752..a2a4be30eca4a 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr @@ -11,7 +11,7 @@ note: inside `_::__rg_oom` --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC | LL | #[alloc_error_handler] - | ---------------------- in this procedural macro expansion + | ---------------------- in this attribute macro expansion LL | fn alloc_error_handler(layout: Layout) -> ! { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr index 15314fac37b2c..aad45c422e2b8 100644 --- a/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/alloc-error-handler-bad-signature-1.rs:10:1 | LL | #[alloc_error_handler] - | ---------------------- in this procedural macro expansion + | ---------------------- in this attribute macro expansion LL | // fn oom( LL | || info: &Layout, LL | || ) -> () @@ -23,7 +23,7 @@ error[E0308]: mismatched types --> $DIR/alloc-error-handler-bad-signature-1.rs:10:1 | LL | #[alloc_error_handler] - | ---------------------- in this procedural macro expansion + | ---------------------- in this attribute macro expansion LL | // fn oom( LL | || info: &Layout, LL | || ) -> () diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr index 2ab4263841128..581d19474191f 100644 --- a/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/alloc-error-handler-bad-signature-2.rs:10:1 | LL | #[alloc_error_handler] - | ---------------------- in this procedural macro expansion + | ---------------------- in this attribute macro expansion LL | // fn oom( LL | || info: Layout, LL | || ) { @@ -31,7 +31,7 @@ error[E0308]: mismatched types --> $DIR/alloc-error-handler-bad-signature-2.rs:10:1 | LL | #[alloc_error_handler] - | ---------------------- in this procedural macro expansion + | ---------------------- in this attribute macro expansion LL | // fn oom( LL | || info: Layout, LL | || ) { diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr index 3a410174f548e..91147df71eb4e 100644 --- a/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/alloc-error-handler-bad-signature-3.rs:10:1 | LL | #[alloc_error_handler] - | ---------------------- in this procedural macro expansion + | ---------------------- in this attribute macro expansion LL | fn oom() -> ! { | _-^^^^^^^^^^^^ LL | | loop {} diff --git a/tests/ui/allocator/not-an-allocator.stderr b/tests/ui/allocator/not-an-allocator.stderr index 079bf9334ebc3..f33a698ed7817 100644 --- a/tests/ui/allocator/not-an-allocator.stderr +++ b/tests/ui/allocator/not-an-allocator.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:11 | LL | #[global_allocator] - | ------------------- in this procedural macro expansion + | ------------------- in this attribute macro expansion LL | static A: usize = 0; | ^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | @@ -12,7 +12,7 @@ error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:11 | LL | #[global_allocator] - | ------------------- in this procedural macro expansion + | ------------------- in this attribute macro expansion LL | static A: usize = 0; | ^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | @@ -23,7 +23,7 @@ error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:11 | LL | #[global_allocator] - | ------------------- in this procedural macro expansion + | ------------------- in this attribute macro expansion LL | static A: usize = 0; | ^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | @@ -34,7 +34,7 @@ error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:11 | LL | #[global_allocator] - | ------------------- in this procedural macro expansion + | ------------------- in this attribute macro expansion LL | static A: usize = 0; | ^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | diff --git a/tests/ui/allocator/two-allocators.stderr b/tests/ui/allocator/two-allocators.stderr index 5308232a20b59..1a9a5910eecc4 100644 --- a/tests/ui/allocator/two-allocators.stderr +++ b/tests/ui/allocator/two-allocators.stderr @@ -4,7 +4,7 @@ error: cannot define multiple global allocators LL | static A: System = System; | -------------------------- previous global allocator defined here LL | #[global_allocator] - | ------------------- in this procedural macro expansion + | ------------------- in this attribute macro expansion LL | static B: System = System; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot define a new global allocator diff --git a/tests/ui/custom_test_frameworks/mismatch.stderr b/tests/ui/custom_test_frameworks/mismatch.stderr index c7798635fbf17..7cdfaa9e804ee 100644 --- a/tests/ui/custom_test_frameworks/mismatch.stderr +++ b/tests/ui/custom_test_frameworks/mismatch.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `TestDescAndFn: Testable` is not satisfied --> $DIR/mismatch.rs:9:1 | LL | #[test] - | ------- in this procedural macro expansion + | ------- in this attribute macro expansion LL | fn wrong_kind(){} | ^^^^^^^^^^^^^^^^^ the trait `Testable` is not implemented for `TestDescAndFn` | diff --git a/tests/ui/proc-macro/span-from-proc-macro.stderr b/tests/ui/proc-macro/span-from-proc-macro.stderr index 452c04df8779e..c79ab04eadf4e 100644 --- a/tests/ui/proc-macro/span-from-proc-macro.stderr +++ b/tests/ui/proc-macro/span-from-proc-macro.stderr @@ -10,7 +10,7 @@ LL | field: MissingType ::: $DIR/span-from-proc-macro.rs:8:1 | LL | #[error_from_attribute] - | ----------------------- in this procedural macro expansion + | ----------------------- in this attribute macro expansion error[E0412]: cannot find type `OtherMissingType` in this scope --> $DIR/auxiliary/span-from-proc-macro.rs:42:21 diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index b89c5e8dda840..020c2e6f24198 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `f32: Termination` is not satisfied --> $DIR/termination-trait-test-wrong-type.rs:6:31 | LL | #[test] - | ------- in this procedural macro expansion + | ------- in this attribute macro expansion LL | fn can_parse_zero_as_f32() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32` | diff --git a/tests/ui/test-attrs/issue-12997-2.stderr b/tests/ui/test-attrs/issue-12997-2.stderr index 1123630a4a1f1..41d0074ad1a20 100644 --- a/tests/ui/test-attrs/issue-12997-2.stderr +++ b/tests/ui/test-attrs/issue-12997-2.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-12997-2.rs:8:1 | LL | #[bench] - | -------- in this procedural macro expansion + | -------- in this attribute macro expansion LL | fn bar(x: isize) { } | ^^^^^^^^^^^^^^^^^^^^ | | diff --git a/tests/ui/test-attrs/test-function-signature.stderr b/tests/ui/test-attrs/test-function-signature.stderr index c025163c0bd9c..55d09970b3203 100644 --- a/tests/ui/test-attrs/test-function-signature.stderr +++ b/tests/ui/test-attrs/test-function-signature.stderr @@ -26,7 +26,7 @@ error[E0277]: the trait bound `i32: Termination` is not satisfied --> $DIR/test-function-signature.rs:9:13 | LL | #[test] - | ------- in this procedural macro expansion + | ------- in this attribute macro expansion LL | fn bar() -> i32 { | ^^^ the trait `Termination` is not implemented for `i32` | From bad0d45b2dc2b2be36e9e82604a6c3dd95dba08a Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 6 Jul 2025 15:15:01 -0700 Subject: [PATCH 13/23] mbe: Parse macro attribute rules This handles various kinds of errors, but does not allow applying the attributes yet. This adds the feature gate `macro_attr`. --- compiler/rustc_expand/messages.ftl | 3 + compiler/rustc_expand/src/errors.rs | 18 ++++ compiler/rustc_expand/src/mbe/diagnostics.rs | 3 +- compiler/rustc_expand/src/mbe/macro_check.rs | 6 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 96 +++++++++++++++---- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + .../feature-gates/feature-gate-macro-attr.rs | 4 + .../feature-gate-macro-attr.stderr | 13 +++ tests/ui/parser/macro/macro-attr-bad.rs | 32 +++++++ tests/ui/parser/macro/macro-attr-bad.stderr | 80 ++++++++++++++++ 11 files changed, 238 insertions(+), 20 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-macro-attr.rs create mode 100644 tests/ui/feature-gates/feature-gate-macro-attr.stderr create mode 100644 tests/ui/parser/macro/macro-attr-bad.rs create mode 100644 tests/ui/parser/macro/macro-attr-bad.stderr diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 5a53670c865d4..1f8f3be68092a 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -70,6 +70,9 @@ expand_invalid_fragment_specifier = invalid fragment specifier `{$fragment}` .help = {$help} +expand_macro_args_bad_delim = macro attribute argument matchers require parentheses +expand_macro_args_bad_delim_sugg = the delimiters should be `(` and `)` + expand_macro_body_stability = macros cannot have body stability attributes .label = invalid body stability attribute diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index fd1391a554a8a..e58269991fcb0 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -482,3 +482,21 @@ mod metavar_exprs { pub key: MacroRulesNormalizedIdent, } } + +#[derive(Diagnostic)] +#[diag(expand_macro_args_bad_delim)] +pub(crate) struct MacroArgsBadDelim { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: MacroArgsBadDelimSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(expand_macro_args_bad_delim_sugg, applicability = "machine-applicable")] +pub(crate) struct MacroArgsBadDelimSugg { + #[suggestion_part(code = "(")] + pub open: Span, + #[suggestion_part(code = ")")] + pub close: Span, +} diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 7a280d671f413..468488ebf7d0d 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -81,11 +81,12 @@ pub(super) fn failed_to_match_macro( // Check whether there's a missing comma in this macro call, like `println!("{}" a);` if let Some((arg, comma_span)) = arg.add_comma() { for rule in rules { + let MacroRule::Func { lhs, .. } = rule else { continue }; let parser = parser_from_cx(psess, arg.clone(), Recovery::Allowed); let mut tt_parser = TtParser::new(name); if let Success(_) = - tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, &mut NoopTracker) + tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) { if comma_span.is_dummy() { err.note("you might be missing a comma"); diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index bbdff866feba4..25987a5036635 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -193,15 +193,19 @@ struct MacroState<'a> { /// Arguments: /// - `psess` is used to emit diagnostics and lints /// - `node_id` is used to emit lints -/// - `lhs` and `rhs` represent the rule +/// - `args`, `lhs`, and `rhs` represent the rule pub(super) fn check_meta_variables( psess: &ParseSess, node_id: NodeId, + args: Option<&TokenTree>, lhs: &TokenTree, rhs: &TokenTree, ) -> Result<(), ErrorGuaranteed> { let mut guar = None; let mut binders = Binders::default(); + if let Some(args) = args { + check_binders(psess, node_id, args, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); + } check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar); guar.map_or(Ok(()), Err) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 52d38c35f9808..d72f01a4dbda4 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -6,12 +6,12 @@ use std::{mem, slice}; use ast::token::IdentIsRaw; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; -use rustc_ast::token::{self, NonterminalKind, Token, TokenKind}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; +use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; +use rustc_ast::tokenstream::{self, DelimSpan, TokenStream}; use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; @@ -23,7 +23,7 @@ use rustc_lint_defs::builtin::{ use rustc_parse::exp; use rustc_parse::parser::{Parser, Recovery}; use rustc_session::Session; -use rustc_session::parse::ParseSess; +use rustc_session::parse::{ParseSess, feature_err}; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; use rustc_span::{Ident, Span, kw, sym}; @@ -35,11 +35,13 @@ use crate::base::{ DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, }; +use crate::errors; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; +use crate::mbe::macro_check::check_meta_variables; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser}; use crate::mbe::quoted::{RulePart, parse_one_tt}; use crate::mbe::transcribe::transcribe; -use crate::mbe::{self, KleeneOp, macro_check}; +use crate::mbe::{self, KleeneOp}; pub(crate) struct ParserAnyMacro<'a> { parser: Parser<'a>, @@ -123,10 +125,18 @@ impl<'a> ParserAnyMacro<'a> { } } -pub(super) struct MacroRule { - pub(super) lhs: Vec, - lhs_span: Span, - rhs: mbe::TokenTree, +pub(super) enum MacroRule { + /// A function-style rule, for use with `m!()` + Func { lhs: Vec, lhs_span: Span, rhs: mbe::TokenTree }, + /// An attr rule, for use with `#[m]` + #[expect(unused)] + Attr { + args: Vec, + args_span: Span, + body: Vec, + body_span: Span, + rhs: mbe::TokenTree, + }, } pub struct MacroRulesMacroExpander { @@ -138,10 +148,15 @@ pub struct MacroRulesMacroExpander { } impl MacroRulesMacroExpander { - pub fn get_unused_rule(&self, rule_i: usize) -> Option<(&Ident, Span)> { + pub fn get_unused_rule(&self, rule_i: usize) -> Option<(&Ident, MultiSpan)> { // If the rhs contains an invocation like `compile_error!`, don't report it as unused. - let rule = &self.rules[rule_i]; - if has_compile_error_macro(&rule.rhs) { None } else { Some((&self.name, rule.lhs_span)) } + let (span, rhs) = match self.rules[rule_i] { + MacroRule::Func { lhs_span, ref rhs, .. } => (MultiSpan::from_span(lhs_span), rhs), + MacroRule::Attr { args_span, body_span, ref rhs, .. } => { + (MultiSpan::from_spans(vec![args_span, body_span]), rhs) + } + }; + if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) } } } @@ -245,14 +260,17 @@ fn expand_macro<'cx>( match try_success_result { Ok((rule_index, rule, named_matches)) => { - let mbe::TokenTree::Delimited(rhs_span, _, ref rhs) = rule.rhs else { + let MacroRule::Func { rhs, .. } = rule else { + panic!("try_match_macro returned non-func rule"); + }; + let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { cx.dcx().span_bug(sp, "malformed macro rhs"); }; - let arm_span = rule.rhs.span(); + let arm_span = rhs_span.entire(); // rhs has holes ( `$id` and `$(...)` that need filled) let id = cx.current_expansion.id; - let tts = match transcribe(psess, &named_matches, rhs, rhs_span, transparency, id) { + let tts = match transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) { Ok(tts) => tts, Err(err) => { let guar = err.emit(); @@ -327,6 +345,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( // Try each arm's matchers. let mut tt_parser = TtParser::new(name); for (i, rule) in rules.iter().enumerate() { + let MacroRule::Func { lhs, .. } = rule else { continue }; let _tracing_span = trace_span!("Matching arm", %i); // Take a snapshot of the state of pre-expansion gating at this point. @@ -335,7 +354,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut()); - let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, track); + let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, track); track.after_arm(&result); @@ -404,6 +423,25 @@ pub fn compile_declarative_macro( let mut rules = Vec::new(); while p.token != token::Eof { + let args = if p.eat_keyword_noexpect(sym::attr) { + if !features.macro_attr() { + feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable") + .emit(); + } + if let Some(guar) = check_no_eof(sess, &p, "expected macro attr args") { + return dummy_syn_ext(guar); + } + let args = p.parse_token_tree(); + check_args_parens(sess, &args); + let args = parse_one_tt(args, RulePart::Pattern, sess, node_id, features, edition); + check_emission(check_lhs(sess, node_id, &args)); + if let Some(guar) = check_no_eof(sess, &p, "expected macro attr body") { + return dummy_syn_ext(guar); + } + Some(args) + } else { + None + }; let lhs_tt = p.parse_token_tree(); let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition); check_emission(check_lhs(sess, node_id, &lhs_tt)); @@ -416,7 +454,7 @@ pub fn compile_declarative_macro( let rhs_tt = p.parse_token_tree(); let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition); check_emission(check_rhs(sess, &rhs_tt)); - check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt)); + check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs_tt)); let lhs_span = lhs_tt.span(); // Convert the lhs into `MatcherLoc` form, which is better for doing the // actual matching. @@ -425,7 +463,17 @@ pub fn compile_declarative_macro( } else { return dummy_syn_ext(guar.unwrap()); }; - rules.push(MacroRule { lhs, lhs_span, rhs: rhs_tt }); + if let Some(args) = args { + let args_span = args.span(); + let mbe::TokenTree::Delimited(.., delimited) = args else { + return dummy_syn_ext(guar.unwrap()); + }; + let args = mbe::macro_parser::compute_locs(&delimited.tts); + let body_span = lhs_span; + rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt }); + } else { + rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt }); + } if p.token == token::Eof { break; } @@ -469,6 +517,18 @@ fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option Result<(), ErrorGuaranteed> { let e1 = check_lhs_nt_follows(sess, node_id, lhs); let e2 = check_lhs_no_empty_seq(sess, slice::from_ref(lhs)); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ca71bcebfdd3a..ae1f57c1ef610 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -554,6 +554,8 @@ declare_features! ( (unstable, link_arg_attribute, "1.76.0", Some(99427)), /// Allows fused `loop`/`match` for direct intraprocedural jumps. (incomplete, loop_match, "1.90.0", Some(132306)), + /// Allow `macro_rules!` attribute rules + (unstable, macro_attr, "CURRENT_RUSTC_VERSION", Some(83527)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 36197950221ee..5462ed38dd3db 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1311,6 +1311,7 @@ symbols! { lt, m68k_target_feature, macro_at_most_once_rep, + macro_attr, macro_attributes_in_derive_output, macro_concat, macro_escape, diff --git a/tests/ui/feature-gates/feature-gate-macro-attr.rs b/tests/ui/feature-gates/feature-gate-macro-attr.rs new file mode 100644 index 0000000000000..8419d85114725 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-attr.rs @@ -0,0 +1,4 @@ +#![crate_type = "lib"] + +macro_rules! myattr { attr() {} => {} } +//~^ ERROR `macro_rules!` attributes are unstable diff --git a/tests/ui/feature-gates/feature-gate-macro-attr.stderr b/tests/ui/feature-gates/feature-gate-macro-attr.stderr new file mode 100644 index 0000000000000..b58418527c5b0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-attr.stderr @@ -0,0 +1,13 @@ +error[E0658]: `macro_rules!` attributes are unstable + --> $DIR/feature-gate-macro-attr.rs:3:1 + | +LL | macro_rules! myattr { attr() {} => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_attr)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/macro/macro-attr-bad.rs b/tests/ui/parser/macro/macro-attr-bad.rs new file mode 100644 index 0000000000000..4313a4d04abf4 --- /dev/null +++ b/tests/ui/parser/macro/macro-attr-bad.rs @@ -0,0 +1,32 @@ +#![crate_type = "lib"] +#![feature(macro_attr)] + +macro_rules! attr_incomplete_1 { attr } +//~^ ERROR macro definition ended unexpectedly + +macro_rules! attr_incomplete_2 { attr() } +//~^ ERROR macro definition ended unexpectedly + +macro_rules! attr_incomplete_3 { attr() {} } +//~^ ERROR expected `=>` + +macro_rules! attr_incomplete_4 { attr() {} => } +//~^ ERROR macro definition ended unexpectedly + +macro_rules! attr_noparens_1 { attr{} {} => {} } +//~^ ERROR macro attribute argument matchers require parentheses + +macro_rules! attr_noparens_2 { attr[] {} => {} } +//~^ ERROR macro attribute argument matchers require parentheses + +macro_rules! attr_noparens_3 { attr _ {} => {} } +//~^ ERROR invalid macro matcher + +macro_rules! attr_dup_matcher_1 { attr() {$x:ident $x:ident} => {} } +//~^ ERROR duplicate matcher binding + +macro_rules! attr_dup_matcher_2 { attr($x:ident $x:ident) {} => {} } +//~^ ERROR duplicate matcher binding + +macro_rules! attr_dup_matcher_3 { attr($x:ident) {$x:ident} => {} } +//~^ ERROR duplicate matcher binding diff --git a/tests/ui/parser/macro/macro-attr-bad.stderr b/tests/ui/parser/macro/macro-attr-bad.stderr new file mode 100644 index 0000000000000..4d286b6664937 --- /dev/null +++ b/tests/ui/parser/macro/macro-attr-bad.stderr @@ -0,0 +1,80 @@ +error: macro definition ended unexpectedly + --> $DIR/macro-attr-bad.rs:4:38 + | +LL | macro_rules! attr_incomplete_1 { attr } + | ^ expected macro attr args + +error: macro definition ended unexpectedly + --> $DIR/macro-attr-bad.rs:7:40 + | +LL | macro_rules! attr_incomplete_2 { attr() } + | ^ expected macro attr body + +error: expected `=>`, found end of macro arguments + --> $DIR/macro-attr-bad.rs:10:43 + | +LL | macro_rules! attr_incomplete_3 { attr() {} } + | ^ expected `=>` + +error: macro definition ended unexpectedly + --> $DIR/macro-attr-bad.rs:13:46 + | +LL | macro_rules! attr_incomplete_4 { attr() {} => } + | ^ expected right-hand side of macro rule + +error: macro attribute argument matchers require parentheses + --> $DIR/macro-attr-bad.rs:16:36 + | +LL | macro_rules! attr_noparens_1 { attr{} {} => {} } + | ^^ + | +help: the delimiters should be `(` and `)` + | +LL - macro_rules! attr_noparens_1 { attr{} {} => {} } +LL + macro_rules! attr_noparens_1 { attr() {} => {} } + | + +error: macro attribute argument matchers require parentheses + --> $DIR/macro-attr-bad.rs:19:36 + | +LL | macro_rules! attr_noparens_2 { attr[] {} => {} } + | ^^ + | +help: the delimiters should be `(` and `)` + | +LL - macro_rules! attr_noparens_2 { attr[] {} => {} } +LL + macro_rules! attr_noparens_2 { attr() {} => {} } + | + +error: invalid macro matcher; matchers must be contained in balanced delimiters + --> $DIR/macro-attr-bad.rs:22:37 + | +LL | macro_rules! attr_noparens_3 { attr _ {} => {} } + | ^ + +error: duplicate matcher binding + --> $DIR/macro-attr-bad.rs:25:52 + | +LL | macro_rules! attr_dup_matcher_1 { attr() {$x:ident $x:ident} => {} } + | -------- ^^^^^^^^ duplicate binding + | | + | previous binding + +error: duplicate matcher binding + --> $DIR/macro-attr-bad.rs:28:49 + | +LL | macro_rules! attr_dup_matcher_2 { attr($x:ident $x:ident) {} => {} } + | -------- ^^^^^^^^ duplicate binding + | | + | previous binding + +error: duplicate matcher binding + --> $DIR/macro-attr-bad.rs:31:51 + | +LL | macro_rules! attr_dup_matcher_3 { attr($x:ident) {$x:ident} => {} } + | -------- ^^^^^^^^ duplicate binding + | | + | previous binding + +error: aborting due to 10 previous errors + From f0a5e70507c095c4f912f2b0ec31a18bd1447694 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 28 Jul 2025 04:12:12 -0700 Subject: [PATCH 14/23] mbe: Fix error message for using a macro with no `attr` rules as an attribute Avoid saying "a declarative macro cannot be used as an attribute macro"; instead, say that the macro has no `attr` rules. --- compiler/rustc_resolve/messages.ftl | 2 +- .../ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 39e9a9cc58afd..ceef558c0cf95 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -243,7 +243,7 @@ resolve_lowercase_self = .suggestion = try using `Self` resolve_macro_cannot_use_as_attr = - `{$ident}` exists, but a declarative macro cannot be used as an attribute macro + `{$ident}` exists, but has no `attr` rules resolve_macro_cannot_use_as_derive = `{$ident}` exists, but a declarative macro cannot be used as a derive macro diff --git a/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr b/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr index e5b913b208dca..77f8bef83a452 100644 --- a/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr +++ b/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr @@ -11,7 +11,7 @@ error: cannot find attribute `sample` in this scope --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:5:3 | LL | macro_rules! sample { () => {} } - | ------ `sample` exists, but a declarative macro cannot be used as an attribute macro + | ------ `sample` exists, but has no `attr` rules LL | LL | #[sample] | ^^^^^^ From 0cc0b11cceae9bbb39bfb9b267e79b05c0d061c1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Aug 2025 10:38:27 -0700 Subject: [PATCH 15/23] mbe: Emit an error if a macro call has no function-like rules Add a FIXME for moving this error earlier. --- compiler/rustc_expand/src/mbe/diagnostics.rs | 24 +++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 468488ebf7d0d..f4036b5c2e930 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -7,7 +7,7 @@ use rustc_macros::Subdiagnostic; use rustc_parse::parser::{Parser, Recovery, token_descr}; use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; -use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span}; use tracing::debug; use super::macro_rules::{MacroRule, NoopTracker, parser_from_cx}; @@ -25,6 +25,12 @@ pub(super) fn failed_to_match_macro( rules: &[MacroRule], ) -> (Span, ErrorGuaranteed) { debug!("failed to match macro"); + let def_head_span = if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) { + psess.source_map().guess_head_span(def_span) + } else { + DUMMY_SP + }; + // An error occurred, try the expansion again, tracking the expansion closely for better // diagnostics. let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp); @@ -47,6 +53,18 @@ pub(super) fn failed_to_match_macro( let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else { + // FIXME: we should report this at macro resolution time, as we do for + // `resolve_macro_cannot_use_as_attr`. We can do that once we track multiple macro kinds for a + // Def. + if !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) { + let msg = format!("macro has no rules for function-like invocation `{name}!`"); + let mut err = psess.dcx().struct_span_err(sp, msg); + if !def_head_span.is_dummy() { + let msg = "this macro has no rules for function-like invocation"; + err.span_label(def_head_span, msg); + } + return (sp, err.emit()); + } return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro")); }; @@ -54,8 +72,8 @@ pub(super) fn failed_to_match_macro( let mut err = psess.dcx().struct_span_err(span, parse_failure_msg(&token, None)); err.span_label(span, label); - if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) { - err.span_label(psess.source_map().guess_head_span(def_span), "when calling this macro"); + if !def_head_span.is_dummy() { + err.span_label(def_head_span, "when calling this macro"); } annotate_doc_comment(&mut err, psess.source_map(), span); From 34be8abb70d1f3247fd7907b6112934742e0abdc Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 11 Jul 2025 01:40:12 -0700 Subject: [PATCH 16/23] mbe: Handle applying attribute rules with paths Add infrastructure to apply an attribute macro given argument tokens and body tokens. Teach the resolver to consider `macro_rules` macros when looking for an attribute via a path. This does not yet handle local `macro_rules` attributes. --- compiler/rustc_expand/src/mbe/diagnostics.rs | 30 ++-- compiler/rustc_expand/src/mbe/macro_rules.rs | 170 +++++++++++++++++-- compiler/rustc_resolve/src/lib.rs | 3 +- compiler/rustc_resolve/src/macros.rs | 10 +- 4 files changed, 185 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index f4036b5c2e930..5b9d56ee2bc32 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -14,14 +14,15 @@ use super::macro_rules::{MacroRule, NoopTracker, parser_from_cx}; use crate::expand::{AstFragmentKind, parse_ast_fragment}; use crate::mbe::macro_parser::ParseResult::*; use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser}; -use crate::mbe::macro_rules::{Tracker, try_match_macro}; +use crate::mbe::macro_rules::{Tracker, try_match_macro, try_match_macro_attr}; pub(super) fn failed_to_match_macro( psess: &ParseSess, sp: Span, def_span: Span, name: Ident, - arg: TokenStream, + attr_args: Option<&TokenStream>, + body: &TokenStream, rules: &[MacroRule], ) -> (Span, ErrorGuaranteed) { debug!("failed to match macro"); @@ -35,7 +36,11 @@ pub(super) fn failed_to_match_macro( // diagnostics. let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp); - let try_success_result = try_match_macro(psess, name, &arg, rules, &mut tracker); + let try_success_result = if let Some(attr_args) = attr_args { + try_match_macro_attr(psess, name, attr_args, body, rules, &mut tracker) + } else { + try_match_macro(psess, name, body, rules, &mut tracker) + }; if try_success_result.is_ok() { // Nonterminal parser recovery might turn failed matches into successful ones, @@ -56,7 +61,7 @@ pub(super) fn failed_to_match_macro( // FIXME: we should report this at macro resolution time, as we do for // `resolve_macro_cannot_use_as_attr`. We can do that once we track multiple macro kinds for a // Def. - if !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) { + if attr_args.is_none() && !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) { let msg = format!("macro has no rules for function-like invocation `{name}!`"); let mut err = psess.dcx().struct_span_err(sp, msg); if !def_head_span.is_dummy() { @@ -97,10 +102,12 @@ pub(super) fn failed_to_match_macro( } // Check whether there's a missing comma in this macro call, like `println!("{}" a);` - if let Some((arg, comma_span)) = arg.add_comma() { + if attr_args.is_none() + && let Some((body, comma_span)) = body.add_comma() + { for rule in rules { let MacroRule::Func { lhs, .. } = rule else { continue }; - let parser = parser_from_cx(psess, arg.clone(), Recovery::Allowed); + let parser = parser_from_cx(psess, body.clone(), Recovery::Allowed); let mut tt_parser = TtParser::new(name); if let Success(_) = @@ -135,13 +142,13 @@ struct CollectTrackerAndEmitter<'dcx, 'matcher> { struct BestFailure { token: Token, - position_in_tokenstream: u32, + position_in_tokenstream: (bool, u32), msg: &'static str, remaining_matcher: MatcherLoc, } impl BestFailure { - fn is_better_position(&self, position: u32) -> bool { + fn is_better_position(&self, position: (bool, u32)) -> bool { position > self.position_in_tokenstream } } @@ -161,7 +168,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match } } - fn after_arm(&mut self, result: &NamedParseResult) { + fn after_arm(&mut self, in_body: bool, result: &NamedParseResult) { match result { Success(_) => { // Nonterminal parser recovery might turn failed matches into successful ones, @@ -174,14 +181,15 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match Failure((token, approx_position, msg)) => { debug!(?token, ?msg, "a new failure of an arm"); + let position_in_tokenstream = (in_body, *approx_position); if self .best_failure .as_ref() - .is_none_or(|failure| failure.is_better_position(*approx_position)) + .is_none_or(|failure| failure.is_better_position(position_in_tokenstream)) { self.best_failure = Some(BestFailure { token: *token, - position_in_tokenstream: *approx_position, + position_in_tokenstream, msg, remaining_matcher: self .remaining_matcher diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index d72f01a4dbda4..37b236a2e268c 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -29,11 +29,12 @@ use rustc_span::hygiene::Transparency; use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument, trace, trace_span}; +use super::diagnostics::failed_to_match_macro; use super::macro_parser::{NamedMatches, NamedParseResult}; use super::{SequenceRepetition, diagnostics}; use crate::base::{ - DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension, - SyntaxExtensionKind, TTMacroExpander, + AttrProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, + SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, }; use crate::errors; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; @@ -129,7 +130,6 @@ pub(super) enum MacroRule { /// A function-style rule, for use with `m!()` Func { lhs: Vec, lhs_span: Span, rhs: mbe::TokenTree }, /// An attr rule, for use with `#[m]` - #[expect(unused)] Attr { args: Vec, args_span: Span, @@ -180,6 +180,28 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } +impl AttrProcMacro for MacroRulesMacroExpander { + fn expand( + &self, + cx: &mut ExtCtxt<'_>, + sp: Span, + args: TokenStream, + body: TokenStream, + ) -> Result { + expand_macro_attr( + cx, + sp, + self.span, + self.node_id, + self.name, + self.transparency, + args, + body, + &self.rules, + ) + } +} + struct DummyExpander(ErrorGuaranteed); impl TTMacroExpander for DummyExpander { @@ -212,7 +234,7 @@ pub(super) trait Tracker<'matcher> { /// This is called after an arm has been parsed, either successfully or unsuccessfully. When /// this is called, `before_match_loc` was called at least once (with a `MatcherLoc::Eof`). - fn after_arm(&mut self, _result: &NamedParseResult) {} + fn after_arm(&mut self, _in_body: bool, _result: &NamedParseResult) {} /// For tracing. fn description() -> &'static str; @@ -298,13 +320,76 @@ fn expand_macro<'cx>( Err(CanRetry::Yes) => { // Retry and emit a better error. let (span, guar) = - diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, rules); + failed_to_match_macro(cx.psess(), sp, def_span, name, None, &arg, rules); cx.macro_error_and_trace_macros_diag(); DummyResult::any(span, guar) } } } +/// Expands the rules based macro defined by `rules` for a given attribute `args` and `body`. +#[instrument(skip(cx, transparency, args, body, rules))] +fn expand_macro_attr( + cx: &mut ExtCtxt<'_>, + sp: Span, + def_span: Span, + node_id: NodeId, + name: Ident, + transparency: Transparency, + args: TokenStream, + body: TokenStream, + rules: &[MacroRule], +) -> Result { + let psess = &cx.sess.psess; + // Macros defined in the current crate have a real node id, + // whereas macros from an external crate have a dummy id. + let is_local = node_id != DUMMY_NODE_ID; + + if cx.trace_macros() { + let msg = format!( + "expanding `$[{name}({})] {}`", + pprust::tts_to_string(&args), + pprust::tts_to_string(&body), + ); + trace_macros_note(&mut cx.expansions, sp, msg); + } + + // Track nothing for the best performance. + match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) { + Ok((i, rule, named_matches)) => { + let MacroRule::Attr { rhs, .. } = rule else { + panic!("try_macro_match_attr returned non-attr rule"); + }; + let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { + cx.dcx().span_bug(sp, "malformed macro rhs"); + }; + + let id = cx.current_expansion.id; + let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) + .map_err(|e| e.emit())?; + + if cx.trace_macros() { + let msg = format!("to `{}`", pprust::tts_to_string(&tts)); + trace_macros_note(&mut cx.expansions, sp, msg); + } + + if is_local { + cx.resolver.record_macro_rule_usage(node_id, i); + } + + Ok(tts) + } + Err(CanRetry::No(guar)) => Err(guar), + Err(CanRetry::Yes) => { + // Retry and emit a better error. + let (_, guar) = + failed_to_match_macro(cx.psess(), sp, def_span, name, Some(&args), &body, rules); + cx.trace_macros_diag(); + Err(guar) + } + } +} + pub(super) enum CanRetry { Yes, /// We are not allowed to retry macro expansion as a fatal error has been emitted already. @@ -356,7 +441,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, track); - track.after_arm(&result); + track.after_arm(true, &result); match result { Success(named_matches) => { @@ -391,6 +476,60 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( Err(CanRetry::Yes) } +/// Try expanding the macro attribute. Returns the index of the successful arm and its +/// named_matches if it was successful, and nothing if it failed. On failure, it's the caller's job +/// to use `track` accordingly to record all errors correctly. +#[instrument(level = "debug", skip(psess, attr_args, attr_body, rules, track), fields(tracking = %T::description()))] +pub(super) fn try_match_macro_attr<'matcher, T: Tracker<'matcher>>( + psess: &ParseSess, + name: Ident, + attr_args: &TokenStream, + attr_body: &TokenStream, + rules: &'matcher [MacroRule], + track: &mut T, +) -> Result<(usize, &'matcher MacroRule, NamedMatches), CanRetry> { + // This uses the same strategy as `try_match_macro` + let args_parser = parser_from_cx(psess, attr_args.clone(), T::recovery()); + let body_parser = parser_from_cx(psess, attr_body.clone(), T::recovery()); + let mut tt_parser = TtParser::new(name); + for (i, rule) in rules.iter().enumerate() { + let MacroRule::Attr { args, body, .. } = rule else { continue }; + + let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut()); + + let result = tt_parser.parse_tt(&mut Cow::Borrowed(&args_parser), args, track); + track.after_arm(false, &result); + + let mut named_matches = match result { + Success(named_matches) => named_matches, + Failure(_) => { + mem::swap(&mut gated_spans_snapshot, &mut psess.gated_spans.spans.borrow_mut()); + continue; + } + Error(_, _) => return Err(CanRetry::Yes), + ErrorReported(guar) => return Err(CanRetry::No(guar)), + }; + + let result = tt_parser.parse_tt(&mut Cow::Borrowed(&body_parser), body, track); + track.after_arm(true, &result); + + match result { + Success(body_named_matches) => { + psess.gated_spans.merge(gated_spans_snapshot); + named_matches.extend(body_named_matches); + return Ok((i, rule, named_matches)); + } + Failure(_) => { + mem::swap(&mut gated_spans_snapshot, &mut psess.gated_spans.spans.borrow_mut()) + } + Error(_, _) => return Err(CanRetry::Yes), + ErrorReported(guar) => return Err(CanRetry::No(guar)), + } + } + + Err(CanRetry::Yes) +} + /// Converts a macro item into a syntax extension. pub fn compile_declarative_macro( sess: &Session, @@ -401,13 +540,13 @@ pub fn compile_declarative_macro( span: Span, node_id: NodeId, edition: Edition, -) -> (SyntaxExtension, usize) { - let mk_syn_ext = |expander| { - let kind = SyntaxExtensionKind::LegacyBang(expander); +) -> (SyntaxExtension, Option>, usize) { + let mk_syn_ext = |kind| { let is_local = is_defined_in_current_crate(node_id); SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local) }; - let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), 0); + let mk_bang_ext = |expander| mk_syn_ext(SyntaxExtensionKind::LegacyBang(expander)); + let dummy_syn_ext = |guar| (mk_bang_ext(Arc::new(DummyExpander(guar))), None, 0); let macro_rules = macro_def.macro_rules; let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; @@ -420,10 +559,12 @@ pub fn compile_declarative_macro( let mut guar = None; let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); + let mut has_attr_rules = false; let mut rules = Vec::new(); while p.token != token::Eof { let args = if p.eat_keyword_noexpect(sym::attr) { + has_attr_rules = true; if !features.macro_attr() { feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable") .emit(); @@ -499,9 +640,12 @@ pub fn compile_declarative_macro( // Return the number of rules for unused rule linting, if this is a local macro. let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 }; - let expander = - Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules }); - (mk_syn_ext(expander), nrules) + let exp = Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules }); + let opt_attr_ext = has_attr_rules.then(|| { + let exp = Arc::clone(&exp); + Arc::new(mk_syn_ext(SyntaxExtensionKind::Attr(exp))) + }); + (mk_bang_ext(exp), opt_attr_ext, nrules) } fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2a75070ef54db..8a190bf06ed0d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1028,13 +1028,14 @@ struct DeriveData { struct MacroData { ext: Arc, + attr_ext: Option>, nrules: usize, macro_rules: bool, } impl MacroData { fn new(ext: Arc) -> MacroData { - MacroData { ext, nrules: 0, macro_rules: false } + MacroData { ext, attr_ext: None, nrules: 0, macro_rules: false } } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ecf4f797434b5..0692f368ade9c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -835,7 +835,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } _ => None, }, - None => self.get_macro(res).map(|macro_data| Arc::clone(¯o_data.ext)), + None => self.get_macro(res).map(|macro_data| match kind { + Some(MacroKind::Attr) if let Some(ref ext) = macro_data.attr_ext => Arc::clone(ext), + _ => Arc::clone(¯o_data.ext), + }), }; Ok((ext, res)) } @@ -1168,7 +1171,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { node_id: NodeId, edition: Edition, ) -> MacroData { - let (mut ext, mut nrules) = compile_declarative_macro( + let (mut ext, mut attr_ext, mut nrules) = compile_declarative_macro( self.tcx.sess, self.tcx.features(), macro_def, @@ -1185,13 +1188,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. ext.kind = builtin_ext_kind.clone(); + attr_ext = None; nrules = 0; } else { self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident }); } } - MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules } + MacroData { ext: Arc::new(ext), attr_ext, nrules, macro_rules: macro_def.macro_rules } } fn path_accessible( From 549c2fee9f210fe838660b66dfe216bc82af29ed Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 27 Jul 2025 12:06:02 -0700 Subject: [PATCH 17/23] mbe: Handle local `macro_rules` attr resolution Teach the resolver to consider `macro_rules` macros when looking for a local attribute. When looking for an attribute and considering a `macro_rules` macro, load the macro in order to see if it has attribute rules. Include a FIXME about tracking multiple macro kinds for a Def instead. --- compiler/rustc_resolve/src/ident.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f5bc46bf05304..afdcfa330f618 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -625,9 +625,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; match result { - Ok((binding, flags)) - if sub_namespace_match(binding.macro_kind(), macro_kind) => - { + Ok((binding, flags)) => { + let binding_macro_kind = binding.macro_kind(); + // If we're looking for an attribute, that might be supported by a + // `macro_rules!` macro. + // FIXME: Replace this with tracking multiple macro kinds for one Def. + if !(sub_namespace_match(binding_macro_kind, macro_kind) + || (binding_macro_kind == Some(MacroKind::Bang) + && macro_kind == Some(MacroKind::Attr) + && this + .get_macro(binding.res()) + .is_some_and(|macro_data| macro_data.attr_ext.is_some()))) + { + return None; + } + if finalize.is_none() || matches!(scope_set, ScopeSet::Late(..)) { return Some(Ok(binding)); } @@ -704,7 +716,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { innermost_result = Some((binding, flags)); } } - Ok(..) | Err(Determinacy::Determined) => {} + Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, } From 4f999f72dee5e7085a2a5ed11cd917dcad5143be Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 28 Jul 2025 02:00:13 -0700 Subject: [PATCH 18/23] mbe: Add test for `macro_rules` attributes Test macros via path and local macros. --- tests/ui/macros/macro-rules-attr.rs | 90 +++++++++++++++++++++ tests/ui/macros/macro-rules-attr.run.stdout | 15 ++++ tests/ui/macros/macro-rules-attr.stderr | 21 +++++ 3 files changed, 126 insertions(+) create mode 100644 tests/ui/macros/macro-rules-attr.rs create mode 100644 tests/ui/macros/macro-rules-attr.run.stdout create mode 100644 tests/ui/macros/macro-rules-attr.stderr diff --git a/tests/ui/macros/macro-rules-attr.rs b/tests/ui/macros/macro-rules-attr.rs new file mode 100644 index 0000000000000..1d6f09b53e1a5 --- /dev/null +++ b/tests/ui/macros/macro-rules-attr.rs @@ -0,0 +1,90 @@ +//@ run-pass +//@ check-run-results +#![feature(macro_attr)] +#![warn(unused)] + +#[macro_export] +macro_rules! exported_attr { + attr($($args:tt)*) { $($body:tt)* } => { + println!( + "exported_attr: args={:?}, body={:?}", + stringify!($($args)*), + stringify!($($body)*), + ); + }; + { $($args:tt)* } => { + println!("exported_attr!({:?})", stringify!($($args)*)); + }; + attr() {} => { + unused_rule(); + }; + attr() {} => { + compile_error!(); + }; + {} => { + unused_rule(); + }; + {} => { + compile_error!(); + }; +} + +macro_rules! local_attr { + attr($($args:tt)*) { $($body:tt)* } => { + println!( + "local_attr: args={:?}, body={:?}", + stringify!($($args)*), + stringify!($($body)*), + ); + }; + { $($args:tt)* } => { + println!("local_attr!({:?})", stringify!($($args)*)); + }; + attr() {} => { //~ WARN: never used + unused_rule(); + }; + attr() {} => { + compile_error!(); + }; + {} => { //~ WARN: never used + unused_rule(); + }; + {} => { + compile_error!(); + }; +} + +fn main() { + #[crate::exported_attr] + struct S; + #[::exported_attr(arguments, key = "value")] + fn func(_arg: u32) {} + #[self::exported_attr(1)] + #[self::exported_attr(2)] + struct Twice; + + crate::exported_attr!(); + crate::exported_attr!(invoked, arguments); + + #[exported_attr] + struct S; + #[exported_attr(arguments, key = "value")] + fn func(_arg: u32) {} + #[exported_attr(1)] + #[exported_attr(2)] + struct Twice; + + exported_attr!(); + exported_attr!(invoked, arguments); + + #[local_attr] + struct S; + #[local_attr(arguments, key = "value")] + fn func(_arg: u32) {} + #[local_attr(1)] + #[local_attr(2)] + struct Twice; + + local_attr!(); + local_attr!(invoked, arguments); +} diff --git a/tests/ui/macros/macro-rules-attr.run.stdout b/tests/ui/macros/macro-rules-attr.run.stdout new file mode 100644 index 0000000000000..77aa94d54f801 --- /dev/null +++ b/tests/ui/macros/macro-rules-attr.run.stdout @@ -0,0 +1,15 @@ +exported_attr: args="", body="struct S;" +exported_attr: args="arguments, key = \"value\"", body="fn func(_arg: u32) {}" +exported_attr: args="1", body="#[self::exported_attr(2)] struct Twice;" +exported_attr!("") +exported_attr!("invoked, arguments") +exported_attr: args="", body="struct S;" +exported_attr: args="arguments, key = \"value\"", body="fn func(_arg: u32) {}" +exported_attr: args="1", body="#[exported_attr(2)] struct Twice;" +exported_attr!("") +exported_attr!("invoked, arguments") +local_attr: args="", body="struct S;" +local_attr: args="arguments, key = \"value\"", body="fn func(_arg: u32) {}" +local_attr: args="1", body="#[local_attr(2)] struct Twice;" +local_attr!("") +local_attr!("invoked, arguments") diff --git a/tests/ui/macros/macro-rules-attr.stderr b/tests/ui/macros/macro-rules-attr.stderr new file mode 100644 index 0000000000000..567664cd73d32 --- /dev/null +++ b/tests/ui/macros/macro-rules-attr.stderr @@ -0,0 +1,21 @@ +warning: rule #3 of macro `local_attr` is never used + --> $DIR/macro-rules-attr.rs:43:9 + | +LL | attr() {} => { + | ^^ ^^ + | +note: the lint level is defined here + --> $DIR/macro-rules-attr.rs:4:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_macro_rules)]` implied by `#[warn(unused)]` + +warning: rule #5 of macro `local_attr` is never used + --> $DIR/macro-rules-attr.rs:49:5 + | +LL | {} => { + | ^^ + +warning: 2 warnings emitted + From bd5206ee1846f90579e644ebc7874a7300fc6171 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Aug 2025 10:31:37 -0700 Subject: [PATCH 19/23] mbe: Add test for attribute expansion with `compile_error!` --- tests/ui/macros/macro-rules-attr-error.rs | 13 +++++++++++++ tests/ui/macros/macro-rules-attr-error.stderr | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/macros/macro-rules-attr-error.rs create mode 100644 tests/ui/macros/macro-rules-attr-error.stderr diff --git a/tests/ui/macros/macro-rules-attr-error.rs b/tests/ui/macros/macro-rules-attr-error.rs new file mode 100644 index 0000000000000..59fb32a5bfcab --- /dev/null +++ b/tests/ui/macros/macro-rules-attr-error.rs @@ -0,0 +1,13 @@ +#![feature(macro_attr)] + +macro_rules! local_attr { + attr() { $($body:tt)* } => { + compile_error!(concat!("local_attr: ", stringify!($($body)*))); + }; + //~^^ ERROR: local_attr +} + +fn main() { + #[local_attr] + struct S; +} diff --git a/tests/ui/macros/macro-rules-attr-error.stderr b/tests/ui/macros/macro-rules-attr-error.stderr new file mode 100644 index 0000000000000..7d033ae3f03db --- /dev/null +++ b/tests/ui/macros/macro-rules-attr-error.stderr @@ -0,0 +1,13 @@ +error: local_attr: struct S; + --> $DIR/macro-rules-attr-error.rs:5:9 + | +LL | compile_error!(concat!("local_attr: ", stringify!($($body)*))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | #[local_attr] + | ------------- in this attribute macro expansion + | + = note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + From 150019579979ecd6121204f735e525063c184b5d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Aug 2025 10:38:46 -0700 Subject: [PATCH 20/23] mbe: Add a test for calling a macro with no function-like rules --- tests/ui/macros/macro-rules-attr-error.rs | 2 ++ tests/ui/macros/macro-rules-attr-error.stderr | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/ui/macros/macro-rules-attr-error.rs b/tests/ui/macros/macro-rules-attr-error.rs index 59fb32a5bfcab..1c8bb251e20e1 100644 --- a/tests/ui/macros/macro-rules-attr-error.rs +++ b/tests/ui/macros/macro-rules-attr-error.rs @@ -10,4 +10,6 @@ macro_rules! local_attr { fn main() { #[local_attr] struct S; + + local_attr!(arg); //~ ERROR: macro has no rules for function-like invocation } diff --git a/tests/ui/macros/macro-rules-attr-error.stderr b/tests/ui/macros/macro-rules-attr-error.stderr index 7d033ae3f03db..177b700938409 100644 --- a/tests/ui/macros/macro-rules-attr-error.stderr +++ b/tests/ui/macros/macro-rules-attr-error.stderr @@ -9,5 +9,14 @@ LL | #[local_attr] | = note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error: macro has no rules for function-like invocation `local_attr!` + --> $DIR/macro-rules-attr-error.rs:14:5 + | +LL | macro_rules! local_attr { + | ----------------------- this macro has no rules for function-like invocation +... +LL | local_attr!(arg); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors From 9a9ccc0edbf50428d0f12441cf50f32d5ea0f558 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Aug 2025 10:17:43 -0700 Subject: [PATCH 21/23] mbe: Add parser test for macro attribute recovery --- tests/ui/parser/macro/macro-attr-recovery.rs | 19 ++++++++++++ .../parser/macro/macro-attr-recovery.stderr | 31 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/ui/parser/macro/macro-attr-recovery.rs create mode 100644 tests/ui/parser/macro/macro-attr-recovery.stderr diff --git a/tests/ui/parser/macro/macro-attr-recovery.rs b/tests/ui/parser/macro/macro-attr-recovery.rs new file mode 100644 index 0000000000000..dbb795f57aa59 --- /dev/null +++ b/tests/ui/parser/macro/macro-attr-recovery.rs @@ -0,0 +1,19 @@ +#![crate_type = "lib"] +#![feature(macro_attr)] + +macro_rules! attr { + attr[$($args:tt)*] { $($body:tt)* } => { + //~^ ERROR: macro attribute argument matchers require parentheses + //~v ERROR: attr: + compile_error!(concat!( + "attr: args=\"", + stringify!($($args)*), + "\" body=\"", + stringify!($($body)*), + "\"", + )); + }; +} + +#[attr] +struct S; diff --git a/tests/ui/parser/macro/macro-attr-recovery.stderr b/tests/ui/parser/macro/macro-attr-recovery.stderr new file mode 100644 index 0000000000000..ab3a0b7c60720 --- /dev/null +++ b/tests/ui/parser/macro/macro-attr-recovery.stderr @@ -0,0 +1,31 @@ +error: macro attribute argument matchers require parentheses + --> $DIR/macro-attr-recovery.rs:5:9 + | +LL | attr[$($args:tt)*] { $($body:tt)* } => { + | ^^^^^^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL - attr[$($args:tt)*] { $($body:tt)* } => { +LL + attr($($args:tt)*) { $($body:tt)* } => { + | + +error: attr: args="" body="struct S;" + --> $DIR/macro-attr-recovery.rs:8:9 + | +LL | / compile_error!(concat!( +LL | | "attr: args=\"", +LL | | stringify!($($args)*), +LL | | "\" body=\"", +LL | | stringify!($($body)*), +LL | | "\"", +LL | | )); + | |__________^ +... +LL | #[attr] + | ------- in this attribute macro expansion + | + = note: this error originates in the attribute macro `attr` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + From 489734cd08599df822c87d27a38f972413dc13ab Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 28 Jul 2025 15:28:20 -0700 Subject: [PATCH 22/23] mbe: Add a test confirming that a macro attribute can apply itself recursively This allows a macro attribute to implement default arguments by reapplying itself with the defaults filled in, for instance. --- tests/ui/macros/macro-rules-attr-nested.rs | 24 +++++++++++++++++++ .../macros/macro-rules-attr-nested.run.stdout | 3 +++ 2 files changed, 27 insertions(+) create mode 100644 tests/ui/macros/macro-rules-attr-nested.rs create mode 100644 tests/ui/macros/macro-rules-attr-nested.run.stdout diff --git a/tests/ui/macros/macro-rules-attr-nested.rs b/tests/ui/macros/macro-rules-attr-nested.rs new file mode 100644 index 0000000000000..af5c30f00dd9d --- /dev/null +++ b/tests/ui/macros/macro-rules-attr-nested.rs @@ -0,0 +1,24 @@ +//@ run-pass +//@ check-run-results +#![feature(macro_attr)] + +macro_rules! nest { + attr() { struct $name:ident; } => { + println!("nest"); + #[nest(1)] + struct $name; + }; + attr(1) { struct $name:ident; } => { + println!("nest(1)"); + #[nest(2)] + struct $name; + }; + attr(2) { struct $name:ident; } => { + println!("nest(2)"); + }; +} + +fn main() { + #[nest] + struct S; +} diff --git a/tests/ui/macros/macro-rules-attr-nested.run.stdout b/tests/ui/macros/macro-rules-attr-nested.run.stdout new file mode 100644 index 0000000000000..46017f9ae084f --- /dev/null +++ b/tests/ui/macros/macro-rules-attr-nested.run.stdout @@ -0,0 +1,3 @@ +nest +nest(1) +nest(2) From f88839d2abc1c190c3072638518ff06b79686de1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 28 Jul 2025 15:33:09 -0700 Subject: [PATCH 23/23] mbe: Add a test checking for infinite recursion in macro attributes --- .../macros/macro-rules-attr-infinite-recursion.rs | 12 ++++++++++++ .../macro-rules-attr-infinite-recursion.stderr | 14 ++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/macros/macro-rules-attr-infinite-recursion.rs create mode 100644 tests/ui/macros/macro-rules-attr-infinite-recursion.stderr diff --git a/tests/ui/macros/macro-rules-attr-infinite-recursion.rs b/tests/ui/macros/macro-rules-attr-infinite-recursion.rs new file mode 100644 index 0000000000000..dc54c32cad364 --- /dev/null +++ b/tests/ui/macros/macro-rules-attr-infinite-recursion.rs @@ -0,0 +1,12 @@ +#![crate_type = "lib"] +#![feature(macro_attr)] + +macro_rules! attr { + attr() { $($body:tt)* } => { + #[attr] $($body)* + }; + //~^^ ERROR: recursion limit reached +} + +#[attr] +struct S; diff --git a/tests/ui/macros/macro-rules-attr-infinite-recursion.stderr b/tests/ui/macros/macro-rules-attr-infinite-recursion.stderr new file mode 100644 index 0000000000000..7d9a94338f51f --- /dev/null +++ b/tests/ui/macros/macro-rules-attr-infinite-recursion.stderr @@ -0,0 +1,14 @@ +error: recursion limit reached while expanding `#[attr]` + --> $DIR/macro-rules-attr-infinite-recursion.rs:6:9 + | +LL | #[attr] $($body)* + | ^^^^^^^ +... +LL | #[attr] + | ------- in this attribute macro expansion + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`macro_rules_attr_infinite_recursion`) + = note: this error originates in the attribute macro `attr` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error +