mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-20 11:43:04 +00:00
Auto merge of #98910 - Dylan-DPC:rollup-9x82wdg, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #97300 (Implement `FusedIterator` for `std::net::[Into]Incoming`) - #98761 (more `need_type_info` improvements) - #98811 (Interpret: AllocRange Debug impl, and use it more consistently) - #98847 (fix interpreter validity check on Box) - #98854 (clean up the borrowing in rustc_hir_pretty) - #98873 (Suggest `#[derive(Default)]` to enums with `#[default]`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
4045ce641a
@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?;
|
||||
trace!("deallocating: {}", alloc_id);
|
||||
trace!("deallocating: {alloc_id:?}");
|
||||
|
||||
if offset.bytes() != 0 {
|
||||
throw_ub_format!(
|
||||
@ -289,10 +289,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// Deallocating global memory -- always an error
|
||||
return Err(match self.tcx.get_global_alloc(alloc_id) {
|
||||
Some(GlobalAlloc::Function(..)) => {
|
||||
err_ub_format!("deallocating {}, which is a function", alloc_id)
|
||||
err_ub_format!("deallocating {alloc_id:?}, which is a function")
|
||||
}
|
||||
Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
|
||||
err_ub_format!("deallocating {}, which is static memory", alloc_id)
|
||||
err_ub_format!("deallocating {alloc_id:?}, which is static memory")
|
||||
}
|
||||
None => err_ub!(PointerUseAfterFree(alloc_id)),
|
||||
}
|
||||
@ -302,21 +302,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
debug!(?alloc);
|
||||
|
||||
if alloc.mutability == Mutability::Not {
|
||||
throw_ub_format!("deallocating immutable allocation {}", alloc_id);
|
||||
throw_ub_format!("deallocating immutable allocation {alloc_id:?}");
|
||||
}
|
||||
if alloc_kind != kind {
|
||||
throw_ub_format!(
|
||||
"deallocating {}, which is {} memory, using {} deallocation operation",
|
||||
alloc_id,
|
||||
alloc_kind,
|
||||
kind
|
||||
"deallocating {alloc_id:?}, which is {alloc_kind} memory, using {kind} deallocation operation"
|
||||
);
|
||||
}
|
||||
if let Some((size, align)) = old_size_and_align {
|
||||
if size != alloc.size() || align != alloc.align {
|
||||
throw_ub_format!(
|
||||
"incorrect layout on deallocation: {} has size {} and alignment {}, but gave size {} and alignment {}",
|
||||
alloc_id,
|
||||
"incorrect layout on deallocation: {alloc_id:?} has size {} and alignment {}, but gave size {} and alignment {}",
|
||||
alloc.size().bytes(),
|
||||
alloc.align.bytes(),
|
||||
size.bytes(),
|
||||
@ -815,7 +811,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
|
||||
continue;
|
||||
}
|
||||
|
||||
write!(fmt, "{}", id)?;
|
||||
write!(fmt, "{id:?}")?;
|
||||
match self.ecx.memory.alloc_map.get(id) {
|
||||
Some(&(kind, ref alloc)) => {
|
||||
// normal alloc
|
||||
@ -859,25 +855,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
|
||||
|
||||
/// Reading and writing.
|
||||
impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
|
||||
/// `range` is relative to this allocation reference, not the base of the allocation.
|
||||
pub fn write_scalar(
|
||||
&mut self,
|
||||
range: AllocRange,
|
||||
val: ScalarMaybeUninit<Tag>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let range = self.range.subrange(range);
|
||||
debug!(
|
||||
"write_scalar in {} at {:#x}, size {}: {:?}",
|
||||
self.alloc_id,
|
||||
range.start.bytes(),
|
||||
range.size.bytes(),
|
||||
val
|
||||
);
|
||||
debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id);
|
||||
Ok(self
|
||||
.alloc
|
||||
.write_scalar(&self.tcx, range, val)
|
||||
.map_err(|e| e.to_interp_error(self.alloc_id))?)
|
||||
}
|
||||
|
||||
/// `offset` is relative to this allocation reference, not the base of the allocation.
|
||||
pub fn write_ptr_sized(
|
||||
&mut self,
|
||||
offset: Size,
|
||||
@ -896,6 +888,7 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
|
||||
}
|
||||
|
||||
impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
|
||||
/// `range` is relative to this allocation reference, not the base of the allocation.
|
||||
pub fn read_scalar(
|
||||
&self,
|
||||
range: AllocRange,
|
||||
@ -906,24 +899,16 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
|
||||
.alloc
|
||||
.read_scalar(&self.tcx, range, read_provenance)
|
||||
.map_err(|e| e.to_interp_error(self.alloc_id))?;
|
||||
debug!(
|
||||
"read_scalar in {} at {:#x}, size {}: {:?}",
|
||||
self.alloc_id,
|
||||
range.start.bytes(),
|
||||
range.size.bytes(),
|
||||
res
|
||||
);
|
||||
debug!("read_scalar at {:?}{range:?}: {res:?}", self.alloc_id);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn read_integer(
|
||||
&self,
|
||||
offset: Size,
|
||||
size: Size,
|
||||
) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
|
||||
self.read_scalar(alloc_range(offset, size), /*read_provenance*/ false)
|
||||
/// `range` is relative to this allocation reference, not the base of the allocation.
|
||||
pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
|
||||
self.read_scalar(range, /*read_provenance*/ false)
|
||||
}
|
||||
|
||||
/// `offset` is relative to this allocation reference, not the base of the allocation.
|
||||
pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
|
||||
self.read_scalar(
|
||||
alloc_range(offset, self.tcx.data_layout().pointer_size),
|
||||
@ -931,6 +916,7 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
|
||||
)
|
||||
}
|
||||
|
||||
/// `range` is relative to this allocation reference, not the base of the allocation.
|
||||
pub fn check_bytes(
|
||||
&self,
|
||||
range: AllocRange,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic};
|
||||
use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic};
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE,
|
||||
COMMON_VTABLE_ENTRIES_SIZE,
|
||||
@ -102,18 +102,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
)?
|
||||
.expect("cannot be a ZST");
|
||||
let size = vtable
|
||||
.read_integer(
|
||||
.read_integer(alloc_range(
|
||||
pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(),
|
||||
pointer_size,
|
||||
)?
|
||||
))?
|
||||
.check_init()?;
|
||||
let size = size.to_machine_usize(self)?;
|
||||
let size = Size::from_bytes(size);
|
||||
let align = vtable
|
||||
.read_integer(
|
||||
.read_integer(alloc_range(
|
||||
pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(),
|
||||
pointer_size,
|
||||
)?
|
||||
))?
|
||||
.check_init()?;
|
||||
let align = align.to_machine_usize(self)?;
|
||||
let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
|
||||
|
@ -593,16 +593,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
self.check_safe_pointer(value, "reference")?;
|
||||
Ok(true)
|
||||
}
|
||||
ty::Adt(def, ..) if def.is_box() => {
|
||||
let unique = self.ecx.operand_field(value, 0)?;
|
||||
let nonnull = self.ecx.operand_field(&unique, 0)?;
|
||||
let ptr = self.ecx.operand_field(&nonnull, 0)?;
|
||||
self.check_safe_pointer(&ptr, "box")?;
|
||||
|
||||
// Check other fields of Box
|
||||
self.walk_value(value)?;
|
||||
Ok(true)
|
||||
}
|
||||
ty::FnPtr(_sig) => {
|
||||
let value = try_validation!(
|
||||
self.ecx.read_scalar(value).and_then(|v| v.check_init()),
|
||||
@ -813,6 +803,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_box(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
|
||||
self.check_safe_pointer(op, "box")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
|
||||
trace!("visit_value: {:?}, {:?}", *op, op.layout);
|
||||
@ -821,8 +817,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
||||
if self.try_visit_primitive(op)? {
|
||||
return Ok(());
|
||||
}
|
||||
// Sanity check: `builtin_deref` does not know any pointers that are not primitive.
|
||||
assert!(op.layout.ty.builtin_deref(true).is_none());
|
||||
|
||||
// Special check preventing `UnsafeCell` in the inner part of constants
|
||||
if let Some(def) = op.layout.ty.ty_adt_def() {
|
||||
|
@ -151,6 +151,14 @@ macro_rules! make_value_visitor {
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
/// Visits the given value as the pointer of a `Box`. There is nothing to recurse into.
|
||||
/// The type of `v` will be a raw pointer, but this is a field of `Box<T>` and the
|
||||
/// pointee type is the actual `T`.
|
||||
#[inline(always)]
|
||||
fn visit_box(&mut self, _v: &Self::V) -> InterpResult<'tcx>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
/// Visits this value as an aggregate, you are getting an iterator yielding
|
||||
/// all the fields (still in an `InterpResult`, you have to do error handling yourself).
|
||||
/// Recurses into the fields.
|
||||
@ -221,6 +229,47 @@ macro_rules! make_value_visitor {
|
||||
// Slices do not need special handling here: they have `Array` field
|
||||
// placement with length 0, so we enter the `Array` case below which
|
||||
// indirectly uses the metadata to determine the actual length.
|
||||
|
||||
// However, `Box`... let's talk about `Box`.
|
||||
ty::Adt(def, ..) if def.is_box() => {
|
||||
// `Box` is a hybrid primitive-library-defined type that one the one hand is
|
||||
// a dereferenceable pointer, on the other hand has *basically arbitrary
|
||||
// user-defined layout* since the user controls the 'allocator' field. So it
|
||||
// cannot be treated like a normal pointer, since it does not fit into an
|
||||
// `Immediate`. Yeah, it is quite terrible. But many visitors want to do
|
||||
// something with "all boxed pointers", so we handle this mess for them.
|
||||
//
|
||||
// When we hit a `Box`, we do not do the usual `visit_aggregate`; instead,
|
||||
// we (a) call `visit_box` on the pointer value, and (b) recurse on the
|
||||
// allocator field. We also assert tons of things to ensure we do not miss
|
||||
// any other fields.
|
||||
|
||||
// `Box` has two fields: the pointer we care about, and the allocator.
|
||||
assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields");
|
||||
let (unique_ptr, alloc) =
|
||||
(v.project_field(self.ecx(), 0)?, v.project_field(self.ecx(), 1)?);
|
||||
// Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`...
|
||||
// (which means another 2 fields, the second of which is a `PhantomData`)
|
||||
assert_eq!(unique_ptr.layout().fields.count(), 2);
|
||||
let (nonnull_ptr, phantom) = (
|
||||
unique_ptr.project_field(self.ecx(), 0)?,
|
||||
unique_ptr.project_field(self.ecx(), 1)?,
|
||||
);
|
||||
assert!(
|
||||
phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
|
||||
"2nd field of `Unique` should be PhantomData but is {:?}",
|
||||
phantom.layout().ty,
|
||||
);
|
||||
// ... that contains a `NonNull`... (gladly, only a single field here)
|
||||
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
|
||||
let raw_ptr = nonnull_ptr.project_field(self.ecx(), 0)?; // the actual raw ptr
|
||||
// ... whose only field finally is a raw ptr we can dereference.
|
||||
self.visit_box(&raw_ptr)?;
|
||||
|
||||
// The second `Box` field is the allocator, which we recursively check for validity
|
||||
// like in regular structs.
|
||||
self.visit_field(v, 1, &alloc)?;
|
||||
}
|
||||
_ => {},
|
||||
};
|
||||
|
||||
|
@ -21,6 +21,7 @@ Rust MIR: a lowered representation of Rust.
|
||||
#![feature(trusted_step)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(yeet_expr)]
|
||||
#![feature(is_some_with)]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -315,8 +315,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
body_id: Option<hir::BodyId>,
|
||||
failure_span: Span,
|
||||
arg: GenericArg<'tcx>,
|
||||
// FIXME(#94483): Either use this or remove it.
|
||||
_impl_candidates: Vec<ty::TraitRef<'tcx>>,
|
||||
error_code: TypeAnnotationNeeded,
|
||||
should_label_span: bool,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
@ -534,6 +532,23 @@ enum InferSourceKind<'tcx> {
|
||||
},
|
||||
}
|
||||
|
||||
impl<'tcx> InferSource<'tcx> {
|
||||
fn from_expansion(&self) -> bool {
|
||||
let source_from_expansion = match self.kind {
|
||||
InferSourceKind::LetBinding { insert_span, .. }
|
||||
| InferSourceKind::ClosureArg { insert_span, .. }
|
||||
| InferSourceKind::GenericArg { insert_span, .. } => insert_span.from_expansion(),
|
||||
InferSourceKind::FullyQualifiedMethodCall { receiver, .. } => {
|
||||
receiver.span.from_expansion()
|
||||
}
|
||||
InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => {
|
||||
data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion)
|
||||
}
|
||||
};
|
||||
source_from_expansion || self.span.from_expansion()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> InferSourceKind<'tcx> {
|
||||
fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
|
||||
match *self {
|
||||
@ -604,43 +619,65 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
||||
/// Sources with a small cost are prefer and should result
|
||||
/// in a clearer and idiomatic suggestion.
|
||||
fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
|
||||
match arg.unpack() {
|
||||
GenericArgKind::Lifetime(_) => 0, // erased
|
||||
GenericArgKind::Type(ty) => ty_cost(ty),
|
||||
GenericArgKind::Const(_) => 3, // some non-zero value
|
||||
}
|
||||
#[derive(Clone, Copy)]
|
||||
struct CostCtxt<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
|
||||
match ty.kind() {
|
||||
ty::Closure(..) => 100,
|
||||
ty::FnDef(..) => 20,
|
||||
ty::FnPtr(..) => 10,
|
||||
ty::Infer(..) => 0,
|
||||
_ => 1,
|
||||
impl<'tcx> CostCtxt<'tcx> {
|
||||
fn arg_cost(self, arg: GenericArg<'tcx>) -> usize {
|
||||
match arg.unpack() {
|
||||
GenericArgKind::Lifetime(_) => 0, // erased
|
||||
GenericArgKind::Type(ty) => self.ty_cost(ty),
|
||||
GenericArgKind::Const(_) => 3, // some non-zero value
|
||||
}
|
||||
}
|
||||
fn ty_cost(self, ty: Ty<'tcx>) -> usize {
|
||||
match *ty.kind() {
|
||||
ty::Closure(..) => 1000,
|
||||
ty::FnDef(..) => 150,
|
||||
ty::FnPtr(..) => 30,
|
||||
ty::Adt(def, substs) => {
|
||||
5 + self
|
||||
.tcx
|
||||
.generics_of(def.did())
|
||||
.own_substs_no_defaults(self.tcx, substs)
|
||||
.iter()
|
||||
.map(|&arg| self.arg_cost(arg))
|
||||
.sum::<usize>()
|
||||
}
|
||||
ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::<usize>(),
|
||||
ty::Ref(_, ty, _) => 2 + self.ty_cost(ty),
|
||||
ty::Infer(..) => 0,
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The sources are listed in order of preference here.
|
||||
match source.kind {
|
||||
InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
|
||||
InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
|
||||
let tcx = self.infcx.tcx;
|
||||
let ctx = CostCtxt { tcx };
|
||||
let base_cost = match source.kind {
|
||||
InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty),
|
||||
InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty),
|
||||
InferSourceKind::GenericArg { def_id, generic_args, .. } => {
|
||||
let variant_cost = match tcx.def_kind(def_id) {
|
||||
DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
|
||||
_ => 12,
|
||||
// `None::<u32>` and friends are ugly.
|
||||
DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15,
|
||||
_ => 10,
|
||||
};
|
||||
variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
|
||||
variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::<usize>()
|
||||
}
|
||||
InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
|
||||
20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
|
||||
20 + substs.iter().map(|arg| ctx.arg_cost(arg)).sum::<usize>()
|
||||
}
|
||||
InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
|
||||
30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
|
||||
30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let suggestion_may_apply = if source.from_expansion() { 10000 } else { 0 };
|
||||
|
||||
base_cost + suggestion_may_apply
|
||||
}
|
||||
|
||||
/// Uses `fn source_cost` to determine whether this inference source is preferable to
|
||||
@ -648,6 +685,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
|
||||
let cost = self.source_cost(&new_source) + self.attempt;
|
||||
debug!(?cost);
|
||||
self.attempt += 1;
|
||||
if cost < self.infer_source_cost {
|
||||
self.infer_source_cost = cost;
|
||||
@ -655,6 +693,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn node_substs_opt(&self, hir_id: HirId) -> Option<SubstsRef<'tcx>> {
|
||||
let substs = self.typeck_results.node_substs_opt(hir_id);
|
||||
self.infcx.resolve_vars_if_possible(substs)
|
||||
}
|
||||
|
||||
fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
|
||||
let ty = self.typeck_results.node_type_opt(hir_id);
|
||||
self.infcx.resolve_vars_if_possible(ty)
|
||||
@ -737,7 +780,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
match expr.kind {
|
||||
hir::ExprKind::Path(ref path) => {
|
||||
if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) {
|
||||
if let Some(substs) = self.node_substs_opt(expr.hir_id) {
|
||||
return self.path_inferred_subst_iter(expr.hir_id, substs, path);
|
||||
}
|
||||
}
|
||||
@ -765,7 +808,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
||||
if generics.has_impl_trait() {
|
||||
None?
|
||||
}
|
||||
let substs = self.typeck_results.node_substs_opt(expr.hir_id)?;
|
||||
let substs = self.node_substs_opt(expr.hir_id)?;
|
||||
let span = tcx.hir().span(segment.hir_id?);
|
||||
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
|
||||
InsertableGenericArgs {
|
||||
@ -980,8 +1023,10 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
||||
debug!(?args);
|
||||
let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args;
|
||||
let generics = tcx.generics_of(generics_def_id);
|
||||
if let Some(argument_index) =
|
||||
generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg))
|
||||
if let Some(argument_index) = generics
|
||||
.own_substs(substs)
|
||||
.iter()
|
||||
.position(|&arg| self.generic_arg_contains_target(arg))
|
||||
{
|
||||
let substs = self.infcx.resolve_vars_if_possible(substs);
|
||||
let generic_args = &generics.own_substs_no_defaults(tcx, substs)
|
||||
@ -1037,7 +1082,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
||||
.any(|generics| generics.has_impl_trait())
|
||||
};
|
||||
if let ExprKind::MethodCall(path, args, span) = expr.kind
|
||||
&& let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id)
|
||||
&& let Some(substs) = self.node_substs_opt(expr.hir_id)
|
||||
&& substs.iter().any(|arg| self.generic_arg_contains_target(arg))
|
||||
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
|
||||
&& self.infcx.tcx.trait_of_item(def_id).is_some()
|
||||
|
@ -160,12 +160,18 @@ impl AllocError {
|
||||
}
|
||||
|
||||
/// The information that makes up a memory access: offset and size.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AllocRange {
|
||||
pub start: Size,
|
||||
pub size: Size,
|
||||
}
|
||||
|
||||
impl fmt::Debug for AllocRange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "[{:#x}..{:#x}]", self.start.bytes(), self.end().bytes())
|
||||
}
|
||||
}
|
||||
|
||||
/// Free-starting constructor for less syntactic overhead.
|
||||
#[inline(always)]
|
||||
pub fn alloc_range(start: Size, size: Size) -> AllocRange {
|
||||
|
@ -334,36 +334,30 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
|
||||
p,
|
||||
),
|
||||
PointerUseAfterFree(a) => {
|
||||
write!(f, "pointer to {} was dereferenced after this allocation got freed", a)
|
||||
write!(f, "pointer to {a:?} was dereferenced after this allocation got freed")
|
||||
}
|
||||
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size: Size::ZERO, msg } => {
|
||||
write!(
|
||||
f,
|
||||
"{}{alloc_id} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds",
|
||||
msg,
|
||||
alloc_id = alloc_id,
|
||||
"{msg}{alloc_id:?} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds",
|
||||
alloc_size = alloc_size.bytes(),
|
||||
ptr_offset = ptr_offset,
|
||||
)
|
||||
}
|
||||
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => write!(
|
||||
f,
|
||||
"{}{alloc_id} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds",
|
||||
msg,
|
||||
alloc_id = alloc_id,
|
||||
"{msg}{alloc_id:?} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds",
|
||||
alloc_size = alloc_size.bytes(),
|
||||
ptr_size = ptr_size.bytes(),
|
||||
ptr_size_p = pluralize!(ptr_size.bytes()),
|
||||
ptr_offset = ptr_offset,
|
||||
),
|
||||
DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => {
|
||||
write!(f, "null pointer is not a valid pointer for this operation")
|
||||
}
|
||||
DanglingIntPointer(0, msg) => {
|
||||
write!(f, "{}null pointer is not a valid pointer", msg)
|
||||
write!(f, "{msg}null pointer is not a valid pointer")
|
||||
}
|
||||
DanglingIntPointer(i, msg) => {
|
||||
write!(f, "{}0x{:x} is not a valid pointer", msg, i)
|
||||
write!(f, "{msg}{i:#x} is not a valid pointer")
|
||||
}
|
||||
AlignmentCheckFailed { required, has } => write!(
|
||||
f,
|
||||
@ -371,8 +365,8 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
|
||||
has.bytes(),
|
||||
required.bytes()
|
||||
),
|
||||
WriteToReadOnly(a) => write!(f, "writing to {} which is read-only", a),
|
||||
DerefFunctionPointer(a) => write!(f, "accessing {} which contains a function", a),
|
||||
WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"),
|
||||
DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"),
|
||||
ValidationFailure { path: None, msg } => {
|
||||
write!(f, "constructing invalid value: {}", msg)
|
||||
}
|
||||
|
@ -190,11 +190,7 @@ impl fmt::Debug for AllocId {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AllocId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
// No "Display" since AllocIds are not usually user-visible.
|
||||
|
||||
#[derive(TyDecodable, TyEncodable)]
|
||||
enum AllocDiscriminant {
|
||||
@ -470,7 +466,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
return alloc_id;
|
||||
}
|
||||
let id = alloc_map.reserve();
|
||||
debug!("creating alloc {:?} with id {}", alloc, id);
|
||||
debug!("creating alloc {alloc:?} with id {id:?}");
|
||||
alloc_map.alloc_map.insert(id, alloc.clone());
|
||||
alloc_map.dedup.insert(alloc, id);
|
||||
id
|
||||
@ -538,7 +534,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> {
|
||||
match self.get_global_alloc(id) {
|
||||
Some(alloc) => alloc,
|
||||
None => bug!("could not find allocation for {}", id),
|
||||
None => bug!("could not find allocation for {id:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -546,7 +542,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
/// call this function twice, even with the same `Allocation` will ICE the compiler.
|
||||
pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
|
||||
if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
|
||||
bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old);
|
||||
bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ impl Provenance for AllocId {
|
||||
}
|
||||
// Print offset only if it is non-zero.
|
||||
if ptr.offset.bytes() > 0 {
|
||||
write!(f, "+0x{:x}", ptr.offset.bytes())?;
|
||||
write!(f, "+{:#x}", ptr.offset.bytes())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -181,7 +181,7 @@ impl<Tag: Provenance> fmt::Debug for Pointer<Option<Tag>> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.provenance {
|
||||
Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f),
|
||||
None => write!(f, "0x{:x}", self.offset.bytes()),
|
||||
None => write!(f, "{:#x}", self.offset.bytes()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
|
||||
Scalar::Int(int) => write!(f, "0x{:x}", int),
|
||||
Scalar::Int(int) => write!(f, "{:#x}", int),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,12 +716,12 @@ pub fn write_allocations<'tcx>(
|
||||
}
|
||||
write!(w, "{}", display_allocation(tcx, alloc.inner()))
|
||||
};
|
||||
write!(w, "\n{}", id)?;
|
||||
write!(w, "\n{id:?}")?;
|
||||
match tcx.get_global_alloc(id) {
|
||||
// This can't really happen unless there are bugs, but it doesn't cost us anything to
|
||||
// gracefully handle it and allow buggy rustc to be debugged via allocation printing.
|
||||
None => write!(w, " (deallocated)")?,
|
||||
Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?,
|
||||
Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?,
|
||||
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
|
||||
match tcx.eval_static_initializer(did) {
|
||||
Ok(alloc) => {
|
||||
|
@ -452,6 +452,10 @@ impl fmt::Debug for ScalarInt {
|
||||
impl fmt::LowerHex for ScalarInt {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.check_data();
|
||||
if f.alternate() {
|
||||
// Like regular ints, alternate flag adds leading `0x`.
|
||||
write!(f, "0x")?;
|
||||
}
|
||||
// Format as hex number wide enough to fit any value of the given `size`.
|
||||
// So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
|
||||
// Using a block `{self.data}` here to force a copy instead of using `self.data`
|
||||
|
@ -1495,6 +1495,15 @@ impl<'a> Resolver<'a> {
|
||||
err.help("have you added the `#[macro_use]` on the module/import?");
|
||||
return;
|
||||
}
|
||||
if ident.name == kw::Default
|
||||
&& let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
|
||||
&& let Some(span) = self.opt_span(def_id)
|
||||
{
|
||||
err.span_help(
|
||||
self.session.source_map().guess_head_span(span),
|
||||
"consider adding `#[derive(Default)]` to this enum",
|
||||
);
|
||||
}
|
||||
for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
|
||||
if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
|
||||
ident,
|
||||
|
@ -1980,7 +1980,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
body_id,
|
||||
span,
|
||||
trait_ref.self_ty().skip_binder().into(),
|
||||
vec![],
|
||||
ErrorCode::E0282,
|
||||
false,
|
||||
)
|
||||
@ -2005,19 +2004,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
let subst = data.trait_ref.substs.iter().find(|s| s.has_infer_types_or_consts());
|
||||
|
||||
let mut err = if let Some(subst) = subst {
|
||||
let impl_candidates = self
|
||||
.find_similar_impl_candidates(trait_ref)
|
||||
.into_iter()
|
||||
.map(|candidate| candidate.trait_ref)
|
||||
.collect();
|
||||
self.emit_inference_failure_err(
|
||||
body_id,
|
||||
span,
|
||||
subst,
|
||||
impl_candidates,
|
||||
ErrorCode::E0283,
|
||||
true,
|
||||
)
|
||||
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true)
|
||||
} else {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
@ -2117,7 +2104,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282, false)
|
||||
self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false)
|
||||
}
|
||||
|
||||
ty::PredicateKind::Subtype(data) => {
|
||||
@ -2131,14 +2118,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
let SubtypePredicate { a_is_expected: _, a, b } = data;
|
||||
// both must be type variables, or the other would've been instantiated
|
||||
assert!(a.is_ty_var() && b.is_ty_var());
|
||||
self.emit_inference_failure_err(
|
||||
body_id,
|
||||
span,
|
||||
a.into(),
|
||||
vec![],
|
||||
ErrorCode::E0282,
|
||||
true,
|
||||
)
|
||||
self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true)
|
||||
}
|
||||
ty::PredicateKind::Projection(data) => {
|
||||
if predicate.references_error() || self.is_tainted_by_errors() {
|
||||
@ -2155,7 +2135,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
body_id,
|
||||
span,
|
||||
subst,
|
||||
vec![],
|
||||
ErrorCode::E0284,
|
||||
true,
|
||||
);
|
||||
|
@ -1538,15 +1538,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty
|
||||
} else {
|
||||
if !self.is_tainted_by_errors() {
|
||||
self.emit_inference_failure_err(
|
||||
(**self).body_id,
|
||||
sp,
|
||||
ty.into(),
|
||||
vec![],
|
||||
E0282,
|
||||
true,
|
||||
)
|
||||
.emit();
|
||||
self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
|
||||
.emit();
|
||||
}
|
||||
let err = self.tcx.ty_error();
|
||||
self.demand_suptype(sp, err, ty);
|
||||
|
@ -692,7 +692,6 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
||||
Some(self.body.id()),
|
||||
self.span.to_span(self.tcx),
|
||||
t.into(),
|
||||
vec![],
|
||||
E0282,
|
||||
false,
|
||||
)
|
||||
@ -707,7 +706,6 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
||||
Some(self.body.id()),
|
||||
self.span.to_span(self.tcx),
|
||||
c.into(),
|
||||
vec![],
|
||||
E0282,
|
||||
false,
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ use crate::io::prelude::*;
|
||||
|
||||
use crate::fmt;
|
||||
use crate::io::{self, IoSlice, IoSliceMut};
|
||||
use crate::iter::FusedIterator;
|
||||
use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
|
||||
use crate::sys_common::net as net_imp;
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
@ -1009,6 +1010,9 @@ impl<'a> Iterator for Incoming<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "tcp_listener_incoming_fused_iterator", since = "1.64.0")]
|
||||
impl FusedIterator for Incoming<'_> {}
|
||||
|
||||
#[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
|
||||
impl Iterator for IntoIncoming {
|
||||
type Item = io::Result<TcpStream>;
|
||||
@ -1017,6 +1021,9 @@ impl Iterator for IntoIncoming {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
|
||||
impl FusedIterator for IntoIncoming {}
|
||||
|
||||
impl AsInner<net_imp::TcpListener> for TcpListener {
|
||||
fn as_inner(&self) -> &net_imp::TcpListener {
|
||||
&self.0
|
||||
|
8
src/test/ui/enum/suggest-default-attribute.rs
Normal file
8
src/test/ui/enum/suggest-default-attribute.rs
Normal file
@ -0,0 +1,8 @@
|
||||
pub enum Test { //~ HELP consider adding `#[derive(Default)]` to this enum
|
||||
#[default]
|
||||
//~^ ERROR cannot find attribute `default` in this scope
|
||||
First,
|
||||
Second,
|
||||
}
|
||||
|
||||
fn main() {}
|
14
src/test/ui/enum/suggest-default-attribute.stderr
Normal file
14
src/test/ui/enum/suggest-default-attribute.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: cannot find attribute `default` in this scope
|
||||
--> $DIR/suggest-default-attribute.rs:2:7
|
||||
|
|
||||
LL | #[default]
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: consider adding `#[derive(Default)]` to this enum
|
||||
--> $DIR/suggest-default-attribute.rs:1:1
|
||||
|
|
||||
LL | pub enum Test {
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -2,7 +2,12 @@ error[E0282]: type annotations needed
|
||||
--> $DIR/ambiguous_type_parameter.rs:16:19
|
||||
|
|
||||
LL | InMemoryStore.get_raw(&String::default());
|
||||
| ^^^^^^^ cannot infer type for type parameter `K`
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try using a fully qualified path to specify the expected types
|
||||
|
|
||||
LL | <InMemoryStore as Store<String, HashMap<K, String>>>::get_raw(&InMemoryStore, &String::default());
|
||||
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -16,8 +16,8 @@ fn infallible() -> Result<(), std::convert::Infallible> {
|
||||
|
||||
fn main() {
|
||||
let x = || -> Result<_, QualifiedError<_>> {
|
||||
//~^ ERROR type annotations needed for `Result<(), QualifiedError<_>>`
|
||||
infallible()?;
|
||||
Ok(())
|
||||
//~^ ERROR type annotations needed
|
||||
};
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>`
|
||||
--> $DIR/cannot-infer-partial-try-return.rs:18:13
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/cannot-infer-partial-try-return.rs:20:9
|
||||
|
|
||||
LL | let x = || -> Result<_, QualifiedError<_>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | infallible()?;
|
||||
| ------------- type must be known at this point
|
||||
LL | Ok(())
|
||||
| ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
|
||||
|
|
||||
help: try giving this closure an explicit return type
|
||||
help: consider specifying the generic arguments
|
||||
|
|
||||
LL | let x = || -> Result<(), QualifiedError<_>> {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | Ok::<(), QualifiedError<_>>(())
|
||||
| +++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
19
src/test/ui/inference/need_type_info/channel.rs
Normal file
19
src/test/ui/inference/need_type_info/channel.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Test that we suggest specifying the generic argument of `channel`
|
||||
// instead of the return type of that function, which is a lot more
|
||||
// complex.
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
fn no_tuple() {
|
||||
let _data =
|
||||
channel(); //~ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn tuple() {
|
||||
let (_sender, _receiver) =
|
||||
channel(); //~ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn main() {
|
||||
no_tuple();
|
||||
tuple();
|
||||
}
|
25
src/test/ui/inference/need_type_info/channel.stderr
Normal file
25
src/test/ui/inference/need_type_info/channel.stderr
Normal file
@ -0,0 +1,25 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/channel.rs:8:9
|
||||
|
|
||||
LL | channel();
|
||||
| ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
|
||||
|
|
||||
help: consider specifying the generic argument
|
||||
|
|
||||
LL | channel::<T>();
|
||||
| +++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/channel.rs:13:9
|
||||
|
|
||||
LL | channel();
|
||||
| ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
|
||||
|
|
||||
help: consider specifying the generic argument
|
||||
|
|
||||
LL | channel::<T>();
|
||||
| +++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
@ -1,8 +1,13 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/issue-23041.rs:6:22
|
||||
--> $DIR/issue-23041.rs:6:7
|
||||
|
|
||||
LL | b.downcast_ref::<fn(_)->_>();
|
||||
| ^^^^^^^^ cannot infer type
|
||||
| ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref`
|
||||
|
|
||||
help: consider specifying the generic arguments
|
||||
|
|
||||
LL | b.downcast_ref::<fn(_) -> _>();
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,8 +1,13 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/issue-24013.rs:5:20
|
||||
--> $DIR/issue-24013.rs:5:13
|
||||
|
|
||||
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
|
||||
| ^^^^^^ cannot infer type
|
||||
| ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap`
|
||||
|
|
||||
help: consider specifying the generic arguments
|
||||
|
|
||||
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
|
||||
| ~~~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -5,10 +5,10 @@ use std::marker::PhantomData;
|
||||
struct Foo<T> {foo: PhantomData<T>}
|
||||
|
||||
fn main() {
|
||||
let (tx, rx) = //~ ERROR type annotations needed
|
||||
let (tx, rx) =
|
||||
channel();
|
||||
// FIXME(#89862): Suggest adding a generic argument to `channel` instead
|
||||
spawn(move || {
|
||||
tx.send(Foo{ foo: PhantomData });
|
||||
//~^ ERROR type annotations needed
|
||||
});
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
error[E0282]: type annotations needed for `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
|
||||
--> $DIR/issue-25368.rs:8:9
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/issue-25368.rs:11:27
|
||||
|
|
||||
LL | let (tx, rx) =
|
||||
| ^^^^^^^^
|
||||
LL | tx.send(Foo{ foo: PhantomData });
|
||||
| ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
|
||||
|
|
||||
help: consider giving this pattern a type, where the type for type parameter `T` is specified
|
||||
help: consider specifying the generic argument
|
||||
|
|
||||
LL | let (tx, rx): (Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>) =
|
||||
| +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
LL | tx.send(Foo{ foo: PhantomData::<T> });
|
||||
| +++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -13,7 +13,7 @@ error[E0283]: type annotations needed
|
||||
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
|
||||
|
|
||||
LL | x.foo();
|
||||
| ^^^ cannot infer type for struct `Vec<_>`
|
||||
| ^^^
|
||||
|
|
||||
note: multiple `impl`s satisfying `Vec<_>: Foo` found
|
||||
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:9:1
|
||||
@ -23,6 +23,10 @@ LL | impl Foo for Vec<usize> {
|
||||
...
|
||||
LL | impl Foo for Vec<isize> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: try using a fully qualified path to specify the expected types
|
||||
|
|
||||
LL | <Vec<T> as Foo>::foo(&x);
|
||||
| ++++++++++++++++++++++ ~
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
|
||||
|
Loading…
Reference in New Issue
Block a user