From c1241bf7a71ed5175274d33516a29f1c4fe5a3a0 Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 17 Oct 2019 00:57:18 +0800 Subject: [PATCH 01/17] add debuginfo in generator_interior --- src/librustc/hir/mod.rs | 16 ++++++++++++++++ src/librustc_typeck/check/generator_interior.rs | 12 ++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6b354b01518ea..474b5e33c2a0a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1857,6 +1857,22 @@ impl fmt::Display for YieldSource { } } +impl core::convert::From for YieldSource { + fn from(gen_kind: GeneratorKind) -> Self { + match gen_kind { + // Guess based on the kind of the current generator. + GeneratorKind::Gen => Self::Yield, + GeneratorKind::Async(_) => Self::Await, + } + } +} + +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] +pub enum CaptureClause { + CaptureByValue, + CaptureByRef, +} + // N.B., if you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index fcf6b22f74f3c..35d73d5696431 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -32,7 +32,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { debug!("generator_interior: attempting to record type {:?} {:?} {:?} {:?}", ty, scope, expr, source_span); - let live_across_yield = scope.map(|s| { self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| { // If we are recording an expression that is the last yield @@ -54,15 +53,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { }).unwrap_or_else(|| Some(YieldData { span: DUMMY_SP, expr_and_pat_count: 0, - source: match self.kind { // Guess based on the kind of the current generator. - hir::GeneratorKind::Gen => hir::YieldSource::Yield, - hir::GeneratorKind::Async(_) => hir::YieldSource::Await, - }, + source: self.kind.into(), })); if let Some(yield_data) = live_across_yield { let ty = self.fcx.resolve_vars_if_possible(&ty); - debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}", expr, scope, ty, self.expr_count, yield_data.span); @@ -94,6 +89,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { } else { debug!("no type in expr = {:?}, count = {:?}, span = {:?}", expr, self.expr_count, expr.map(|e| e.span)); + let ty = self.fcx.resolve_vars_if_possible(&ty); + if let Some((unresolved_type, unresolved_type_span)) = self.fcx.unresolved_type_vars(&ty) { + debug!("remained unresolved_type = {:?}, unresolved_type_span: {:?}", + unresolved_type, unresolved_type_span); + } } } } From ff4f6a125891b3474fac1cfd2e86784d4ec073a9 Mon Sep 17 00:00:00 2001 From: csmoe Date: Tue, 22 Oct 2019 02:44:12 +0800 Subject: [PATCH 02/17] record previous unresolve span for generator error reporting --- src/librustc/hir/mod.rs | 12 +++--------- src/librustc_typeck/check/generator_interior.rs | 11 +++++++++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 474b5e33c2a0a..2cffcc5bfade8 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1857,9 +1857,9 @@ impl fmt::Display for YieldSource { } } -impl core::convert::From for YieldSource { - fn from(gen_kind: GeneratorKind) -> Self { - match gen_kind { +impl From for YieldSource { + fn from(kind: GeneratorKind) -> Self { + match kind { // Guess based on the kind of the current generator. GeneratorKind::Gen => Self::Yield, GeneratorKind::Async(_) => Self::Await, @@ -1867,12 +1867,6 @@ impl core::convert::From for YieldSource { } } -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum CaptureClause { - CaptureByValue, - CaptureByRef, -} - // N.B., if you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 35d73d5696431..607efca88dd70 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -19,6 +19,7 @@ struct InteriorVisitor<'a, 'tcx> { region_scope_tree: &'tcx region::ScopeTree, expr_count: usize, kind: hir::GeneratorKind, + prev_unresolved_span: Option, } impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { @@ -69,9 +70,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data.source); // If unresolved type isn't a ty_var then unresolved_type_span is None + let span = self.prev_unresolved_span.unwrap_or_else( + || unresolved_type_span.unwrap_or(source_span) + ); self.fcx.need_type_info_err_in_generator( self.kind, - unresolved_type_span.unwrap_or(source_span), + span, unresolved_type, ) .span_note(yield_data.span, &*note) @@ -90,9 +94,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { debug!("no type in expr = {:?}, count = {:?}, span = {:?}", expr, self.expr_count, expr.map(|e| e.span)); let ty = self.fcx.resolve_vars_if_possible(&ty); - if let Some((unresolved_type, unresolved_type_span)) = self.fcx.unresolved_type_vars(&ty) { + if let Some((unresolved_type, unresolved_type_span)) + = self.fcx.unresolved_type_vars(&ty) { debug!("remained unresolved_type = {:?}, unresolved_type_span: {:?}", unresolved_type, unresolved_type_span); + self.prev_unresolved_span = unresolved_type_span; } } } @@ -112,6 +118,7 @@ pub fn resolve_interior<'a, 'tcx>( region_scope_tree: fcx.tcx.region_scope_tree(def_id), expr_count: 0, kind, + prev_unresolved_span: None, }; intravisit::walk_body(&mut visitor, body); From 4c7f5af42ac7e924ddbd66af91367578d2f35614 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sun, 15 Dec 2019 20:11:59 -0600 Subject: [PATCH 03/17] Separate region inference logic from error handling better --- .../borrow_check/diagnostics/region_errors.rs | 37 ++++- .../borrow_check/region_infer/mod.rs | 147 ++++++++---------- 2 files changed, 96 insertions(+), 88 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 8a37e2d02ec71..b78cd6bccf8ca 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -1,10 +1,13 @@ //! Error reporting machinery for lifetime errors. use rustc::hir::def_id::DefId; -use rustc::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc::infer::InferCtxt; -use rustc::infer::NLLRegionVariableOrigin; -use rustc::mir::{ConstraintCategory, Local, Location, Body}; +use rustc::infer::{ + error_reporting::nice_region_error::NiceRegionError, + InferCtxt, NLLRegionVariableOrigin, +}; +use rustc::mir::{ + ConstraintCategory, Local, Location, Body, +}; use rustc::ty::{self, RegionVid}; use rustc_index::vec::IndexVec; use rustc_errors::DiagnosticBuilder; @@ -93,6 +96,32 @@ pub struct ErrorConstraintInfo { } impl<'tcx> RegionInferenceContext<'tcx> { + /// Converts a region inference variable into a `ty::Region` that + /// we can use for error reporting. If `r` is universally bound, + /// then we use the name that we have on record for it. If `r` is + /// existentially bound, then we check its inferred value and try + /// to find a good name from that. Returns `None` if we can't find + /// one (e.g., this is just some random part of the CFG). + pub fn to_error_region(&self, r: RegionVid) -> Option> { + self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name) + } + + /// Returns the [RegionVid] corresponding to the region returned by + /// `to_error_region`. + pub fn to_error_region_vid(&self, r: RegionVid) -> Option { + if self.universal_regions.is_universal_region(r) { + Some(r) + } else { + let r_scc = self.constraint_sccs.scc(r); + let upper_bound = self.universal_upper_bound(r); + if self.scc_values.contains(r_scc, upper_bound) { + self.to_error_region_vid(upper_bound) + } else { + None + } + } + } + /// Tries to find the best constraint to blame for the fact that /// `R: from_region`, where `R` is some region that meets /// `target_test`. This works by following the constraint graph, diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index b6946e2f73fc6..ca29b552733d1 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -928,32 +928,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - /// Converts a region inference variable into a `ty::Region` that - /// we can use for error reporting. If `r` is universally bound, - /// then we use the name that we have on record for it. If `r` is - /// existentially bound, then we check its inferred value and try - /// to find a good name from that. Returns `None` if we can't find - /// one (e.g., this is just some random part of the CFG). - pub fn to_error_region(&self, r: RegionVid) -> Option> { - self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name) - } - - /// Returns the [RegionVid] corresponding to the region returned by - /// `to_error_region`. - pub fn to_error_region_vid(&self, r: RegionVid) -> Option { - if self.universal_regions.is_universal_region(r) { - Some(r) - } else { - let r_scc = self.constraint_sccs.scc(r); - let upper_bound = self.universal_upper_bound(r); - if self.scc_values.contains(r_scc, upper_bound) { - self.to_error_region_vid(upper_bound) - } else { - None - } - } - } - /// Invoked when we have some type-test (e.g., `T: 'X`) that we cannot /// prove to be satisfied. If this is a closure, we will attempt to /// "promote" this type-test into our `ClosureRegionRequirements` and @@ -1164,7 +1138,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// include the CFG anyhow. /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. - fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { + pub (in crate::borrow_check) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); // Find the smallest universal region that contains all other @@ -1458,19 +1432,34 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("check_polonius_subset_errors: subset_error longer_fr={:?},\ shorter_fr={:?}", longer_fr, shorter_fr); - self.report_or_propagate_universal_region_error( + let propagated = self.try_propagate_universal_region_error( *longer_fr, *shorter_fr, - infcx, body, - local_names, - upvars, - mir_def_id, &mut propagated_outlives_requirements, - &mut outlives_suggestion, - errors_buffer, - region_naming, ); + if !propagated { + // If we are not in a context where we can't propagate errors, or we + // could not shrink `fr` to something smaller, then just report an + // error. + // + // Note: in this case, we use the unapproximated regions to report the + // error. This gives better error messages in some cases. + let db = self.report_error( + body, + local_names, + upvars, + infcx, + mir_def_id, + *longer_fr, + NLLRegionVariableOrigin::FreeRegion, + *shorter_fr, + &mut outlives_suggestion, + region_naming, + ); + + db.buffer(errors_buffer); + } } // Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has @@ -1594,48 +1583,59 @@ impl<'tcx> RegionInferenceContext<'tcx> { return None; } - self.report_or_propagate_universal_region_error( + let propagated = self.try_propagate_universal_region_error( longer_fr, shorter_fr, - infcx, body, - local_names, - upvars, - mir_def_id, propagated_outlives_requirements, - outlives_suggestion, - errors_buffer, - region_naming, - ) + ); + + if propagated { + None + } else { + // If we are not in a context where we can't propagate errors, or we + // could not shrink `fr` to something smaller, then just report an + // error. + // + // Note: in this case, we use the unapproximated regions to report the + // error. This gives better error messages in some cases. + let db = self.report_error( + body, + local_names, + upvars, + infcx, + mir_def_id, + longer_fr, + NLLRegionVariableOrigin::FreeRegion, + shorter_fr, + outlives_suggestion, + region_naming, + ); + + db.buffer(errors_buffer); + + Some(ErrorReported) + } } - fn report_or_propagate_universal_region_error( + /// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's + /// creator. If we cannot, then we report an error to the user. + /// + /// Returns `true` if the error was propagated, and `false` otherwise. + fn try_propagate_universal_region_error( &self, longer_fr: RegionVid, shorter_fr: RegionVid, - infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - local_names: &IndexVec>, - upvars: &[Upvar], - mir_def_id: DefId, propagated_outlives_requirements: &mut Option<&mut Vec>>, - outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>, - errors_buffer: &mut Vec, - region_naming: &mut RegionErrorNamingCtx, - ) -> Option { - debug!( - "report_or_propagate_universal_region_error: fr={:?} does not outlive shorter_fr={:?}", - longer_fr, shorter_fr, - ); - + ) -> bool { if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `longer_fr` until we find a non-local region (if we do). // We'll call it `fr-` -- it's ever so slightly smaller than // `longer_fr`. - if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) { - debug!("report_or_propagate_universal_region_error: fr_minus={:?}", fr_minus); + debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); let blame_span_category = self.find_outlives_blame_span(body, longer_fr, @@ -1648,7 +1648,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .universal_region_relations .non_local_upper_bounds(&shorter_fr); debug!( - "report_or_propagate_universal_region_error: shorter_fr_plus={:?}", + "try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus ); for &&fr in &shorter_fr_plus { @@ -1660,32 +1660,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { category: blame_span_category.0, }); } - return None; + return true; } } - // If we are not in a context where we can't propagate errors, or we - // could not shrink `fr` to something smaller, then just report an - // error. - // - // Note: in this case, we use the unapproximated regions to report the - // error. This gives better error messages in some cases. - let db = self.report_error( - body, - local_names, - upvars, - infcx, - mir_def_id, - longer_fr, - NLLRegionVariableOrigin::FreeRegion, - shorter_fr, - outlives_suggestion, - region_naming, - ); - - db.buffer(errors_buffer); - - Some(ErrorReported) + false } fn check_bound_universal_region( From 12d65c28a6beac211edab9981a924f8c9331c9ec Mon Sep 17 00:00:00 2001 From: Christoph Schmidler Date: Sun, 8 Dec 2019 21:22:18 +0100 Subject: [PATCH 04/17] Split up ptr/mod.rs in libcore, one with implementation detail for const ptr and the other with mut ptr --- src/libcore/ptr/const_ptr.rs | 755 ++++++++++ src/libcore/ptr/mod.rs | 1696 +--------------------- src/libcore/ptr/mut_ptr.rs | 925 ++++++++++++ src/test/ui/consts/offset_from_ub.stderr | 20 +- 4 files changed, 1695 insertions(+), 1701 deletions(-) create mode 100644 src/libcore/ptr/const_ptr.rs create mode 100644 src/libcore/ptr/mut_ptr.rs diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs new file mode 100644 index 0000000000000..be2b7ff5f773b --- /dev/null +++ b/src/libcore/ptr/const_ptr.rs @@ -0,0 +1,755 @@ +use crate::cmp::Ordering::{self, Less, Equal, Greater}; +use crate::intrinsics; +use crate::mem; +use super::*; + +// ignore-tidy-undocumented-unsafe + +#[lang = "const_ptr"] +impl *const T { + /// Returns `true` if the pointer is null. + /// + /// Note that unsized types have many possible null pointers, as only the + /// raw data pointer is considered, not their length, vtable, etc. + /// Therefore, two pointers that are null may still not compare equal to + /// each other. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "Follow the rabbit"; + /// let ptr: *const u8 = s.as_ptr(); + /// assert!(!ptr.is_null()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_null(self) -> bool { + // Compare via a cast to a thin pointer, so fat pointers are only + // considering their "data" part for null-ness. + (self as *const u8) == null() + } + + /// Casts to a pointer of another type. + #[stable(feature = "ptr_cast", since = "1.38.0")] + #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")] + #[inline] + pub const fn cast(self) -> *const U { + self as _ + } + + /// Returns `None` if the pointer is null, or else returns a reference to + /// the value wrapped in `Some`. + /// + /// # Safety + /// + /// While this method and its mutable counterpart are useful for + /// null-safety, it is important to note that this is still an unsafe + /// operation because the returned value could be pointing to invalid + /// memory. + /// + /// When calling this method, you have to ensure that *either* the pointer is NULL *or* + /// all of the following is true: + /// - it is properly aligned + /// - it must point to an initialized instance of T; in particular, the pointer must be + /// "dereferencable" in the sense defined [here]. + /// + /// This applies even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// + /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does + /// not necessarily reflect the actual lifetime of the data. *You* must enforce + /// Rust's aliasing rules. In particular, for the duration of this lifetime, + /// the memory the pointer points to must not get mutated (except inside `UnsafeCell`). + /// + /// [here]: crate::ptr#safety + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let ptr: *const u8 = &10u8 as *const u8; + /// + /// unsafe { + /// if let Some(val_back) = ptr.as_ref() { + /// println!("We got back the value: {}!", val_back); + /// } + /// } + /// ``` + /// + /// # Null-unchecked version + /// + /// If you are sure the pointer can never be null and are looking for some kind of + /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can + /// dereference the pointer directly. + /// + /// ``` + /// let ptr: *const u8 = &10u8 as *const u8; + /// + /// unsafe { + /// let val_back = &*ptr; + /// println!("We got back the value: {}!", val_back); + /// } + /// ``` + #[stable(feature = "ptr_as_ref", since = "1.9.0")] + #[inline] + pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { + if self.is_null() { None } else { Some(&*self) } + } + + /// Calculates the offset from a pointer. + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// [`wrapping_offset`]: #method.wrapping_offset + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// let ptr: *const u8 = s.as_ptr(); + /// + /// unsafe { + /// println!("{}", *ptr.offset(1) as char); + /// println!("{}", *ptr.offset(2) as char); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn offset(self, count: isize) -> *const T + where + T: Sized, + { + intrinsics::offset(self, count) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// *not* the same as `y`, and dereferencing it is undefined behavior + /// unless `x` and `y` point into the same allocated object. + /// + /// Compared to [`offset`], this method basically delays the requirement of staying + /// within the same allocated object: [`offset`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`offset`]: #method.offset + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_offset(6); + /// + /// // This loop prints "1, 3, 5, " + /// while ptr != end_rounded_up { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_offset(step); + /// } + /// ``` + #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] + #[inline] + pub fn wrapping_offset(self, count: isize) -> *const T + where + T: Sized, + { + unsafe { intrinsics::arith_offset(self, count) } + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// This function is the inverse of [`offset`]. + /// + /// [`offset`]: #method.offset + /// [`wrapping_offset_from`]: #method.wrapping_offset_from + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and other pointer must be either in bounds or one + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T`. + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// The compiler and standard library generally try to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset_from`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")] + #[inline] + pub const unsafe fn offset_from(self, origin: *const T) -> isize + where + T: Sized, + { + let pointee_size = mem::size_of::(); + let ok = 0 < pointee_size && pointee_size <= isize::max_value() as usize; + // assert that the pointee size is valid in a const eval compatible way + // FIXME: do this with a real assert at some point + [()][(!ok) as usize]; + intrinsics::ptr_offset_from(self, origin) + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers is not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// Though this method is safe for any two pointers, note that its result + /// will be mostly useless if the two pointers aren't into the same allocated + /// object, for example if they point to two different local variables. + /// + /// # Panics + /// + /// This function panics if `T` is a zero-sized type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); + /// assert_eq!(ptr1.wrapping_offset(2), ptr2); + /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); + /// + /// let ptr1: *const i32 = 3 as _; + /// let ptr2: *const i32 = 13 as _; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// ``` + #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] + #[inline] + pub fn wrapping_offset_from(self, origin: *const T) -> isize + where + T: Sized, + { + let pointee_size = mem::size_of::(); + assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + + let d = isize::wrapping_sub(self as _, origin as _); + d.wrapping_div(pointee_size as _) + } + + /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a `usize`. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_add`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// [`wrapping_add`]: #method.wrapping_add + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// let ptr: *const u8 = s.as_ptr(); + /// + /// unsafe { + /// println!("{}", *ptr.add(1) as char); + /// println!("{}", *ptr.add(2) as char); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn add(self, count: usize) -> Self + where + T: Sized, + { + self.offset(count as isize) + } + + /// Calculates the offset from a pointer (convenience for + /// `.offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_sub`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// [`wrapping_sub`]: #method.wrapping_sub + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// + /// unsafe { + /// let end: *const u8 = s.as_ptr().add(3); + /// println!("{}", *end.sub(1) as char); + /// println!("{}", *end.sub(2) as char); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn sub(self, count: usize) -> Self + where + T: Sized, + { + self.offset((count as isize).wrapping_neg()) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// (convenience for `.wrapping_offset(count as isize)`) + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// Compared to [`add`], this method basically delays the requirement of staying + /// within the same allocated object: [`add`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_add` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`add`]: #method.add + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_add(6); + /// + /// // This loop prints "1, 3, 5, " + /// while ptr != end_rounded_up { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_add(step); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub fn wrapping_add(self, count: usize) -> Self + where + T: Sized, + { + self.wrapping_offset(count as isize) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// Compared to [`sub`], this method basically delays the requirement of staying + /// within the same allocated object: [`sub`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`sub`]: #method.sub + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements (backwards) + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let start_rounded_down = ptr.wrapping_sub(2); + /// ptr = ptr.wrapping_add(4); + /// let step = 2; + /// // This loop prints "5, 3, 1, " + /// while ptr != start_rounded_down { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_sub(step); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub fn wrapping_sub(self, count: usize) -> Self + where + T: Sized, + { + self.wrapping_offset((count as isize).wrapping_neg()) + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// See [`ptr::read`] for safety concerns and examples. + /// + /// [`ptr::read`]: ./ptr/fn.read.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read(self) -> T + where + T: Sized, + { + read(self) + } + + /// Performs a volatile read of the value from `self` without moving it. This + /// leaves the memory in `self` unchanged. + /// + /// Volatile operations are intended to act on I/O memory, and are guaranteed + /// to not be elided or reordered by the compiler across other volatile + /// operations. + /// + /// See [`ptr::read_volatile`] for safety concerns and examples. + /// + /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read_volatile(self) -> T + where + T: Sized, + { + read_volatile(self) + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// Unlike `read`, the pointer may be unaligned. + /// + /// See [`ptr::read_unaligned`] for safety concerns and examples. + /// + /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read_unaligned(self) -> T + where + T: Sized, + { + read_unaligned(self) + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy`]. + /// + /// See [`ptr::copy`] for safety concerns and examples. + /// + /// [`ptr::copy`]: ./ptr/fn.copy.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_to(self, dest: *mut T, count: usize) + where + T: Sized, + { + copy(self, dest, count) + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may *not* overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. + /// + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) + where + T: Sized, + { + copy_nonoverlapping(self, dest, count) + } + + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// + /// If it is not possible to align the pointer, the implementation returns + /// `usize::max_value()`. It is permissible for the implementation to *always* + /// return `usize::max_value()`. Only your algorithm's performance can depend + /// on getting a usable offset here, not its correctness. + /// + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `wrapping_add` method. + /// + /// There are no guarantees whatsoever that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// # fn foo(n: usize) { + /// # use std::mem::align_of; + /// # unsafe { + /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; + /// let ptr = &x[n] as *const u8; + /// let offset = ptr.align_offset(align_of::()); + /// if offset < x.len() - n - 1 { + /// let u16_ptr = ptr.add(offset) as *const u16; + /// assert_ne!(*u16_ptr, 500); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } } + /// ``` + #[stable(feature = "align_offset", since = "1.36.0")] + pub fn align_offset(self, align: usize) -> usize + where + T: Sized, + { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + unsafe { align_offset(self, align) } + } +} + +// Equality for pointers +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for *const T { + #[inline] + fn eq(&self, other: &*const T) -> bool { *self == *other } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for *const T {} + +// Comparison for pointers +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for *const T { + #[inline] + fn cmp(&self, other: &*const T) -> Ordering { + if self < other { + Less + } else if self == other { + Equal + } else { + Greater + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for *const T { + #[inline] + fn partial_cmp(&self, other: &*const T) -> Option { + Some(self.cmp(other)) + } + + #[inline] + fn lt(&self, other: &*const T) -> bool { *self < *other } + + #[inline] + fn le(&self, other: &*const T) -> bool { *self <= *other } + + #[inline] + fn gt(&self, other: &*const T) -> bool { *self > *other } + + #[inline] + fn ge(&self, other: &*const T) -> bool { *self >= *other } +} diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 776165e7bd70c..a3a73ff6c6cf6 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -65,16 +65,15 @@ //! [`write_volatile`]: ./fn.write_volatile.html //! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling -// ignore-tidy-filelength // ignore-tidy-undocumented-unsafe #![stable(feature = "rust1", since = "1.0.0")] -use crate::cmp::Ordering::{self, Equal, Greater, Less}; +use crate::intrinsics; use crate::fmt; use crate::hash; -use crate::intrinsics; use crate::mem::{self, MaybeUninit}; +use crate::cmp::Ordering; #[stable(feature = "rust1", since = "1.0.0")] pub use crate::intrinsics::copy_nonoverlapping; @@ -93,6 +92,9 @@ mod unique; #[unstable(feature = "ptr_internals", issue = "0")] pub use unique::Unique; +mod const_ptr; +mod mut_ptr; + /// Executes the destructor (if any) of the pointed-to value. /// /// This is semantically equivalent to calling [`ptr::read`] and discarding @@ -1034,1586 +1036,6 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { intrinsics::volatile_store(dst, src); } -#[lang = "const_ptr"] -impl *const T { - /// Returns `true` if the pointer is null. - /// - /// Note that unsized types have many possible null pointers, as only the - /// raw data pointer is considered, not their length, vtable, etc. - /// Therefore, two pointers that are null may still not compare equal to - /// each other. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "Follow the rabbit"; - /// let ptr: *const u8 = s.as_ptr(); - /// assert!(!ptr.is_null()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_null(self) -> bool { - // Compare via a cast to a thin pointer, so fat pointers are only - // considering their "data" part for null-ness. - (self as *const u8) == null() - } - - /// Casts to a pointer of another type. - #[stable(feature = "ptr_cast", since = "1.38.0")] - #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")] - #[inline] - pub const fn cast(self) -> *const U { - self as _ - } - - /// Returns `None` if the pointer is null, or else returns a reference to - /// the value wrapped in `Some`. - /// - /// # Safety - /// - /// While this method and its mutable counterpart are useful for - /// null-safety, it is important to note that this is still an unsafe - /// operation because the returned value could be pointing to invalid - /// memory. - /// - /// When calling this method, you have to ensure that *either* the pointer is NULL *or* - /// all of the following is true: - /// - it is properly aligned - /// - it must point to an initialized instance of T; in particular, the pointer must be - /// "dereferencable" in the sense defined [here]. - /// - /// This applies even if the result of this method is unused! - /// (The part about being initialized is not yet fully decided, but until - /// it is, the only safe approach is to ensure that they are indeed initialized.) - /// - /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does - /// not necessarily reflect the actual lifetime of the data. *You* must enforce - /// Rust's aliasing rules. In particular, for the duration of this lifetime, - /// the memory the pointer points to must not get mutated (except inside `UnsafeCell`). - /// - /// [here]: crate::ptr#safety - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let ptr: *const u8 = &10u8 as *const u8; - /// - /// unsafe { - /// if let Some(val_back) = ptr.as_ref() { - /// println!("We got back the value: {}!", val_back); - /// } - /// } - /// ``` - /// - /// # Null-unchecked version - /// - /// If you are sure the pointer can never be null and are looking for some kind of - /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can - /// dereference the pointer directly. - /// - /// ``` - /// let ptr: *const u8 = &10u8 as *const u8; - /// - /// unsafe { - /// let val_back = &*ptr; - /// println!("We got back the value: {}!", val_back); - /// } - /// ``` - #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[inline] - pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { - if self.is_null() { None } else { Some(&*self) } - } - - /// Calculates the offset from a pointer. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_offset`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// [`wrapping_offset`]: #method.wrapping_offset - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// let ptr: *const u8 = s.as_ptr(); - /// - /// unsafe { - /// println!("{}", *ptr.offset(1) as char); - /// println!("{}", *ptr.offset(2) as char); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn offset(self, count: isize) -> *const T - where - T: Sized, - { - intrinsics::offset(self, count) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is - /// *not* the same as `y`, and dereferencing it is undefined behavior - /// unless `x` and `y` point into the same allocated object. - /// - /// Compared to [`offset`], this method basically delays the requirement of staying - /// within the same allocated object: [`offset`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized - /// better and is thus preferrable in performance-sensitive code. - /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// - /// [`offset`]: #method.offset - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let step = 2; - /// let end_rounded_up = ptr.wrapping_offset(6); - /// - /// // This loop prints "1, 3, 5, " - /// while ptr != end_rounded_up { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_offset(step); - /// } - /// ``` - #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] - #[inline] - pub fn wrapping_offset(self, count: isize) -> *const T - where - T: Sized, - { - unsafe { intrinsics::arith_offset(self, count) } - } - - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// This function is the inverse of [`offset`]. - /// - /// [`offset`]: #method.offset - /// [`wrapping_offset_from`]: #method.wrapping_offset_from - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and other pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance between the pointers, in bytes, must be an exact multiple - /// of the size of `T`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// The compiler and standard library generally try to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_offset_from`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Panics - /// - /// This function panics if `T` is a Zero-Sized Type ("ZST"). - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_offset_from)] - /// - /// let a = [0; 5]; - /// let ptr1: *const i32 = &a[1]; - /// let ptr2: *const i32 = &a[3]; - /// unsafe { - /// assert_eq!(ptr2.offset_from(ptr1), 2); - /// assert_eq!(ptr1.offset_from(ptr2), -2); - /// assert_eq!(ptr1.offset(2), ptr2); - /// assert_eq!(ptr2.offset(-2), ptr1); - /// } - /// ``` - #[unstable(feature = "ptr_offset_from", issue = "41079")] - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")] - #[inline] - pub const unsafe fn offset_from(self, origin: *const T) -> isize - where - T: Sized, - { - let pointee_size = mem::size_of::(); - let ok = 0 < pointee_size && pointee_size <= isize::max_value() as usize; - // assert that the pointee size is valid in a const eval compatible way - // FIXME: do this with a real assert at some point - [()][(!ok) as usize]; - intrinsics::ptr_offset_from(self, origin) - } - - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// If the address different between the two pointers is not a multiple of - /// `mem::size_of::()` then the result of the division is rounded towards - /// zero. - /// - /// Though this method is safe for any two pointers, note that its result - /// will be mostly useless if the two pointers aren't into the same allocated - /// object, for example if they point to two different local variables. - /// - /// # Panics - /// - /// This function panics if `T` is a zero-sized type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_wrapping_offset_from)] - /// - /// let a = [0; 5]; - /// let ptr1: *const i32 = &a[1]; - /// let ptr2: *const i32 = &a[3]; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); - /// assert_eq!(ptr1.wrapping_offset(2), ptr2); - /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); - /// - /// let ptr1: *const i32 = 3 as _; - /// let ptr2: *const i32 = 13 as _; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// ``` - #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] - #[inline] - pub fn wrapping_offset_from(self, origin: *const T) -> isize - where - T: Sized, - { - let pointee_size = mem::size_of::(); - assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); - - let d = isize::wrapping_sub(self as _, origin as _); - d.wrapping_div(pointee_size as _) - } - - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_add`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// [`wrapping_add`]: #method.wrapping_add - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// let ptr: *const u8 = s.as_ptr(); - /// - /// unsafe { - /// println!("{}", *ptr.add(1) as char); - /// println!("{}", *ptr.add(2) as char); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn add(self, count: usize) -> Self - where - T: Sized, - { - self.offset(count as isize) - } - - /// Calculates the offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_sub`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// [`wrapping_sub`]: #method.wrapping_sub - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// - /// unsafe { - /// let end: *const u8 = s.as_ptr().add(3); - /// println!("{}", *end.sub(1) as char); - /// println!("{}", *end.sub(2) as char); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn sub(self, count: usize) -> Self - where - T: Sized, - { - self.offset((count as isize).wrapping_neg()) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// Compared to [`add`], this method basically delays the requirement of staying - /// within the same allocated object: [`add`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_add` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized - /// better and is thus preferrable in performance-sensitive code. - /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// - /// [`add`]: #method.add - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let step = 2; - /// let end_rounded_up = ptr.wrapping_add(6); - /// - /// // This loop prints "1, 3, 5, " - /// while ptr != end_rounded_up { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_add(step); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub fn wrapping_add(self, count: usize) -> Self - where - T: Sized, - { - self.wrapping_offset(count as isize) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// Compared to [`sub`], this method basically delays the requirement of staying - /// within the same allocated object: [`sub`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized - /// better and is thus preferrable in performance-sensitive code. - /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// - /// [`sub`]: #method.sub - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements (backwards) - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let start_rounded_down = ptr.wrapping_sub(2); - /// ptr = ptr.wrapping_add(4); - /// let step = 2; - /// // This loop prints "5, 3, 1, " - /// while ptr != start_rounded_down { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_sub(step); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub fn wrapping_sub(self, count: usize) -> Self - where - T: Sized, - { - self.wrapping_offset((count as isize).wrapping_neg()) - } - - /// Reads the value from `self` without moving it. This leaves the - /// memory in `self` unchanged. - /// - /// See [`ptr::read`] for safety concerns and examples. - /// - /// [`ptr::read`]: ./ptr/fn.read.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read(self) -> T - where - T: Sized, - { - read(self) - } - - /// Performs a volatile read of the value from `self` without moving it. This - /// leaves the memory in `self` unchanged. - /// - /// Volatile operations are intended to act on I/O memory, and are guaranteed - /// to not be elided or reordered by the compiler across other volatile - /// operations. - /// - /// See [`ptr::read_volatile`] for safety concerns and examples. - /// - /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read_volatile(self) -> T - where - T: Sized, - { - read_volatile(self) - } - - /// Reads the value from `self` without moving it. This leaves the - /// memory in `self` unchanged. - /// - /// Unlike `read`, the pointer may be unaligned. - /// - /// See [`ptr::read_unaligned`] for safety concerns and examples. - /// - /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read_unaligned(self) -> T - where - T: Sized, - { - read_unaligned(self) - } - - /// Copies `count * size_of` bytes from `self` to `dest`. The source - /// and destination may overlap. - /// - /// NOTE: this has the *same* argument order as [`ptr::copy`]. - /// - /// See [`ptr::copy`] for safety concerns and examples. - /// - /// [`ptr::copy`]: ./ptr/fn.copy.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_to(self, dest: *mut T, count: usize) - where - T: Sized, - { - copy(self, dest, count) - } - - /// Copies `count * size_of` bytes from `self` to `dest`. The source - /// and destination may *not* overlap. - /// - /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. - /// - /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. - /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) - where - T: Sized, - { - copy_nonoverlapping(self, dest, count) - } - - /// Computes the offset that needs to be applied to the pointer in order to make it aligned to - /// `align`. - /// - /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. It is permissible for the implementation to *always* - /// return `usize::max_value()`. Only your algorithm's performance can depend - /// on getting a usable offset here, not its correctness. - /// - /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be - /// used with the `wrapping_add` method. - /// - /// There are no guarantees whatsoever that offsetting the pointer will not overflow or go - /// beyond the allocation that the pointer points into. It is up to the caller to ensure that - /// the returned offset is correct in all terms other than alignment. - /// - /// # Panics - /// - /// The function panics if `align` is not a power-of-two. - /// - /// # Examples - /// - /// Accessing adjacent `u8` as `u16` - /// - /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; - /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; - /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); - /// } else { - /// // while the pointer can be aligned via `offset`, it would point - /// // outside the allocation - /// } - /// # } } - /// ``` - #[stable(feature = "align_offset", since = "1.36.0")] - pub fn align_offset(self, align: usize) -> usize - where - T: Sized, - { - if !align.is_power_of_two() { - panic!("align_offset: align is not a power-of-two"); - } - unsafe { align_offset(self, align) } - } -} - -#[lang = "mut_ptr"] -impl *mut T { - /// Returns `true` if the pointer is null. - /// - /// Note that unsized types have many possible null pointers, as only the - /// raw data pointer is considered, not their length, vtable, etc. - /// Therefore, two pointers that are null may still not compare equal to - /// each other. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = [1, 2, 3]; - /// let ptr: *mut u32 = s.as_mut_ptr(); - /// assert!(!ptr.is_null()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_null(self) -> bool { - // Compare via a cast to a thin pointer, so fat pointers are only - // considering their "data" part for null-ness. - (self as *mut u8) == null_mut() - } - - /// Casts to a pointer of another type. - #[stable(feature = "ptr_cast", since = "1.38.0")] - #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")] - #[inline] - pub const fn cast(self) -> *mut U { - self as _ - } - - /// Returns `None` if the pointer is null, or else returns a reference to - /// the value wrapped in `Some`. - /// - /// # Safety - /// - /// While this method and its mutable counterpart are useful for - /// null-safety, it is important to note that this is still an unsafe - /// operation because the returned value could be pointing to invalid - /// memory. - /// - /// When calling this method, you have to ensure that if the pointer is - /// non-NULL, then it is properly aligned, dereferencable (for the whole - /// size of `T`) and points to an initialized instance of `T`. This applies - /// even if the result of this method is unused! - /// (The part about being initialized is not yet fully decided, but until - /// it is, the only safe approach is to ensure that they are indeed initialized.) - /// - /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does - /// not necessarily reflect the actual lifetime of the data. It is up to the - /// caller to ensure that for the duration of this lifetime, the memory this - /// pointer points to does not get written to outside of `UnsafeCell`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let ptr: *mut u8 = &mut 10u8 as *mut u8; - /// - /// unsafe { - /// if let Some(val_back) = ptr.as_ref() { - /// println!("We got back the value: {}!", val_back); - /// } - /// } - /// ``` - /// - /// # Null-unchecked version - /// - /// If you are sure the pointer can never be null and are looking for some kind of - /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can - /// dereference the pointer directly. - /// - /// ``` - /// let ptr: *mut u8 = &mut 10u8 as *mut u8; - /// - /// unsafe { - /// let val_back = &*ptr; - /// println!("We got back the value: {}!", val_back); - /// } - /// ``` - #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[inline] - pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { - if self.is_null() { None } else { Some(&*self) } - } - - /// Calculates the offset from a pointer. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_offset`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// [`wrapping_offset`]: #method.wrapping_offset - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = [1, 2, 3]; - /// let ptr: *mut u32 = s.as_mut_ptr(); - /// - /// unsafe { - /// println!("{}", *ptr.offset(1)); - /// println!("{}", *ptr.offset(2)); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn offset(self, count: isize) -> *mut T - where - T: Sized, - { - intrinsics::offset(self, count) as *mut T - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is - /// *not* the same as `y`, and dereferencing it is undefined behavior - /// unless `x` and `y` point into the same allocated object. - /// - /// Compared to [`offset`], this method basically delays the requirement of staying - /// within the same allocated object: [`offset`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized - /// better and is thus preferrable in performance-sensitive code. - /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// - /// [`offset`]: #method.offset - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements - /// let mut data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *mut u8 = data.as_mut_ptr(); - /// let step = 2; - /// let end_rounded_up = ptr.wrapping_offset(6); - /// - /// while ptr != end_rounded_up { - /// unsafe { - /// *ptr = 0; - /// } - /// ptr = ptr.wrapping_offset(step); - /// } - /// assert_eq!(&data, &[0, 2, 0, 4, 0]); - /// ``` - #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] - #[inline] - pub fn wrapping_offset(self, count: isize) -> *mut T - where - T: Sized, - { - unsafe { intrinsics::arith_offset(self, count) as *mut T } - } - - /// Returns `None` if the pointer is null, or else returns a mutable - /// reference to the value wrapped in `Some`. - /// - /// # Safety - /// - /// As with [`as_ref`], this is unsafe because it cannot verify the validity - /// of the returned pointer, nor can it ensure that the lifetime `'a` - /// returned is indeed a valid lifetime for the contained data. - /// - /// When calling this method, you have to ensure that *either* the pointer is NULL *or* - /// all of the following is true: - /// - it is properly aligned - /// - it must point to an initialized instance of T; in particular, the pointer must be - /// "dereferencable" in the sense defined [here]. - /// - /// This applies even if the result of this method is unused! - /// (The part about being initialized is not yet fully decided, but until - /// it is the only safe approach is to ensure that they are indeed initialized.) - /// - /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does - /// not necessarily reflect the actual lifetime of the data. *You* must enforce - /// Rust's aliasing rules. In particular, for the duration of this lifetime, - /// the memory this pointer points to must not get accessed (read or written) - /// through any other pointer. - /// - /// [here]: crate::ptr#safety - /// [`as_ref`]: #method.as_ref - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = [1, 2, 3]; - /// let ptr: *mut u32 = s.as_mut_ptr(); - /// let first_value = unsafe { ptr.as_mut().unwrap() }; - /// *first_value = 4; - /// println!("{:?}", s); // It'll print: "[4, 2, 3]". - /// ``` - #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[inline] - pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { - if self.is_null() { None } else { Some(&mut *self) } - } - - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// This function is the inverse of [`offset`]. - /// - /// [`offset`]: #method.offset-1 - /// [`wrapping_offset_from`]: #method.wrapping_offset_from-1 - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and other pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance between the pointers, in bytes, must be an exact multiple - /// of the size of `T`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// The compiler and standard library generally try to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_offset_from`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Panics - /// - /// This function panics if `T` is a Zero-Sized Type ("ZST"). - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_offset_from)] - /// - /// let mut a = [0; 5]; - /// let ptr1: *mut i32 = &mut a[1]; - /// let ptr2: *mut i32 = &mut a[3]; - /// unsafe { - /// assert_eq!(ptr2.offset_from(ptr1), 2); - /// assert_eq!(ptr1.offset_from(ptr2), -2); - /// assert_eq!(ptr1.offset(2), ptr2); - /// assert_eq!(ptr2.offset(-2), ptr1); - /// } - /// ``` - #[unstable(feature = "ptr_offset_from", issue = "41079")] - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")] - #[inline] - pub const unsafe fn offset_from(self, origin: *const T) -> isize - where - T: Sized, - { - (self as *const T).offset_from(origin) - } - - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// If the address different between the two pointers is not a multiple of - /// `mem::size_of::()` then the result of the division is rounded towards - /// zero. - /// - /// Though this method is safe for any two pointers, note that its result - /// will be mostly useless if the two pointers aren't into the same allocated - /// object, for example if they point to two different local variables. - /// - /// # Panics - /// - /// This function panics if `T` is a zero-sized type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_wrapping_offset_from)] - /// - /// let mut a = [0; 5]; - /// let ptr1: *mut i32 = &mut a[1]; - /// let ptr2: *mut i32 = &mut a[3]; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); - /// assert_eq!(ptr1.wrapping_offset(2), ptr2); - /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); - /// - /// let ptr1: *mut i32 = 3 as _; - /// let ptr2: *mut i32 = 13 as _; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// ``` - #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] - #[inline] - pub fn wrapping_offset_from(self, origin: *const T) -> isize - where - T: Sized, - { - (self as *const T).wrapping_offset_from(origin) - } - - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_add`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// [`wrapping_add`]: #method.wrapping_add - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// let ptr: *const u8 = s.as_ptr(); - /// - /// unsafe { - /// println!("{}", *ptr.add(1) as char); - /// println!("{}", *ptr.add(2) as char); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn add(self, count: usize) -> Self - where - T: Sized, - { - self.offset(count as isize) - } - - /// Calculates the offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_sub`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// [`wrapping_sub`]: #method.wrapping_sub - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// - /// unsafe { - /// let end: *const u8 = s.as_ptr().add(3); - /// println!("{}", *end.sub(1) as char); - /// println!("{}", *end.sub(2) as char); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn sub(self, count: usize) -> Self - where - T: Sized, - { - self.offset((count as isize).wrapping_neg()) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// Compared to [`add`], this method basically delays the requirement of staying - /// within the same allocated object: [`add`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_add` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized - /// better and is thus preferrable in performance-sensitive code. - /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// - /// [`add`]: #method.add - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let step = 2; - /// let end_rounded_up = ptr.wrapping_add(6); - /// - /// // This loop prints "1, 3, 5, " - /// while ptr != end_rounded_up { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_add(step); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub fn wrapping_add(self, count: usize) -> Self - where - T: Sized, - { - self.wrapping_offset(count as isize) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. - /// - /// Compared to [`sub`], this method basically delays the requirement of staying - /// within the same allocated object: [`sub`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized - /// better and is thus preferrable in performance-sensitive code. - /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// - /// [`sub`]: #method.sub - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements (backwards) - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let start_rounded_down = ptr.wrapping_sub(2); - /// ptr = ptr.wrapping_add(4); - /// let step = 2; - /// // This loop prints "5, 3, 1, " - /// while ptr != start_rounded_down { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_sub(step); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub fn wrapping_sub(self, count: usize) -> Self - where - T: Sized, - { - self.wrapping_offset((count as isize).wrapping_neg()) - } - - /// Reads the value from `self` without moving it. This leaves the - /// memory in `self` unchanged. - /// - /// See [`ptr::read`] for safety concerns and examples. - /// - /// [`ptr::read`]: ./ptr/fn.read.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read(self) -> T - where - T: Sized, - { - read(self) - } - - /// Performs a volatile read of the value from `self` without moving it. This - /// leaves the memory in `self` unchanged. - /// - /// Volatile operations are intended to act on I/O memory, and are guaranteed - /// to not be elided or reordered by the compiler across other volatile - /// operations. - /// - /// See [`ptr::read_volatile`] for safety concerns and examples. - /// - /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read_volatile(self) -> T - where - T: Sized, - { - read_volatile(self) - } - - /// Reads the value from `self` without moving it. This leaves the - /// memory in `self` unchanged. - /// - /// Unlike `read`, the pointer may be unaligned. - /// - /// See [`ptr::read_unaligned`] for safety concerns and examples. - /// - /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read_unaligned(self) -> T - where - T: Sized, - { - read_unaligned(self) - } - - /// Copies `count * size_of` bytes from `self` to `dest`. The source - /// and destination may overlap. - /// - /// NOTE: this has the *same* argument order as [`ptr::copy`]. - /// - /// See [`ptr::copy`] for safety concerns and examples. - /// - /// [`ptr::copy`]: ./ptr/fn.copy.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_to(self, dest: *mut T, count: usize) - where - T: Sized, - { - copy(self, dest, count) - } - - /// Copies `count * size_of` bytes from `self` to `dest`. The source - /// and destination may *not* overlap. - /// - /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. - /// - /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. - /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) - where - T: Sized, - { - copy_nonoverlapping(self, dest, count) - } - - /// Copies `count * size_of` bytes from `src` to `self`. The source - /// and destination may overlap. - /// - /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. - /// - /// See [`ptr::copy`] for safety concerns and examples. - /// - /// [`ptr::copy`]: ./ptr/fn.copy.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_from(self, src: *const T, count: usize) - where - T: Sized, - { - copy(src, self, count) - } - - /// Copies `count * size_of` bytes from `src` to `self`. The source - /// and destination may *not* overlap. - /// - /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. - /// - /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. - /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) - where - T: Sized, - { - copy_nonoverlapping(src, self, count) - } - - /// Executes the destructor (if any) of the pointed-to value. - /// - /// See [`ptr::drop_in_place`] for safety concerns and examples. - /// - /// [`ptr::drop_in_place`]: ./ptr/fn.drop_in_place.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn drop_in_place(self) { - drop_in_place(self) - } - - /// Overwrites a memory location with the given value without reading or - /// dropping the old value. - /// - /// See [`ptr::write`] for safety concerns and examples. - /// - /// [`ptr::write`]: ./ptr/fn.write.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn write(self, val: T) - where - T: Sized, - { - write(self, val) - } - - /// Invokes memset on the specified pointer, setting `count * size_of::()` - /// bytes of memory starting at `self` to `val`. - /// - /// See [`ptr::write_bytes`] for safety concerns and examples. - /// - /// [`ptr::write_bytes`]: ./ptr/fn.write_bytes.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn write_bytes(self, val: u8, count: usize) - where - T: Sized, - { - write_bytes(self, val, count) - } - - /// Performs a volatile write of a memory location with the given value without - /// reading or dropping the old value. - /// - /// Volatile operations are intended to act on I/O memory, and are guaranteed - /// to not be elided or reordered by the compiler across other volatile - /// operations. - /// - /// See [`ptr::write_volatile`] for safety concerns and examples. - /// - /// [`ptr::write_volatile`]: ./ptr/fn.write_volatile.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn write_volatile(self, val: T) - where - T: Sized, - { - write_volatile(self, val) - } - - /// Overwrites a memory location with the given value without reading or - /// dropping the old value. - /// - /// Unlike `write`, the pointer may be unaligned. - /// - /// See [`ptr::write_unaligned`] for safety concerns and examples. - /// - /// [`ptr::write_unaligned`]: ./ptr/fn.write_unaligned.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn write_unaligned(self, val: T) - where - T: Sized, - { - write_unaligned(self, val) - } - - /// Replaces the value at `self` with `src`, returning the old - /// value, without dropping either. - /// - /// See [`ptr::replace`] for safety concerns and examples. - /// - /// [`ptr::replace`]: ./ptr/fn.replace.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn replace(self, src: T) -> T - where - T: Sized, - { - replace(self, src) - } - - /// Swaps the values at two mutable locations of the same type, without - /// deinitializing either. They may overlap, unlike `mem::swap` which is - /// otherwise equivalent. - /// - /// See [`ptr::swap`] for safety concerns and examples. - /// - /// [`ptr::swap`]: ./ptr/fn.swap.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn swap(self, with: *mut T) - where - T: Sized, - { - swap(self, with) - } - - /// Computes the offset that needs to be applied to the pointer in order to make it aligned to - /// `align`. - /// - /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. It is permissible for the implementation to *always* - /// return `usize::max_value()`. Only your algorithm's performance can depend - /// on getting a usable offset here, not its correctness. - /// - /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be - /// used with the `wrapping_add` method. - /// - /// There are no guarantees whatsoever that offsetting the pointer will not overflow or go - /// beyond the allocation that the pointer points into. It is up to the caller to ensure that - /// the returned offset is correct in all terms other than alignment. - /// - /// # Panics - /// - /// The function panics if `align` is not a power-of-two. - /// - /// # Examples - /// - /// Accessing adjacent `u8` as `u16` - /// - /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; - /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; - /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); - /// } else { - /// // while the pointer can be aligned via `offset`, it would point - /// // outside the allocation - /// } - /// # } } - /// ``` - #[stable(feature = "align_offset", since = "1.36.0")] - pub fn align_offset(self, align: usize) -> usize - where - T: Sized, - { - if !align.is_power_of_two() { - panic!("align_offset: align is not a power-of-two"); - } - unsafe { align_offset(self, align) } - } -} - /// Align pointer `p`. /// /// Calculate offset (in terms of elements of `stride` stride) that has to be applied @@ -2728,29 +1150,6 @@ pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { usize::max_value() } -// Equality for pointers -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for *const T { - #[inline] - fn eq(&self, other: &*const T) -> bool { - *self == *other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for *const T {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for *mut T { - #[inline] - fn eq(&self, other: &*mut T) -> bool { - *self == *other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for *mut T {} - /// Compares raw pointers for equality. /// /// This is the same as using the `==` operator, but less generic: @@ -2944,88 +1343,3 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L } - -// Comparison for pointers -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for *const T { - #[inline] - fn cmp(&self, other: &*const T) -> Ordering { - if self < other { - Less - } else if self == other { - Equal - } else { - Greater - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for *const T { - #[inline] - fn partial_cmp(&self, other: &*const T) -> Option { - Some(self.cmp(other)) - } - - #[inline] - fn lt(&self, other: &*const T) -> bool { - *self < *other - } - - #[inline] - fn le(&self, other: &*const T) -> bool { - *self <= *other - } - - #[inline] - fn gt(&self, other: &*const T) -> bool { - *self > *other - } - - #[inline] - fn ge(&self, other: &*const T) -> bool { - *self >= *other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for *mut T { - #[inline] - fn cmp(&self, other: &*mut T) -> Ordering { - if self < other { - Less - } else if self == other { - Equal - } else { - Greater - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for *mut T { - #[inline] - fn partial_cmp(&self, other: &*mut T) -> Option { - Some(self.cmp(other)) - } - - #[inline] - fn lt(&self, other: &*mut T) -> bool { - *self < *other - } - - #[inline] - fn le(&self, other: &*mut T) -> bool { - *self <= *other - } - - #[inline] - fn gt(&self, other: &*mut T) -> bool { - *self > *other - } - - #[inline] - fn ge(&self, other: &*mut T) -> bool { - *self >= *other - } -} diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs new file mode 100644 index 0000000000000..fd5decbd7eac5 --- /dev/null +++ b/src/libcore/ptr/mut_ptr.rs @@ -0,0 +1,925 @@ +use crate::cmp::Ordering::{self, Less, Equal, Greater}; +use crate::intrinsics; +use super::*; + +// ignore-tidy-undocumented-unsafe + +#[lang = "mut_ptr"] +impl *mut T { + /// Returns `true` if the pointer is null. + /// + /// Note that unsized types have many possible null pointers, as only the + /// raw data pointer is considered, not their length, vtable, etc. + /// Therefore, two pointers that are null may still not compare equal to + /// each other. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = [1, 2, 3]; + /// let ptr: *mut u32 = s.as_mut_ptr(); + /// assert!(!ptr.is_null()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_null(self) -> bool { + // Compare via a cast to a thin pointer, so fat pointers are only + // considering their "data" part for null-ness. + (self as *mut u8) == null_mut() + } + + /// Casts to a pointer of another type. + #[stable(feature = "ptr_cast", since = "1.38.0")] + #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")] + #[inline] + pub const fn cast(self) -> *mut U { + self as _ + } + + /// Returns `None` if the pointer is null, or else returns a reference to + /// the value wrapped in `Some`. + /// + /// # Safety + /// + /// While this method and its mutable counterpart are useful for + /// null-safety, it is important to note that this is still an unsafe + /// operation because the returned value could be pointing to invalid + /// memory. + /// + /// When calling this method, you have to ensure that if the pointer is + /// non-NULL, then it is properly aligned, dereferencable (for the whole + /// size of `T`) and points to an initialized instance of `T`. This applies + /// even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// + /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does + /// not necessarily reflect the actual lifetime of the data. It is up to the + /// caller to ensure that for the duration of this lifetime, the memory this + /// pointer points to does not get written to outside of `UnsafeCell`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let ptr: *mut u8 = &mut 10u8 as *mut u8; + /// + /// unsafe { + /// if let Some(val_back) = ptr.as_ref() { + /// println!("We got back the value: {}!", val_back); + /// } + /// } + /// ``` + /// + /// # Null-unchecked version + /// + /// If you are sure the pointer can never be null and are looking for some kind of + /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can + /// dereference the pointer directly. + /// + /// ``` + /// let ptr: *mut u8 = &mut 10u8 as *mut u8; + /// + /// unsafe { + /// let val_back = &*ptr; + /// println!("We got back the value: {}!", val_back); + /// } + /// ``` + #[stable(feature = "ptr_as_ref", since = "1.9.0")] + #[inline] + pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { + if self.is_null() { None } else { Some(&*self) } + } + + /// Calculates the offset from a pointer. + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// [`wrapping_offset`]: #method.wrapping_offset + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = [1, 2, 3]; + /// let ptr: *mut u32 = s.as_mut_ptr(); + /// + /// unsafe { + /// println!("{}", *ptr.offset(1)); + /// println!("{}", *ptr.offset(2)); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn offset(self, count: isize) -> *mut T + where + T: Sized, + { + intrinsics::offset(self, count) as *mut T + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// *not* the same as `y`, and dereferencing it is undefined behavior + /// unless `x` and `y` point into the same allocated object. + /// + /// Compared to [`offset`], this method basically delays the requirement of staying + /// within the same allocated object: [`offset`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`offset`]: #method.offset + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements + /// let mut data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *mut u8 = data.as_mut_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_offset(6); + /// + /// while ptr != end_rounded_up { + /// unsafe { + /// *ptr = 0; + /// } + /// ptr = ptr.wrapping_offset(step); + /// } + /// assert_eq!(&data, &[0, 2, 0, 4, 0]); + /// ``` + #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] + #[inline] + pub fn wrapping_offset(self, count: isize) -> *mut T + where + T: Sized, + { + unsafe { intrinsics::arith_offset(self, count) as *mut T } + } + + /// Returns `None` if the pointer is null, or else returns a mutable + /// reference to the value wrapped in `Some`. + /// + /// # Safety + /// + /// As with [`as_ref`], this is unsafe because it cannot verify the validity + /// of the returned pointer, nor can it ensure that the lifetime `'a` + /// returned is indeed a valid lifetime for the contained data. + /// + /// When calling this method, you have to ensure that *either* the pointer is NULL *or* + /// all of the following is true: + /// - it is properly aligned + /// - it must point to an initialized instance of T; in particular, the pointer must be + /// "dereferencable" in the sense defined [here]. + /// + /// This applies even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is the only safe approach is to ensure that they are indeed initialized.) + /// + /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does + /// not necessarily reflect the actual lifetime of the data. *You* must enforce + /// Rust's aliasing rules. In particular, for the duration of this lifetime, + /// the memory this pointer points to must not get accessed (read or written) + /// through any other pointer. + /// + /// [here]: crate::ptr#safety + /// [`as_ref`]: #method.as_ref + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = [1, 2, 3]; + /// let ptr: *mut u32 = s.as_mut_ptr(); + /// let first_value = unsafe { ptr.as_mut().unwrap() }; + /// *first_value = 4; + /// println!("{:?}", s); // It'll print: "[4, 2, 3]". + /// ``` + #[stable(feature = "ptr_as_ref", since = "1.9.0")] + #[inline] + pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { + if self.is_null() { None } else { Some(&mut *self) } + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// This function is the inverse of [`offset`]. + /// + /// [`offset`]: #method.offset-1 + /// [`wrapping_offset_from`]: #method.wrapping_offset_from-1 + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and other pointer must be either in bounds or one + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T`. + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// The compiler and standard library generally try to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset_from`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_offset_from)] + /// + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")] + #[inline] + pub const unsafe fn offset_from(self, origin: *const T) -> isize + where + T: Sized, + { + (self as *const T).offset_from(origin) + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers is not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// Though this method is safe for any two pointers, note that its result + /// will be mostly useless if the two pointers aren't into the same allocated + /// object, for example if they point to two different local variables. + /// + /// # Panics + /// + /// This function panics if `T` is a zero-sized type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset_from)] + /// + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); + /// assert_eq!(ptr1.wrapping_offset(2), ptr2); + /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); + /// + /// let ptr1: *mut i32 = 3 as _; + /// let ptr2: *mut i32 = 13 as _; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// ``` + #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] + #[inline] + pub fn wrapping_offset_from(self, origin: *const T) -> isize + where + T: Sized, + { + (self as *const T).wrapping_offset_from(origin) + } + + /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a `usize`. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_add`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// [`wrapping_add`]: #method.wrapping_add + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// let ptr: *const u8 = s.as_ptr(); + /// + /// unsafe { + /// println!("{}", *ptr.add(1) as char); + /// println!("{}", *ptr.add(2) as char); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn add(self, count: usize) -> Self + where + T: Sized, + { + self.offset(count as isize) + } + + /// Calculates the offset from a pointer (convenience for + /// `.offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_sub`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// [`wrapping_sub`]: #method.wrapping_sub + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// + /// unsafe { + /// let end: *const u8 = s.as_ptr().add(3); + /// println!("{}", *end.sub(1) as char); + /// println!("{}", *end.sub(2) as char); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn sub(self, count: usize) -> Self + where + T: Sized, + { + self.offset((count as isize).wrapping_neg()) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// (convenience for `.wrapping_offset(count as isize)`) + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// Compared to [`add`], this method basically delays the requirement of staying + /// within the same allocated object: [`add`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_add` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`add`]: #method.add + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_add(6); + /// + /// // This loop prints "1, 3, 5, " + /// while ptr != end_rounded_up { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_add(step); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub fn wrapping_add(self, count: usize) -> Self + where + T: Sized, + { + self.wrapping_offset(count as isize) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// In particular, the resulting pointer remains attached to the same allocated + /// object that `self` points to. It may *not* be used to access a + /// different allocated object. Note that in Rust, + /// every (stack-allocated) variable is considered a separate allocated object. + /// + /// Compared to [`sub`], this method basically delays the requirement of staying + /// within the same allocated object: [`sub`] is immediate Undefined Behavior when + /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads + /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized + /// better and is thus preferrable in performance-sensitive code. + /// + /// If you need to cross object boundaries, cast the pointer to an integer and + /// do the arithmetic there. + /// + /// [`sub`]: #method.sub + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements (backwards) + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let start_rounded_down = ptr.wrapping_sub(2); + /// ptr = ptr.wrapping_add(4); + /// let step = 2; + /// // This loop prints "5, 3, 1, " + /// while ptr != start_rounded_down { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_sub(step); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub fn wrapping_sub(self, count: usize) -> Self + where + T: Sized, + { + self.wrapping_offset((count as isize).wrapping_neg()) + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// See [`ptr::read`] for safety concerns and examples. + /// + /// [`ptr::read`]: ./ptr/fn.read.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read(self) -> T + where + T: Sized, + { + read(self) + } + + /// Performs a volatile read of the value from `self` without moving it. This + /// leaves the memory in `self` unchanged. + /// + /// Volatile operations are intended to act on I/O memory, and are guaranteed + /// to not be elided or reordered by the compiler across other volatile + /// operations. + /// + /// See [`ptr::read_volatile`] for safety concerns and examples. + /// + /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read_volatile(self) -> T + where + T: Sized, + { + read_volatile(self) + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// Unlike `read`, the pointer may be unaligned. + /// + /// See [`ptr::read_unaligned`] for safety concerns and examples. + /// + /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read_unaligned(self) -> T + where + T: Sized, + { + read_unaligned(self) + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy`]. + /// + /// See [`ptr::copy`] for safety concerns and examples. + /// + /// [`ptr::copy`]: ./ptr/fn.copy.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_to(self, dest: *mut T, count: usize) + where + T: Sized, + { + copy(self, dest, count) + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may *not* overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. + /// + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) + where + T: Sized, + { + copy_nonoverlapping(self, dest, count) + } + + /// Copies `count * size_of` bytes from `src` to `self`. The source + /// and destination may overlap. + /// + /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. + /// + /// See [`ptr::copy`] for safety concerns and examples. + /// + /// [`ptr::copy`]: ./ptr/fn.copy.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_from(self, src: *const T, count: usize) + where + T: Sized, + { + copy(src, self, count) + } + + /// Copies `count * size_of` bytes from `src` to `self`. The source + /// and destination may *not* overlap. + /// + /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. + /// + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) + where + T: Sized, + { + copy_nonoverlapping(src, self, count) + } + + /// Executes the destructor (if any) of the pointed-to value. + /// + /// See [`ptr::drop_in_place`] for safety concerns and examples. + /// + /// [`ptr::drop_in_place`]: ./ptr/fn.drop_in_place.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn drop_in_place(self) { + drop_in_place(self) + } + + /// Overwrites a memory location with the given value without reading or + /// dropping the old value. + /// + /// See [`ptr::write`] for safety concerns and examples. + /// + /// [`ptr::write`]: ./ptr/fn.write.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn write(self, val: T) + where + T: Sized, + { + write(self, val) + } + + /// Invokes memset on the specified pointer, setting `count * size_of::()` + /// bytes of memory starting at `self` to `val`. + /// + /// See [`ptr::write_bytes`] for safety concerns and examples. + /// + /// [`ptr::write_bytes`]: ./ptr/fn.write_bytes.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn write_bytes(self, val: u8, count: usize) + where + T: Sized, + { + write_bytes(self, val, count) + } + + /// Performs a volatile write of a memory location with the given value without + /// reading or dropping the old value. + /// + /// Volatile operations are intended to act on I/O memory, and are guaranteed + /// to not be elided or reordered by the compiler across other volatile + /// operations. + /// + /// See [`ptr::write_volatile`] for safety concerns and examples. + /// + /// [`ptr::write_volatile`]: ./ptr/fn.write_volatile.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn write_volatile(self, val: T) + where + T: Sized, + { + write_volatile(self, val) + } + + /// Overwrites a memory location with the given value without reading or + /// dropping the old value. + /// + /// Unlike `write`, the pointer may be unaligned. + /// + /// See [`ptr::write_unaligned`] for safety concerns and examples. + /// + /// [`ptr::write_unaligned`]: ./ptr/fn.write_unaligned.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn write_unaligned(self, val: T) + where + T: Sized, + { + write_unaligned(self, val) + } + + /// Replaces the value at `self` with `src`, returning the old + /// value, without dropping either. + /// + /// See [`ptr::replace`] for safety concerns and examples. + /// + /// [`ptr::replace`]: ./ptr/fn.replace.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn replace(self, src: T) -> T + where + T: Sized, + { + replace(self, src) + } + + /// Swaps the values at two mutable locations of the same type, without + /// deinitializing either. They may overlap, unlike `mem::swap` which is + /// otherwise equivalent. + /// + /// See [`ptr::swap`] for safety concerns and examples. + /// + /// [`ptr::swap`]: ./ptr/fn.swap.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn swap(self, with: *mut T) + where + T: Sized, + { + swap(self, with) + } + + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// + /// If it is not possible to align the pointer, the implementation returns + /// `usize::max_value()`. It is permissible for the implementation to *always* + /// return `usize::max_value()`. Only your algorithm's performance can depend + /// on getting a usable offset here, not its correctness. + /// + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `wrapping_add` method. + /// + /// There are no guarantees whatsoever that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// # fn foo(n: usize) { + /// # use std::mem::align_of; + /// # unsafe { + /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; + /// let ptr = &x[n] as *const u8; + /// let offset = ptr.align_offset(align_of::()); + /// if offset < x.len() - n - 1 { + /// let u16_ptr = ptr.add(offset) as *const u16; + /// assert_ne!(*u16_ptr, 500); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } } + /// ``` + #[stable(feature = "align_offset", since = "1.36.0")] + pub fn align_offset(self, align: usize) -> usize + where + T: Sized, + { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + unsafe { align_offset(self, align) } + } +} + +// Equality for pointers +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for *mut T { + #[inline] + fn eq(&self, other: &*mut T) -> bool { *self == *other } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for *mut T {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for *mut T { + #[inline] + fn cmp(&self, other: &*mut T) -> Ordering { + if self < other { + Less + } else if self == other { + Equal + } else { + Greater + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for *mut T { + #[inline] + fn partial_cmp(&self, other: &*mut T) -> Option { + Some(self.cmp(other)) + } + + #[inline] + fn lt(&self, other: &*mut T) -> bool { *self < *other } + + #[inline] + fn le(&self, other: &*mut T) -> bool { *self <= *other } + + #[inline] + fn gt(&self, other: &*mut T) -> bool { *self > *other } + + #[inline] + fn ge(&self, other: &*mut T) -> bool { *self >= *other } +} diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index 1bd09034bfc91..ac08b2f2427c7 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -1,11 +1,11 @@ error: any use of this value will cause an error - --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | ptr_offset_from cannot compute offset of pointers into different allocations. - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:19:27 + | inside call to `std::ptr::const_ptr::::offset_from` at $DIR/offset_from_ub.rs:19:27 | ::: $DIR/offset_from_ub.rs:13:1 | @@ -21,13 +21,13 @@ LL | | }; = note: `#[deny(const_err)]` on by default error: any use of this value will cause an error - --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | a memory access tried to interpret some bytes as a pointer - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:25:14 + | inside call to `std::ptr::const_ptr::::offset_from` at $DIR/offset_from_ub.rs:25:14 | ::: $DIR/offset_from_ub.rs:23:1 | @@ -38,13 +38,13 @@ LL | | }; | |__- error: any use of this value will cause an error - --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | exact_div: 1 cannot be divided by 2 without remainder - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:33:14 + | inside call to `std::ptr::const_ptr::::offset_from` at $DIR/offset_from_ub.rs:33:14 | ::: $DIR/offset_from_ub.rs:28:1 | @@ -58,13 +58,13 @@ LL | | }; | |__- error: any use of this value will cause an error - --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | invalid use of NULL pointer - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:39:14 + | inside call to `std::ptr::const_ptr::::offset_from` at $DIR/offset_from_ub.rs:39:14 | ::: $DIR/offset_from_ub.rs:36:1 | @@ -76,13 +76,13 @@ LL | | }; | |__- error: any use of this value will cause an error - --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | a memory access tried to interpret some bytes as a pointer - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:46:14 + | inside call to `std::ptr::const_ptr::::offset_from` at $DIR/offset_from_ub.rs:46:14 | ::: $DIR/offset_from_ub.rs:42:1 | From ffbde9f44a4cb91e05d2f8524d24c6ac6cad66c6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 19 Dec 2019 17:19:55 +0100 Subject: [PATCH 05/17] is_binding_pat: don't use _ arm --- src/librustc/middle/region.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index aa6f28398289f..b33101ad78b98 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1221,7 +1221,14 @@ fn resolve_local<'tcx>( is_binding_pat(&subpat) } - _ => false, + PatKind::Or(_) | + PatKind::Ref(_, _) | + PatKind::Binding(hir::BindingAnnotation::Unannotated, ..) | + PatKind::Binding(hir::BindingAnnotation::Mutable, ..) | + PatKind::Wild | + PatKind::Path(_) | + PatKind::Lit(_) | + PatKind::Range(_, _, _) => false, } } From 4414f0d0e0e30f961b26a1f357fb78118be16cc7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 19 Dec 2019 17:33:10 +0100 Subject: [PATCH 06/17] is_binding_pat: treat or-pat like tuple-pat --- src/librustc/middle/region.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index b33101ad78b98..e050e5f894255 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1173,6 +1173,7 @@ fn resolve_local<'tcx>( /// | VariantName(..., P&, ...) /// | [ ..., P&, ... ] /// | ( ..., P&, ... ) + /// | ... "|" P& "|" ... /// | box P& fn is_binding_pat(pat: &hir::Pat) -> bool { // Note that the code below looks for *explicit* refs only, that is, it won't @@ -1212,6 +1213,7 @@ fn resolve_local<'tcx>( pats3.iter().any(|p| is_binding_pat(&p)) } + PatKind::Or(ref subpats) | PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => { subpats.iter().any(|p| is_binding_pat(&p)) @@ -1221,7 +1223,6 @@ fn resolve_local<'tcx>( is_binding_pat(&subpat) } - PatKind::Or(_) | PatKind::Ref(_, _) | PatKind::Binding(hir::BindingAnnotation::Unannotated, ..) | PatKind::Binding(hir::BindingAnnotation::Mutable, ..) | From 43fc9347dae11968166c9a92e1879ce61ed8f1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 12 Dec 2019 14:48:46 -0800 Subject: [PATCH 07/17] Tweak errors for missing associated types and type parameters --- src/librustc_typeck/astconv.rs | 277 +++++++++++++----- src/test/compile-fail/issue-23595-1.rs | 4 +- .../ui/associated-type-bounds/duplicate.rs | 138 ++++----- .../associated-type-bounds/duplicate.stderr | 138 ++++----- ...mbig-between-bound-and-where-clause.stderr | 54 ++++ ...pe-projection-from-multiple-supertraits.rs | 15 +- ...rojection-from-multiple-supertraits.stderr | 57 +++- .../associated-types-incomplete-object.rs | 6 +- .../associated-types-incomplete-object.stderr | 21 +- .../associated-types-path-1.stderr | 9 + src/test/ui/error-codes/E0191.stderr | 6 +- src/test/ui/error-codes/E0220.stderr | 6 +- src/test/ui/error-codes/E0221.stderr | 20 +- src/test/ui/error-codes/E0393.stderr | 5 +- src/test/ui/error-codes/E0719.stderr | 4 +- ...-gate-unboxed-closures-manual-impls.stderr | 9 +- .../feature-gate-unboxed-closures.stderr | 3 +- src/test/ui/issues/issue-19482.rs | 2 +- src/test/ui/issues/issue-19482.stderr | 6 +- src/test/ui/issues/issue-21950.stderr | 21 +- src/test/ui/issues/issue-22370.stderr | 5 +- src/test/ui/issues/issue-22434.rs | 2 +- src/test/ui/issues/issue-22434.stderr | 6 +- src/test/ui/issues/issue-22560.stderr | 39 ++- src/test/ui/issues/issue-23024.rs | 2 +- src/test/ui/issues/issue-23024.stderr | 9 +- src/test/ui/issues/issue-28344.stderr | 8 +- ...type-argument-instead-of-assoc-type.stderr | 9 +- .../trait-alias-object-fail.stderr | 6 +- ...ject-with-self-in-projection-output-bad.rs | 4 +- ...-with-self-in-projection-output-bad.stderr | 12 +- ...parameter-defaults-referencing-Self.stderr | 9 +- .../unboxed-closure-feature-gate.stderr | 2 +- ...nboxed-closure-sugar-not-used-on-fn.stderr | 10 +- .../unboxed-closure-sugar-region.stderr | 2 +- ...ong-number-number-type-parameters-3.stderr | 2 +- .../ui/unspecified-self-in-trait-ref.stderr | 9 +- 37 files changed, 616 insertions(+), 321 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 290f86d626e6c..c0d110971c90f 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -491,8 +491,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Option>, args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs>, bool), provided_kind: impl Fn(&GenericParamDef, &GenericArg) -> subst::GenericArg<'tcx>, - inferred_kind: impl Fn(Option<&[subst::GenericArg<'tcx>]>, &GenericParamDef, bool) - -> subst::GenericArg<'tcx>, + mut inferred_kind: impl FnMut( + Option<&[subst::GenericArg<'tcx>]>, + &GenericParamDef, + bool, + ) -> subst::GenericArg<'tcx>, ) -> SubstsRef<'tcx> { // Collect the segments of the path; we need to substitute arguments // for parameters throughout the entire path (wherever there are @@ -665,6 +668,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { false }; + let mut missing_type_params = vec![]; let substs = Self::create_substs_for_generic_args( tcx, def_id, @@ -702,16 +706,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // defaults. This will lead to an ICE if we are not // careful! if default_needs_object_self(param) { - struct_span_err!(tcx.sess, span, E0393, - "the type parameter `{}` must be explicitly specified", - param.name - ) - .span_label(span, format!( - "missing reference to `{}`", param.name)) - .note(&format!( - "because of the default `Self` reference, type parameters \ - must be specified on object types")) - .emit(); + missing_type_params.push(param.name.to_string()); tcx.types.err.into() } else { // This is a default type parameter. @@ -748,6 +743,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }, ); + if !missing_type_params.is_empty() { + let display = missing_type_params.iter() + .map(|n| format!("`{}`", n)) + .collect::>().join(", "); + let mut err = struct_span_err!(tcx.sess, span, E0393, + "the type parameter{} {} must be explicitly specified", + pluralize!(missing_type_params.len()), + display, + ); + err.span_label(self.tcx().def_span(def_id), &format!( + "type parameter{} {} must be specified for this", + pluralize!(missing_type_params.len()), + display, + )); + let mut suggested = false; + if let (Ok(snippet), true) = ( + tcx.sess.source_map().span_to_snippet(span), + // Don't suggest setting the type params if there are some already: the order is + // tricky to get right and the user will already know what the syntax is. + generic_args.args.is_empty(), + ) { + if snippet.ends_with('>') { + // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion + // we would have to preserve the right order. For now, as clearly the user is + // aware of the syntax, we do nothing. + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + err.span_suggestion( + span, + &format!( + "set the type parameter{plural} to the desired type{plural}", + plural=pluralize!(missing_type_params.len()), + ), + format!("{}<{}>", snippet, missing_type_params.join(", ")), + Applicability::HasPlaceholders, + ); + suggested = true; + } + } + if !suggested { + err.span_label(span, format!( + "missing reference{} to {}", + pluralize!(missing_type_params.len()), + display, + )); + } + err.note(&format!("because of the default `Self` reference, type parameters must be \ + specified on object types")); + err.emit(); + } // Convert associated-type bindings or constraints into a separate vector. // Example: Given this: @@ -813,8 +859,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); + let path_span = if trait_ref.path.segments.len() == 1 { + // FIXME: `trait_ref.path.span` can point to a full path with multiple + // segments, even though `trait_ref.path.segments` is of length `1`. Work + // around that bug here, even though it should be fixed elsewhere. + // This would otherwise cause an invalid suggestion. For an example, look at + // `src/test/ui/issues/issue-28344.rs`. + trait_ref.path.segments[0].ident.span + } else { + trait_ref.path.span + }; let (substs, assoc_bindings, potential_assoc_types) = self.create_substs_for_ast_trait_ref( - trait_ref.path.span, + path_span, trait_def_id, self_ty, trait_ref.path.segments.last().unwrap(), @@ -899,8 +955,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment, ) -> (SubstsRef<'tcx>, Vec>, Option>) { - debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", - trait_segment); + debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); let trait_def = self.tcx().trait_def(trait_def_id); @@ -908,13 +963,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_segment.generic_args().parenthesized != trait_def.paren_sugar { // For now, require that parenthetical notation be used only with `Fn()` etc. - let msg = if trait_def.paren_sugar { - "the precise format of `Fn`-family traits' type parameters is subject to change. \ - Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead" + let (msg, help) = if trait_def.paren_sugar { + ( + "the precise format of `Fn`-family traits' type parameters is subject to \ + change", + Some("use parenthetical notation instead: `Fn(Foo, Bar) -> Baz`"), + ) } else { - "parenthetical notation is only stable when used with `Fn`-family traits" + ("parenthetical notation is only stable when used with `Fn`-family traits", None) }; - feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures, span, msg).emit(); + let sess = &self.tcx().sess.parse_sess; + let mut err = feature_err(sess, sym::unboxed_closures, span, msg); + if let Some(help) = help { + err.help(help); + } + err.emit(); } self.create_substs_for_ast_path(span, @@ -1168,11 +1231,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if !speculative { dup_bindings.entry(assoc_ty.def_id) .and_modify(|prev_span| { - struct_span_err!(self.tcx().sess, binding.span, E0719, - "the value of the associated type `{}` (from the trait `{}`) \ - is already specified", - binding.item_name, - tcx.def_path_str(assoc_ty.container.id())) + struct_span_err!( + self.tcx().sess, + binding.span, + E0719, + "the value of the associated type `{}` (from trait `{}`) \ + is already specified", + binding.item_name, + tcx.def_path_str(assoc_ty.container.id()) + ) .span_label(binding.span, "re-bound here") .span_label(*prev_span, format!("`{}` bound here first", binding.item_name)) .emit(); @@ -1211,25 +1278,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Ok(()) } - fn ast_path_to_ty(&self, - span: Span, - did: DefId, - item_segment: &hir::PathSegment) - -> Ty<'tcx> - { + fn ast_path_to_ty(&self, span: Span, did: DefId, item_segment: &hir::PathSegment) -> Ty<'tcx> { let substs = self.ast_path_substs_for_ty(span, did, item_segment); - self.normalize_ty( - span, - self.tcx().at(span).type_of(did).subst(self.tcx(), substs) - ) + self.normalize_ty(span, self.tcx().at(span).type_of(did).subst(self.tcx(), substs)) } - fn conv_object_ty_poly_trait_ref(&self, + fn conv_object_ty_poly_trait_ref( + &self, span: Span, trait_bounds: &[hir::PolyTraitRef], - lifetime: &hir::Lifetime) - -> Ty<'tcx> - { + lifetime: &hir::Lifetime, + ) -> Ty<'tcx> { let tcx = self.tcx(); let mut bounds = Bounds::default(); @@ -1337,63 +1396,111 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if !associated_types.is_empty() { + // Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path` + // `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will + // be valid, otherwise we would suggest `dyn Foo + 'a`. See tests + // `issue-22434.rs` and `issue-22560.rs` for examples. + let sugg_span = if potential_assoc_types.is_empty() && trait_bounds.len() == 1 { + if trait_bounds[0].trait_ref.path.segments.len() == 1 && + trait_bounds[0].trait_ref.path.segments[0].args.is_none() + { + // FIXME: `trait_ref.path.span` can point to a full path with multiple + // segments, even though `trait_ref.path.segments` is of length `1`. Work + // around that bug here, even though it should be fixed elsewhere. + // This would otherwise cause an invalid suggestion. For an example, look at + // `src/test/ui/issues/issue-28344.rs`. + trait_bounds[0].trait_ref.path.segments[0].ident.span + } else { + trait_bounds[0].trait_ref.path.span + } + } else { + span + }; let names = associated_types.iter().map(|item_def_id| { let assoc_item = tcx.associated_item(*item_def_id); let trait_def_id = assoc_item.container.id(); - format!( - "`{}` (from the trait `{}`)", - assoc_item.ident, - tcx.def_path_str(trait_def_id), - ) + format!("`{}` (from trait `{}`)", assoc_item.ident, tcx.def_path_str(trait_def_id)) }).collect::>().join(", "); let mut err = struct_span_err!( tcx.sess, - span, + sugg_span, E0191, "the value of the associated type{} {} must be specified", pluralize!(associated_types.len()), names, ); - let (suggest, potential_assoc_types_spans) = - if potential_assoc_types.len() == associated_types.len() { - // Only suggest when the amount of missing associated types equals the number of - // extra type arguments present, as that gives us a relatively high confidence - // that the user forgot to give the associtated type's name. The canonical - // example would be trying to use `Iterator` instead of - // `Iterator`. - (true, potential_assoc_types) - } else { - (false, Vec::new()) - }; let mut suggestions = Vec::new(); + let mut applicability = Applicability::MaybeIncorrect; for (i, item_def_id) in associated_types.iter().enumerate() { let assoc_item = tcx.associated_item(*item_def_id); - err.span_label( - span, - format!("associated type `{}` must be specified", assoc_item.ident), - ); if let Some(sp) = tcx.hir().span_if_local(*item_def_id) { err.span_label(sp, format!("`{}` defined here", assoc_item.ident)); } - if suggest { + if potential_assoc_types.len() == associated_types.len() { + // Only suggest when the amount of missing associated types equals the number of + // extra type arguments present, as that gives us a relatively high confidence + // that the user forgot to give the associtated type's name. The canonical + // example would be trying to use `Iterator` instead of + // `Iterator`. if let Ok(snippet) = tcx.sess.source_map().span_to_snippet( - potential_assoc_types_spans[i], + potential_assoc_types[i], ) { suggestions.push(( - potential_assoc_types_spans[i], + potential_assoc_types[i], format!("{} = {}", assoc_item.ident, snippet), )); } } } + let mut suggestions_len = suggestions.len(); + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sugg_span) { + if potential_assoc_types.is_empty() && trait_bounds.len() == 1 && + // Do not attempt to suggest when we don't know which path segment needs the + // type parameter set. + trait_bounds[0].trait_ref.path.segments.len() == 1 + { + debug!("path segments {:?}", trait_bounds[0].trait_ref.path.segments); + applicability = Applicability::HasPlaceholders; + let assoc_types: Vec = associated_types.iter() + .map(|item_def_id| { + let assoc_item = tcx.associated_item(*item_def_id); + format!("{} = Type", assoc_item.ident) + }) + .collect(); + let sugg = assoc_types.join(", "); + if snippet.ends_with('>') { + // The user wrote `Trait<'a>` or similar and we don't have a type we can + // suggest, but at least we can clue them to the correct syntax + // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the + // suggestion. + suggestions.push((sugg_span, format!( + "{}, {}>", + &snippet[..snippet.len()-1], + sugg, + ))); + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + suggestions.push((sugg_span, format!("{}<{}>", snippet, sugg))); + } + suggestions_len = assoc_types.len(); + } + } + if suggestions.len() != 1 { + // We don't need this label if there's an inline suggestion, show otherwise. + let names = associated_types.iter() + .map(|t| format!("`{}`", tcx.associated_item(*t).ident)) + .collect::>() + .join(", "); + err.span_label(span, format!( + "associated type{} {} must be specified", + pluralize!(associated_types.len()), + names, + )); + } if !suggestions.is_empty() { - let msg = format!("if you meant to specify the associated {}, write", - if suggestions.len() == 1 { "type" } else { "types" }); - err.multipart_suggestion( - &msg, - suggestions, - Applicability::MaybeIncorrect, - ); + let msg = format!("specify the associated type{}", pluralize!(suggestions_len)); + err.multipart_suggestion(&msg, suggestions, applicability); } err.emit(); } @@ -1584,15 +1691,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .and_then(|item| self.tcx().hir().span_if_local(item.def_id)); - if let Some(span) = bound_span { - err.span_label(span, format!("ambiguous `{}` from `{}`", - assoc_name, - bound.print_only_trait_path())); + if let Some(bound_span) = bound_span { + err.span_label(bound_span, format!( + "ambiguous `{}` from `{}`", + assoc_name, + bound.print_only_trait_path(), + )); + err.span_suggestion( + span, + "use fully qualified syntax to disambiguate", + format!( + "<{} as {}>::{}", + ty_param_name, + bound.print_only_trait_path(), + assoc_name, + ), + Applicability::MaybeIncorrect, + ); } else { - span_note!(&mut err, span, - "associated type `{}` could derive from `{}`", - ty_param_name, - bound.print_only_trait_path()); + err.note(&format!( + "associated type `{}` could derive from `{}`", + ty_param_name, + bound.print_only_trait_path(), + )); } } err.emit(); diff --git a/src/test/compile-fail/issue-23595-1.rs b/src/test/compile-fail/issue-23595-1.rs index 2912c4ead7a0a..1970b9af14e9a 100644 --- a/src/test/compile-fail/issue-23595-1.rs +++ b/src/test/compile-fail/issue-23595-1.rs @@ -1,12 +1,12 @@ #![feature(associated_type_defaults)] -use std::ops::{Index}; +use std::ops::Index; trait Hierarchy { type Value; type ChildKey; type Children = dyn Index; - //~^ ERROR: the value of the associated types `Value` (from the trait `Hierarchy`), `ChildKey` + //~^ ERROR: the value of the associated types `Value` (from trait `Hierarchy`), `ChildKey` fn data(&self) -> Option<(Self::Value, Self::Children)>; } diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs index a89fd9807da8f..64bc9eeec2529 100644 --- a/src/test/ui/associated-type-bounds/duplicate.rs +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -9,175 +9,175 @@ use std::iter; struct SI1> { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] struct SI2> { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] struct SI3> { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] struct SW1 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] struct SW2 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] struct SW3 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] enum EI1> { V(T) } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] enum EI2> { V(T) } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] enum EI3> { V(T) } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] enum EW1 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] enum EW2 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] enum EW3 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] union UI1> { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] union UI2> { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] union UI3> { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] union UW1 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] union UW2 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] union UW3 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FI1>() {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FI2>() {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FI3>() {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FW1() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FW2() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FW3() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT1() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT2() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT3() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FAPIT1(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FAPIT2(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FAPIT3(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] const CIT1: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] const CIT2: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] const CIT3: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] static SIT1: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] static SIT2: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] static SIT3: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn lit1() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn lit2() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn lit3() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] type TAI1> = T; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] type TAI2> = T; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] type TAI3> = T; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] type TAW1 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] type TAW2 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] type TAW3 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] type ETAI1> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses //~| ERROR could not find defining uses type ETAI2> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses //~| ERROR could not find defining uses type ETAI3> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses //~| ERROR could not find defining uses type ETAI4 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses //~| ERROR could not find defining uses type ETAI5 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses //~| ERROR could not find defining uses type ETAI6 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses //~| ERROR could not find defining uses trait TRI1> {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRI2> {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRI3> {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRS1: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRS2: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRS3: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRW1 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRW2 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRW3 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRSW1 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRSW2 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRSW3 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRA1 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRA2 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] trait TRA3 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] type TADyn1 = dyn Iterator; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses type TADyn2 = Box>; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses type TADyn3 = dyn Iterator; -//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses //~| ERROR could not find defining uses diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr index e5e85d6856fd3..caecc5e85f6e7 100644 --- a/src/test/ui/associated-type-bounds/duplicate.stderr +++ b/src/test/ui/associated-type-bounds/duplicate.stderr @@ -6,7 +6,7 @@ LL | #![feature(impl_trait_in_bindings)] | = note: `#[warn(incomplete_features)]` on by default -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:11:36 | LL | struct SI1> { f: T } @@ -14,7 +14,7 @@ LL | struct SI1> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:13:36 | LL | struct SI2> { f: T } @@ -22,7 +22,7 @@ LL | struct SI2> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:15:39 | LL | struct SI3> { f: T } @@ -30,7 +30,7 @@ LL | struct SI3> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:17:45 | LL | struct SW1 where T: Iterator { f: T } @@ -38,7 +38,7 @@ LL | struct SW1 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:19:45 | LL | struct SW2 where T: Iterator { f: T } @@ -46,7 +46,7 @@ LL | struct SW2 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:21:48 | LL | struct SW3 where T: Iterator { f: T } @@ -54,7 +54,7 @@ LL | struct SW3 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:24:34 | LL | enum EI1> { V(T) } @@ -62,7 +62,7 @@ LL | enum EI1> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:26:34 | LL | enum EI2> { V(T) } @@ -70,7 +70,7 @@ LL | enum EI2> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:28:37 | LL | enum EI3> { V(T) } @@ -78,7 +78,7 @@ LL | enum EI3> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:30:43 | LL | enum EW1 where T: Iterator { V(T) } @@ -86,7 +86,7 @@ LL | enum EW1 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:32:43 | LL | enum EW2 where T: Iterator { V(T) } @@ -94,7 +94,7 @@ LL | enum EW2 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:34:46 | LL | enum EW3 where T: Iterator { V(T) } @@ -102,7 +102,7 @@ LL | enum EW3 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:37:35 | LL | union UI1> { f: T } @@ -110,7 +110,7 @@ LL | union UI1> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:39:35 | LL | union UI2> { f: T } @@ -118,7 +118,7 @@ LL | union UI2> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:41:38 | LL | union UI3> { f: T } @@ -126,7 +126,7 @@ LL | union UI3> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:43:44 | LL | union UW1 where T: Iterator { f: T } @@ -134,7 +134,7 @@ LL | union UW1 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:45:44 | LL | union UW2 where T: Iterator { f: T } @@ -142,7 +142,7 @@ LL | union UW2 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:47:47 | LL | union UW3 where T: Iterator { f: T } @@ -150,7 +150,7 @@ LL | union UW3 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:50:32 | LL | fn FI1>() {} @@ -158,7 +158,7 @@ LL | fn FI1>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:52:32 | LL | fn FI2>() {} @@ -166,7 +166,7 @@ LL | fn FI2>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:54:35 | LL | fn FI3>() {} @@ -174,7 +174,7 @@ LL | fn FI3>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:56:43 | LL | fn FW1() where T: Iterator {} @@ -182,7 +182,7 @@ LL | fn FW1() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:58:43 | LL | fn FW2() where T: Iterator {} @@ -190,7 +190,7 @@ LL | fn FW2() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:60:46 | LL | fn FW3() where T: Iterator {} @@ -198,7 +198,7 @@ LL | fn FW3() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:69:40 | LL | fn FAPIT1(_: impl Iterator) {} @@ -206,7 +206,7 @@ LL | fn FAPIT1(_: impl Iterator) {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:71:40 | LL | fn FAPIT2(_: impl Iterator) {} @@ -214,7 +214,7 @@ LL | fn FAPIT2(_: impl Iterator) {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:73:43 | LL | fn FAPIT3(_: impl Iterator) {} @@ -222,7 +222,7 @@ LL | fn FAPIT3(_: impl Iterator) {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:63:42 | LL | fn FRPIT1() -> impl Iterator { iter::empty() } @@ -230,7 +230,7 @@ LL | fn FRPIT1() -> impl Iterator { iter::empty() } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:65:42 | LL | fn FRPIT2() -> impl Iterator { iter::empty() } @@ -238,7 +238,7 @@ LL | fn FRPIT2() -> impl Iterator { iter::empty() } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:67:45 | LL | fn FRPIT3() -> impl Iterator { iter::empty() } @@ -246,7 +246,7 @@ LL | fn FRPIT3() -> impl Iterator { iter::empty() | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:76:39 | LL | const CIT1: impl Iterator = iter::empty(); @@ -254,7 +254,7 @@ LL | const CIT1: impl Iterator = iter::empty(); | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:78:39 | LL | const CIT2: impl Iterator = iter::empty(); @@ -262,7 +262,7 @@ LL | const CIT2: impl Iterator = iter::empty(); | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:80:42 | LL | const CIT3: impl Iterator = iter::empty(); @@ -270,7 +270,7 @@ LL | const CIT3: impl Iterator = iter::empty(); | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:82:40 | LL | static SIT1: impl Iterator = iter::empty(); @@ -278,7 +278,7 @@ LL | static SIT1: impl Iterator = iter::empty(); | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:84:40 | LL | static SIT2: impl Iterator = iter::empty(); @@ -286,7 +286,7 @@ LL | static SIT2: impl Iterator = iter::empty(); | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:86:43 | LL | static SIT3: impl Iterator = iter::empty(); @@ -294,7 +294,7 @@ LL | static SIT3: impl Iterator = iter::empty(); | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:89:46 | LL | fn lit1() { let _: impl Iterator = iter::empty(); } @@ -302,7 +302,7 @@ LL | fn lit1() { let _: impl Iterator = iter::empty(); } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:91:46 | LL | fn lit2() { let _: impl Iterator = iter::empty(); } @@ -310,7 +310,7 @@ LL | fn lit2() { let _: impl Iterator = iter::empty(); } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:93:49 | LL | fn lit3() { let _: impl Iterator = iter::empty(); } @@ -318,7 +318,7 @@ LL | fn lit3() { let _: impl Iterator = iter::empt | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:96:35 | LL | type TAI1> = T; @@ -326,7 +326,7 @@ LL | type TAI1> = T; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:98:35 | LL | type TAI2> = T; @@ -334,7 +334,7 @@ LL | type TAI2> = T; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:100:38 | LL | type TAI3> = T; @@ -342,7 +342,7 @@ LL | type TAI3> = T; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:102:44 | LL | type TAW1 where T: Iterator = T; @@ -350,7 +350,7 @@ LL | type TAW1 where T: Iterator = T; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:104:44 | LL | type TAW2 where T: Iterator = T; @@ -358,7 +358,7 @@ LL | type TAW2 where T: Iterator = T; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:106:47 | LL | type TAW3 where T: Iterator = T; @@ -372,7 +372,7 @@ error: could not find defining uses LL | type ETAI1> = impl Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:109:36 | LL | type ETAI1> = impl Copy; @@ -386,7 +386,7 @@ error: could not find defining uses LL | type ETAI2> = impl Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:114:36 | LL | type ETAI2> = impl Copy; @@ -400,7 +400,7 @@ error: could not find defining uses LL | type ETAI3> = impl Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:119:39 | LL | type ETAI3> = impl Copy; @@ -414,7 +414,7 @@ error: could not find defining uses LL | type ETAI4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:124:40 | LL | type ETAI4 = impl Iterator; @@ -428,7 +428,7 @@ error: could not find defining uses LL | type ETAI5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:129:40 | LL | type ETAI5 = impl Iterator; @@ -442,7 +442,7 @@ error: could not find defining uses LL | type ETAI6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:134:43 | LL | type ETAI6 = impl Iterator; @@ -450,7 +450,7 @@ LL | type ETAI6 = impl Iterator; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:140:36 | LL | trait TRI1> {} @@ -458,7 +458,7 @@ LL | trait TRI1> {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:142:36 | LL | trait TRI2> {} @@ -466,7 +466,7 @@ LL | trait TRI2> {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:144:39 | LL | trait TRI3> {} @@ -474,7 +474,7 @@ LL | trait TRI3> {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:146:34 | LL | trait TRS1: Iterator {} @@ -482,7 +482,7 @@ LL | trait TRS1: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:148:34 | LL | trait TRS2: Iterator {} @@ -490,7 +490,7 @@ LL | trait TRS2: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:150:37 | LL | trait TRS3: Iterator {} @@ -498,7 +498,7 @@ LL | trait TRS3: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:152:45 | LL | trait TRW1 where T: Iterator {} @@ -506,7 +506,7 @@ LL | trait TRW1 where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:154:45 | LL | trait TRW2 where T: Iterator {} @@ -514,7 +514,7 @@ LL | trait TRW2 where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:156:48 | LL | trait TRW3 where T: Iterator {} @@ -522,7 +522,7 @@ LL | trait TRW3 where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:158:46 | LL | trait TRSW1 where Self: Iterator {} @@ -530,7 +530,7 @@ LL | trait TRSW1 where Self: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:160:46 | LL | trait TRSW2 where Self: Iterator {} @@ -538,7 +538,7 @@ LL | trait TRSW2 where Self: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:162:49 | LL | trait TRSW3 where Self: Iterator {} @@ -546,7 +546,7 @@ LL | trait TRSW3 where Self: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:164:43 | LL | trait TRA1 { type A: Iterator; } @@ -554,7 +554,7 @@ LL | trait TRA1 { type A: Iterator; } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:166:43 | LL | trait TRA2 { type A: Iterator; } @@ -562,7 +562,7 @@ LL | trait TRA2 { type A: Iterator; } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:168:46 | LL | trait TRA3 { type A: Iterator; } @@ -570,7 +570,7 @@ LL | trait TRA3 { type A: Iterator; } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:171:40 | LL | type TADyn1 = dyn Iterator; @@ -578,7 +578,7 @@ LL | type TADyn1 = dyn Iterator; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:175:44 | LL | type TADyn2 = Box>; @@ -586,7 +586,7 @@ LL | type TADyn2 = Box>; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:179:43 | LL | type TADyn3 = dyn Iterator; diff --git a/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr b/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr index 9ec6ffb05657a..6de8459954c68 100644 --- a/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr +++ b/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr @@ -9,6 +9,15 @@ LL | type Color; ... LL | fn a(_: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn a(_: ::Color) { + | ^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn a(_: ::Color) { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:20:12 @@ -21,6 +30,15 @@ LL | type Color; ... LL | fn b(_: C::Color) where C : Vehicle+Box { | ^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn b(_: ::Color) where C : Vehicle+Box { + | ^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn b(_: ::Color) where C : Vehicle+Box { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:24:12 @@ -33,6 +51,15 @@ LL | type Color; ... LL | fn c(_: C::Color) where C : Vehicle, C : Box { | ^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn c(_: ::Color) where C : Vehicle, C : Box { + | ^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn c(_: ::Color) where C : Vehicle, C : Box { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:35:20 @@ -45,6 +72,15 @@ LL | type Color; ... LL | fn e(&self, _: X::Color) where X : Box; | ^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn e(&self, _: ::Color) where X : Box; + | ^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn e(&self, _: ::Color) where X : Box; + | ^^^^^^^^^^^^^^^^^^^^^ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:38:20 @@ -57,6 +93,15 @@ LL | type Color; ... LL | fn f(&self, _: X::Color) where X : Box { } | ^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn f(&self, _: ::Color) where X : Box { } + | ^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn f(&self, _: ::Color) where X : Box { } + | ^^^^^^^^^^^^^^^^^^^^^ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:30:20 @@ -69,6 +114,15 @@ LL | type Color; ... LL | fn d(&self, _: X::Color) where X : Box { } | ^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn d(&self, _: ::Color) where X : Box { } + | ^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn d(&self, _: ::Color) where X : Box { } + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs index 7a678445796e6..f50587bac1655 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs @@ -20,13 +20,26 @@ fn dent(c: C, color: C::Color) { //~^ ERROR ambiguous associated type `Color` in bounds of `C` } +// FIXME: add error code to detect this case and explain that you'll want the approach in +// `dent_object_3` of using a new type param and relying on the `where` clauses. fn dent_object(c: dyn BoxCar) { //~^ ERROR ambiguous associated type - //~| ERROR the value of the associated type `Color` (from the trait `Vehicle`) must be specified + //~| ERROR the value of the associated type `Color` (from trait `Vehicle`) must be specified } fn paint(c: C, d: C::Color) { //~^ ERROR ambiguous associated type `Color` in bounds of `C` } +fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { + //~^ ERROR the value of the associated types `Color` (from trait `Vehicle`), `Color` (from + //~| ERROR equality constraints are not yet supported in where clauses +} + +fn dent_object_3(c: X) +where X: BoxCar, + X: Vehicle, + X: Box +{} // OK! + pub fn main() { } diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr index 6118ebef125a5..4f14cffb0656e 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr @@ -1,3 +1,9 @@ +error: equality constraints are not yet supported in where clauses (see #20041) + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:34:46 + | +LL | fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:19:32 | @@ -9,9 +15,18 @@ LL | type Color; ... LL | fn dent(c: C, color: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn dent(c: C, color: ::Color) { + | ^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn dent(c: C, color: ::Color) { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0221]: ambiguous associated type `Color` in bounds of `BoxCar` - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:37 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:25:37 | LL | type Color; | ----------- ambiguous `Color` from `Vehicle` @@ -21,18 +36,27 @@ LL | type Color; ... LL | fn dent_object(c: dyn BoxCar) { | ^^^^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn dent_object(c: dyn BoxCar<::Color>) { + | ^^^^^^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn dent_object(c: dyn BoxCar<::Color>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0191]: the value of the associated type `Color` (from the trait `Vehicle`) must be specified - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:26 +error[E0191]: the value of the associated type `Color` (from trait `Vehicle`) must be specified + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:25:30 | LL | type Color; | ----------- `Color` defined here ... LL | fn dent_object(c: dyn BoxCar) { - | ^^^^^^^^^^^^^^^^^^^^^^^ associated type `Color` must be specified + | ^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `BoxCar` error[E0221]: ambiguous associated type `Color` in bounds of `C` - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:28:29 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:30:29 | LL | type Color; | ----------- ambiguous `Color` from `Vehicle` @@ -42,8 +66,29 @@ LL | type Color; ... LL | fn paint(c: C, d: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` + | +help: use fully qualified syntax to disambiguate + | +LL | fn paint(c: C, d: ::Color) { + | ^^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | fn paint(c: C, d: ::Color) { + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0191]: the value of the associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:34:32 + | +LL | type Color; + | ----------- `Color` defined here +... +LL | type Color; + | ----------- `Color` defined here +... +LL | fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { + | ^^^^^^ help: specify the associated types: `BoxCar` -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0191, E0221. For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/associated-types/associated-types-incomplete-object.rs b/src/test/ui/associated-types/associated-types-incomplete-object.rs index 4993b13121549..4627dfd2b7808 100644 --- a/src/test/ui/associated-types/associated-types-incomplete-object.rs +++ b/src/test/ui/associated-types/associated-types-incomplete-object.rs @@ -21,11 +21,11 @@ pub fn main() { let a = &42isize as &dyn Foo; let b = &42isize as &dyn Foo; - //~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified + //~^ ERROR the value of the associated type `B` (from trait `Foo`) must be specified let c = &42isize as &dyn Foo; - //~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified + //~^ ERROR the value of the associated type `A` (from trait `Foo`) must be specified let d = &42isize as &dyn Foo; - //~^ ERROR the value of the associated types `A` (from the trait `Foo`), `B` (from the trait + //~^ ERROR the value of the associated types `A` (from trait `Foo`), `B` (from trait } diff --git a/src/test/ui/associated-types/associated-types-incomplete-object.stderr b/src/test/ui/associated-types/associated-types-incomplete-object.stderr index b4c08f4a4cce5..24732271c420f 100644 --- a/src/test/ui/associated-types/associated-types-incomplete-object.stderr +++ b/src/test/ui/associated-types/associated-types-incomplete-object.stderr @@ -1,23 +1,23 @@ -error[E0191]: the value of the associated type `B` (from the trait `Foo`) must be specified - --> $DIR/associated-types-incomplete-object.rs:23:26 +error[E0191]: the value of the associated type `B` (from trait `Foo`) must be specified + --> $DIR/associated-types-incomplete-object.rs:23:30 | LL | type B; | ------- `B` defined here ... LL | let b = &42isize as &dyn Foo; - | ^^^^^^^^^^^^^^^^ associated type `B` must be specified + | ^^^^^^^^^^^^ help: specify the associated type: `Foo` -error[E0191]: the value of the associated type `A` (from the trait `Foo`) must be specified - --> $DIR/associated-types-incomplete-object.rs:26:26 +error[E0191]: the value of the associated type `A` (from trait `Foo`) must be specified + --> $DIR/associated-types-incomplete-object.rs:26:30 | LL | type A; | ------- `A` defined here ... LL | let c = &42isize as &dyn Foo; - | ^^^^^^^^^^^^^^^ associated type `A` must be specified + | ^^^^^^^^^^^ help: specify the associated type: `Foo` -error[E0191]: the value of the associated types `A` (from the trait `Foo`), `B` (from the trait `Foo`) must be specified - --> $DIR/associated-types-incomplete-object.rs:29:26 +error[E0191]: the value of the associated types `A` (from trait `Foo`), `B` (from trait `Foo`) must be specified + --> $DIR/associated-types-incomplete-object.rs:29:30 | LL | type A; | ------- `A` defined here @@ -25,10 +25,7 @@ LL | type B; | ------- `B` defined here ... LL | let d = &42isize as &dyn Foo; - | ^^^^^^^ - | | - | associated type `A` must be specified - | associated type `B` must be specified + | ^^^ help: specify the associated types: `Foo` error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/associated-types-path-1.stderr b/src/test/ui/associated-types/associated-types-path-1.stderr index a10cf7f890c15..b7856e20afaad 100644 --- a/src/test/ui/associated-types/associated-types-path-1.stderr +++ b/src/test/ui/associated-types/associated-types-path-1.stderr @@ -15,6 +15,15 @@ LL | type A; ... LL | pub fn f2(a: T, x: T::A) {} | ^^^^ ambiguous associated type `A` + | +help: use fully qualified syntax to disambiguate + | +LL | pub fn f2(a: T, x: ::A) {} + | ^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | pub fn f2(a: T, x: ::A) {} + | ^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0191.stderr b/src/test/ui/error-codes/E0191.stderr index 92fa85bca0eff..d69a14916e198 100644 --- a/src/test/ui/error-codes/E0191.stderr +++ b/src/test/ui/error-codes/E0191.stderr @@ -1,11 +1,11 @@ -error[E0191]: the value of the associated type `Bar` (from the trait `Trait`) must be specified - --> $DIR/E0191.rs:5:12 +error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified + --> $DIR/E0191.rs:5:16 | LL | type Bar; | --------- `Bar` defined here ... LL | type Foo = dyn Trait; - | ^^^^^^^^^ associated type `Bar` must be specified + | ^^^^^ help: specify the associated type: `Trait` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0220.stderr b/src/test/ui/error-codes/E0220.stderr index 5da302748cdaf..58a92fe98323b 100644 --- a/src/test/ui/error-codes/E0220.stderr +++ b/src/test/ui/error-codes/E0220.stderr @@ -4,14 +4,14 @@ error[E0220]: associated type `F` not found for `Trait` LL | type Foo = dyn Trait; | ^^^^^ associated type `F` not found -error[E0191]: the value of the associated type `Bar` (from the trait `Trait`) must be specified - --> $DIR/E0220.rs:5:12 +error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified + --> $DIR/E0220.rs:5:16 | LL | type Bar; | --------- `Bar` defined here ... LL | type Foo = dyn Trait; - | ^^^^^^^^^^^^^^^^ associated type `Bar` must be specified + | ^^^^^^^^^^^^ help: specify the associated type: `Trait` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0221.stderr b/src/test/ui/error-codes/E0221.stderr index 043f0c68bbc22..0b4819143ceb6 100644 --- a/src/test/ui/error-codes/E0221.stderr +++ b/src/test/ui/error-codes/E0221.stderr @@ -9,6 +9,15 @@ LL | type A: T2; LL | fn do_something() { LL | let _: Self::A; | ^^^^^^^ ambiguous associated type `A` + | +help: use fully qualified syntax to disambiguate + | +LL | let _: ::A; + | ^^^^^^^^^^^^^^^^ +help: use fully qualified syntax to disambiguate + | +LL | let _: ::A; + | ^^^^^^^^^^^^^^^^ error[E0221]: ambiguous associated type `Err` in bounds of `Self` --> $DIR/E0221.rs:21:16 @@ -16,14 +25,13 @@ error[E0221]: ambiguous associated type `Err` in bounds of `Self` LL | type Err: T3; | ------------- ambiguous `Err` from `My` LL | fn test() { -LL | let _: Self::Err; - | ^^^^^^^^^ ambiguous associated type `Err` - | -note: associated type `Self` could derive from `std::str::FromStr` - --> $DIR/E0221.rs:21:16 - | LL | let _: Self::Err; | ^^^^^^^^^ + | | + | ambiguous associated type `Err` + | help: use fully qualified syntax to disambiguate: `::Err` + | + = note: associated type `Self` could derive from `std::str::FromStr` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0393.stderr b/src/test/ui/error-codes/E0393.stderr index 543e3213633c8..7771bacc9ed93 100644 --- a/src/test/ui/error-codes/E0393.stderr +++ b/src/test/ui/error-codes/E0393.stderr @@ -1,8 +1,11 @@ error[E0393]: the type parameter `T` must be explicitly specified --> $DIR/E0393.rs:3:47 | +LL | trait A {} + | ------------------ type parameter `T` must be specified for this +LL | LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {} - | ^ missing reference to `T` + | ^ help: set the type parameter to the desired type: `A` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/test/ui/error-codes/E0719.stderr b/src/test/ui/error-codes/E0719.stderr index c5b9a71c65994..a046fbfc3d04a 100644 --- a/src/test/ui/error-codes/E0719.stderr +++ b/src/test/ui/error-codes/E0719.stderr @@ -1,4 +1,4 @@ -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/E0719.rs:1:33 | LL | trait Foo: Iterator {} @@ -6,7 +6,7 @@ LL | trait Foo: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/E0719.rs:6:42 | LL | fn test() -> Box> { diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index 657bf13c8739e..48230dc035b58 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -34,7 +34,7 @@ LL | extern "rust-call" fn call_once(&self, args: ()) -> () {} = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6 | LL | impl Fn<()> for Foo { @@ -42,6 +42,7 @@ LL | impl Fn<()> for Foo { | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error[E0229]: associated type bindings are not allowed here --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:15:6 @@ -49,7 +50,7 @@ error[E0229]: associated type bindings are not allowed here LL | impl FnOnce() for Foo1 { | ^^^^^^^^ associated type not allowed here -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:21:6 | LL | impl FnMut<()> for Bar { @@ -57,8 +58,9 @@ LL | impl FnMut<()> for Bar { | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:27:6 | LL | impl FnOnce<()> for Baz { @@ -66,6 +68,7 @@ LL | impl FnOnce<()> for Baz { | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error: aborting due to 8 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr index f343a42eb8fa9..67814a5d01698 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr @@ -7,7 +7,7 @@ LL | extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/feature-gate-unboxed-closures.rs:5:6 | LL | impl FnOnce<(u32, u32)> for Test { @@ -15,6 +15,7 @@ LL | impl FnOnce<(u32, u32)> for Test { | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-19482.rs b/src/test/ui/issues/issue-19482.rs index 9e4b77d87f8b5..3f3c5de9b1404 100644 --- a/src/test/ui/issues/issue-19482.rs +++ b/src/test/ui/issues/issue-19482.rs @@ -8,6 +8,6 @@ trait Foo { } fn bar(x: &dyn Foo) {} -//~^ ERROR the associated type `A` (from the trait `Foo`) must be specified +//~^ ERROR the associated type `A` (from trait `Foo`) must be specified pub fn main() {} diff --git a/src/test/ui/issues/issue-19482.stderr b/src/test/ui/issues/issue-19482.stderr index f1e5419c71229..42a5a01596905 100644 --- a/src/test/ui/issues/issue-19482.stderr +++ b/src/test/ui/issues/issue-19482.stderr @@ -1,11 +1,11 @@ -error[E0191]: the value of the associated type `A` (from the trait `Foo`) must be specified - --> $DIR/issue-19482.rs:10:12 +error[E0191]: the value of the associated type `A` (from trait `Foo`) must be specified + --> $DIR/issue-19482.rs:10:16 | LL | type A; | ------- `A` defined here ... LL | fn bar(x: &dyn Foo) {} - | ^^^^^^^ associated type `A` must be specified + | ^^^ help: specify the associated type: `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr index 9be7b052da31c..c904236b31b37 100644 --- a/src/test/ui/issues/issue-21950.stderr +++ b/src/test/ui/issues/issue-21950.stderr @@ -1,16 +1,27 @@ error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-21950.rs:5:18 | -LL | &dyn Add; - | ^^^ missing reference to `Rhs` +LL | &dyn Add; + | ^^^ help: set the type parameter to the desired type: `Add` + | + ::: $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | / pub trait Add { +LL | | /// The resulting type after applying the `+` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn add(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_- type parameter `Rhs` must be specified for this | = note: because of the default `Self` reference, type parameters must be specified on object types -error[E0191]: the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified - --> $DIR/issue-21950.rs:5:14 +error[E0191]: the value of the associated type `Output` (from trait `std::ops::Add`) must be specified + --> $DIR/issue-21950.rs:5:18 | LL | &dyn Add; - | ^^^^^^^ associated type `Output` must be specified + | ^^^ help: specify the associated type: `Add` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-22370.stderr b/src/test/ui/issues/issue-22370.stderr index 3ce164e9548b4..950c12ef7a21c 100644 --- a/src/test/ui/issues/issue-22370.stderr +++ b/src/test/ui/issues/issue-22370.stderr @@ -1,8 +1,11 @@ error[E0393]: the type parameter `T` must be explicitly specified --> $DIR/issue-22370.rs:3:14 | +LL | trait A {} + | ------------------ type parameter `T` must be specified for this +LL | LL | fn f(a: &dyn A) {} - | ^ missing reference to `T` + | ^ help: set the type parameter to the desired type: `A` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/test/ui/issues/issue-22434.rs b/src/test/ui/issues/issue-22434.rs index 3e800a2b61db9..34057b46ecd42 100644 --- a/src/test/ui/issues/issue-22434.rs +++ b/src/test/ui/issues/issue-22434.rs @@ -3,6 +3,6 @@ pub trait Foo { } type I<'a> = &'a (dyn Foo + 'a); -//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified +//~^ ERROR the value of the associated type `A` (from trait `Foo`) must be specified fn main() {} diff --git a/src/test/ui/issues/issue-22434.stderr b/src/test/ui/issues/issue-22434.stderr index eb78c4fc311fc..79b9d85610bce 100644 --- a/src/test/ui/issues/issue-22434.stderr +++ b/src/test/ui/issues/issue-22434.stderr @@ -1,11 +1,11 @@ -error[E0191]: the value of the associated type `A` (from the trait `Foo`) must be specified - --> $DIR/issue-22434.rs:5:19 +error[E0191]: the value of the associated type `A` (from trait `Foo`) must be specified + --> $DIR/issue-22434.rs:5:23 | LL | type A; | ------- `A` defined here ... LL | type I<'a> = &'a (dyn Foo + 'a); - | ^^^^^^^^^^^^ associated type `A` must be specified + | ^^^ help: specify the associated type: `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22560.stderr b/src/test/ui/issues/issue-22560.stderr index 5b58adb197c69..bce49aaf16ddc 100644 --- a/src/test/ui/issues/issue-22560.stderr +++ b/src/test/ui/issues/issue-22560.stderr @@ -1,16 +1,38 @@ error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-22560.rs:6:13 | -LL | Sub; - | ^^^ missing reference to `Rhs` +LL | Sub; + | ^^^ help: set the type parameter to the desired type: `Sub` + | + ::: $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | / pub trait Sub { +LL | | /// The resulting type after applying the `-` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn sub(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_- type parameter `Rhs` must be specified for this | = note: because of the default `Self` reference, type parameters must be specified on object types error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-22560.rs:3:17 | -LL | type Test = dyn Add + - | ^^^ missing reference to `Rhs` +LL | type Test = dyn Add + + | ^^^ help: set the type parameter to the desired type: `Add` + | + ::: $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | / pub trait Add { +LL | | /// The resulting type after applying the `+` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn add(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_- type parameter `Rhs` must be specified for this | = note: because of the default `Self` reference, type parameters must be specified on object types @@ -29,20 +51,15 @@ LL | Sub; | additional non-auto trait | trait alias used in trait object type (additional use) -error[E0191]: the value of the associated types `Output` (from the trait `std::ops::Add`), `Output` (from the trait `std::ops::Sub`) must be specified +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified --> $DIR/issue-22560.rs:3:13 | LL | type Test = dyn Add + | _____________^ - | |_____________| - | | LL | | LL | | LL | | Sub; - | | ^ - | |_______________| - | |_______________associated type `Output` must be specified - | associated type `Output` must be specified + | |_______________^ associated types `Output`, `Output` must be specified error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-23024.rs b/src/test/ui/issues/issue-23024.rs index 2638e15f0eae5..6367536816292 100644 --- a/src/test/ui/issues/issue-23024.rs +++ b/src/test/ui/issues/issue-23024.rs @@ -9,5 +9,5 @@ fn main() println!("{:?}",(vfnfer[0] as dyn Fn)(3)); //~^ ERROR the precise format of `Fn`-family traits' //~| ERROR wrong number of type arguments: expected 1, found 0 [E0107] - //~| ERROR the value of the associated type `Output` (from the trait `std::ops::FnOnce`) + //~| ERROR the value of the associated type `Output` (from trait `std::ops::FnOnce`) } diff --git a/src/test/ui/issues/issue-23024.stderr b/src/test/ui/issues/issue-23024.stderr index 43561938ef1c6..11d5c9f1f2e1f 100644 --- a/src/test/ui/issues/issue-23024.stderr +++ b/src/test/ui/issues/issue-23024.stderr @@ -1,4 +1,4 @@ -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/issue-23024.rs:9:39 | LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); @@ -6,6 +6,7 @@ LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error[E0107]: wrong number of type arguments: expected 1, found 0 --> $DIR/issue-23024.rs:9:39 @@ -13,11 +14,11 @@ error[E0107]: wrong number of type arguments: expected 1, found 0 LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); | ^^ expected 1 type argument -error[E0191]: the value of the associated type `Output` (from the trait `std::ops::FnOnce`) must be specified - --> $DIR/issue-23024.rs:9:35 +error[E0191]: the value of the associated type `Output` (from trait `std::ops::FnOnce`) must be specified + --> $DIR/issue-23024.rs:9:39 | LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); - | ^^^^^^ associated type `Output` must be specified + | ^^ help: specify the associated type: `Fn` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr index 34ce2358a0a29..e315317c98a6c 100644 --- a/src/test/ui/issues/issue-28344.stderr +++ b/src/test/ui/issues/issue-28344.stderr @@ -1,8 +1,8 @@ -error[E0191]: the value of the associated type `Output` (from the trait `std::ops::BitXor`) must be specified +error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified --> $DIR/issue-28344.rs:4:17 | LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); - | ^^^^^^^^^^^^^ associated type `Output` must be specified + | ^^^^^^ help: specify the associated type: `BitXor` error[E0599]: no function or associated item named `bitor` found for type `dyn std::ops::BitXor<_>` in the current scope --> $DIR/issue-28344.rs:4:25 @@ -13,11 +13,11 @@ LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); | function or associated item not found in `dyn std::ops::BitXor<_>` | help: there is a method with a similar name: `bitxor` -error[E0191]: the value of the associated type `Output` (from the trait `std::ops::BitXor`) must be specified +error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified --> $DIR/issue-28344.rs:8:13 | LL | let g = BitXor::bitor; - | ^^^^^^^^^^^^^ associated type `Output` must be specified + | ^^^^^^ help: specify the associated type: `BitXor` error[E0599]: no function or associated item named `bitor` found for type `dyn std::ops::BitXor<_>` in the current scope --> $DIR/issue-28344.rs:8:21 diff --git a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr index 098d76a5c48c6..321196d14b7aa 100644 --- a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr +++ b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr @@ -6,7 +6,7 @@ LL | i: Box>, | | | unexpected type argument -error[E0191]: the value of the associated types `A` (from the trait `T`), `C` (from the trait `T`) must be specified +error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:12 | LL | type A; @@ -16,12 +16,9 @@ LL | type C; | ------- `C` defined here ... LL | i: Box>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | associated type `A` must be specified - | associated type `C` must be specified + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified | -help: if you meant to specify the associated types, write +help: specify the associated types | LL | i: Box>, | ^^^^^^^^^ ^^^^^^^^^ diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr index 9a9b917703085..5551b1303b927 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr @@ -6,11 +6,11 @@ LL | let _: &dyn EqAlias = &123; | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses -error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified - --> $DIR/trait-alias-object-fail.rs:9:13 +error[E0191]: the value of the associated type `Item` (from trait `std::iter::Iterator`) must be specified + --> $DIR/trait-alias-object-fail.rs:9:17 | LL | let _: &dyn IteratorAlias = &vec![123].into_iter(); - | ^^^^^^^^^^^^^^^^^ associated type `Item` must be specified + | ^^^^^^^^^^^^^ help: specify the associated type: `IteratorAlias` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs b/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs index 766bd147431b4..f34fa80a0ceec 100644 --- a/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs +++ b/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs @@ -43,8 +43,8 @@ impl NormalizableHelper for u32 fn main() { let _x: Box> = Box::new(2u32); - //~^ ERROR the value of the associated type `Output` (from the trait `Base`) must be specified + //~^ ERROR the value of the associated type `Output` (from trait `Base`) must be specified let _y: Box> = Box::new(2u32); - //~^ ERROR the value of the associated type `Output` (from the trait `Base`) must be specified + //~^ ERROR the value of the associated type `Output` (from trait `Base`) must be specified } diff --git a/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr b/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr index 350f8ea850709..79eb27e101a9b 100644 --- a/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr +++ b/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr @@ -1,20 +1,20 @@ -error[E0191]: the value of the associated type `Output` (from the trait `Base`) must be specified - --> $DIR/trait-object-with-self-in-projection-output-bad.rs:45:17 +error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified + --> $DIR/trait-object-with-self-in-projection-output-bad.rs:45:21 | LL | type Output; | ------------ `Output` defined here ... LL | let _x: Box> = Box::new(2u32); - | ^^^^^^^^^^^^^^^^^^^^^^ associated type `Output` must be specified + | ^^^^^^^^^^^^^^^^^^ help: specify the associated type: `Helper` -error[E0191]: the value of the associated type `Output` (from the trait `Base`) must be specified - --> $DIR/trait-object-with-self-in-projection-output-bad.rs:48:17 +error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified + --> $DIR/trait-object-with-self-in-projection-output-bad.rs:48:21 | LL | type Output; | ------------ `Output` defined here ... LL | let _y: Box> = Box::new(2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `Output` must be specified + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `NormalizableHelper` error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr b/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr index 0d6ca9d9dcd9f..eafd3cf79dbb0 100644 --- a/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr +++ b/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr @@ -1,8 +1,13 @@ error[E0393]: the type parameter `T` must be explicitly specified --> $DIR/type-parameter-defaults-referencing-Self.rs:10:16 | -LL | fn foo(x: &dyn Foo) { } - | ^^^ missing reference to `T` +LL | / trait Foo { +LL | | fn method(&self); +LL | | } + | |_- type parameter `T` must be specified for this +LL | +LL | fn foo(x: &dyn Foo) { } + | ^^^ help: set the type parameter to the desired type: `Foo` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr index a76954287e4d4..7ae8caee6f8be 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr @@ -2,7 +2,7 @@ error[E0658]: parenthetical notation is only stable when used with `Fn`-family t --> $DIR/unboxed-closure-feature-gate.rs:13:20 | LL | let x: Box; - | ^^^^^^^^^^ + | ^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr index c116728190f3e..d661603465cc3 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr @@ -1,20 +1,22 @@ -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:17 | LL | fn bar1(x: &dyn Fn<(), Output=()>) { - | ^^^^^^^^^^^^^^^^^ + | ^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:7:28 | LL | fn bar2(x: &T) where T: Fn<()> { - | ^^^^^^ + | ^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error: aborting due to 2 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr index e9d51983a7a48..b92f054498b68 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr @@ -2,7 +2,7 @@ error[E0107]: wrong number of lifetime arguments: expected 1, found 0 --> $DIR/unboxed-closure-sugar-region.rs:30:51 | LL | fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) { - | ^^^^^^^^^^ expected 1 lifetime argument + | ^^^ expected 1 lifetime argument error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr index f42ac38d370d5..f482098cbffcb 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr @@ -2,7 +2,7 @@ error[E0107]: wrong number of type arguments: expected 3, found 1 --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 | LL | fn foo(_: &dyn Three()) - | ^^^^^^^ expected 3 type arguments + | ^^^^^ expected 3 type arguments error[E0220]: associated type `Output` not found for `Three<(), [type error], [type error]>` --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/unspecified-self-in-trait-ref.stderr index 06370cec90e2d..b72d45ebdbfbc 100644 --- a/src/test/ui/unspecified-self-in-trait-ref.stderr +++ b/src/test/ui/unspecified-self-in-trait-ref.stderr @@ -25,8 +25,13 @@ LL | let d = Bar::::lol(); error[E0393]: the type parameter `A` must be explicitly specified --> $DIR/unspecified-self-in-trait-ref.rs:18:13 | -LL | let e = Bar::::lol(); - | ^^^^^^^^^^^^^^^^^ missing reference to `A` +LL | / pub trait Bar { +LL | | fn foo(&self); +LL | | } + | |_- type parameter `A` must be specified for this +... +LL | let e = Bar::::lol(); + | ^^^ missing reference to `A` | = note: because of the default `Self` reference, type parameters must be specified on object types From a89f03d9cc6751014b79afd05444c886dc30878f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 12 Dec 2019 15:22:46 -0800 Subject: [PATCH 08/17] Fix case in `associated-type-projection-from-multiple-supertraits.rs` This still doesn't handle the case entirely correctly, requiring a more targeted approach with a better suggestion, but at least now the suggested syntax makes *some* sense. --- src/librustc_typeck/astconv.rs | 4 +++- ...-type-projection-from-multiple-supertraits.stderr | 12 ++++++------ src/test/ui/error-codes/E0220.stderr | 4 ++-- src/test/ui/span/type-binding.stderr | 2 +- .../unboxed-closure-sugar-wrong-trait.stderr | 4 ++-- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c0d110971c90f..42113a2943b19 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -890,6 +890,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bounds, speculative, &mut dup_bindings, + span, ); // Okay to ignore `Err` because of `ErrorReported` (see above). } @@ -1146,6 +1147,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bounds: &mut Bounds<'tcx>, speculative: bool, dup_bindings: &mut FxHashMap, + path_span: Span, ) -> Result<(), ErrorReported> { let tcx = self.tcx(); @@ -1212,7 +1214,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { || traits::supertraits(tcx, trait_ref), &trait_ref.print_only_trait_path().to_string(), binding.item_name, - binding.span + path_span, ) }?; diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr index 4f14cffb0656e..9a5787db41ee8 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr @@ -26,7 +26,7 @@ LL | fn dent(c: C, color: ::Color) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0221]: ambiguous associated type `Color` in bounds of `BoxCar` - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:25:37 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:25:30 | LL | type Color; | ----------- ambiguous `Color` from `Vehicle` @@ -35,16 +35,16 @@ LL | type Color; | ----------- ambiguous `Color` from `Box` ... LL | fn dent_object(c: dyn BoxCar) { - | ^^^^^^^^^^^ ambiguous associated type `Color` + | ^^^^^^^^^^^^^^^^^^^ ambiguous associated type `Color` | help: use fully qualified syntax to disambiguate | -LL | fn dent_object(c: dyn BoxCar<::Color>) { - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | fn dent_object(c: dyn ::Color) { + | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully qualified syntax to disambiguate | -LL | fn dent_object(c: dyn BoxCar<::Color>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn dent_object(c: dyn ::Color) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0191]: the value of the associated type `Color` (from trait `Vehicle`) must be specified --> $DIR/associated-type-projection-from-multiple-supertraits.rs:25:30 diff --git a/src/test/ui/error-codes/E0220.stderr b/src/test/ui/error-codes/E0220.stderr index 58a92fe98323b..73e66ceb84564 100644 --- a/src/test/ui/error-codes/E0220.stderr +++ b/src/test/ui/error-codes/E0220.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `F` not found for `Trait` - --> $DIR/E0220.rs:5:22 + --> $DIR/E0220.rs:5:16 | LL | type Foo = dyn Trait; - | ^^^^^ associated type `F` not found + | ^^^^^^^^^^^^ associated type `F` not found error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified --> $DIR/E0220.rs:5:16 diff --git a/src/test/ui/span/type-binding.stderr b/src/test/ui/span/type-binding.stderr index c3e954555325e..5b64fe1889280 100644 --- a/src/test/ui/span/type-binding.stderr +++ b/src/test/ui/span/type-binding.stderr @@ -1,5 +1,5 @@ error[E0220]: associated type `Trget` not found for `std::ops::Deref` - --> $DIR/type-binding.rs:6:20 + --> $DIR/type-binding.rs:6:14 | LL | fn homura>(_: T) {} | ^^^^^^^^^^^ help: there is an associated type with a similar name: `Target` diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr index c81402a3dcc00..ff65fd968c5e7 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr @@ -5,10 +5,10 @@ LL | fn f isize>(x: F) {} | ^^^^^^^^^^^^ unexpected type argument error[E0220]: associated type `Output` not found for `Trait` - --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:24 + --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:8 | LL | fn f isize>(x: F) {} - | ^^^^^ associated type `Output` not found + | ^^^^^^^^^^^^^^^^^^^^^ associated type `Output` not found error: aborting due to 2 previous errors From e9ef8c60614fca7dcfcac6fe033c242cc07dfa2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 12 Dec 2019 17:26:19 -0800 Subject: [PATCH 09/17] review comments: move error reporting to their own methods --- src/librustc_typeck/astconv.rs | 354 ++++++++++++++++++--------------- 1 file changed, 192 insertions(+), 162 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 42113a2943b19..3ed75969bd733 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -743,57 +743,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }, ); - if !missing_type_params.is_empty() { - let display = missing_type_params.iter() - .map(|n| format!("`{}`", n)) - .collect::>().join(", "); - let mut err = struct_span_err!(tcx.sess, span, E0393, - "the type parameter{} {} must be explicitly specified", - pluralize!(missing_type_params.len()), - display, - ); - err.span_label(self.tcx().def_span(def_id), &format!( - "type parameter{} {} must be specified for this", - pluralize!(missing_type_params.len()), - display, - )); - let mut suggested = false; - if let (Ok(snippet), true) = ( - tcx.sess.source_map().span_to_snippet(span), - // Don't suggest setting the type params if there are some already: the order is - // tricky to get right and the user will already know what the syntax is. - generic_args.args.is_empty(), - ) { - if snippet.ends_with('>') { - // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion - // we would have to preserve the right order. For now, as clearly the user is - // aware of the syntax, we do nothing. - } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator`. - err.span_suggestion( - span, - &format!( - "set the type parameter{plural} to the desired type{plural}", - plural=pluralize!(missing_type_params.len()), - ), - format!("{}<{}>", snippet, missing_type_params.join(", ")), - Applicability::HasPlaceholders, - ); - suggested = true; - } - } - if !suggested { - err.span_label(span, format!( - "missing reference{} to {}", - pluralize!(missing_type_params.len()), - display, - )); - } - err.note(&format!("because of the default `Self` reference, type parameters must be \ - specified on object types")); - err.emit(); - } + + self.complain_about_missing_type_params( + missing_type_params, + def_id, + span, + generic_args.args.is_empty(), + ); // Convert associated-type bindings or constraints into a separate vector. // Example: Given this: @@ -826,6 +782,67 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (substs, assoc_bindings, potential_assoc_types) } + fn complain_about_missing_type_params( + &self, + missing_type_params: Vec, + def_id: DefId, + span: Span, + empty_generic_args: bool, + ) { + if missing_type_params.is_empty() { + return; + } + let display = missing_type_params.iter() + .map(|n| format!("`{}`", n)) + .collect::>().join(", "); + let mut err = struct_span_err!(self.tcx().sess, span, E0393, + "the type parameter{} {} must be explicitly specified", + pluralize!(missing_type_params.len()), + display, + ); + err.span_label(self.tcx().def_span(def_id), &format!( + "type parameter{} {} must be specified for this", + pluralize!(missing_type_params.len()), + display, + )); + let mut suggested = false; + if let (Ok(snippet), true) = ( + self.tcx().sess.source_map().span_to_snippet(span), + // Don't suggest setting the type params if there are some already: the order is + // tricky to get right and the user will already know what the syntax is. + empty_generic_args, + ) { + if snippet.ends_with('>') { + // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion + // we would have to preserve the right order. For now, as clearly the user is + // aware of the syntax, we do nothing. + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + err.span_suggestion( + span, + &format!( + "set the type parameter{plural} to the desired type{plural}", + plural=pluralize!(missing_type_params.len()), + ), + format!("{}<{}>", snippet, missing_type_params.join(", ")), + Applicability::HasPlaceholders, + ); + suggested = true; + } + } + if !suggested { + err.span_label(span, format!( + "missing reference{} to {}", + pluralize!(missing_type_params.len()), + display, + )); + } + err.note(&format!("because of the default `Self` reference, type parameters must be \ + specified on object types")); + err.emit(); + } + /// Instantiates the path for the given trait reference, assuming that it's /// bound to a valid trait type. Returns the `DefId` of the defining trait. /// The type _cannot_ be a type other than a trait type. @@ -859,13 +876,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - let path_span = if trait_ref.path.segments.len() == 1 { + let path_span = if let [segment] = &trait_ref.path.segments[..] { // FIXME: `trait_ref.path.span` can point to a full path with multiple // segments, even though `trait_ref.path.segments` is of length `1`. Work // around that bug here, even though it should be fixed elsewhere. // This would otherwise cause an invalid suggestion. For an example, look at // `src/test/ui/issues/issue-28344.rs`. - trait_ref.path.segments[0].ident.span + segment.ident.span } else { trait_ref.path.span }; @@ -1397,115 +1414,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { associated_types.remove(&projection_bound.projection_def_id()); } - if !associated_types.is_empty() { - // Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path` - // `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will - // be valid, otherwise we would suggest `dyn Foo + 'a`. See tests - // `issue-22434.rs` and `issue-22560.rs` for examples. - let sugg_span = if potential_assoc_types.is_empty() && trait_bounds.len() == 1 { - if trait_bounds[0].trait_ref.path.segments.len() == 1 && - trait_bounds[0].trait_ref.path.segments[0].args.is_none() - { - // FIXME: `trait_ref.path.span` can point to a full path with multiple - // segments, even though `trait_ref.path.segments` is of length `1`. Work - // around that bug here, even though it should be fixed elsewhere. - // This would otherwise cause an invalid suggestion. For an example, look at - // `src/test/ui/issues/issue-28344.rs`. - trait_bounds[0].trait_ref.path.segments[0].ident.span - } else { - trait_bounds[0].trait_ref.path.span - } - } else { - span - }; - let names = associated_types.iter().map(|item_def_id| { - let assoc_item = tcx.associated_item(*item_def_id); - let trait_def_id = assoc_item.container.id(); - format!("`{}` (from trait `{}`)", assoc_item.ident, tcx.def_path_str(trait_def_id)) - }).collect::>().join(", "); - let mut err = struct_span_err!( - tcx.sess, - sugg_span, - E0191, - "the value of the associated type{} {} must be specified", - pluralize!(associated_types.len()), - names, - ); - let mut suggestions = Vec::new(); - let mut applicability = Applicability::MaybeIncorrect; - for (i, item_def_id) in associated_types.iter().enumerate() { - let assoc_item = tcx.associated_item(*item_def_id); - if let Some(sp) = tcx.hir().span_if_local(*item_def_id) { - err.span_label(sp, format!("`{}` defined here", assoc_item.ident)); - } - if potential_assoc_types.len() == associated_types.len() { - // Only suggest when the amount of missing associated types equals the number of - // extra type arguments present, as that gives us a relatively high confidence - // that the user forgot to give the associtated type's name. The canonical - // example would be trying to use `Iterator` instead of - // `Iterator`. - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet( - potential_assoc_types[i], - ) { - suggestions.push(( - potential_assoc_types[i], - format!("{} = {}", assoc_item.ident, snippet), - )); - } - } - } - let mut suggestions_len = suggestions.len(); - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sugg_span) { - if potential_assoc_types.is_empty() && trait_bounds.len() == 1 && - // Do not attempt to suggest when we don't know which path segment needs the - // type parameter set. - trait_bounds[0].trait_ref.path.segments.len() == 1 - { - debug!("path segments {:?}", trait_bounds[0].trait_ref.path.segments); - applicability = Applicability::HasPlaceholders; - let assoc_types: Vec = associated_types.iter() - .map(|item_def_id| { - let assoc_item = tcx.associated_item(*item_def_id); - format!("{} = Type", assoc_item.ident) - }) - .collect(); - let sugg = assoc_types.join(", "); - if snippet.ends_with('>') { - // The user wrote `Trait<'a>` or similar and we don't have a type we can - // suggest, but at least we can clue them to the correct syntax - // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the - // suggestion. - suggestions.push((sugg_span, format!( - "{}, {}>", - &snippet[..snippet.len()-1], - sugg, - ))); - } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator`. - suggestions.push((sugg_span, format!("{}<{}>", snippet, sugg))); - } - suggestions_len = assoc_types.len(); - } - } - if suggestions.len() != 1 { - // We don't need this label if there's an inline suggestion, show otherwise. - let names = associated_types.iter() - .map(|t| format!("`{}`", tcx.associated_item(*t).ident)) - .collect::>() - .join(", "); - err.span_label(span, format!( - "associated type{} {} must be specified", - pluralize!(associated_types.len()), - names, - )); - } - if !suggestions.is_empty() { - let msg = format!("specify the associated type{}", pluralize!(suggestions_len)); - err.multipart_suggestion(&msg, suggestions, applicability); - } - err.emit(); - } + self.complain_about_missing_associated_types( + span, + associated_types, + potential_assoc_types, + trait_bounds, + ); // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as // `dyn Trait + Send`. @@ -1585,6 +1499,122 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty } + fn complain_about_missing_associated_types( + &self, + span: Span, + associated_types: BTreeSet, + potential_assoc_types: Vec, + trait_bounds: &[hir::PolyTraitRef], + ) { + if associated_types.is_empty() { + return; + } + // Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path` + // `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will + // be valid, otherwise we would suggest `dyn Foo + 'a`. See tests + // `issue-22434.rs` and `issue-22560.rs` for examples. + let sugg_span = match (&potential_assoc_types[..], &trait_bounds) { + ([], [bound]) => match &bound.trait_ref.path.segments[..] { + // FIXME: `trait_ref.path.span` can point to a full path with multiple + // segments, even though `trait_ref.path.segments` is of length `1`. Work + // around that bug here, even though it should be fixed elsewhere. + // This would otherwise cause an invalid suggestion. For an example, look at + // `src/test/ui/issues/issue-28344.rs`. + [segment] if segment.args.is_none() => segment.ident.span, + _ => bound.trait_ref.path.span, + }, + _ => span, + }; + let tcx = self.tcx(); + let names = associated_types.iter().map(|item_def_id| { + let assoc_item = tcx.associated_item(*item_def_id); + let trait_def_id = assoc_item.container.id(); + format!("`{}` (from trait `{}`)", assoc_item.ident, tcx.def_path_str(trait_def_id)) + }).collect::>().join(", "); + let mut err = struct_span_err!( + tcx.sess, + sugg_span, + E0191, + "the value of the associated type{} {} must be specified", + pluralize!(associated_types.len()), + names, + ); + let mut suggestions = Vec::new(); + let mut applicability = Applicability::MaybeIncorrect; + for (i, item_def_id) in associated_types.iter().enumerate() { + let assoc_item = tcx.associated_item(*item_def_id); + if let Some(sp) = tcx.hir().span_if_local(*item_def_id) { + err.span_label(sp, format!("`{}` defined here", assoc_item.ident)); + } + if potential_assoc_types.len() == associated_types.len() { + // Only suggest when the amount of missing associated types equals the number of + // extra type arguments present, as that gives us a relatively high confidence + // that the user forgot to give the associtated type's name. The canonical + // example would be trying to use `Iterator` instead of + // `Iterator`. + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet( + potential_assoc_types[i], + ) { + suggestions.push(( + potential_assoc_types[i], + format!("{} = {}", assoc_item.ident, snippet), + )); + } + } + } + let mut suggestions_len = suggestions.len(); + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sugg_span) { + if potential_assoc_types.is_empty() && trait_bounds.len() == 1 && + // Do not attempt to suggest when we don't know which path segment needs the + // type parameter set. + trait_bounds[0].trait_ref.path.segments.len() == 1 + { + debug!("path segments {:?}", trait_bounds[0].trait_ref.path.segments); + applicability = Applicability::HasPlaceholders; + let assoc_types: Vec = associated_types.iter() + .map(|item_def_id| { + let assoc_item = tcx.associated_item(*item_def_id); + format!("{} = Type", assoc_item.ident) + }) + .collect(); + let sugg = assoc_types.join(", "); + if snippet.ends_with('>') { + // The user wrote `Trait<'a>` or similar and we don't have a type we can + // suggest, but at least we can clue them to the correct syntax + // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the + // suggestion. + suggestions.push((sugg_span, format!( + "{}, {}>", + &snippet[..snippet.len()-1], + sugg, + ))); + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + suggestions.push((sugg_span, format!("{}<{}>", snippet, sugg))); + } + suggestions_len = assoc_types.len(); + } + } + if suggestions.len() != 1 { + // We don't need this label if there's an inline suggestion, show otherwise. + let names = associated_types.iter() + .map(|t| format!("`{}`", tcx.associated_item(*t).ident)) + .collect::>() + .join(", "); + err.span_label(span, format!( + "associated type{} {} must be specified", + pluralize!(associated_types.len()), + names, + )); + } + if !suggestions.is_empty() { + let msg = format!("specify the associated type{}", pluralize!(suggestions_len)); + err.multipart_suggestion(&msg, suggestions, applicability); + } + err.emit(); + } + fn report_ambiguous_associated_type( &self, span: Span, From fef3c8fc3b6c8b920460fbe20c62503d3eb912ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 12 Dec 2019 21:15:19 -0800 Subject: [PATCH 10/17] Handle more specific case E0222 --- src/librustc_error_codes/error_codes.rs | 3 +- src/librustc_error_codes/error_codes/E0222.md | 51 ++++++ src/librustc_passes/ast_validation.rs | 10 +- src/librustc_typeck/astconv.rs | 150 ++++++++++++------ ...pe-projection-from-multiple-supertraits.rs | 4 +- ...rojection-from-multiple-supertraits.stderr | 46 +++--- .../where-equality-constraints.stderr | 12 +- 7 files changed, 195 insertions(+), 81 deletions(-) create mode 100644 src/librustc_error_codes/error_codes/E0222.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 9c1bec39b29e2..c7bdc5963df7e 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -116,6 +116,7 @@ E0211: include_str!("./error_codes/E0211.md"), E0214: include_str!("./error_codes/E0214.md"), E0220: include_str!("./error_codes/E0220.md"), E0221: include_str!("./error_codes/E0221.md"), +E0222: include_str!("./error_codes/E0222.md"), E0223: include_str!("./error_codes/E0223.md"), E0225: include_str!("./error_codes/E0225.md"), E0229: include_str!("./error_codes/E0229.md"), @@ -456,8 +457,6 @@ E0745: include_str!("./error_codes/E0745.md"), // E0217, // ambiguous associated type, defined in multiple supertraits // E0218, // no associated type defined // E0219, // associated type defined in higher-ranked supertrait -// E0222, // Error code E0045 (variadic function must have C or cdecl calling - // convention) duplicate E0224, // at least one non-builtin train is required for an object type E0226, // only a single explicit lifetime bound is permitted E0227, // ambiguous lifetime bound, explicit lifetime bound required diff --git a/src/librustc_error_codes/error_codes/E0222.md b/src/librustc_error_codes/error_codes/E0222.md new file mode 100644 index 0000000000000..66b6c4d712b70 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0222.md @@ -0,0 +1,51 @@ +An attempt was made to constrain an associated type. +For example: + +```compile_fail,E0222 +pub trait Vehicle { + type Color; +} + +pub trait Box { + type Color; +} + +pub trait BoxCar : Box + Vehicle {} + +fn dent_object(c: dyn BoxCar) {} // Invalid constraint +``` + +In this example, `BoxCar` has two super-traits: `Vehicle` and `Box`. Both of +these traits define an associated type `Color`. `BoxCar` inherits two types +with that name from both super-traits. Because of this, we need to use the +fully qualified path syntax to refer to the appropriate `Color` associated +type, either `::Color` or `::Color`, but this +syntax is not allowed to be used in a function signature. + +In order to encode this kind of constraint, a `where` clause and a new type +parameter are needed: + +``` +pub trait Vehicle { + type Color; +} + +pub trait Box { + type Color; +} + +pub trait BoxCar : Box + Vehicle {} + +// Introduce a new `CAR` type parameter +fn foo( + c: CAR, +) where + // Bind the type parameter `CAR` to the trait `BoxCar` + CAR: BoxCar, + // Further restrict `::Color` to be the same as the + // type parameter `COLOR` + CAR: Vehicle, + // We can also simultaneously restrict the other trait's associated type + CAR: Box +{} +``` diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 202b6ae2f94c4..d619e7e1d7682 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -683,9 +683,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { for predicate in &generics.where_clause.predicates { if let WherePredicate::EqPredicate(ref predicate) = *predicate { - self.err_handler() - .span_err(predicate.span, "equality constraints are not yet \ - supported in where clauses (see #20041)"); + self.err_handler().struct_span_err( + predicate.span, + "equality constraints are not yet supported in where clauses", + ) + .span_label(predicate.span, "not supported") + .note("for more information, see #20041") + .emit(); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3ed75969bd733..db753b8a3fb4c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1220,10 +1220,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - let candidate = if self.trait_defines_associated_type_named(trait_ref.def_id(), - binding.item_name) { + let candidate = if self.trait_defines_associated_type_named( + trait_ref.def_id(), + binding.item_name, + ) { // Simple case: X is defined in the current trait. - Ok(trait_ref) + trait_ref } else { // Otherwise, we have to walk through the supertraits to find // those that do. @@ -1232,8 +1234,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &trait_ref.print_only_trait_path().to_string(), binding.item_name, path_span, - ) - }?; + match binding.kind { + ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), + _ => None, + }, + )? + }; let (assoc_ident, def_scope) = tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); @@ -1564,19 +1570,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } let mut suggestions_len = suggestions.len(); if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sugg_span) { - if potential_assoc_types.is_empty() && trait_bounds.len() == 1 && + let assoc_types: Vec = associated_types.iter() + .map(|item_def_id| { + let assoc_item = tcx.associated_item(*item_def_id); + format!("{} = Type", assoc_item.ident) + }) + .collect(); + let dedup = assoc_types.clone().drain(..).collect::>(); + + if dedup.len() != assoc_types.len() && trait_bounds.len() == 1 { + // If there are duplicates associated type names and a single trait bound do not + // use structured suggestion, it means that there are multiple super-traits with + // the same associated type name. + err.help("consider introducing a new type parameter, adding `where` constraints \ + using the fully-qualified path to the associated type"); + } else if dedup.len() == assoc_types.len() && + potential_assoc_types.is_empty() && + trait_bounds.len() == 1 && // Do not attempt to suggest when we don't know which path segment needs the // type parameter set. trait_bounds[0].trait_ref.path.segments.len() == 1 { - debug!("path segments {:?}", trait_bounds[0].trait_ref.path.segments); applicability = Applicability::HasPlaceholders; - let assoc_types: Vec = associated_types.iter() - .map(|item_def_id| { - let assoc_item = tcx.associated_item(*item_def_id); - format!("{} = Type", assoc_item.ident) - }) - .collect(); let sugg = assoc_types.join(", "); if snippet.ends_with('>') { // The user wrote `Trait<'a>` or similar and we don't have a type we can @@ -1602,7 +1617,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|t| format!("`{}`", tcx.associated_item(*t).ident)) .collect::>() .join(", "); - err.span_label(span, format!( + err.span_label(sugg_span, format!( "associated type{} {} must be specified", pluralize!(associated_types.len()), names, @@ -1635,10 +1650,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); } else { err.span_suggestion( - span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", type_str, trait_str, name), - Applicability::HasPlaceholders + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", type_str, trait_str, name), + Applicability::HasPlaceholders ); } err.emit(); @@ -1648,12 +1663,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter // This function will fail if there are no suitable bounds or there is // any ambiguity. - fn find_bound_for_assoc_item(&self, - ty_param_def_id: DefId, - assoc_name: ast::Ident, - span: Span) - -> Result, ErrorReported> - { + fn find_bound_for_assoc_item( + &self, + ty_param_def_id: DefId, + assoc_name: ast::Ident, + span: Span, + ) -> Result, ErrorReported> { let tcx = self.tcx(); debug!( @@ -1675,16 +1690,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ¶m_name.as_str(), assoc_name, span, + None, ) } - fn one_bound_for_assoc_type(&self, - all_candidates: impl Fn() -> I, - ty_param_name: &str, - assoc_name: ast::Ident, - span: Span) - -> Result, ErrorReported> - where I: Iterator> + // Checks that `bounds` contains exactly one element and reports appropriate + // errors otherwise. + fn one_bound_for_assoc_type( + &self, + all_candidates: impl Fn() -> I, + ty_param_name: &str, + assoc_name: ast::Ident, + span: Span, + is_equality: Option, + ) -> Result, ErrorReported> + where I: Iterator>, { let mut matching_candidates = all_candidates().filter(|r| { self.trait_defines_associated_type_named(r.def_id(), assoc_name) @@ -1709,13 +1729,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2); let bounds = iter::once(bound).chain(iter::once(bound2)).chain(matching_candidates); - let mut err = struct_span_err!( - self.tcx().sess, span, E0221, - "ambiguous associated type `{}` in bounds of `{}`", - assoc_name, - ty_param_name); + let mut err = if is_equality.is_some() { + // More specific Error Index entry. + struct_span_err!( + self.tcx().sess, span, E0222, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name + ) + } else { + struct_span_err!( + self.tcx().sess, span, E0221, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name + ) + }; err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); + let mut where_bounds = vec![]; for bound in bounds { let bound_span = self.tcx().associated_items(bound.def_id()).find(|item| { item.kind == ty::AssocKind::Type && @@ -1729,17 +1761,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_name, bound.print_only_trait_path(), )); - err.span_suggestion( - span, - "use fully qualified syntax to disambiguate", - format!( - "<{} as {}>::{}", - ty_param_name, - bound.print_only_trait_path(), - assoc_name, - ), - Applicability::MaybeIncorrect, - ); + if let Some(constraint) = &is_equality { + where_bounds.push(format!( + " T: {trait}::{assoc} = {constraint}", + trait=bound.print_only_trait_path(), + assoc=assoc_name, + constraint=constraint, + )); + } else { + err.span_suggestion( + span, + "use fully qualified syntax to disambiguate", + format!( + "<{} as {}>::{}", + ty_param_name, + bound.print_only_trait_path(), + assoc_name, + ), + Applicability::MaybeIncorrect, + ); + } } else { err.note(&format!( "associated type `{}` could derive from `{}`", @@ -1748,9 +1789,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { )); } } + if !where_bounds.is_empty() { + err.help(&format!( + "consider introducing a new type parameter `T` and adding `where` constraints:\ + \n where\n T: {},\n{}", + ty_param_name, + where_bounds.join(",\n"), + )); + } err.emit(); + if !where_bounds.is_empty() { + return Err(ErrorReported); + } } - return Ok(bound); } @@ -1856,7 +1907,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { || traits::supertraits(tcx, ty::Binder::bind(trait_ref)), "Self", assoc_ident, - span + span, + None, )? } (&ty::Param(_), Res::SelfTy(Some(param_did), None)) | diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs index f50587bac1655..77ed784f1fa74 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs @@ -20,11 +20,9 @@ fn dent(c: C, color: C::Color) { //~^ ERROR ambiguous associated type `Color` in bounds of `C` } -// FIXME: add error code to detect this case and explain that you'll want the approach in -// `dent_object_3` of using a new type param and relying on the `where` clauses. fn dent_object(c: dyn BoxCar) { //~^ ERROR ambiguous associated type - //~| ERROR the value of the associated type `Color` (from trait `Vehicle`) must be specified + //~| ERROR the value of the associated types `Color` (from trait `Vehicle`), `Color` (from } fn paint(c: C, d: C::Color) { diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr index 9a5787db41ee8..aa46e5d077f3e 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr @@ -1,8 +1,10 @@ -error: equality constraints are not yet supported in where clauses (see #20041) - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:34:46 +error: equality constraints are not yet supported in where clauses + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:46 | LL | fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported + | + = note: for more information, see #20041 error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:19:32 @@ -25,8 +27,8 @@ help: use fully qualified syntax to disambiguate LL | fn dent(c: C, color: ::Color) { | ^^^^^^^^^^^^^^^^^^^^^ -error[E0221]: ambiguous associated type `Color` in bounds of `BoxCar` - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:25:30 +error[E0222]: ambiguous associated type `Color` in bounds of `BoxCar` + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30 | LL | type Color; | ----------- ambiguous `Color` from `Vehicle` @@ -37,26 +39,28 @@ LL | type Color; LL | fn dent_object(c: dyn BoxCar) { | ^^^^^^^^^^^^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate - | -LL | fn dent_object(c: dyn ::Color) { - | ^^^^^^^^^^^^^^^^^^^^^^ -help: use fully qualified syntax to disambiguate - | -LL | fn dent_object(c: dyn ::Color) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider introducing a new type parameter `T` and adding `where` constraints: + where + T: BoxCar, + T: Box::Color = COLOR, + T: Vehicle::Color = COLOR -error[E0191]: the value of the associated type `Color` (from trait `Vehicle`) must be specified - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:25:30 +error[E0191]: the value of the associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30 | LL | type Color; | ----------- `Color` defined here ... +LL | type Color; + | ----------- `Color` defined here +... LL | fn dent_object(c: dyn BoxCar) { - | ^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `BoxCar` + | ^^^^^^^^^^^^^^^^^^^ associated types `Color`, `Color` must be specified + | + = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated type error[E0221]: ambiguous associated type `Color` in bounds of `C` - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:30:29 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:28:29 | LL | type Color; | ----------- ambiguous `Color` from `Vehicle` @@ -77,7 +81,7 @@ LL | fn paint(c: C, d: ::Color) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0191]: the value of the associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:34:32 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:32 | LL | type Color; | ----------- `Color` defined here @@ -86,9 +90,11 @@ LL | type Color; | ----------- `Color` defined here ... LL | fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { - | ^^^^^^ help: specify the associated types: `BoxCar` + | ^^^^^^ associated types `Color`, `Color` must be specified + | + = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated type error: aborting due to 6 previous errors -Some errors have detailed explanations: E0191, E0221. +Some errors have detailed explanations: E0191, E0221, E0222. For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/where-clauses/where-equality-constraints.stderr b/src/test/ui/where-clauses/where-equality-constraints.stderr index 220447079c629..235354b58fe6d 100644 --- a/src/test/ui/where-clauses/where-equality-constraints.stderr +++ b/src/test/ui/where-clauses/where-equality-constraints.stderr @@ -1,14 +1,18 @@ -error: equality constraints are not yet supported in where clauses (see #20041) +error: equality constraints are not yet supported in where clauses --> $DIR/where-equality-constraints.rs:1:14 | LL | fn f() where u8 = u16 {} - | ^^^^^^^^ + | ^^^^^^^^ not supported + | + = note: for more information, see #20041 -error: equality constraints are not yet supported in where clauses (see #20041) +error: equality constraints are not yet supported in where clauses --> $DIR/where-equality-constraints.rs:3:14 | LL | fn g() where for<'a> &'static (u8,) == u16, {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported + | + = note: for more information, see #20041 error: aborting due to 2 previous errors From a4ec575aa54d4da5f2c77e569bfff9c582b2e871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 13 Dec 2019 08:22:58 -0800 Subject: [PATCH 11/17] Use structured suggestion for bad `Fn` traits --- src/librustc_typeck/astconv.rs | 31 ++++++++++++++++--- ...-gate-unboxed-closures-manual-impls.stderr | 9 ++---- .../feature-gate-unboxed-closures.stderr | 3 +- src/test/ui/issues/issue-23024.stderr | 3 +- ...nboxed-closure-sugar-not-used-on-fn.stderr | 6 ++-- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index db753b8a3fb4c..1badfd78964e3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -7,6 +7,7 @@ use crate::hir::{self, GenericArg, GenericArgs, ExprKind}; use crate::hir::def::{CtorOf, Res, DefKind}; use crate::hir::def_id::DefId; use crate::hir::HirVec; +use crate::hir::print; use crate::hir::ptr::P; use crate::lint; use crate::middle::lang_items::SizedTraitLangItem; @@ -981,19 +982,41 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_segment.generic_args().parenthesized != trait_def.paren_sugar { // For now, require that parenthetical notation be used only with `Fn()` etc. - let (msg, help) = if trait_def.paren_sugar { + let (msg, sugg) = if trait_def.paren_sugar { ( "the precise format of `Fn`-family traits' type parameters is subject to \ change", - Some("use parenthetical notation instead: `Fn(Foo, Bar) -> Baz`"), + Some(format!( + "{}{} -> {}", + trait_segment.ident, + trait_segment.args.as_ref() + .and_then(|args| args.args.get(0)) + .and_then(|arg| match arg { + hir::GenericArg::Type(ty) => { + Some(print::to_string(print::NO_ANN, |s| s.print_type(ty))) + } + _ => None, + }) + .unwrap_or_else(|| "()".to_string()), + trait_segment.generic_args().bindings.iter() + .filter_map(|b| match (b.ident.as_str() == "Output", &b.kind) { + (true, hir::TypeBindingKind::Equality { ty }) => { + Some(print::to_string(print::NO_ANN, |s| s.print_type(ty))) + } + _ => None, + }) + .next() + .unwrap_or_else(|| "()".to_string()), + )), ) } else { ("parenthetical notation is only stable when used with `Fn`-family traits", None) }; let sess = &self.tcx().sess.parse_sess; let mut err = feature_err(sess, sym::unboxed_closures, span, msg); - if let Some(help) = help { - err.help(help); + if let Some(sugg) = sugg { + let msg = "use parenthetical notation instead"; + err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); } err.emit(); } diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index 48230dc035b58..4addd16649ea0 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -38,11 +38,10 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6 | LL | impl Fn<()> for Foo { - | ^^^^^^ + | ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable - = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error[E0229]: associated type bindings are not allowed here --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:15:6 @@ -54,21 +53,19 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:21:6 | LL | impl FnMut<()> for Bar { - | ^^^^^^^^^ + | ^^^^^^^^^ help: use parenthetical notation instead: `FnMut() -> ()` | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable - = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:27:6 | LL | impl FnOnce<()> for Baz { - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce() -> ()` | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable - = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error: aborting due to 8 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr index 67814a5d01698..005ff06e68898 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr @@ -11,11 +11,10 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/feature-gate-unboxed-closures.rs:5:6 | LL | impl FnOnce<(u32, u32)> for Test { - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce(u32, u32) -> ()` | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable - = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-23024.stderr b/src/test/ui/issues/issue-23024.stderr index 11d5c9f1f2e1f..1c6dd28ce539e 100644 --- a/src/test/ui/issues/issue-23024.stderr +++ b/src/test/ui/issues/issue-23024.stderr @@ -2,11 +2,10 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/issue-23024.rs:9:39 | LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); - | ^^ + | ^^ help: use parenthetical notation instead: `Fn() -> ()` | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable - = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error[E0107]: wrong number of type arguments: expected 1, found 0 --> $DIR/issue-23024.rs:9:39 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr index d661603465cc3..ba9d984e7036c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr @@ -2,21 +2,19 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:17 | LL | fn bar1(x: &dyn Fn<(), Output=()>) { - | ^^ + | ^^ help: use parenthetical notation instead: `Fn() -> ()` | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable - = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:7:28 | LL | fn bar2(x: &T) where T: Fn<()> { - | ^^ + | ^^ help: use parenthetical notation instead: `Fn() -> ()` | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable - = help: use parenthetical notation instead: `Fn(Foo, Bar) -> Baz` error: aborting due to 2 previous errors From e21be128364bc97092bbc181d5926fc91ffbc6d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 13 Dec 2019 11:37:31 -0800 Subject: [PATCH 12/17] Avoid output dependency on std spans --- src/test/ui/issues/issue-21950.rs | 15 ++++-- src/test/ui/issues/issue-21950.stderr | 27 +++++------ src/test/ui/issues/issue-22560.rs | 19 +++++--- src/test/ui/issues/issue-22560.stderr | 66 +++++++++++---------------- 4 files changed, 60 insertions(+), 67 deletions(-) diff --git a/src/test/ui/issues/issue-21950.rs b/src/test/ui/issues/issue-21950.rs index 0bc87824ccec3..72a98bd8ddd8a 100644 --- a/src/test/ui/issues/issue-21950.rs +++ b/src/test/ui/issues/issue-21950.rs @@ -1,8 +1,13 @@ -use std::ops::Add; +trait Add { + type Output; +} + +impl Add for i32 { + type Output = i32; +} fn main() { - let x = &10 as - &dyn Add; - //~^ ERROR E0393 - //~| ERROR E0191 + let x = &10 as &dyn Add; + //~^ ERROR E0393 + //~| ERROR E0191 } diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr index c904236b31b37..93c2444f884de 100644 --- a/src/test/ui/issues/issue-21950.stderr +++ b/src/test/ui/issues/issue-21950.stderr @@ -1,27 +1,24 @@ error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/issue-21950.rs:5:18 + --> $DIR/issue-21950.rs:10:25 | -LL | &dyn Add; - | ^^^ help: set the type parameter to the desired type: `Add` - | - ::: $SRC_DIR/libcore/ops/arith.rs:LL:COL - | -LL | / pub trait Add { -LL | | /// The resulting type after applying the `+` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | / trait Add { LL | | type Output; -... | -LL | | fn add(self, rhs: Rhs) -> Self::Output; LL | | } | |_- type parameter `Rhs` must be specified for this +... +LL | let x = &10 as &dyn Add; + | ^^^ help: set the type parameter to the desired type: `Add` | = note: because of the default `Self` reference, type parameters must be specified on object types -error[E0191]: the value of the associated type `Output` (from trait `std::ops::Add`) must be specified - --> $DIR/issue-21950.rs:5:18 +error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified + --> $DIR/issue-21950.rs:10:25 | -LL | &dyn Add; - | ^^^ help: specify the associated type: `Add` +LL | type Output; + | ------------ `Output` defined here +... +LL | let x = &10 as &dyn Add; + | ^^^ help: specify the associated type: `Add` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-22560.rs b/src/test/ui/issues/issue-22560.rs index acee99dbedcc4..44be8817b08c7 100644 --- a/src/test/ui/issues/issue-22560.rs +++ b/src/test/ui/issues/issue-22560.rs @@ -1,10 +1,15 @@ -use std::ops::{Add, Sub}; +trait Add { + type Output; +} -type Test = dyn Add + - //~^ ERROR E0393 - //~| ERROR E0191 - Sub; - //~^ ERROR E0393 - //~| ERROR E0225 +trait Sub { + type Output; +} + +type Test = dyn Add + Sub; +//~^ ERROR E0393 +//~| ERROR E0191 +//~| ERROR E0393 +//~| ERROR E0225 fn main() { } diff --git a/src/test/ui/issues/issue-22560.stderr b/src/test/ui/issues/issue-22560.stderr index bce49aaf16ddc..4466a40f0da61 100644 --- a/src/test/ui/issues/issue-22560.stderr +++ b/src/test/ui/issues/issue-22560.stderr @@ -1,65 +1,51 @@ error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/issue-22560.rs:6:13 + --> $DIR/issue-22560.rs:9:23 | -LL | Sub; - | ^^^ help: set the type parameter to the desired type: `Sub` - | - ::: $SRC_DIR/libcore/ops/arith.rs:LL:COL - | -LL | / pub trait Sub { -LL | | /// The resulting type after applying the `-` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | / trait Sub { LL | | type Output; -... | -LL | | fn sub(self, rhs: Rhs) -> Self::Output; LL | | } | |_- type parameter `Rhs` must be specified for this +LL | +LL | type Test = dyn Add + Sub; + | ^^^ help: set the type parameter to the desired type: `Sub` | = note: because of the default `Self` reference, type parameters must be specified on object types error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/issue-22560.rs:3:17 - | -LL | type Test = dyn Add + - | ^^^ help: set the type parameter to the desired type: `Add` - | - ::: $SRC_DIR/libcore/ops/arith.rs:LL:COL + --> $DIR/issue-22560.rs:9:17 | -LL | / pub trait Add { -LL | | /// The resulting type after applying the `+` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | / trait Add { LL | | type Output; -... | -LL | | fn add(self, rhs: Rhs) -> Self::Output; LL | | } | |_- type parameter `Rhs` must be specified for this +... +LL | type Test = dyn Add + Sub; + | ^^^ help: set the type parameter to the desired type: `Add` | = note: because of the default `Self` reference, type parameters must be specified on object types error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/issue-22560.rs:6:13 + --> $DIR/issue-22560.rs:9:23 | -LL | type Test = dyn Add + - | --- - | | +LL | type Test = dyn Add + Sub; + | --- ^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) | first non-auto trait | trait alias used in trait object type (first use) -... -LL | Sub; - | ^^^ - | | - | additional non-auto trait - | trait alias used in trait object type (additional use) -error[E0191]: the value of the associated types `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified - --> $DIR/issue-22560.rs:3:13 +error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified + --> $DIR/issue-22560.rs:9:13 | -LL | type Test = dyn Add + - | _____________^ -LL | | -LL | | -LL | | Sub; - | |_______________^ associated types `Output`, `Output` must be specified +LL | type Output; + | ------------ `Output` defined here +... +LL | type Output; + | ------------ `Output` defined here +... +LL | type Test = dyn Add + Sub; + | ^^^^^^^^^^^^^ associated types `Output`, `Output` must be specified error: aborting due to 4 previous errors From a4883ba4c6970c5604e30edb78a60f8f8d7872ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 17 Dec 2019 18:15:06 -0800 Subject: [PATCH 13/17] Account for multiple trait bounds with missing associated types --- src/librustc_typeck/astconv.rs | 261 +++++++++++------- ...rojection-from-multiple-supertraits.stderr | 16 +- .../missing-associated-types.rs | 27 ++ .../missing-associated-types.stderr | 129 +++++++++ src/test/ui/issues/issue-22560.stderr | 13 +- ...type-argument-instead-of-assoc-type.stderr | 4 +- 6 files changed, 341 insertions(+), 109 deletions(-) create mode 100644 src/test/ui/associated-types/missing-associated-types.rs create mode 100644 src/test/ui/associated-types/missing-associated-types.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1badfd78964e3..d0536e8eed57b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -27,7 +27,7 @@ use syntax::errors::pluralize; use syntax::feature_gate::feature_err; use syntax::util::lev_distance::find_best_match_for_name; use syntax::symbol::sym; -use syntax_pos::{DUMMY_SP, Span, MultiSpan}; +use syntax_pos::{DUMMY_SP, MultiSpan, Span}; use crate::util::common::ErrorReported; use crate::util::nodemap::FxHashMap; @@ -1393,20 +1393,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Use a `BTreeSet` to keep output in a more consistent order. - let mut associated_types = BTreeSet::default(); + let mut associated_types: FxHashMap> = FxHashMap::default(); - let regular_traits_refs = bounds.trait_bounds + let regular_traits_refs_spans = bounds.trait_bounds .into_iter() - .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())) - .map(|(trait_ref, _)| trait_ref); - for trait_ref in traits::elaborate_trait_refs(tcx, regular_traits_refs) { + .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + + for (base_trait_ref, span) in regular_traits_refs_spans { + debug!("conv_object_ty_poly_trait_ref regular_trait_ref `{:?}`", base_trait_ref); + let mut new_bounds = vec![]; + for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) { debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref); match trait_ref { ty::Predicate::Trait(pred) => { - associated_types + associated_types.entry(span).or_default() .extend(tcx.associated_items(pred.def_id()) - .filter(|item| item.kind == ty::AssocKind::Type) - .map(|item| item.def_id)); + .filter(|item| item.kind == ty::AssocKind::Type) + .map(|item| item.def_id)); } ty::Predicate::Projection(pred) => { // A `Self` within the original bound will be substituted with a @@ -1432,19 +1435,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // which is uglier but works. See the discussion in #56288 for alternatives. if !references_self { // Include projections defined on supertraits. - bounds.projection_bounds.push((pred, DUMMY_SP)) + new_bounds.push((pred, span)); } } _ => () } + } + bounds.projection_bounds.extend(new_bounds); } for (projection_bound, _) in &bounds.projection_bounds { - associated_types.remove(&projection_bound.projection_def_id()); + for (_, def_ids) in &mut associated_types { + def_ids.remove(&projection_bound.projection_def_id()); + } } self.complain_about_missing_associated_types( - span, associated_types, potential_assoc_types, trait_bounds, @@ -1530,125 +1536,188 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn complain_about_missing_associated_types( &self, - span: Span, - associated_types: BTreeSet, + mut associated_types: FxHashMap>, potential_assoc_types: Vec, trait_bounds: &[hir::PolyTraitRef], ) { - if associated_types.is_empty() { + if !associated_types.values().any(|v| v.len() > 0) { return; } - // Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path` - // `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will - // be valid, otherwise we would suggest `dyn Foo + 'a`. See tests - // `issue-22434.rs` and `issue-22560.rs` for examples. - let sugg_span = match (&potential_assoc_types[..], &trait_bounds) { + let tcx = self.tcx(); + let mut names = vec![]; + + // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and + // `issue-22560.rs`. + let mut trait_bound_spans: Vec = vec![]; + for (span, item_def_ids) in &associated_types { + if !item_def_ids.is_empty() { + trait_bound_spans.push(*span); + } + for item_def_id in item_def_ids { + let assoc_item = tcx.associated_item(*item_def_id); + let trait_def_id = assoc_item.container.id(); + names.push(format!( + "`{}` (from trait `{}`)", + assoc_item.ident, + tcx.def_path_str(trait_def_id), + )); + } + } + + match (&potential_assoc_types[..], &trait_bounds) { ([], [bound]) => match &bound.trait_ref.path.segments[..] { // FIXME: `trait_ref.path.span` can point to a full path with multiple // segments, even though `trait_ref.path.segments` is of length `1`. Work // around that bug here, even though it should be fixed elsewhere. // This would otherwise cause an invalid suggestion. For an example, look at - // `src/test/ui/issues/issue-28344.rs`. - [segment] if segment.args.is_none() => segment.ident.span, - _ => bound.trait_ref.path.span, + // `src/test/ui/issues/issue-28344.rs` where instead of the following: + // + // error[E0191]: the value of the associated type `Output` + // (from trait `std::ops::BitXor`) must be specified + // --> $DIR/issue-28344.rs:4:17 + // | + // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); + // | ^^^^^^ help: specify the associated type: + // | `BitXor` + // + // we would output: + // + // error[E0191]: the value of the associated type `Output` + // (from trait `std::ops::BitXor`) must be specified + // --> $DIR/issue-28344.rs:4:17 + // | + // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); + // | ^^^^^^^^^^^^^ help: specify the associated type: + // | `BitXor::bitor` + [segment] if segment.args.is_none() => { + trait_bound_spans = vec![segment.ident.span]; + associated_types = associated_types.into_iter() + .map(|(_, defs)| (segment.ident.span, defs)) + .collect(); + } + _ => {} }, - _ => span, - }; - let tcx = self.tcx(); - let names = associated_types.iter().map(|item_def_id| { - let assoc_item = tcx.associated_item(*item_def_id); - let trait_def_id = assoc_item.container.id(); - format!("`{}` (from trait `{}`)", assoc_item.ident, tcx.def_path_str(trait_def_id)) - }).collect::>().join(", "); + _ => {} + } let mut err = struct_span_err!( tcx.sess, - sugg_span, + trait_bound_spans, E0191, "the value of the associated type{} {} must be specified", - pluralize!(associated_types.len()), - names, + pluralize!(names.len()), + names.join(", "), ); - let mut suggestions = Vec::new(); - let mut applicability = Applicability::MaybeIncorrect; - for (i, item_def_id) in associated_types.iter().enumerate() { - let assoc_item = tcx.associated_item(*item_def_id); - if let Some(sp) = tcx.hir().span_if_local(*item_def_id) { - err.span_label(sp, format!("`{}` defined here", assoc_item.ident)); - } - if potential_assoc_types.len() == associated_types.len() { + let mut suggestions = vec![]; + let mut types_count = 0; + let mut where_constraints = vec![]; + for (span, def_ids) in &associated_types { + let assoc_items: Vec<_> = def_ids.iter() + .map(|def_id| tcx.associated_item(*def_id)) + .collect(); + let mut names: FxHashMap<_, usize> = FxHashMap::default(); + for item in &assoc_items { + types_count += 1; + *names.entry(item.ident.name).or_insert(0) += 1; + } + let mut dupes = false; + for item in &assoc_items { + let prefix = if names[&item.ident.name] > 1 { + let trait_def_id = item.container.id(); + dupes = true; + format!("{}::", tcx.def_path_str(trait_def_id)) + } else { + String::new() + }; + if let Some(sp) = tcx.hir().span_if_local(item.def_id) { + err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident)); + } + } + if potential_assoc_types.len() == assoc_items.len() { // Only suggest when the amount of missing associated types equals the number of // extra type arguments present, as that gives us a relatively high confidence // that the user forgot to give the associtated type's name. The canonical // example would be trying to use `Iterator` instead of // `Iterator`. - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet( - potential_assoc_types[i], - ) { - suggestions.push(( - potential_assoc_types[i], - format!("{} = {}", assoc_item.ident, snippet), - )); + for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet( + *potential, + ) { + suggestions.push(( + *potential, + format!("{} = {}", item.ident, snippet), + )); + } } - } - } - let mut suggestions_len = suggestions.len(); - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sugg_span) { - let assoc_types: Vec = associated_types.iter() - .map(|item_def_id| { - let assoc_item = tcx.associated_item(*item_def_id); - format!("{} = Type", assoc_item.ident) - }) - .collect(); - let dedup = assoc_types.clone().drain(..).collect::>(); - - if dedup.len() != assoc_types.len() && trait_bounds.len() == 1 { - // If there are duplicates associated type names and a single trait bound do not - // use structured suggestion, it means that there are multiple super-traits with - // the same associated type name. - err.help("consider introducing a new type parameter, adding `where` constraints \ - using the fully-qualified path to the associated type"); - } else if dedup.len() == assoc_types.len() && - potential_assoc_types.is_empty() && - trait_bounds.len() == 1 && - // Do not attempt to suggest when we don't know which path segment needs the - // type parameter set. - trait_bounds[0].trait_ref.path.segments.len() == 1 - { - applicability = Applicability::HasPlaceholders; - let sugg = assoc_types.join(", "); - if snippet.ends_with('>') { + } else if let (Ok(snippet), false) = ( + tcx.sess.source_map().span_to_snippet(*span), + dupes, + ) { + let types: Vec<_> = assoc_items.iter() + .map(|item| format!("{} = Type", item.ident)) + .collect(); + let code = if snippet.ends_with(">") { // The user wrote `Trait<'a>` or similar and we don't have a type we can // suggest, but at least we can clue them to the correct syntax // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the // suggestion. - suggestions.push((sugg_span, format!( - "{}, {}>", - &snippet[..snippet.len()-1], - sugg, - ))); + format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", ")) } else { // The user wrote `Iterator`, so we don't have a type we can suggest, but at // least we can clue them to the correct syntax `Iterator`. - suggestions.push((sugg_span, format!("{}<{}>", snippet, sugg))); - } - suggestions_len = assoc_types.len(); + format!("{}<{}>", snippet, types.join(", ")) + }; + suggestions.push((*span, code)); + } else if dupes { + where_constraints.push(*span); } } + let where_msg = "consider introducing a new type parameter, adding `where` constraints \ + using the fully-qualified path to the associated types"; + if !where_constraints.is_empty() && suggestions.is_empty() { + // If there are duplicates associated type names and a single trait bound do not + // use structured suggestion, it means that there are multiple super-traits with + // the same associated type name. + err.help(where_msg); + } if suggestions.len() != 1 { // We don't need this label if there's an inline suggestion, show otherwise. - let names = associated_types.iter() - .map(|t| format!("`{}`", tcx.associated_item(*t).ident)) - .collect::>() - .join(", "); - err.span_label(sugg_span, format!( - "associated type{} {} must be specified", - pluralize!(associated_types.len()), - names, - )); + for (span, def_ids) in &associated_types { + let assoc_items: Vec<_> = def_ids.iter() + .map(|def_id| tcx.associated_item(*def_id)) + .collect(); + let mut names: FxHashMap<_, usize> = FxHashMap::default(); + for item in &assoc_items { + types_count += 1; + *names.entry(item.ident.name).or_insert(0) += 1; + } + let mut label = vec![]; + for item in &assoc_items { + let postfix = if names[&item.ident.name] > 1 { + let trait_def_id = item.container.id(); + format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) + } else { + String::new() + }; + label.push(format!("`{}`{}", item.ident, postfix)); + } + if !label.is_empty() { + err.span_label(*span, format!( + "associated type{} {} must be specified", + pluralize!(label.len()), + label.join(", "), + )); + } + } } if !suggestions.is_empty() { - let msg = format!("specify the associated type{}", pluralize!(suggestions_len)); - err.multipart_suggestion(&msg, suggestions, applicability); + err.multipart_suggestion( + &format!("specify the associated type{}", pluralize!(types_count)), + suggestions, + Applicability::HasPlaceholders, + ); + if !where_constraints.is_empty() { + err.span_help(where_constraints, where_msg); + } } err.emit(); } diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr index aa46e5d077f3e..8eb296d4998af 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr @@ -49,15 +49,15 @@ error[E0191]: the value of the associated types `Color` (from trait `Vehicle`), --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30 | LL | type Color; - | ----------- `Color` defined here + | ----------- `Vehicle::Color` defined here ... LL | type Color; - | ----------- `Color` defined here + | ----------- `Box::Color` defined here ... LL | fn dent_object(c: dyn BoxCar) { - | ^^^^^^^^^^^^^^^^^^^ associated types `Color`, `Color` must be specified + | ^^^^^^^^^^^^^^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified | - = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated type + = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:28:29 @@ -84,15 +84,15 @@ error[E0191]: the value of the associated types `Color` (from trait `Vehicle`), --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:32 | LL | type Color; - | ----------- `Color` defined here + | ----------- `Vehicle::Color` defined here ... LL | type Color; - | ----------- `Color` defined here + | ----------- `Box::Color` defined here ... LL | fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { - | ^^^^^^ associated types `Color`, `Color` must be specified + | ^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified | - = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated type + = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types error: aborting due to 6 previous errors diff --git a/src/test/ui/associated-types/missing-associated-types.rs b/src/test/ui/associated-types/missing-associated-types.rs new file mode 100644 index 0000000000000..3c8410e39bd09 --- /dev/null +++ b/src/test/ui/associated-types/missing-associated-types.rs @@ -0,0 +1,27 @@ +use std::ops::{Add, Sub, Mul, Div}; +trait X: Mul + Div {} +trait Y: Div { + type A; +} +trait Z: Div { + type A; + type B; +} +trait Fine: Div {} + +type Foo = dyn Add + Sub + X + Y; +//~^ ERROR only auto traits can be used as additional traits in a trait object +//~| ERROR the value of the associated types +type Bar = dyn Add + Sub + X + Z; +//~^ ERROR only auto traits can be used as additional traits in a trait object +//~| ERROR the value of the associated types +type Baz = dyn Add + Sub + Y; +//~^ ERROR only auto traits can be used as additional traits in a trait object +//~| ERROR the value of the associated types +type Bat = dyn Add + Sub + Fine; +//~^ ERROR only auto traits can be used as additional traits in a trait object +//~| ERROR the value of the associated types +type Bal = dyn X; +//~^ ERROR the value of the associated types + +fn main() {} diff --git a/src/test/ui/associated-types/missing-associated-types.stderr b/src/test/ui/associated-types/missing-associated-types.stderr new file mode 100644 index 0000000000000..7be266388177a --- /dev/null +++ b/src/test/ui/associated-types/missing-associated-types.stderr @@ -0,0 +1,129 @@ +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/missing-associated-types.rs:12:32 + | +LL | type Foo = dyn Add + Sub + X + Y; + | -------- ^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified + --> $DIR/missing-associated-types.rs:12:52 + | +LL | type A; + | ------- `A` defined here +... +LL | type Foo = dyn Add + Sub + X + Y; + | ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated type `A` must be specified + | | | | + | | | associated type `Output` must be specified + | | associated type `Output` must be specified + | associated type `Output` must be specified + | +help: specify the associated types + | +LL | type Foo = dyn Add + Sub + X + Y; + | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/missing-associated-types.rs:15:32 + | +LL | type Bar = dyn Add + Sub + X + Z; + | -------- ^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`), `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + --> $DIR/missing-associated-types.rs:15:21 + | +LL | type A; + | ------- `A` defined here +LL | type B; + | ------- `B` defined here +... +LL | type Bar = dyn Add + Sub + X + Z; + | ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated types `A`, `B`, `Output` must be specified + | | | | + | | | associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + | | associated type `Output` must be specified + | associated type `Output` must be specified + | +help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types + --> $DIR/missing-associated-types.rs:15:43 + | +LL | type Bar = dyn Add + Sub + X + Z; + | ^^^^^^ +help: specify the associated types + | +LL | type Bar = dyn Add + Sub + X + Z; + | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/missing-associated-types.rs:18:32 + | +LL | type Baz = dyn Add + Sub + Y; + | -------- ^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Sub`), `A` (from trait `Y`), `Output` (from trait `std::ops::Add`) must be specified + --> $DIR/missing-associated-types.rs:18:32 + | +LL | type A; + | ------- `A` defined here +... +LL | type Baz = dyn Add + Sub + Y; + | ^^^^^^^^ ^^^^^^^^ ^^^^^^ associated type `A` must be specified + | | | + | | associated type `Output` must be specified + | associated type `Output` must be specified + | +help: specify the associated types + | +LL | type Baz = dyn Add + Sub + Y; + | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/missing-associated-types.rs:21:32 + | +LL | type Bat = dyn Add + Sub + Fine; + | -------- ^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Sub`), `Output` (from trait `std::ops::Add`) must be specified + --> $DIR/missing-associated-types.rs:21:32 + | +LL | type Bat = dyn Add + Sub + Fine; + | ^^^^^^^^ ^^^^^^^^ associated type `Output` must be specified + | | + | associated type `Output` must be specified + | +help: specify the associated types + | +LL | type Bat = dyn Add + Sub + Fine; + | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + --> $DIR/missing-associated-types.rs:24:21 + | +LL | type Bal = dyn X; + | ^^^^^^ associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + | + = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0191, E0225. +For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/issues/issue-22560.stderr b/src/test/ui/issues/issue-22560.stderr index 4466a40f0da61..bf80b24fa563e 100644 --- a/src/test/ui/issues/issue-22560.stderr +++ b/src/test/ui/issues/issue-22560.stderr @@ -35,8 +35,8 @@ LL | type Test = dyn Add + Sub; | first non-auto trait | trait alias used in trait object type (first use) -error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified - --> $DIR/issue-22560.rs:9:13 +error[E0191]: the value of the associated types `Output` (from trait `Sub`), `Output` (from trait `Add`) must be specified + --> $DIR/issue-22560.rs:9:23 | LL | type Output; | ------------ `Output` defined here @@ -45,7 +45,14 @@ LL | type Output; | ------------ `Output` defined here ... LL | type Test = dyn Add + Sub; - | ^^^^^^^^^^^^^ associated types `Output`, `Output` must be specified + | ^^^ ^^^ associated type `Output` must be specified + | | + | associated type `Output` must be specified + | +help: specify the associated types + | +LL | type Test = dyn Add + Sub; + | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr index 321196d14b7aa..58a73187fb158 100644 --- a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr +++ b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr @@ -7,7 +7,7 @@ LL | i: Box>, | unexpected type argument error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified - --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:12 + --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16 | LL | type A; | ------- `A` defined here @@ -16,7 +16,7 @@ LL | type C; | ------- `C` defined here ... LL | i: Box>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified | help: specify the associated types | From 87bf6bdd94298250e9c93b680c94f62f78ceb890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 18 Dec 2019 11:12:50 -0800 Subject: [PATCH 14/17] Cleanup: move code to their own methods and deduplicate actions --- src/librustc_typeck/astconv.rs | 165 ++++++++++-------- .../missing-associated-types.stderr | 4 +- 2 files changed, 94 insertions(+), 75 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d0536e8eed57b..6a57c48209539 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -783,6 +783,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (substs, assoc_bindings, potential_assoc_types) } + /// On missing type parameters, emit an E0393 error and provide a structured suggestion using + /// the type parameter's name as a placeholder. fn complain_about_missing_type_params( &self, missing_type_params: Vec, @@ -956,8 +958,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment - ) -> ty::TraitRef<'tcx> - { + ) -> ty::TraitRef<'tcx> { let (substs, assoc_bindings, _) = self.create_substs_for_ast_trait_ref(span, trait_def_id, @@ -967,15 +968,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::TraitRef::new(trait_def_id, substs) } - fn create_substs_for_ast_trait_ref<'a>( + /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit + /// an error and attempt to build a reasonable structured suggestion. + fn complain_about_internal_fn_trait( &self, span: Span, trait_def_id: DefId, - self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment, - ) -> (SubstsRef<'tcx>, Vec>, Option>) { - debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); - + ) { let trait_def = self.tcx().trait_def(trait_def_id); if !self.tcx().features().unboxed_closures && @@ -1020,19 +1020,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } err.emit(); } + } + + fn create_substs_for_ast_trait_ref<'a>( + &self, + span: Span, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + trait_segment: &'a hir::PathSegment, + ) -> (SubstsRef<'tcx>, Vec>, Option>) { + debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); + + self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); - self.create_substs_for_ast_path(span, - trait_def_id, - trait_segment.generic_args(), - trait_segment.infer_args, - Some(self_ty)) + self.create_substs_for_ast_path( + span, + trait_def_id, + trait_segment.generic_args(), + trait_segment.infer_args, + Some(self_ty), + ) } - fn trait_defines_associated_type_named(&self, - trait_def_id: DefId, - assoc_name: ast::Ident) - -> bool - { + fn trait_defines_associated_type_named( + &self, + trait_def_id: DefId, + assoc_name: ast::Ident, + ) -> bool { self.tcx().associated_items(trait_def_id).any(|item| { item.kind == ty::AssocKind::Type && self.tcx().hygienic_eq(assoc_name, item.ident, trait_def_id) @@ -1400,48 +1414,49 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); for (base_trait_ref, span) in regular_traits_refs_spans { - debug!("conv_object_ty_poly_trait_ref regular_trait_ref `{:?}`", base_trait_ref); - let mut new_bounds = vec![]; for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) { - debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref); - match trait_ref { - ty::Predicate::Trait(pred) => { - associated_types.entry(span).or_default() - .extend(tcx.associated_items(pred.def_id()) - .filter(|item| item.kind == ty::AssocKind::Type) - .map(|item| item.def_id)); - } - ty::Predicate::Projection(pred) => { - // A `Self` within the original bound will be substituted with a - // `trait_object_dummy_self`, so check for that. - let references_self = - pred.skip_binder().ty.walk().any(|t| t == dummy_self); - - // If the projection output contains `Self`, force the user to - // elaborate it explicitly to avoid a lot of complexity. - // - // The "classicaly useful" case is the following: - // ``` - // trait MyTrait: FnMut() -> ::MyOutput { - // type MyOutput; - // } - // ``` - // - // Here, the user could theoretically write `dyn MyTrait`, - // but actually supporting that would "expand" to an infinitely-long type - // `fix $ τ → dyn MyTrait::MyOutput`. - // - // Instead, we force the user to write `dyn MyTrait`, - // which is uglier but works. See the discussion in #56288 for alternatives. - if !references_self { - // Include projections defined on supertraits. - new_bounds.push((pred, span)); + debug!( + "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", + trait_ref + ); + match trait_ref { + ty::Predicate::Trait(pred) => { + associated_types.entry(span).or_default() + .extend(tcx.associated_items(pred.def_id()) + .filter(|item| item.kind == ty::AssocKind::Type) + .map(|item| item.def_id)); + } + ty::Predicate::Projection(pred) => { + // A `Self` within the original bound will be substituted with a + // `trait_object_dummy_self`, so check for that. + let references_self = + pred.skip_binder().ty.walk().any(|t| t == dummy_self); + + // If the projection output contains `Self`, force the user to + // elaborate it explicitly to avoid a lot of complexity. + // + // The "classicaly useful" case is the following: + // ``` + // trait MyTrait: FnMut() -> ::MyOutput { + // type MyOutput; + // } + // ``` + // + // Here, the user could theoretically write `dyn MyTrait`, + // but actually supporting that would "expand" to an infinitely-long type + // `fix $ τ → dyn MyTrait::MyOutput`. + // + // Instead, we force the user to write + // `dyn MyTrait`, which is uglier but works. See + // the discussion in #56288 for alternatives. + if !references_self { + // Include projections defined on supertraits. + bounds.projection_bounds.push((pred, span)); + } } + _ => () } - _ => () - } } - bounds.projection_bounds.extend(new_bounds); } for (projection_bound, _) in &bounds.projection_bounds { @@ -1534,9 +1549,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty } + /// When there are any missing associated types, emit an E0191 error and attempt to supply a + /// reasonable suggestion on how to write it. For the case of multiple associated types in the + /// same trait bound have the same name (as they come from different super-traits), we instead + /// emit a generic note suggesting using a `where` clause to constraint instead. fn complain_about_missing_associated_types( &self, - mut associated_types: FxHashMap>, + associated_types: FxHashMap>, potential_assoc_types: Vec, trait_bounds: &[hir::PolyTraitRef], ) { @@ -1544,17 +1563,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return; } let tcx = self.tcx(); + // FIXME: Marked `mut` so that we can replace the spans further below with a more + // appropriate one, but this should be handled earlier in the span assignment. + let mut associated_types: FxHashMap> = associated_types.into_iter() + .map(|(span, def_ids)| ( + span, + def_ids.into_iter().map(|did| tcx.associated_item(did)).collect(), + )).collect(); let mut names = vec![]; // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and // `issue-22560.rs`. let mut trait_bound_spans: Vec = vec![]; - for (span, item_def_ids) in &associated_types { - if !item_def_ids.is_empty() { + for (span, items) in &associated_types { + if !items.is_empty() { trait_bound_spans.push(*span); } - for item_def_id in item_def_ids { - let assoc_item = tcx.associated_item(*item_def_id); + for assoc_item in items { let trait_def_id = assoc_item.container.id(); names.push(format!( "`{}` (from trait `{}`)", @@ -1592,7 +1617,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { [segment] if segment.args.is_none() => { trait_bound_spans = vec![segment.ident.span]; associated_types = associated_types.into_iter() - .map(|(_, defs)| (segment.ident.span, defs)) + .map(|(_, items)| (segment.ident.span, items)) .collect(); } _ => {} @@ -1610,17 +1635,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut suggestions = vec![]; let mut types_count = 0; let mut where_constraints = vec![]; - for (span, def_ids) in &associated_types { - let assoc_items: Vec<_> = def_ids.iter() - .map(|def_id| tcx.associated_item(*def_id)) - .collect(); + for (span, assoc_items) in &associated_types { let mut names: FxHashMap<_, usize> = FxHashMap::default(); - for item in &assoc_items { + for item in assoc_items { types_count += 1; *names.entry(item.ident.name).or_insert(0) += 1; } let mut dupes = false; - for item in &assoc_items { + for item in assoc_items { let prefix = if names[&item.ident.name] > 1 { let trait_def_id = item.container.id(); dupes = true; @@ -1681,17 +1703,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if suggestions.len() != 1 { // We don't need this label if there's an inline suggestion, show otherwise. - for (span, def_ids) in &associated_types { - let assoc_items: Vec<_> = def_ids.iter() - .map(|def_id| tcx.associated_item(*def_id)) - .collect(); + for (span, assoc_items) in &associated_types { let mut names: FxHashMap<_, usize> = FxHashMap::default(); - for item in &assoc_items { + for item in assoc_items { types_count += 1; *names.entry(item.ident.name).or_insert(0) += 1; } let mut label = vec![]; - for item in &assoc_items { + for item in assoc_items { let postfix = if names[&item.ident.name] > 1 { let trait_def_id = item.container.id(); format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) diff --git a/src/test/ui/associated-types/missing-associated-types.stderr b/src/test/ui/associated-types/missing-associated-types.stderr index 7be266388177a..7d5207fa321ba 100644 --- a/src/test/ui/associated-types/missing-associated-types.stderr +++ b/src/test/ui/associated-types/missing-associated-types.stderr @@ -38,8 +38,8 @@ LL | type Bar = dyn Add + Sub + X + Z; | first non-auto trait | trait alias used in trait object type (first use) -error[E0191]: the value of the associated types `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`), `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified - --> $DIR/missing-associated-types.rs:15:21 +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Sub`), `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Add`) must be specified + --> $DIR/missing-associated-types.rs:15:43 | LL | type A; | ------- `A` defined here From 97219d87feee2a87bc93f7f7ef5120e526a6307d Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 15 Dec 2019 11:08:43 +0000 Subject: [PATCH 15/17] Don't suppress move errors for union fields --- .../dataflow/move_paths/builder.rs | 31 +++++++++++++------ .../move-from-union-field-issue-66500.rs | 30 ++++++++++++++++++ .../move-from-union-field-issue-66500.stderr | 27 ++++++++++++++++ 3 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/borrowck/move-from-union-field-issue-66500.rs create mode 100644 src/test/ui/borrowck/move-from-union-field-issue-66500.stderr diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index fa0864e0de760..971e9a1b3b281 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -103,6 +103,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } }; + // The move path index of the first union that we find. Once this is + // some we stop creating child move paths, since moves from unions + // move the whole thing. + // We continue looking for other move errors though so that moving + // from `*(u.f: &_)` isn't allowed. + let mut union_path = None; + for (i, elem) in place.projection.iter().enumerate() { let proj_base = &place.projection[..i]; let body = self.builder.body; @@ -127,9 +134,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { InteriorOfTypeWithDestructor { container_ty: place_ty }, )); } - // move out of union - always move the entire union ty::Adt(adt, _) if adt.is_union() => { - return Err(MoveError::UnionMove { path: base }); + union_path.get_or_insert(base); } ty::Slice(_) => { return Err(MoveError::cannot_move_out_of( @@ -155,15 +161,22 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { _ => {} }; - base = self.add_move_path(base, elem, |tcx| { - Place { - base: place.base.clone(), - projection: tcx.intern_place_elems(&place.projection[..i+1]), - } - }); + if union_path.is_none() { + base = self.add_move_path(base, elem, |tcx| { + Place { + base: place.base.clone(), + projection: tcx.intern_place_elems(&place.projection[..i+1]), + } + }); + } } - Ok(base) + if let Some(base) = union_path { + // Move out of union - always move the entire union. + Err(MoveError::UnionMove { path: base }) + } else { + Ok(base) + } } fn add_move_path( diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs new file mode 100644 index 0000000000000..8fbf120fc1c78 --- /dev/null +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs @@ -0,0 +1,30 @@ +// Moving from a reference/raw pointer should be an error, even when they're +// the field of a union. + +#![feature(untagged_unions)] + +union Pointers { + a: &'static String, + b: &'static mut String, + c: *const String, + d: *mut String, +} + +unsafe fn move_ref(u: Pointers) -> String { + *u.a + //~^ ERROR cannot move out of `*u.a` +} +unsafe fn move_ref_mut(u: Pointers) -> String { + *u.b + //~^ ERROR cannot move out of `*u.b` +} +unsafe fn move_ptr(u: Pointers) -> String { + *u.c + //~^ ERROR cannot move out of `*u.c` +} +unsafe fn move_ptr_mut(u: Pointers) -> String { + *u.d + //~^ ERROR cannot move out of `*u.d` +} + +fn main() {} diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr new file mode 100644 index 0000000000000..a7cb1c9e22135 --- /dev/null +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -0,0 +1,27 @@ +error[E0507]: cannot move out of `*u.a` which is behind a shared reference + --> $DIR/move-from-union-field-issue-66500.rs:14:5 + | +LL | *u.a + | ^^^^ move occurs because `*u.a` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.b` which is behind a mutable reference + --> $DIR/move-from-union-field-issue-66500.rs:18:5 + | +LL | *u.b + | ^^^^ move occurs because `*u.b` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.c` which is behind a raw pointer + --> $DIR/move-from-union-field-issue-66500.rs:22:5 + | +LL | *u.c + | ^^^^ move occurs because `*u.c` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.d` which is behind a raw pointer + --> $DIR/move-from-union-field-issue-66500.rs:26:5 + | +LL | *u.d + | ^^^^ move occurs because `*u.d` has type `std::string::String`, which does not implement the `Copy` trait + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0507`. From d72ceb4cd630b4ae498d26f31b4ca0fcb4d11923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Dec 2019 11:23:57 -0800 Subject: [PATCH 16/17] Fix suggestion span for typo in associated type name --- src/librustc_typeck/astconv.rs | 48 +++++++++++-------- .../associated-types-path-1.stderr | 4 +- src/test/ui/error-codes/E0220.stderr | 4 +- src/test/ui/issues/issue-23595-2.stderr | 4 +- src/test/ui/issues/issue-39211.stderr | 4 +- src/test/ui/issues/issue-59029-1.stderr | 4 +- src/test/ui/span/type-binding.stderr | 4 +- .../not_well_formed.stderr | 4 +- 8 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6a57c48209539..750b505e7e59c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1814,7 +1814,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_name: ast::Ident, span: Span, is_equality: Option, - ) -> Result, ErrorReported> + ) -> Result, ErrorReported> where I: Iterator>, { let mut matching_candidates = all_candidates().filter(|r| { @@ -1828,7 +1828,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { all_candidates, ty_param_name, assoc_name, - span + span, ); return Err(ErrorReported); } @@ -1916,16 +1916,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return Ok(bound); } - fn complain_about_assoc_type_not_found(&self, - all_candidates: impl Fn() -> I, - ty_param_name: &str, - assoc_name: ast::Ident, - span: Span) - where I: Iterator> { - let mut err = struct_span_err!(self.tcx().sess, span, E0220, - "associated type `{}` not found for `{}`", - assoc_name, - ty_param_name); + fn complain_about_assoc_type_not_found( + &self, + all_candidates: impl Fn() -> I, + ty_param_name: &str, + assoc_name: ast::Ident, + span: Span, + ) where I: Iterator> { + // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a + // valid span, so we point at the whole path segment instead. + let span = if assoc_name.span != DUMMY_SP { + assoc_name.span + } else { + span + }; + let mut err = struct_span_err!( + self.tcx().sess, span, E0220, + "associated type `{}` not found for `{}`", + assoc_name, + ty_param_name + ); let all_candidate_names: Vec<_> = all_candidates() .map(|r| self.tcx().associated_items(r.def_id())) @@ -1939,22 +1949,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .collect(); - if let Some(suggested_name) = find_best_match_for_name( - all_candidate_names.iter(), - &assoc_name.as_str(), - None, + if let (Some(suggested_name), true) = ( + find_best_match_for_name(all_candidate_names.iter(), &assoc_name.as_str(), None), + assoc_name.span != DUMMY_SP, ) { err.span_suggestion( - span, + assoc_name.span, "there is an associated type with a similar name", suggested_name.to_string(), Applicability::MaybeIncorrect, ); } else { - err.span_label( - span, - format!("associated type `{}` not found", assoc_name) - ); + err.span_label(span, format!("associated type `{}` not found", assoc_name)); } err.emit(); diff --git a/src/test/ui/associated-types/associated-types-path-1.stderr b/src/test/ui/associated-types/associated-types-path-1.stderr index b7856e20afaad..60db7749082e5 100644 --- a/src/test/ui/associated-types/associated-types-path-1.stderr +++ b/src/test/ui/associated-types/associated-types-path-1.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `A` not found for `T` - --> $DIR/associated-types-path-1.rs:10:23 + --> $DIR/associated-types-path-1.rs:10:26 | LL | pub fn f1(a: T, x: T::A) {} - | ^^^^ associated type `A` not found + | ^ associated type `A` not found error[E0221]: ambiguous associated type `A` in bounds of `T` --> $DIR/associated-types-path-1.rs:11:34 diff --git a/src/test/ui/error-codes/E0220.stderr b/src/test/ui/error-codes/E0220.stderr index 73e66ceb84564..4fa83d8bf6e82 100644 --- a/src/test/ui/error-codes/E0220.stderr +++ b/src/test/ui/error-codes/E0220.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `F` not found for `Trait` - --> $DIR/E0220.rs:5:16 + --> $DIR/E0220.rs:5:22 | LL | type Foo = dyn Trait; - | ^^^^^^^^^^^^ associated type `F` not found + | ^ associated type `F` not found error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified --> $DIR/E0220.rs:5:16 diff --git a/src/test/ui/issues/issue-23595-2.stderr b/src/test/ui/issues/issue-23595-2.stderr index f1004db0b0904..dded673f6eed6 100644 --- a/src/test/ui/issues/issue-23595-2.stderr +++ b/src/test/ui/issues/issue-23595-2.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `anything_here_kills_it` not found for `Self` - --> $DIR/issue-23595-2.rs:6:16 + --> $DIR/issue-23595-2.rs:6:22 | LL | type B = C; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found + | ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found error: aborting due to previous error diff --git a/src/test/ui/issues/issue-39211.stderr b/src/test/ui/issues/issue-39211.stderr index ea850ea57d5b6..c14c663e5a1a9 100644 --- a/src/test/ui/issues/issue-39211.stderr +++ b/src/test/ui/issues/issue-39211.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `Row` not found for `M` - --> $DIR/issue-39211.rs:11:17 + --> $DIR/issue-39211.rs:11:20 | LL | let a = [3; M::Row::DIM]; - | ^^^^^^^^^^^ associated type `Row` not found + | ^^^ associated type `Row` not found error: aborting due to previous error diff --git a/src/test/ui/issues/issue-59029-1.stderr b/src/test/ui/issues/issue-59029-1.stderr index ed1d98c40d18a..fb1de9759c5cf 100644 --- a/src/test/ui/issues/issue-59029-1.stderr +++ b/src/test/ui/issues/issue-59029-1.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `Res` not found for `Self` - --> $DIR/issue-59029-1.rs:5:46 + --> $DIR/issue-59029-1.rs:5:52 | LL | trait MkSvc = Svc where Self::Res: Svc; - | ^^^^^^^^^ associated type `Res` not found + | ^^^ associated type `Res` not found error: aborting due to previous error diff --git a/src/test/ui/span/type-binding.stderr b/src/test/ui/span/type-binding.stderr index 5b64fe1889280..f69899335539a 100644 --- a/src/test/ui/span/type-binding.stderr +++ b/src/test/ui/span/type-binding.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `Trget` not found for `std::ops::Deref` - --> $DIR/type-binding.rs:6:14 + --> $DIR/type-binding.rs:6:20 | LL | fn homura>(_: T) {} - | ^^^^^^^^^^^ help: there is an associated type with a similar name: `Target` + | ^^^^^ help: there is an associated type with a similar name: `Target` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr index d374d6d33ee73..c2b6f7eae9f3d 100644 --- a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr +++ b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `Assoc` not found for `V` - --> $DIR/not_well_formed.rs:10:26 + --> $DIR/not_well_formed.rs:10:29 | LL | type Foo = impl Trait; - | ^^^^^^^^ associated type `Assoc` not found + | ^^^^^ associated type `Assoc` not found error: aborting due to previous error From 90ef197a6eb0287b85b054f94e53951dddc15576 Mon Sep 17 00:00:00 2001 From: Who? Me?! Date: Fri, 20 Dec 2019 14:49:32 -0600 Subject: [PATCH 17/17] Better comment Co-Authored-By: matthewjasper --- src/librustc_mir/borrow_check/region_infer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index ca29b552733d1..dedc6b9b09af2 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -1619,7 +1619,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's - /// creator. If we cannot, then we report an error to the user. + /// creator. If we cannot, then the caller should report an error to the user. /// /// Returns `true` if the error was propagated, and `false` otherwise. fn try_propagate_universal_region_error(