Auto merge of #109692 - Nilstrieb:rollup-hq65rps, r=Nilstrieb

Rollup of 8 pull requests

Successful merges:

 - #91793 (socket ancillary data implementation for FreeBSD (from 13 and above).)
 - #92284 (Change advance(_back)_by to return the remainder instead of the number of processed elements)
 - #102472 (stop special-casing `'static` in evaluation)
 - #108480 (Use Rayon's TLV directly)
 - #109321 (Erase impl regions when checking for impossible to eagerly monomorphize items)
 - #109470 (Correctly substitute GAT's type used in `normalize_param_env` in `check_type_bounds`)
 - #109562 (Update ar_archive_writer to 0.1.3)
 - #109629 (remove obsolete `givens` from regionck)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-28 15:18:16 +00:00
commit 478cbb42b7
77 changed files with 1011 additions and 745 deletions

View File

@ -106,11 +106,11 @@ checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
[[package]]
name = "ar_archive_writer"
version = "0.1.1"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
checksum = "b0639441fd17a3197d1cbca8dc8768cc172a63b64b4bb6c372e8f41ed0acc9bb"
dependencies = [
"object 0.29.0",
"object 0.30.1",
]
[[package]]
@ -2689,9 +2689,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "indexmap"
version = "1.9.2"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
@ -4160,21 +4160,19 @@ dependencies = [
[[package]]
name = "rustc-rayon"
version = "0.4.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a79f0b0b2609e2eacf9758013f50e7176cb4b29fd6436a747b14a5362c8727a"
checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rustc-rayon-core",
]
[[package]]
name = "rustc-rayon-core"
version = "0.4.1"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02269144a0db9bb55cf5d4a41a5a0e95b334b0b78b08269018ca9b0250718c30"
checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",

View File

@ -235,9 +235,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.9.2"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",

View File

@ -25,7 +25,7 @@ target-lexicon = "0.12.0"
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
indexmap = "1.9.1"
indexmap = "1.9.3"
libloading = { version = "0.7.3", optional = true }
once_cell = "1.10.0"
smallvec = "1.8.1"

View File

@ -110,7 +110,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
// FIXME use ArArchiveBuilder on most targets again once reading thin archives is
// implemented
if true || sess.target.arch == "wasm32" || sess.target.arch == "wasm64" {
if true {
Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
} else {
Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))

View File

@ -10,12 +10,12 @@ arrayvec = { version = "0.7", default-features = false }
bitflags = "1.2.1"
cfg-if = "1.0"
ena = "0.14.2"
indexmap = { version = "1.9.1" }
indexmap = { version = "1.9.3" }
jobserver_crate = { version = "0.1.13", package = "jobserver" }
libc = "0.2"
measureme = "10.0.0"
rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true }
rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc-rayon = { version = "0.5.0", optional = true }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc-hash = "1.1.0"
rustc_index = { path = "../rustc_index", package = "rustc_index" }
@ -51,4 +51,4 @@ features = [
memmap2 = "0.2.1"
[features]
rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rayon", "rayon-core"]
rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon", "rustc-rayon-core"]

View File

@ -330,7 +330,6 @@ fn compare_method_predicate_entailment<'tcx>(
// lifetime parameters.
let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
Some(infcx),
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()),
);
infcx.process_registered_region_obligations(
@ -727,7 +726,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// lifetime parameters.
let outlives_environment = OutlivesEnvironment::with_bounds(
param_env,
Some(infcx),
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
);
infcx
@ -1876,14 +1874,17 @@ pub(super) fn check_type_bounds<'tcx>(
impl_ty: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
let param_env = tcx.param_env(impl_ty.def_id);
let container_id = impl_ty.container_id(tcx);
// Given
//
// impl<A, B> Foo<u32> for (A, B) {
// type Bar<C> =...
// type Bar<C> = Wrapper<A, B, C>
// }
//
// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
// - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
// - `normalize_impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
// - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
// - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
// the *trait* with the generic associated type parameters (as bound vars).
//
@ -1912,56 +1913,46 @@ pub(super) fn check_type_bounds<'tcx>(
// Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
// elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
// the trait (notably, that X: Eq and T: Family).
let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
let mut substs = smallvec::SmallVec::with_capacity(defs.count());
if let Some(def_id) = defs.parent {
let parent_defs = tcx.generics_of(def_id);
InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
tcx.mk_param_from_def(param)
});
}
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
smallvec::SmallVec::with_capacity(defs.count());
InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
GenericParamDefKind::Type { .. } => {
let kind = ty::BoundTyKind::Param(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Ty(kind);
bound_vars.push(bound_var);
tcx.mk_bound(
ty::INNERMOST,
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
GenericParamDefKind::Lifetime => {
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Region(kind);
bound_vars.push(bound_var);
tcx.mk_re_late_bound(
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
tcx.mk_const(
ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
tcx.type_of(param.def_id).subst_identity(),
)
.into()
}
});
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
let impl_ty_substs = tcx.mk_substs(&substs);
let container_id = impl_ty.container_id(tcx);
let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
let impl_ty_value = tcx.type_of(impl_ty.def_id).subst_identity();
let param_env = tcx.param_env(impl_ty.def_id);
smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
// Extend the impl's identity substs with late-bound GAT vars
let normalize_impl_ty_substs = ty::InternalSubsts::identity_for_item(tcx, container_id)
.extend_to(tcx, impl_ty.def_id, |param, _| match param.kind {
GenericParamDefKind::Type { .. } => {
let kind = ty::BoundTyKind::Param(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Ty(kind);
bound_vars.push(bound_var);
tcx.mk_bound(
ty::INNERMOST,
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
GenericParamDefKind::Lifetime => {
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Region(kind);
bound_vars.push(bound_var);
tcx.mk_re_late_bound(
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
tcx.mk_const(
ty::ConstKind::Bound(
ty::INNERMOST,
ty::BoundVar::from_usize(bound_vars.len() - 1),
),
tcx.type_of(param.def_id)
.no_bound_vars()
.expect("const parameter types cannot be generic"),
)
.into()
}
});
// When checking something like
//
// trait X { type Y: PartialEq<<Self as X>::Y> }
@ -1971,9 +1962,13 @@ pub(super) fn check_type_bounds<'tcx>(
// we want <T as X>::Y to normalize to S. This is valid because we are
// checking the default value specifically here. Add this equality to the
// ParamEnv for normalization specifically.
let normalize_impl_ty = tcx.type_of(impl_ty.def_id).subst(tcx, normalize_impl_ty_substs);
let rebased_substs =
normalize_impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
let normalize_param_env = {
let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
match impl_ty_value.kind() {
match normalize_impl_ty.kind() {
ty::Alias(ty::Projection, proj)
if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
{
@ -1987,7 +1982,7 @@ pub(super) fn check_type_bounds<'tcx>(
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
term: impl_ty_value.into(),
term: normalize_impl_ty.into(),
},
bound_vars,
)
@ -2068,8 +2063,7 @@ pub(super) fn check_type_bounds<'tcx>(
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
let outlives_environment =
OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
infcx.err_ctxt().check_region_obligations_and_report_errors(
impl_ty.def_id.expect_local(),

View File

@ -114,8 +114,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
return;
}
let outlives_environment =
OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
let _ = infcx
.err_ctxt()
@ -675,7 +674,6 @@ fn resolve_regions_with_wf_tys<'tcx>(
let infcx = tcx.infer_ctxt().build();
let outlives_environment = OutlivesEnvironment::with_bounds(
param_env,
Some(&infcx),
infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
);
let region_bound_pairs = outlives_environment.region_bound_pairs();

View File

@ -179,7 +179,7 @@ fn get_impl_substs(
}
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
let _ =
infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {

View File

@ -238,15 +238,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Note that there are two tests to check that this remains true
// (`regions-reassign-{match,let}-bound-pointer.rs`).
//
// 2. Things go horribly wrong if we use subtype. The reason for
// THIS is a fairly subtle case involving bound regions. See the
// `givens` field in `region_constraints`, as well as the test
// 2. An outdated issue related to the old HIR borrowck. See the test
// `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
// for details. Short version is that we must sometimes detect
// relationships between specific region variables and regions
// bound in a closure signature, and that detection gets thrown
// off when we substitute fresh region variables here to enable
// subtyping.
}
/// Compute the new expected type and default binding mode from the old ones

View File

@ -640,11 +640,9 @@ pub fn make_query_region_constraints<'tcx>(
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
region_constraints: &RegionConstraintData<'tcx>,
) -> QueryRegionConstraints<'tcx> {
let RegionConstraintData { constraints, verifys, givens, member_constraints } =
region_constraints;
let RegionConstraintData { constraints, verifys, member_constraints } = region_constraints;
assert!(verifys.is_empty());
assert!(givens.is_empty());
debug!(?constraints);

View File

@ -43,18 +43,16 @@ pub struct TypeFreshener<'a, 'tcx> {
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
keep_static: bool,
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'tcx>) -> TypeFreshener<'a, 'tcx> {
TypeFreshener {
infcx,
ty_freshen_count: 0,
const_freshen_count: 0,
ty_freshen_map: Default::default(),
const_freshen_map: Default::default(),
keep_static,
}
}
@ -121,18 +119,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
| ty::ReFree(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
| ty::ReStatic
| ty::ReError(_)
| ty::ReErased => {
// replace all free regions with 'erased
self.interner().lifetimes.re_erased
}
ty::ReStatic => {
if self.keep_static {
r
} else {
self.interner().lifetimes.re_erased
}
}
| ty::ReErased => self.interner().lifetimes.re_erased,
}
}

View File

@ -13,7 +13,7 @@ use rustc_data_structures::graph::implementation::{
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
use rustc_data_structures::intern::Interned;
use rustc_index::vec::{Idx, IndexVec};
use rustc_index::vec::IndexVec;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::PlaceholderRegion;
use rustc_middle::ty::{self, Ty, TyCtxt};
@ -132,7 +132,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
let graph = self.construct_graph();
self.expand_givens(&graph);
self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
@ -164,38 +163,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
// Givens are a kind of horrible hack to account for
// constraints like 'c <= '0 that are known to hold due to
// closure signatures (see the comment above on the `givens`
// field). They should go away. But until they do, the role
// of this fn is to account for the transitive nature:
//
// Given 'c <= '0
// and '0 <= '1
// then 'c <= '1
let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
for (r, vid) in seeds {
// While all things transitively reachable in the graph
// from the variable (`'0` in the example above).
let seed_index = NodeIndex(vid.index() as usize);
for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
let succ_index = succ_index.0;
// The first N nodes correspond to the region
// variables. Other nodes correspond to constant
// regions.
if succ_index < self.num_vars() {
let succ_vid = RegionVid::new(succ_index);
// Add `'c <= '1`.
self.data.givens.insert((r, succ_vid));
}
}
}
}
/// Gets the LUb of a given region and the empty region
fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> {
match *a_region {
@ -362,18 +329,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
) -> bool {
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
match *a_region {
// Check if this relationship is implied by a given.
ty::ReEarlyBound(_) | ty::ReFree(_) => {
if self.data.givens.contains(&(a_region, b_vid)) {
debug!("given");
return false;
}
}
_ => {}
}
match *b_data {
VarValue::Empty(empty_ui) => {
let lub = match self.lub_empty(a_region) {

View File

@ -713,12 +713,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
freshen::TypeFreshener::new(self, false)
}
/// Like `freshener`, but does not replace `'static` regions.
pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
freshen::TypeFreshener::new(self, true)
freshen::TypeFreshener::new(self)
}
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
@ -874,10 +869,6 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
}
pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
}
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
where
T: at::ToTrace<'tcx>,

View File

@ -1,9 +1,9 @@
use crate::infer::free_regions::FreeRegionMap;
use crate::infer::{GenericKind, InferCtxt};
use crate::infer::GenericKind;
use crate::traits::query::OutlivesBound;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
use rustc_middle::ty::{self, Region};
use super::explicit_outlives_bounds;
@ -75,7 +75,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
region_bound_pairs: Default::default(),
};
builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
builder.add_outlives_bounds(explicit_outlives_bounds(param_env));
builder
}
@ -89,11 +89,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
pub fn with_bounds(
param_env: ty::ParamEnv<'tcx>,
infcx: Option<&InferCtxt<'tcx>>,
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
) -> Self {
let mut builder = Self::builder(param_env);
builder.add_outlives_bounds(infcx, extra_bounds);
builder.add_outlives_bounds(extra_bounds);
builder.build()
}
@ -120,12 +119,7 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
}
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
///
/// The `infcx` parameter is optional; if the implied bounds may
/// contain inference variables, it must be supplied, in which
/// case we will register "givens" on the inference context. (See
/// `RegionConstraintData`.)
fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
@ -142,27 +136,17 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
}
OutlivesBound::RegionSubRegion(r_a, r_b) => {
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
infcx
.expect("no infcx provided but region vars found")
.add_given(r_a, vid_b);
} else {
// In principle, we could record (and take
// advantage of) every relationship here, but
// we are also free not to -- it simply means
// strictly less that we can successfully type
// check. Right now we only look for things
// relationships between free regions. (It may
// also be that we should revise our inference
// system to be more general and to make use
// of *every* relationship that arises here,
// but presently we do not.)
if r_a.is_free_or_static() && r_b.is_free() {
self.region_relation.add(r_a, r_b)
}
}
}
OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
(
ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
) => self.region_relation.add(r_a, r_b),
(ty::ReError(_), _) | (_, ty::ReError(_)) => {}
// FIXME(#109628): We shouldn't have existential variables in implied bounds.
// Panic here once the linked issue is resolved!
(ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
_ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
},
}
}
}

View File

@ -424,9 +424,6 @@ impl<'tcx> MiniGraph<'tcx> {
&AddConstraint(Constraint::RegSubReg(a, b)) => {
each_edge(a, b);
}
&AddGiven(a, b) => {
each_edge(a, tcx.mk_re_var(b));
}
&AddVerify(i) => span_bug!(
verifys[i].origin.span(),
"we never add verifications while doing higher-ranked things",

View File

@ -7,7 +7,7 @@ use super::{
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
@ -104,26 +104,6 @@ pub struct RegionConstraintData<'tcx> {
/// An example is a `A <= B` where neither `A` nor `B` are
/// inference variables.
pub verifys: Vec<Verify<'tcx>>,
/// A "given" is a relationship that is known to hold. In
/// particular, we often know from closure fn signatures that a
/// particular free region must be a subregion of a region
/// variable:
///
/// foo.iter().filter(<'a> |x: &'a &'b T| ...)
///
/// In situations like this, `'b` is in fact a region variable
/// introduced by the call to `iter()`, and `'a` is a bound region
/// on the closure (as indicated by the `<'a>` prefix). If we are
/// naive, we wind up inferring that `'b` must be `'static`,
/// because we require that it be greater than `'a` and we do not
/// know what `'a` is precisely.
///
/// This hashmap is used to avoid that naive scenario. Basically
/// we record the fact that `'a <= 'b` is implied by the fn
/// signature, and then ignore the constraint when solving
/// equations. This is a bit of a hack but seems to work.
pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>,
}
/// Represents a constraint that influences the inference process.
@ -297,9 +277,6 @@ pub(crate) enum UndoLog<'tcx> {
/// We added the given `verify`.
AddVerify(usize),
/// We added the given `given`.
AddGiven(Region<'tcx>, ty::RegionVid),
/// We added a GLB/LUB "combination variable".
AddCombination(CombineMapType, TwoRegions<'tcx>),
}
@ -348,9 +325,6 @@ impl<'tcx> RegionConstraintStorage<'tcx> {
self.data.verifys.pop();
assert_eq!(self.data.verifys.len(), index);
}
AddGiven(sub, sup) => {
self.data.givens.remove(&(sub, sup));
}
AddCombination(Glb, ref regions) => {
self.glbs.remove(regions);
}
@ -492,15 +466,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
self.undo_log.push(AddVerify(index));
}
pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
// cannot add givens once regions are resolved
if self.data.givens.insert((sub, sup)) {
debug!("add_given({:?} <= {:?})", sub, sup);
self.undo_log.push(AddGiven(sub, sup));
}
}
pub(super) fn make_eqregion(
&mut self,
origin: SubregionOrigin<'tcx>,
@ -804,11 +769,8 @@ impl<'tcx> RegionConstraintData<'tcx> {
/// Returns `true` if this region constraint data contains no constraints, and `false`
/// otherwise.
pub fn is_empty(&self) -> bool {
let RegionConstraintData { constraints, member_constraints, verifys, givens } = self;
constraints.is_empty()
&& member_constraints.is_empty()
&& verifys.is_empty()
&& givens.is_empty()
let RegionConstraintData { constraints, member_constraints, verifys } = self;
constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty()
}
}

View File

@ -8,8 +8,8 @@ edition = "2021"
[dependencies]
libloading = "0.7.1"
tracing = "0.1"
rustc-rayon-core = { version = "0.4.0", optional = true }
rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc-rayon = { version = "0.5.0", optional = true }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
@ -52,4 +52,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
[features]
llvm = ['rustc_codegen_llvm']
rustc_use_parallel_compiler = ['rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']
rustc_use_parallel_compiler = ['rustc-rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']

View File

@ -183,7 +183,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
.try_collect_active_jobs()
.expect("active jobs shouldn't be locked in deadlock handler")
});
let registry = rustc_rayon_core::Registry::current();
let registry = rayon_core::Registry::current();
thread::spawn(move || deadlock(query_map, &registry));
});
if let Some(size) = get_stack_size() {

View File

@ -26,8 +26,8 @@ rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_query_system = { path = "../rustc_query_system" }
rustc-rayon-core = { version = "0.4.0", optional = true }
rustc-rayon = { version = "0.4.0", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc-rayon = { version = "0.5.0", optional = true }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }

View File

@ -4,6 +4,8 @@ use crate::dep_graph::TaskDepsRef;
use crate::ty::query;
use rustc_data_structures::sync::{self, Lock};
use rustc_errors::Diagnostic;
#[cfg(not(parallel_compiler))]
use std::cell::Cell;
use std::mem;
use std::ptr;
use thin_vec::ThinVec;
@ -47,52 +49,15 @@ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
}
}
// Import the thread-local variable from Rayon, which is preserved for Rayon jobs.
#[cfg(parallel_compiler)]
mod tlv {
use rustc_rayon_core as rayon_core;
use std::ptr;
/// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
/// This is used to get the pointer to the current `ImplicitCtxt`.
#[inline]
pub(super) fn get_tlv() -> *const () {
ptr::from_exposed_addr(rayon_core::tlv::get())
}
/// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
/// to `value` during the call to `f`. It is restored to its previous value after.
/// This is used to set the pointer to the new `ImplicitCtxt`.
#[inline]
pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
rayon_core::tlv::with(value.expose_addr(), f)
}
}
use rayon_core::tlv::TLV;
// Otherwise define our own
#[cfg(not(parallel_compiler))]
mod tlv {
use std::cell::Cell;
use std::ptr;
thread_local! {
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
}
/// Gets the pointer to the current `ImplicitCtxt`.
#[inline]
pub(super) fn get_tlv() -> *const () {
TLV.with(|tlv| tlv.get())
}
/// Sets TLV to `value` during the call to `f`.
/// It is restored to its previous value after.
/// This is used to set the pointer to the new `ImplicitCtxt`.
#[inline]
pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
let old = TLV.replace(value);
let _reset = rustc_data_structures::OnDrop(move || TLV.set(old));
f()
}
thread_local! {
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
}
#[inline]
@ -111,7 +76,11 @@ pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) ->
where
F: FnOnce() -> R,
{
tlv::with_tlv(erase(context), f)
TLV.with(|tlv| {
let old = tlv.replace(erase(context));
let _reset = rustc_data_structures::OnDrop(move || tlv.set(old));
f()
})
}
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
@ -120,7 +89,7 @@ pub fn with_context_opt<F, R>(f: F) -> R
where
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
{
let context = tlv::get_tlv();
let context = TLV.get();
if context.is_null() {
f(None)
} else {

View File

@ -1327,27 +1327,40 @@ fn create_mono_items_for_default_impls<'tcx>(
return;
}
let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
return;
};
// Lifetimes never affect trait selection, so we are allowed to eagerly
// instantiate an instance of an impl method if the impl (and method,
// which we check below) is only parameterized over lifetime. In that case,
// we use the ReErased, which has no lifetime information associated with
// it, to validate whether or not the impl is legal to instantiate at all.
let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
unreachable!(
"`own_requires_monomorphization` check means that \
we should have no type/const params"
)
}
};
let impl_substs = InternalSubsts::for_item(tcx, item.owner_id.to_def_id(), only_region_params);
let trait_ref = trait_ref.subst(tcx, impl_substs);
// Unlike 'lazy' monomorphization that begins by collecting items transitively
// called by `main` or other global items, when eagerly monomorphizing impl
// items, we never actually check that the predicates of this impl are satisfied
// in a empty reveal-all param env (i.e. with no assumptions).
//
// Even though this impl has no substitutions, because we don't consider higher-
// ranked predicates such as `for<'a> &'a mut [u8]: Copy` to be trivially false,
// we must now check that the impl has no impossible-to-satisfy predicates.
if tcx.subst_and_check_impossible_predicates((
item.owner_id.to_def_id(),
&InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()),
)) {
// Even though this impl has no type or const substitutions, because we don't
// consider higher-ranked predicates such as `for<'a> &'a mut [u8]: Copy` to
// be trivially false. We must now check that the impl has no impossible-to-satisfy
// predicates.
if tcx.subst_and_check_impossible_predicates((item.owner_id.to_def_id(), impl_substs)) {
return;
}
let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
return;
};
let trait_ref = trait_ref.subst_identity();
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
@ -1360,12 +1373,9 @@ fn create_mono_items_for_default_impls<'tcx>(
continue;
}
let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
trait_ref.substs[param.index as usize]
}
});
// As mentioned above, the method is legal to eagerly instantiate if it
// only has lifetime substitutions. This is validated by
let substs = trait_ref.substs.extend_to(tcx, method.def_id, only_region_params);
let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, substs);
let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);

View File

@ -16,7 +16,7 @@ rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_query_system = { path = "../rustc_query_system" }
rustc-rayon-core = { version = "0.4.0", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }

View File

@ -15,7 +15,7 @@ rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc-rayon-core = { version = "0.4.0", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }

View File

@ -18,11 +18,11 @@ use std::num::NonZeroU64;
#[cfg(parallel_compiler)]
use {
parking_lot::{Condvar, Mutex},
rayon_core,
rustc_data_structures::fx::FxHashSet,
rustc_data_structures::sync::Lock,
rustc_data_structures::sync::Lrc,
rustc_data_structures::{jobserver, OnDrop},
rustc_rayon_core as rayon_core,
rustc_span::DUMMY_SP,
std::iter,
std::process,

View File

@ -4,7 +4,7 @@ version = "0.0.0"
edition = "2021"
[dependencies]
indexmap = "1.9.1"
indexmap = "1.9.3"
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"

View File

@ -18,4 +18,4 @@ tracing = "0.1"
sha1 = "0.10.0"
sha2 = "0.10.1"
md5 = { package = "md-5", version = "0.10.0" }
indexmap = { version = "1.9.1" }
indexmap = { version = "1.9.3" }

View File

@ -402,7 +402,6 @@ fn resolve_negative_obligation<'tcx>(
let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
Some(&infcx),
infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
);

View File

@ -111,7 +111,6 @@ pub fn type_allowed_to_implement_copy<'tcx>(
// Check regions assuming the self type of the impl is WF
let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
Some(&infcx),
infcx.implied_bounds_tys(
param_env,
parent_cause.body_id,

View File

@ -3,7 +3,8 @@ use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use crate::traits::query::NoSolution;
use crate::traits::{ObligationCause, ObligationCtxt};
use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::{self, ParamEnv, Ty};
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
use rustc_span::def_id::LocalDefId;
pub use rustc_middle::traits::query::OutlivesBound;
@ -52,6 +53,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
body_id: LocalDefId,
ty: Ty<'tcx>,
) -> Vec<OutlivesBound<'tcx>> {
let ty = self.resolve_vars_if_possible(ty);
let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
assert!(!ty.needs_infer());
let span = self.tcx.def_span(body_id);
let result = param_env
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
@ -106,10 +111,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
tys: FxIndexSet<Ty<'tcx>>,
) -> Bounds<'a, 'tcx> {
tys.into_iter()
.map(move |ty| {
let ty = self.resolve_vars_if_possible(ty);
self.implied_outlives_bounds(param_env, body_id, ty)
})
.map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
.flatten()
}
}

View File

@ -211,7 +211,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
freshener: infcx.freshener_keep_static(),
freshener: infcx.freshener(),
intercrate_ambiguity_causes: None,
query_mode: TraitQueryMode::Standard,
}
@ -770,14 +770,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => {
// A global type with no late-bound regions can only
// contain the "'static" lifetime (any other lifetime
// would either be late-bound or local), so it is guaranteed
// to outlive any other lifetime
if pred.0.is_global() && !pred.0.has_late_bound_vars() {
Ok(EvaluatedToOk)
} else {
// A global type with no free lifetimes or generic parameters
// outlives anything.
if pred.0.has_free_regions()
|| pred.0.has_late_bound_regions()
|| pred.0.has_non_region_infer()
|| pred.0.has_non_region_infer()
{
Ok(EvaluatedToOkModuloRegions)
} else {
Ok(EvaluatedToOk)
}
}
@ -1825,6 +1827,12 @@ enum DropVictim {
No,
}
impl DropVictim {
fn drop_if(should_drop: bool) -> DropVictim {
if should_drop { DropVictim::Yes } else { DropVictim::No }
}
}
/// ## Winnowing
///
/// Winnowing is the process of attempting to resolve ambiguity by
@ -1890,11 +1898,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// or the current one if tied (they should both evaluate to the same answer). This is
// probably best characterized as a "hack", since we might prefer to just do our
// best to *not* create essentially duplicate candidates in the first place.
if other.bound_vars().len() <= victim.bound_vars().len() {
DropVictim::Yes
} else {
DropVictim::No
}
DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len())
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
&& other.skip_binder().polarity == victim.skip_binder().polarity
@ -1924,17 +1928,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ObjectCandidate(_)
| ProjectionCandidate(..),
) => {
if is_global(other_cand) {
DropVictim::No
} else {
// We have a where clause so don't go around looking
// for impls. Arbitrarily give param candidates priority
// over projection and object candidates.
//
// Global bounds from the where clause should be ignored
// here (see issue #50825).
DropVictim::Yes
}
// We have a where clause so don't go around looking
// for impls. Arbitrarily give param candidates priority
// over projection and object candidates.
//
// Global bounds from the where clause should be ignored
// here (see issue #50825).
DropVictim::drop_if(!is_global(other_cand))
}
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
// Prefer these to a global where-clause bound
@ -1956,18 +1956,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
if is_global(victim_cand) && other.evaluation.must_apply_modulo_regions() {
DropVictim::Yes
} else {
DropVictim::No
}
DropVictim::drop_if(
is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
)
}
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
| (ObjectCandidate(i), ObjectCandidate(j)) => {
// Arbitrarily pick the lower numbered candidate for backwards
// compatibility reasons. Don't let this affect inference.
if i < j && !needs_infer { DropVictim::Yes } else { DropVictim::No }
DropVictim::drop_if(i < j && !needs_infer)
}
(ObjectCandidate(_), ProjectionCandidate(..))
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
@ -2018,55 +2016,65 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
}
if other.evaluation.must_apply_considering_regions() {
match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
// Subtle: If the predicate we are evaluating has inference
// variables, do *not* allow discarding candidates due to
// marker trait impls.
//
// Without this restriction, we could end up accidentally
// constraining inference variables based on an arbitrarily
// chosen trait impl.
//
// Imagine we have the following code:
//
// ```rust
// #[marker] trait MyTrait {}
// impl MyTrait for u8 {}
// impl MyTrait for bool {}
// ```
//
// And we are evaluating the predicate `<_#0t as MyTrait>`.
//
// During selection, we will end up with one candidate for each
// impl of `MyTrait`. If we were to discard one impl in favor
// of the other, we would be left with one candidate, causing
// us to "successfully" select the predicate, unifying
// _#0t with (for example) `u8`.
//
// However, we have no reason to believe that this unification
// is correct - we've essentially just picked an arbitrary
// *possibility* for _#0t, and required that this be the *only*
// possibility.
//
// Eventually, we will either:
// 1) Unify all inference variables in the predicate through
// some other means (e.g. type-checking of a function). We will
// then be in a position to drop marker trait candidates
// without constraining inference variables (since there are
// none left to constrain)
// 2) Be left with some unconstrained inference variables. We
// will then correctly report an inference error, since the
// existence of multiple marker trait impls tells us nothing
// about which one should actually apply.
if needs_infer { DropVictim::No } else { DropVictim::Yes }
}
Some(_) => DropVictim::Yes,
None => DropVictim::No,
match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
// For #33140 the impl headers must be exactly equal, the trait must not have
// any associated items and there are no where-clauses.
//
// We can just arbitrarily drop one of the impls.
Some(ty::ImplOverlapKind::Issue33140) => {
assert_eq!(other.evaluation, victim.evaluation);
DropVictim::Yes
}
} else {
DropVictim::No
// For candidates which already reference errors it doesn't really
// matter what we do 🤷
Some(ty::ImplOverlapKind::Permitted { marker: false }) => {
DropVictim::drop_if(other.evaluation.must_apply_considering_regions())
}
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
// Subtle: If the predicate we are evaluating has inference
// variables, do *not* allow discarding candidates due to
// marker trait impls.
//
// Without this restriction, we could end up accidentally
// constraining inference variables based on an arbitrarily
// chosen trait impl.
//
// Imagine we have the following code:
//
// ```rust
// #[marker] trait MyTrait {}
// impl MyTrait for u8 {}
// impl MyTrait for bool {}
// ```
//
// And we are evaluating the predicate `<_#0t as MyTrait>`.
//
// During selection, we will end up with one candidate for each
// impl of `MyTrait`. If we were to discard one impl in favor
// of the other, we would be left with one candidate, causing
// us to "successfully" select the predicate, unifying
// _#0t with (for example) `u8`.
//
// However, we have no reason to believe that this unification
// is correct - we've essentially just picked an arbitrary
// *possibility* for _#0t, and required that this be the *only*
// possibility.
//
// Eventually, we will either:
// 1) Unify all inference variables in the predicate through
// some other means (e.g. type-checking of a function). We will
// then be in a position to drop marker trait candidates
// without constraining inference variables (since there are
// none left to constrain)
// 2) Be left with some unconstrained inference variables. We
// will then correctly report an inference error, since the
// existence of multiple marker trait impls tells us nothing
// about which one should actually apply.
DropVictim::drop_if(
!needs_infer && other.evaluation.must_apply_considering_regions(),
)
}
None => DropVictim::No,
}
}

View File

@ -1,4 +1,5 @@
use core::iter::{FusedIterator, TrustedLen};
use core::num::NonZeroUsize;
use core::{array, fmt, mem::MaybeUninit, ops::Try, ptr};
use crate::alloc::{Allocator, Global};
@ -54,15 +55,16 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
if self.inner.len < n {
let len = self.inner.len;
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let len = self.inner.len;
let rem = if len < n {
self.inner.clear();
Err(len)
n - len
} else {
self.inner.drain(..n);
Ok(())
}
0
};
NonZeroUsize::new(rem).map_or(Ok(()), Err)
}
#[inline]
@ -182,15 +184,16 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let len = self.inner.len;
if len >= n {
self.inner.truncate(len - n);
Ok(())
} else {
let rem = if len < n {
self.inner.clear();
Err(len)
}
n - len
} else {
self.inner.truncate(len - n);
0
};
NonZeroUsize::new(rem).map_or(Ok(()), Err)
}
fn try_rfold<B, F, R>(&mut self, mut init: B, mut f: F) -> R

View File

@ -1,4 +1,5 @@
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
use core::num::NonZeroUsize;
use core::ops::Try;
use core::{fmt, mem, slice};
@ -55,13 +56,15 @@ impl<'a, T> Iterator for Iter<'a, T> {
}
}
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let m = match self.i1.advance_by(n) {
Ok(_) => return Ok(()),
Err(m) => m,
};
mem::swap(&mut self.i1, &mut self.i2);
self.i1.advance_by(n - m).map_err(|o| o + m)
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let remaining = self.i1.advance_by(n);
match remaining {
Ok(()) => return Ok(()),
Err(n) => {
mem::swap(&mut self.i1, &mut self.i2);
self.i1.advance_by(n.get())
}
}
}
#[inline]
@ -125,14 +128,14 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
}
}
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let m = match self.i2.advance_back_by(n) {
Ok(_) => return Ok(()),
Err(m) => m,
};
mem::swap(&mut self.i1, &mut self.i2);
self.i2.advance_back_by(n - m).map_err(|o| m + o)
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
match self.i2.advance_back_by(n) {
Ok(()) => return Ok(()),
Err(n) => {
mem::swap(&mut self.i1, &mut self.i2);
self.i2.advance_back_by(n.get())
}
}
}
fn rfold<Acc, F>(self, accum: Acc, mut f: F) -> Acc

View File

@ -1,4 +1,5 @@
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
use core::num::NonZeroUsize;
use core::ops::Try;
use core::{fmt, mem, slice};
@ -47,13 +48,14 @@ impl<'a, T> Iterator for IterMut<'a, T> {
}
}
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let m = match self.i1.advance_by(n) {
Ok(_) => return Ok(()),
Err(m) => m,
};
mem::swap(&mut self.i1, &mut self.i2);
self.i1.advance_by(n - m).map_err(|o| o + m)
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
match self.i1.advance_by(n) {
Ok(()) => return Ok(()),
Err(remaining) => {
mem::swap(&mut self.i1, &mut self.i2);
self.i1.advance_by(remaining.get())
}
}
}
#[inline]
@ -117,14 +119,14 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
}
}
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let m = match self.i2.advance_back_by(n) {
Ok(_) => return Ok(()),
Err(m) => m,
};
mem::swap(&mut self.i1, &mut self.i2);
self.i2.advance_back_by(n - m).map_err(|o| m + o)
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
match self.i2.advance_back_by(n) {
Ok(()) => return Ok(()),
Err(remaining) => {
mem::swap(&mut self.i1, &mut self.i2);
self.i2.advance_back_by(remaining.get())
}
}
}
fn rfold<Acc, F>(self, accum: Acc, mut f: F) -> Acc

View File

@ -11,6 +11,7 @@ use core::iter::{
};
use core::marker::PhantomData;
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
use core::num::NonZeroUsize;
#[cfg(not(no_global_oom_handling))]
use core::ops::Deref;
use core::ptr::{self, NonNull};
@ -213,7 +214,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let step_size = self.len().min(n);
let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size);
if T::IS_ZST {
@ -227,10 +228,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
unsafe {
ptr::drop_in_place(to_drop);
}
if step_size < n {
return Err(step_size);
}
Ok(())
NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
}
#[inline]
@ -313,7 +311,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let step_size = self.len().min(n);
if T::IS_ZST {
// SAFETY: same as for advance_by()
@ -327,10 +325,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
unsafe {
ptr::drop_in_place(to_drop);
}
if step_size < n {
return Err(step_size);
}
Ok(())
NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
}
}

View File

@ -1,5 +1,7 @@
use core::alloc::{Allocator, Layout};
use core::assert_eq;
use core::iter::IntoIterator;
use core::num::NonZeroUsize;
use core::ptr::NonNull;
use std::alloc::System;
use std::assert_matches::assert_matches;
@ -1062,21 +1064,21 @@ fn test_into_iter_leak() {
#[test]
fn test_into_iter_advance_by() {
let mut i = [1, 2, 3, 4, 5].into_iter();
i.advance_by(0).unwrap();
i.advance_back_by(0).unwrap();
let mut i = vec![1, 2, 3, 4, 5].into_iter();
assert_eq!(i.advance_by(0), Ok(()));
assert_eq!(i.advance_back_by(0), Ok(()));
assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]);
i.advance_by(1).unwrap();
i.advance_back_by(1).unwrap();
assert_eq!(i.advance_by(1), Ok(()));
assert_eq!(i.advance_back_by(1), Ok(()));
assert_eq!(i.as_slice(), [2, 3, 4]);
assert_eq!(i.advance_back_by(usize::MAX), Err(3));
assert_eq!(i.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 3).unwrap()));
assert_eq!(i.advance_by(usize::MAX), Err(0));
assert_eq!(i.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap()));
i.advance_by(0).unwrap();
i.advance_back_by(0).unwrap();
assert_eq!(i.advance_by(0), Ok(()));
assert_eq!(i.advance_back_by(0), Ok(()));
assert_eq!(i.len(), 0);
}
@ -1124,7 +1126,7 @@ fn test_into_iter_zst() {
for _ in vec![C; 5].into_iter().rev() {}
let mut it = vec![C, C].into_iter();
it.advance_by(1).unwrap();
assert_eq!(it.advance_by(1), Ok(()));
drop(it);
let mut it = vec![C, C].into_iter();

View File

@ -1,3 +1,4 @@
use core::num::NonZeroUsize;
use std::assert_matches::assert_matches;
use std::collections::TryReserveErrorKind::*;
use std::collections::{vec_deque::Drain, VecDeque};
@ -426,6 +427,28 @@ fn test_into_iter() {
assert_eq!(it.next(), Some(7));
assert_eq!(it.size_hint(), (5, Some(5)));
}
// advance_by
{
let mut d = VecDeque::new();
for i in 0..=4 {
d.push_back(i);
}
for i in 6..=8 {
d.push_front(i);
}
let mut it = d.into_iter();
assert_eq!(it.advance_by(1), Ok(()));
assert_eq!(it.next(), Some(7));
assert_eq!(it.advance_back_by(1), Ok(()));
assert_eq!(it.next_back(), Some(3));
let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
assert_eq!(it.advance_by(10), Err(NonZeroUsize::new(5).unwrap()));
let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
assert_eq!(it.advance_back_by(10), Err(NonZeroUsize::new(5).unwrap()));
}
}
#[test]

View File

@ -1,5 +1,6 @@
//! Defines the `IntoIter` owned iterator for arrays.
use crate::num::NonZeroUsize;
use crate::{
fmt,
iter::{self, ExactSizeIterator, FusedIterator, TrustedLen},
@ -284,12 +285,11 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
self.next_back()
}
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let original_len = self.len();
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
// This also moves the start, which marks them as conceptually "dropped",
// so if anything goes bad then our drop impl won't double-free them.
let range_to_drop = self.alive.take_prefix(n);
let remaining = n - range_to_drop.len();
// SAFETY: These elements are currently initialized, so it's fine to drop them.
unsafe {
@ -297,7 +297,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
}
if n > original_len { Err(original_len) } else { Ok(()) }
NonZeroUsize::new(remaining).map_or(Ok(()), Err)
}
}
@ -334,12 +334,11 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
})
}
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let original_len = self.len();
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
// This also moves the end, which marks them as conceptually "dropped",
// so if anything goes bad then our drop impl won't double-free them.
let range_to_drop = self.alive.take_suffix(n);
let remaining = n - range_to_drop.len();
// SAFETY: These elements are currently initialized, so it's fine to drop them.
unsafe {
@ -347,7 +346,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
}
if n > original_len { Err(original_len) } else { Ok(()) }
NonZeroUsize::new(remaining).map_or(Ok(()), Err)
}
}

View File

@ -1,3 +1,4 @@
use crate::num::NonZeroUsize;
use crate::ops::{NeverShortCircuit, Try};
/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
@ -26,7 +27,7 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
I::advance_by(self.0, n)
}
@ -62,7 +63,7 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
I::advance_back_by(self.0, n)
}

View File

@ -1,4 +1,5 @@
use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
use crate::num::NonZeroUsize;
use crate::ops::Try;
/// An iterator that links two iterators together, in a chain.
@ -95,38 +96,33 @@ where
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let mut rem = n;
fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
if let Some(ref mut a) = self.a {
match a.advance_by(rem) {
n = match a.advance_by(n) {
Ok(()) => return Ok(()),
Err(k) => rem -= k,
}
Err(k) => k.get(),
};
self.a = None;
}
if let Some(ref mut b) = self.b {
match b.advance_by(rem) {
Ok(()) => return Ok(()),
Err(k) => rem -= k,
}
return b.advance_by(n);
// we don't fuse the second iterator
}
if rem == 0 { Ok(()) } else { Err(n - rem) }
NonZeroUsize::new(n).map_or(Ok(()), Err)
}
#[inline]
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
if let Some(ref mut a) = self.a {
match a.advance_by(n) {
n = match a.advance_by(n) {
Ok(()) => match a.next() {
None => n = 0,
None => 0,
x => return x,
},
Err(k) => n -= k,
}
Err(k) => k.get(),
};
self.a = None;
}
@ -186,38 +182,33 @@ where
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let mut rem = n;
fn advance_back_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
if let Some(ref mut b) = self.b {
match b.advance_back_by(rem) {
n = match b.advance_back_by(n) {
Ok(()) => return Ok(()),
Err(k) => rem -= k,
}
Err(k) => k.get(),
};
self.b = None;
}
if let Some(ref mut a) = self.a {
match a.advance_back_by(rem) {
Ok(()) => return Ok(()),
Err(k) => rem -= k,
}
return a.advance_back_by(n);
// we don't fuse the second iterator
}
if rem == 0 { Ok(()) } else { Err(n - rem) }
NonZeroUsize::new(n).map_or(Ok(()), Err)
}
#[inline]
fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
if let Some(ref mut b) = self.b {
match b.advance_back_by(n) {
n = match b.advance_back_by(n) {
Ok(()) => match b.next_back() {
None => n = 0,
None => 0,
x => return x,
},
Err(k) => n -= k,
}
Err(k) => k.get(),
};
self.b = None;
}

View File

@ -4,6 +4,7 @@ use crate::iter::adapters::{
use crate::iter::{FusedIterator, TrustedLen};
use crate::mem::MaybeUninit;
use crate::mem::SizedTypeProperties;
use crate::num::NonZeroUsize;
use crate::ops::Try;
use crate::{array, ptr};
@ -89,7 +90,7 @@ where
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.it.advance_by(n)
}
@ -130,7 +131,7 @@ where
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.it.advance_back_by(n)
}
}

View File

@ -1,3 +1,4 @@
use crate::num::NonZeroUsize;
use crate::{iter::FusedIterator, ops::Try};
/// An iterator that repeats endlessly.
@ -81,23 +82,22 @@ where
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let mut rem = n;
match self.iter.advance_by(rem) {
ret @ Ok(_) => return ret,
Err(advanced) => rem -= advanced,
}
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let mut n = match self.iter.advance_by(n) {
Ok(()) => return Ok(()),
Err(rem) => rem.get(),
};
while rem > 0 {
while n > 0 {
self.iter = self.orig.clone();
match self.iter.advance_by(rem) {
ret @ Ok(_) => return ret,
Err(0) => return Err(n - rem),
Err(advanced) => rem -= advanced,
}
n = match self.iter.advance_by(n) {
Ok(()) => return Ok(()),
e @ Err(rem) if rem.get() == n => return e,
Err(rem) => rem.get(),
};
}
Ok(())
NonZeroUsize::new(n).map_or(Ok(()), Err)
}
// No `fold` override, because `fold` doesn't make much sense for `Cycle`,

View File

@ -2,6 +2,7 @@ use crate::iter::adapters::{
zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
use crate::num::NonZeroUsize;
use crate::ops::Try;
/// An iterator that yields the current count and the element during iteration.
@ -114,17 +115,14 @@ where
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
match self.iter.advance_by(n) {
ret @ Ok(_) => {
self.count += n;
ret
}
ret @ Err(advanced) => {
self.count += advanced;
ret
}
}
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let remaining = self.iter.advance_by(n);
let advanced = match remaining {
Ok(()) => n,
Err(rem) => n - rem.get(),
};
self.count += advanced;
remaining
}
#[rustc_inherit_overflow_checks]
@ -208,7 +206,7 @@ where
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
// we do not need to update the count since that only tallies the number of items
// consumed from the front. consuming items from the back can never reduce that.
self.iter.advance_back_by(n)

View File

@ -1,5 +1,6 @@
use crate::fmt;
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen};
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try};
/// An iterator that maps each element to an iterator, and yields the elements
@ -75,7 +76,7 @@ where
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.inner.advance_by(n)
}
@ -120,7 +121,7 @@ where
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.inner.advance_back_by(n)
}
}
@ -236,7 +237,7 @@ where
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.inner.advance_by(n)
}
@ -281,7 +282,7 @@ where
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.inner.advance_back_by(n)
}
}
@ -552,18 +553,18 @@ where
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
#[inline]
#[rustc_inherit_overflow_checks]
fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
match iter.advance_by(n) {
Ok(()) => ControlFlow::Break(()),
Err(advanced) => ControlFlow::Continue(n - advanced),
Err(remaining) => ControlFlow::Continue(remaining.get()),
}
}
match self.iter_try_fold(n, advance) {
ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
_ => Ok(()),
}
}
@ -642,18 +643,18 @@ where
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
#[inline]
#[rustc_inherit_overflow_checks]
fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
match iter.advance_back_by(n) {
Ok(()) => ControlFlow::Break(()),
Err(advanced) => ControlFlow::Continue(n - advanced),
Err(remaining) => ControlFlow::Continue(remaining.get()),
}
}
match self.iter_try_rfold(n, advance) {
ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
_ => Ok(()),
}
}

View File

@ -1,4 +1,5 @@
use crate::iter::{FusedIterator, TrustedLen};
use crate::num::NonZeroUsize;
use crate::ops::Try;
/// A double-ended iterator with the direction inverted.
@ -38,7 +39,7 @@ where
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.iter.advance_back_by(n)
}
@ -83,7 +84,7 @@ where
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.iter.advance_by(n)
}

View File

@ -1,5 +1,6 @@
use crate::intrinsics::unlikely;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try};
/// An iterator that skips over `n` elements of `iter`.
@ -128,34 +129,27 @@ where
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let mut rem = n;
let step_one = self.n.saturating_add(rem);
fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
let skip_inner = self.n;
let skip_and_advance = skip_inner.saturating_add(n);
match self.iter.advance_by(step_one) {
Ok(_) => {
rem -= step_one - self.n;
self.n = 0;
}
Err(advanced) => {
let advanced_without_skip = advanced.saturating_sub(self.n);
self.n = self.n.saturating_sub(advanced);
return if n == 0 { Ok(()) } else { Err(advanced_without_skip) };
let remainder = match self.iter.advance_by(skip_and_advance) {
Ok(()) => 0,
Err(n) => n.get(),
};
let advanced_inner = skip_and_advance - remainder;
n -= advanced_inner.saturating_sub(skip_inner);
self.n = self.n.saturating_sub(advanced_inner);
// skip_and_advance may have saturated
if unlikely(remainder == 0 && n > 0) {
n = match self.iter.advance_by(n) {
Ok(()) => 0,
Err(n) => n.get(),
}
}
// step_one calculation may have saturated
if unlikely(rem > 0) {
return match self.iter.advance_by(rem) {
ret @ Ok(_) => ret,
Err(advanced) => {
rem -= advanced;
Err(n - rem)
}
};
}
Ok(())
NonZeroUsize::new(n).map_or(Ok(()), Err)
}
}
@ -209,13 +203,11 @@ where
impl_fold_via_try_fold! { rfold -> try_rfold }
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let min = crate::cmp::min(self.len(), n);
return match self.iter.advance_back_by(min) {
ret @ Ok(_) if n <= min => ret,
Ok(_) => Err(min),
_ => panic!("ExactSizeIterator contract violation"),
};
let rem = self.iter.advance_back_by(min);
assert!(rem.is_ok(), "ExactSizeIterator contract violation");
NonZeroUsize::new(n - min).map_or(Ok(()), Err)
}
}

View File

@ -1,5 +1,6 @@
use crate::cmp;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try};
/// An iterator that only iterates over the first `n` iterations of `iter`.
@ -121,18 +122,15 @@ where
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let min = self.n.min(n);
match self.iter.advance_by(min) {
Ok(_) => {
self.n -= min;
if min < n { Err(min) } else { Ok(()) }
}
ret @ Err(advanced) => {
self.n -= advanced;
ret
}
}
let rem = match self.iter.advance_by(min) {
Ok(()) => 0,
Err(rem) => rem.get(),
};
let advanced = min - rem;
self.n -= advanced;
NonZeroUsize::new(n - advanced).map_or(Ok(()), Err)
}
}
@ -223,7 +221,7 @@ where
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
// The amount by which the inner iterator needs to be shortened for it to be
// at most as long as the take() amount.
let trim_inner = self.iter.len().saturating_sub(self.n);
@ -232,12 +230,14 @@ where
// about having to advance more than usize::MAX here.
let advance_by = trim_inner.saturating_add(n);
let advanced = match self.iter.advance_back_by(advance_by) {
Ok(_) => advance_by - trim_inner,
Err(advanced) => advanced - trim_inner,
let remainder = match self.iter.advance_back_by(advance_by) {
Ok(()) => 0,
Err(rem) => rem.get(),
};
self.n -= advanced;
return if advanced < n { Err(advanced) } else { Ok(()) };
let advanced_by_inner = advance_by - remainder;
let advanced_by = advanced_by_inner - trim_inner;
self.n -= advanced_by;
NonZeroUsize::new(n - advanced_by).map_or(Ok(()), Err)
}
}

View File

@ -1,6 +1,7 @@
use crate::convert::TryFrom;
use crate::marker::Destruct;
use crate::mem;
use crate::num::NonZeroUsize;
use crate::ops::{self, Try};
use super::{
@ -530,12 +531,12 @@ trait RangeIteratorImpl {
// Iterator
fn spec_next(&mut self) -> Option<Self::Item>;
fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
fn spec_advance_by(&mut self, n: usize) -> Result<(), usize>;
fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
// DoubleEndedIterator
fn spec_next_back(&mut self) -> Option<Self::Item>;
fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>;
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
}
impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A> {
@ -567,7 +568,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
}
#[inline]
default fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> {
default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let available = if self.start <= self.end {
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
} else {
@ -579,7 +580,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
self.start =
Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld");
if taken < n { Err(taken) } else { Ok(()) }
NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
}
#[inline]
@ -608,7 +609,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
}
#[inline]
default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> {
default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let available = if self.start <= self.end {
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
} else {
@ -620,7 +621,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
self.end =
Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld");
if taken < n { Err(taken) } else { Ok(()) }
NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
}
}
@ -651,7 +652,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
}
#[inline]
fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> {
fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let available = if self.start <= self.end {
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
} else {
@ -666,7 +667,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
// Otherwise 0 is returned which always safe to use.
self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) };
if taken < n { Err(taken) } else { Ok(()) }
NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
}
#[inline]
@ -695,7 +696,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
}
#[inline]
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let available = if self.start <= self.end {
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
} else {
@ -707,7 +708,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
// SAFETY: same as the spec_advance_by() implementation
self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) };
if taken < n { Err(taken) } else { Ok(()) }
NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
}
}
@ -757,7 +758,7 @@ impl<A: ~const Step + ~const Destruct> const Iterator for ops::Range<A> {
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.spec_advance_by(n)
}
@ -836,7 +837,7 @@ impl<A: ~const Step + ~const Destruct> const DoubleEndedIterator for ops::Range<
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.spec_advance_back_by(n)
}
}

View File

@ -1,4 +1,5 @@
use crate::iter::{FusedIterator, TrustedLen};
use crate::num::NonZeroUsize;
/// Creates a new iterator that endlessly repeats a single element.
///
@ -80,7 +81,7 @@ impl<A: Clone> Iterator for Repeat<A> {
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
// Advancing an infinite iterator of a single element is a no-op.
let _ = n;
Ok(())
@ -109,7 +110,7 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
// Advancing an infinite iterator of a single element is a no-op.
let _ = n;
Ok(())

View File

@ -1,5 +1,6 @@
use crate::iter::{FusedIterator, TrustedLen};
use crate::mem::ManuallyDrop;
use crate::num::NonZeroUsize;
/// Creates a new iterator that repeats a single element a given number of times.
///
@ -137,7 +138,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
}
#[inline]
fn advance_by(&mut self, skip: usize) -> Result<(), usize> {
fn advance_by(&mut self, skip: usize) -> Result<(), NonZeroUsize> {
let len = self.count;
if skip >= len {
@ -145,7 +146,8 @@ impl<A: Clone> Iterator for RepeatN<A> {
}
if skip > len {
Err(len)
// SAFETY: we just checked that the difference is positive
Err(unsafe { NonZeroUsize::new_unchecked(skip - len) })
} else {
self.count = len - skip;
Ok(())
@ -178,7 +180,7 @@ impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.advance_by(n)
}

View File

@ -1,4 +1,5 @@
use crate::marker::Destruct;
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try};
/// An iterator able to yield elements from both ends.
@ -100,10 +101,11 @@ pub trait DoubleEndedIterator: Iterator {
/// eagerly skip `n` elements starting from the back by calling [`next_back`] up
/// to `n` times until [`None`] is encountered.
///
/// `advance_back_by(n)` will return [`Ok(())`] if the iterator successfully advances by
/// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number of
/// elements the iterator is advanced by before running out of elements (i.e. the length
/// of the iterator). Note that `k` is always less than `n`.
/// `advance_back_by(n)` will return `Ok(())` if the iterator successfully advances by
/// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered, where `k`
/// is remaining number of steps that could not be advanced because the iterator ran out.
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
/// Otherwise, `k` is always less than `n`.
///
/// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its
/// outer iterator until it finds an inner iterator that is not empty, which then often
@ -120,25 +122,29 @@ pub trait DoubleEndedIterator: Iterator {
/// ```
/// #![feature(iter_advance_by)]
///
/// use std::num::NonZeroUsize;
/// let a = [3, 4, 5, 6];
/// let mut iter = a.iter();
///
/// assert_eq!(iter.advance_back_by(2), Ok(()));
/// assert_eq!(iter.next_back(), Some(&4));
/// assert_eq!(iter.advance_back_by(0), Ok(()));
/// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped
/// assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&3` was skipped
/// ```
///
/// [`Ok(())`]: Ok
/// [`Err(k)`]: Err
#[inline]
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize>
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>
where
Self::Item: ~const Destruct,
{
for i in 0..n {
self.next_back().ok_or(i)?;
if self.next_back().is_none() {
// SAFETY: `i` is always less than `n`.
return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
}
}
Ok(())
}
@ -188,7 +194,9 @@ pub trait DoubleEndedIterator: Iterator {
#[stable(feature = "iter_nth_back", since = "1.37.0")]
#[rustc_do_not_const_check]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.advance_back_by(n).ok()?;
if self.advance_back_by(n).is_err() {
return None;
}
self.next_back()
}
@ -374,7 +382,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
fn next_back(&mut self) -> Option<I::Item> {
(**self).next_back()
}
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
(**self).advance_back_by(n)
}
fn nth_back(&mut self, n: usize) -> Option<I::Item> {

View File

@ -1,6 +1,7 @@
use crate::array;
use crate::cmp::{self, Ordering};
use crate::marker::Destruct;
use crate::num::NonZeroUsize;
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
use super::super::try_process;
@ -308,10 +309,11 @@ pub trait Iterator {
/// This method will eagerly skip `n` elements by calling [`next`] up to `n`
/// times until [`None`] is encountered.
///
/// `advance_by(n)` will return [`Ok(())`][Ok] if the iterator successfully advances by
/// `n` elements, or [`Err(k)`][Err] if [`None`] is encountered, where `k` is the number
/// of elements the iterator is advanced by before running out of elements (i.e. the
/// length of the iterator). Note that `k` is always less than `n`.
/// `advance_by(n)` will return `Ok(())` if the iterator successfully advances by
/// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered,
/// where `k` is remaining number of steps that could not be advanced because the iterator ran out.
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
/// Otherwise, `k` is always less than `n`.
///
/// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`]
/// can advance its outer iterator until it finds an inner iterator that is not empty, which
@ -327,22 +329,26 @@ pub trait Iterator {
/// ```
/// #![feature(iter_advance_by)]
///
/// use std::num::NonZeroUsize;
/// let a = [1, 2, 3, 4];
/// let mut iter = a.iter();
///
/// assert_eq!(iter.advance_by(2), Ok(()));
/// assert_eq!(iter.next(), Some(&3));
/// assert_eq!(iter.advance_by(0), Ok(()));
/// assert_eq!(iter.advance_by(100), Err(1)); // only `&4` was skipped
/// assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&4` was skipped
/// ```
#[inline]
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
fn advance_by(&mut self, n: usize) -> Result<(), usize>
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>
where
Self::Item: ~const Destruct,
{
for i in 0..n {
self.next().ok_or(i)?;
if self.next().is_none() {
// SAFETY: `i` is always less than `n`.
return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
}
}
Ok(())
}
@ -4013,7 +4019,7 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
fn size_hint(&self) -> (usize, Option<usize>) {
(**self).size_hint()
}
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
(**self).advance_by(n)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {

View File

@ -1,5 +1,6 @@
use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub};
use crate::iter::{FusedIterator, TrustedLen};
use crate::num::NonZeroUsize;
/// Like a `Range<usize>`, but with a safety invariant that `start <= end`.
///
@ -132,10 +133,9 @@ impl Iterator for IndexRange {
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let original_len = self.len();
self.take_prefix(n);
if n > original_len { Err(original_len) } else { Ok(()) }
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let taken = self.take_prefix(n);
NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
}
}
@ -151,10 +151,9 @@ impl DoubleEndedIterator for IndexRange {
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let original_len = self.len();
self.take_suffix(n);
if n > original_len { Err(original_len) } else { Ok(()) }
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let taken = self.take_suffix(n);
NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
}
}

View File

@ -176,11 +176,11 @@ macro_rules! iterator {
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let advance = cmp::min(len!(self), n);
// SAFETY: By construction, `advance` does not exceed `self.len()`.
unsafe { self.post_inc_start(advance) };
if advance == n { Ok(()) } else { Err(advance) }
NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
}
#[inline]
@ -371,11 +371,11 @@ macro_rules! iterator {
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
let advance = cmp::min(len!(self), n);
// SAFETY: By construction, `advance` does not exceed `self.len()`.
unsafe { self.pre_dec_end(advance) };
if advance == n { Ok(()) } else { Err(advance) }
NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
}
}

View File

@ -1,5 +1,6 @@
use core::array;
use core::{array, assert_eq};
use core::convert::TryFrom;
use core::num::NonZeroUsize;
use core::sync::atomic::{AtomicUsize, Ordering};
#[test]
@ -557,7 +558,7 @@ fn array_intoiter_advance_by() {
assert_eq!(counter.get(), 13);
let r = it.advance_by(123456);
assert_eq!(r, Err(87));
assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap()));
assert_eq!(it.len(), 0);
assert_eq!(counter.get(), 100);
@ -567,7 +568,7 @@ fn array_intoiter_advance_by() {
assert_eq!(counter.get(), 100);
let r = it.advance_by(10);
assert_eq!(r, Err(0));
assert_eq!(r, Err(NonZeroUsize::new(10).unwrap()));
assert_eq!(it.len(), 0);
assert_eq!(counter.get(), 100);
}
@ -610,7 +611,7 @@ fn array_intoiter_advance_back_by() {
assert_eq!(counter.get(), 13);
let r = it.advance_back_by(123456);
assert_eq!(r, Err(87));
assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap()));
assert_eq!(it.len(), 0);
assert_eq!(counter.get(), 100);
@ -620,7 +621,7 @@ fn array_intoiter_advance_back_by() {
assert_eq!(counter.get(), 100);
let r = it.advance_back_by(10);
assert_eq!(r, Err(0));
assert_eq!(r, Err(NonZeroUsize::new(10).unwrap()));
assert_eq!(it.len(), 0);
assert_eq!(counter.get(), 100);
}
@ -679,8 +680,8 @@ fn array_into_iter_fold() {
let a = [1, 2, 3, 4, 5, 6];
let mut it = a.into_iter();
it.advance_by(1).unwrap();
it.advance_back_by(2).unwrap();
assert_eq!(it.advance_by(1), Ok(()));
assert_eq!(it.advance_back_by(2), Ok(()));
let s = it.fold(10, |a, b| 10 * a + b);
assert_eq!(s, 10234);
}
@ -695,8 +696,8 @@ fn array_into_iter_rfold() {
let a = [1, 2, 3, 4, 5, 6];
let mut it = a.into_iter();
it.advance_by(1).unwrap();
it.advance_back_by(2).unwrap();
assert_eq!(it.advance_by(1), Ok(()));
assert_eq!(it.advance_back_by(2), Ok(()));
let s = it.rfold(10, |a, b| 10 * a + b);
assert_eq!(s, 10432);
}

View File

@ -1,5 +1,6 @@
use super::*;
use core::iter::*;
use core::num::NonZeroUsize;
#[test]
fn test_iterator_chain() {
@ -31,28 +32,28 @@ fn test_iterator_chain_advance_by() {
for i in 0..xs.len() {
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
iter.advance_by(i).unwrap();
assert_eq!(iter.advance_by(i), Ok(()));
assert_eq!(iter.next(), Some(&xs[i]));
assert_eq!(iter.advance_by(100), Err(len - i - 1));
iter.advance_by(0).unwrap();
assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap()));
assert_eq!(iter.advance_by(0), Ok(()));
}
for i in 0..ys.len() {
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
iter.advance_by(xs.len() + i).unwrap();
assert_eq!(iter.advance_by(xs.len() + i), Ok(()));
assert_eq!(iter.next(), Some(&ys[i]));
assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
iter.advance_by(0).unwrap();
assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (ys.len() - i - 1)).unwrap()));
assert_eq!(iter.advance_by(0), Ok(()));
}
let mut iter = xs.iter().chain(ys);
iter.advance_by(len).unwrap();
assert_eq!(iter.advance_by(len), Ok(()));
assert_eq!(iter.next(), None);
iter.advance_by(0).unwrap();
assert_eq!(iter.advance_by(0), Ok(()));
let mut iter = xs.iter().chain(ys);
assert_eq!(iter.advance_by(len + 1), Err(len));
iter.advance_by(0).unwrap();
assert_eq!(iter.advance_by(len + 1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!(iter.advance_by(0), Ok(()));
}
test_chain(&[], &[]);
@ -68,28 +69,28 @@ fn test_iterator_chain_advance_back_by() {
for i in 0..ys.len() {
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
iter.advance_back_by(i).unwrap();
assert_eq!(iter.advance_back_by(i), Ok(()));
assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
iter.advance_back_by(0).unwrap();
assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap()));
assert_eq!(iter.advance_back_by(0), Ok(()));
}
for i in 0..xs.len() {
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
iter.advance_back_by(ys.len() + i).unwrap();
assert_eq!(iter.advance_back_by(ys.len() + i), Ok(()));
assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
iter.advance_back_by(0).unwrap();
assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (xs.len() - i - 1)).unwrap()));
assert_eq!(iter.advance_back_by(0), Ok(()));
}
let mut iter = xs.iter().chain(ys);
iter.advance_back_by(len).unwrap();
assert_eq!(iter.advance_back_by(len), Ok(()));
assert_eq!(iter.next_back(), None);
iter.advance_back_by(0).unwrap();
assert_eq!(iter.advance_back_by(0), Ok(()));
let mut iter = xs.iter().chain(ys);
assert_eq!(iter.advance_back_by(len + 1), Err(len));
iter.advance_back_by(0).unwrap();
assert_eq!(iter.advance_back_by(len + 1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!(iter.advance_back_by(0), Ok(()));
}
test_chain(&[], &[]);

View File

@ -1,4 +1,5 @@
use core::iter::*;
use core::num::NonZeroUsize;
#[test]
fn test_iterator_enumerate() {
@ -55,6 +56,20 @@ fn test_iterator_enumerate_count() {
assert_eq!(xs.iter().enumerate().count(), 6);
}
#[test]
fn test_iterator_enumerate_advance_by() {
let xs = [0, 1, 2, 3, 4, 5];
let mut it = xs.iter().enumerate();
assert_eq!(it.advance_by(0), Ok(()));
assert_eq!(it.next(), Some((0, &0)));
assert_eq!(it.advance_by(1), Ok(()));
assert_eq!(it.next(), Some((2, &2)));
assert_eq!(it.advance_by(2), Ok(()));
assert_eq!(it.next(), Some((5, &5)));
assert_eq!(it.advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!(it.next(), None);
}
#[test]
fn test_iterator_enumerate_fold() {
let xs = [0, 1, 2, 3, 4, 5];

View File

@ -1,5 +1,7 @@
use core::assert_eq;
use super::*;
use core::iter::*;
use core::num::NonZeroUsize;
#[test]
fn test_iterator_flatten() {
@ -61,19 +63,19 @@ fn test_flatten_try_folds() {
fn test_flatten_advance_by() {
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
it.advance_by(5).unwrap();
assert_eq!(it.advance_by(5), Ok(()));
assert_eq!(it.next(), Some(5));
it.advance_by(9).unwrap();
assert_eq!(it.advance_by(9), Ok(()));
assert_eq!(it.next(), Some(15));
it.advance_back_by(4).unwrap();
assert_eq!(it.advance_back_by(4), Ok(()));
assert_eq!(it.next_back(), Some(35));
it.advance_back_by(9).unwrap();
assert_eq!(it.advance_back_by(9), Ok(()));
assert_eq!(it.next_back(), Some(25));
assert_eq!(it.advance_by(usize::MAX), Err(9));
assert_eq!(it.advance_back_by(usize::MAX), Err(0));
it.advance_by(0).unwrap();
it.advance_back_by(0).unwrap();
assert_eq!(it.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 9).unwrap()));
assert_eq!(it.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap()));
assert_eq!(it.advance_by(0), Ok(()));
assert_eq!(it.advance_back_by(0), Ok(()));
assert_eq!(it.size_hint(), (0, Some(0)));
}
@ -174,19 +176,19 @@ fn test_flatten_count() {
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
assert_eq!(it.clone().count(), 40);
it.advance_by(5).unwrap();
assert_eq!(it.advance_by(5), Ok(()));
assert_eq!(it.clone().count(), 35);
it.advance_back_by(5).unwrap();
assert_eq!(it.advance_back_by(5), Ok(()));
assert_eq!(it.clone().count(), 30);
it.advance_by(10).unwrap();
assert_eq!(it.advance_by(10), Ok(()));
assert_eq!(it.clone().count(), 20);
it.advance_back_by(8).unwrap();
assert_eq!(it.advance_back_by(8), Ok(()));
assert_eq!(it.clone().count(), 12);
it.advance_by(4).unwrap();
assert_eq!(it.advance_by(4), Ok(()));
assert_eq!(it.clone().count(), 8);
it.advance_back_by(5).unwrap();
assert_eq!(it.advance_back_by(5), Ok(()));
assert_eq!(it.clone().count(), 3);
it.advance_by(3).unwrap();
assert_eq!(it.advance_by(3), Ok(()));
assert_eq!(it.clone().count(), 0);
}
@ -195,18 +197,18 @@ fn test_flatten_last() {
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
assert_eq!(it.clone().last(), Some(39));
it.advance_by(5).unwrap(); // 5..40
assert_eq!(it.advance_by(5), Ok(())); // 5..40
assert_eq!(it.clone().last(), Some(39));
it.advance_back_by(5).unwrap(); // 5..35
assert_eq!(it.advance_back_by(5), Ok(())); // 5..35
assert_eq!(it.clone().last(), Some(34));
it.advance_by(10).unwrap(); // 15..35
assert_eq!(it.advance_by(10), Ok(())); // 15..35
assert_eq!(it.clone().last(), Some(34));
it.advance_back_by(8).unwrap(); // 15..27
assert_eq!(it.advance_back_by(8), Ok(())); // 15..27
assert_eq!(it.clone().last(), Some(26));
it.advance_by(4).unwrap(); // 19..27
assert_eq!(it.advance_by(4), Ok(())); // 19..27
assert_eq!(it.clone().last(), Some(26));
it.advance_back_by(5).unwrap(); // 19..22
assert_eq!(it.advance_back_by(5), Ok(())); // 19..22
assert_eq!(it.clone().last(), Some(21));
it.advance_by(3).unwrap(); // 22..22
assert_eq!(it.advance_by(3), Ok(())); // 22..22
assert_eq!(it.clone().last(), None);
}

View File

@ -1,4 +1,5 @@
use core::iter::*;
use core::num::NonZeroUsize;
use super::Unfuse;
@ -74,11 +75,14 @@ fn test_iterator_skip_nth() {
#[test]
fn test_skip_advance_by() {
assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
assert_eq!((0..0).skip(10).advance_by(1), Err(0));
assert_eq!((0u128..(usize::MAX as u128) + 1).skip(usize::MAX).advance_by(usize::MAX), Err(1));
assert_eq!((0u128..u128::MAX).skip(usize::MAX).advance_by(1), Ok(()));
assert_eq!((0..0).skip(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!(
(0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5),
Err(NonZeroUsize::new(usize::MAX - 16).unwrap())
);
assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), Ok(()));
assert_eq!((0..2).skip(1).advance_back_by(10), Err(1));
assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap()));
assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
}

View File

@ -1,4 +1,5 @@
use core::iter::*;
use core::num::NonZeroUsize;
#[test]
fn test_iterator_take() {
@ -78,21 +79,21 @@ fn test_take_advance_by() {
let mut take = (0..10).take(3);
assert_eq!(take.advance_by(2), Ok(()));
assert_eq!(take.next(), Some(2));
assert_eq!(take.advance_by(1), Err(0));
assert_eq!(take.advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!((0..0).take(10).advance_by(0), Ok(()));
assert_eq!((0..0).take(10).advance_by(1), Err(0));
assert_eq!((0..10).take(4).advance_by(5), Err(4));
assert_eq!((0..0).take(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!((0..10).take(4).advance_by(5), Err(NonZeroUsize::new(1).unwrap()));
let mut take = (0..10).take(3);
assert_eq!(take.advance_back_by(2), Ok(()));
assert_eq!(take.next(), Some(0));
assert_eq!(take.advance_back_by(1), Err(0));
assert_eq!(take.advance_back_by(1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!((0..2).take(1).advance_back_by(10), Err(1));
assert_eq!((0..0).take(1).advance_back_by(1), Err(0));
assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap()));
assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(100));
assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 100).unwrap()));
}
#[test]

View File

@ -1,3 +1,4 @@
use core::num::NonZeroUsize;
use super::*;
#[test]
@ -287,25 +288,25 @@ fn test_range_step() {
#[test]
fn test_range_advance_by() {
let mut r = 0..usize::MAX;
r.advance_by(0).unwrap();
r.advance_back_by(0).unwrap();
assert_eq!(Ok(()), r.advance_by(0));
assert_eq!(Ok(()), r.advance_back_by(0));
assert_eq!(r.len(), usize::MAX);
r.advance_by(1).unwrap();
r.advance_back_by(1).unwrap();
assert_eq!(Ok(()), r.advance_by(1));
assert_eq!(Ok(()), r.advance_back_by(1));
assert_eq!((r.start, r.end), (1, usize::MAX - 1));
assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2));
assert_eq!(Err(NonZeroUsize::new(2).unwrap()), r.advance_by(usize::MAX));
r.advance_by(0).unwrap();
r.advance_back_by(0).unwrap();
assert_eq!(Ok(()), r.advance_by(0));
assert_eq!(Ok(()), r.advance_back_by(0));
let mut r = 0u128..u128::MAX;
r.advance_by(usize::MAX).unwrap();
r.advance_back_by(usize::MAX).unwrap();
assert_eq!(Ok(()), r.advance_by(usize::MAX));
assert_eq!(Ok(()), r.advance_back_by(usize::MAX));
assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128));
}

View File

@ -1,3 +1,5 @@
use core::num::NonZeroUsize;
/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped
/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min`
/// return the correct element if some of them are equal.
@ -150,11 +152,11 @@ fn test_iterator_advance_by() {
let mut iter = v.iter();
assert_eq!(iter.advance_by(i), Ok(()));
assert_eq!(iter.next().unwrap(), &v[i]);
assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
}
assert_eq!(v.iter().advance_by(v.len()), Ok(()));
assert_eq!(v.iter().advance_by(100), Err(v.len()));
assert_eq!(v.iter().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
}
#[test]
@ -165,11 +167,11 @@ fn test_iterator_advance_back_by() {
let mut iter = v.iter();
assert_eq!(iter.advance_back_by(i), Ok(()));
assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
}
assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
assert_eq!(v.iter().advance_back_by(100), Err(v.len()));
assert_eq!(v.iter().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
}
#[test]
@ -180,11 +182,11 @@ fn test_iterator_rev_advance_back_by() {
let mut iter = v.iter().rev();
assert_eq!(iter.advance_back_by(i), Ok(()));
assert_eq!(iter.next_back().unwrap(), &v[i]);
assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
}
assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len()));
assert_eq!(v.iter().rev().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
}
#[test]
@ -424,11 +426,11 @@ fn test_iterator_rev_advance_by() {
let mut iter = v.iter().rev();
assert_eq!(iter.advance_by(i), Ok(()));
assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
}
assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
assert_eq!(v.iter().rev().advance_by(100), Err(v.len()));
assert_eq!(v.iter().rev().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
}
#[test]

View File

@ -1,6 +1,7 @@
use core::cell::Cell;
use core::cmp::Ordering;
use core::mem::MaybeUninit;
use core::num::NonZeroUsize;
use core::result::Result::{Err, Ok};
use core::slice;
@ -142,20 +143,20 @@ fn test_iterator_advance_by() {
for i in 0..=v.len() {
let mut iter = v.iter();
iter.advance_by(i).unwrap();
assert_eq!(iter.advance_by(i), Ok(()));
assert_eq!(iter.as_slice(), &v[i..]);
}
let mut iter = v.iter();
assert_eq!(iter.advance_by(v.len() + 1), Err(v.len()));
assert_eq!(iter.advance_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!(iter.as_slice(), &[]);
let mut iter = v.iter();
iter.advance_by(3).unwrap();
assert_eq!(iter.advance_by(3), Ok(()));
assert_eq!(iter.as_slice(), &v[3..]);
iter.advance_by(2).unwrap();
assert_eq!(iter.advance_by(2), Ok(()));
assert_eq!(iter.as_slice(), &[]);
iter.advance_by(0).unwrap();
assert_eq!(iter.advance_by(0), Ok(()));
}
#[test]
@ -164,20 +165,20 @@ fn test_iterator_advance_back_by() {
for i in 0..=v.len() {
let mut iter = v.iter();
iter.advance_back_by(i).unwrap();
assert_eq!(iter.advance_back_by(i), Ok(()));
assert_eq!(iter.as_slice(), &v[..v.len() - i]);
}
let mut iter = v.iter();
assert_eq!(iter.advance_back_by(v.len() + 1), Err(v.len()));
assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap()));
assert_eq!(iter.as_slice(), &[]);
let mut iter = v.iter();
iter.advance_back_by(3).unwrap();
assert_eq!(iter.advance_back_by(3), Ok(()));
assert_eq!(iter.as_slice(), &v[..v.len() - 3]);
iter.advance_back_by(2).unwrap();
assert_eq!(iter.advance_back_by(2), Ok(()));
assert_eq!(iter.as_slice(), &[]);
iter.advance_back_by(0).unwrap();
assert_eq!(iter.advance_back_by(0), Ok(()));
}
#[test]

View File

@ -6,6 +6,9 @@ fn main() {
if target.contains("freebsd") {
if env::var("RUST_STD_FREEBSD_12_ABI").is_ok() {
println!("cargo:rustc-cfg=freebsd12");
} else if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() {
println!("cargo:rustc-cfg=freebsd12");
println!("cargo:rustc-cfg=freebsd13");
}
} else if target.contains("linux")
|| target.contains("netbsd")

View File

@ -86,7 +86,12 @@ fn add_to_ancillary_data<T>(
cmsg_level: libc::c_int,
cmsg_type: libc::c_int,
) -> bool {
let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
#[cfg(not(target_os = "freebsd"))]
let cmsg_size = source.len().checked_mul(size_of::<T>());
#[cfg(target_os = "freebsd")]
let cmsg_size = Some(unsafe { libc::SOCKCRED2SIZE(1) });
let source_len = if let Some(source_len) = cmsg_size {
if let Ok(source_len) = u32::try_from(source_len) {
source_len
} else {
@ -178,7 +183,13 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
}
}
#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
#[cfg(all(
doc,
not(target_os = "android"),
not(target_os = "linux"),
not(target_os = "netbsd"),
not(target_os = "freebsd")
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
#[derive(Clone)]
pub struct SocketCred(());
@ -194,6 +205,11 @@ pub struct SocketCred(libc::ucred);
#[derive(Clone)]
pub struct SocketCred(libc::sockcred);
#[cfg(target_os = "freebsd")]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
#[derive(Clone)]
pub struct SocketCred(libc::sockcred2);
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
#[cfg(any(target_os = "android", target_os = "linux"))]
impl SocketCred {
@ -246,6 +262,66 @@ impl SocketCred {
}
}
#[cfg(target_os = "freebsd")]
impl SocketCred {
/// Create a Unix credential struct.
///
/// PID, UID and GID is set to 0.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
#[must_use]
pub fn new() -> SocketCred {
SocketCred(libc::sockcred2 {
sc_version: 0,
sc_pid: 0,
sc_uid: 0,
sc_euid: 0,
sc_gid: 0,
sc_egid: 0,
sc_ngroups: 0,
sc_groups: [0; 1],
})
}
/// Set the PID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_pid(&mut self, pid: libc::pid_t) {
self.0.sc_pid = pid;
}
/// Get the current PID.
#[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_pid(&self) -> libc::pid_t {
self.0.sc_pid
}
/// Set the UID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_uid(&mut self, uid: libc::uid_t) {
self.0.sc_euid = uid;
}
/// Get the current UID.
#[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_uid(&self) -> libc::uid_t {
self.0.sc_euid
}
/// Set the GID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_gid(&mut self, gid: libc::gid_t) {
self.0.sc_egid = gid;
}
/// Get the current GID.
#[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_gid(&self) -> libc::gid_t {
self.0.sc_egid
}
}
#[cfg(target_os = "netbsd")]
impl SocketCred {
/// Create a Unix credential struct.
@ -271,6 +347,7 @@ impl SocketCred {
}
/// Get the current PID.
#[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_pid(&self) -> libc::pid_t {
self.0.sc_pid
@ -283,6 +360,7 @@ impl SocketCred {
}
/// Get the current UID.
#[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_uid(&self) -> libc::uid_t {
self.0.sc_uid
@ -295,6 +373,7 @@ impl SocketCred {
}
/// Get the current GID.
#[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_gid(&self) -> libc::gid_t {
self.0.sc_gid
@ -316,7 +395,13 @@ impl<'a> Iterator for ScmRights<'a> {
}
}
#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
#[cfg(all(
doc,
not(target_os = "android"),
not(target_os = "linux"),
not(target_os = "netbsd"),
not(target_os = "freebsd")
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
@ -327,11 +412,21 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
#[cfg(target_os = "freebsd")]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred2>);
#[cfg(target_os = "netbsd")]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
impl<'a> Iterator for ScmCredentials<'a> {
type Item = SocketCred;
@ -353,7 +448,13 @@ pub enum AncillaryError {
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub enum AncillaryData<'a> {
ScmRights(ScmRights<'a>),
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
ScmCredentials(ScmCredentials<'a>),
}
@ -376,7 +477,13 @@ impl<'a> AncillaryData<'a> {
///
/// `data` must contain a valid control message and the control message must be type of
/// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
unsafe fn as_credentials(data: &'a [u8]) -> Self {
let ancillary_data_iter = AncillaryDataIter::new(data);
let scm_credentials = ScmCredentials(ancillary_data_iter);
@ -395,6 +502,8 @@ impl<'a> AncillaryData<'a> {
libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
#[cfg(any(target_os = "android", target_os = "linux",))]
libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
#[cfg(target_os = "freebsd")]
libc::SCM_CREDS2 => Ok(AncillaryData::as_credentials(data)),
#[cfg(target_os = "netbsd")]
libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
cmsg_type => {
@ -603,12 +712,18 @@ impl<'a> SocketAncillary<'a> {
/// Add credentials to the ancillary data.
///
/// The function returns `true` if there was enough space in the buffer.
/// If there was not enough space then no credentials was appended.
/// The function returns `true` if there is enough space in the buffer.
/// If there is not enough space then no credentials will be appended.
/// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
/// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
/// and type `SCM_CREDENTIALS`, `SCM_CREDS`, or `SCM_CREDS2`.
///
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
self.truncated = false;
@ -617,8 +732,10 @@ impl<'a> SocketAncillary<'a> {
&mut self.length,
creds,
libc::SOL_SOCKET,
#[cfg(not(target_os = "netbsd"))]
#[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))]
libc::SCM_CREDENTIALS,
#[cfg(target_os = "freebsd")]
libc::SCM_CREDS2,
#[cfg(target_os = "netbsd")]
libc::SCM_CREDS,
)

View File

@ -808,8 +808,24 @@ impl UnixDatagram {
///
/// # Examples
///
#[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
#[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
#[cfg_attr(
any(
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
),
doc = "```no_run"
)]
#[cfg_attr(
not(any(
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
)),
doc = "```ignore"
)]
/// #![feature(unix_socket_ancillary_data)]
/// use std::os::unix::net::UnixDatagram;
///
@ -819,7 +835,13 @@ impl UnixDatagram {
/// Ok(())
/// }
/// ```
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
self.0.set_passcred(passcred)
@ -831,7 +853,13 @@ impl UnixDatagram {
/// Get the socket option `SO_PASSCRED`.
///
/// [`set_passcred`]: UnixDatagram::set_passcred
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn passcred(&self) -> io::Result<bool> {
self.0.passcred()

View File

@ -397,8 +397,24 @@ impl UnixStream {
///
/// # Examples
///
#[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
#[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
#[cfg_attr(
any(
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
),
doc = "```no_run"
)]
#[cfg_attr(
not(any(
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
)),
doc = "```ignore"
)]
/// #![feature(unix_socket_ancillary_data)]
/// use std::os::unix::net::UnixStream;
///
@ -408,7 +424,13 @@ impl UnixStream {
/// Ok(())
/// }
/// ```
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
self.0.set_passcred(passcred)
@ -420,7 +442,13 @@ impl UnixStream {
/// Get the socket option `SO_PASSCRED`.
///
/// [`set_passcred`]: UnixStream::set_passcred
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn passcred(&self) -> io::Result<bool> {
self.0.passcred()

View File

@ -646,7 +646,7 @@ fn test_send_vectored_fds_unix_stream() {
}
}
#[cfg(any(target_os = "android", target_os = "linux",))]
#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
#[test]
fn test_send_vectored_with_ancillary_to_unix_datagram() {
fn getpid() -> libc::pid_t {

View File

@ -443,6 +443,17 @@ impl Socket {
Ok(passcred != 0)
}
#[cfg(target_os = "freebsd")]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
setsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT, passcred as libc::c_int)
}
#[cfg(target_os = "freebsd")]
pub fn passcred(&self) -> io::Result<bool> {
let passcred: libc::c_int = getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)?;
Ok(passcred != 0)
}
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking = nonblocking as libc::c_int;

View File

@ -125,6 +125,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
(Some(Mode::Std), "no_rc", None),
(Some(Mode::Std), "no_sync", None),
(Some(Mode::Std), "freebsd12", None),
(Some(Mode::Std), "freebsd13", None),
(Some(Mode::Std), "backtrace_in_libstd", None),
/* Extra values not defined in the built-in targets yet, but used in std */
(Some(Mode::Std), "target_env", Some(&["libnx"])),

View File

@ -0,0 +1,19 @@
//compile-flags: --crate-type=lib -Clink-dead-code=on
// build-pass
// Make sure that we don't monomorphize the impossible method `<() as Visit>::visit`,
// which does not hold under a reveal-all param env.
pub trait Visit {
fn visit() {}
}
pub trait Array {
type Element;
}
impl<'a> Visit for () where (): Array<Element = &'a ()> {}
impl Array for () {
type Element = ();
}

View File

@ -0,0 +1,17 @@
// check-pass
trait Foo {
type Assoc<T>: PartialEq<Self::Assoc<i32>>;
}
impl Foo for () {
type Assoc<T> = Wrapper<T>;
}
struct Wrapper<T>(T);
impl<T> PartialEq<Wrapper<i32>> for Wrapper<T> {
fn eq(&self, _other: &Wrapper<i32>) -> bool { true }
}
fn main() {}

View File

@ -0,0 +1,24 @@
// Because of #109628, we can have unbounded region vars in implied bounds.
// Make sure we don't ICE in this case!
//
// check-pass
pub trait MapAccess {
type Error;
fn next_key_seed(&mut self) -> Option<Self::Error>;
}
struct Access<'a> {
_marker: std::marker::PhantomData<&'a ()>,
}
// implied_bounds(Option<Self::Error>) = ['?1: 'a, ]
// where '?1 is a fresh region var.
impl<'a, 'b: 'a> MapAccess for Access<'a> {
type Error = ();
fn next_key_seed(&mut self) -> Option<Self::Error> {
unimplemented!()
}
}
fn main() {}

View File

@ -0,0 +1,58 @@
// Test that we get implied bounds from complex projections after normalization.
// check-pass
// implementations wil ensure that
// WF(<T as Combine<'a>>::Ty) implies T: 'a
trait Combine<'a> {
type Ty;
}
impl<'a, T: 'a> Combine<'a> for Box<T> {
type Ty = &'a T;
}
// ======= Wrappers ======
// normalizes to a projection
struct WrapA<T>(T);
impl<'a, T> Combine<'a> for WrapA<T>
where
T: Combine<'a>,
{
type Ty = T::Ty;
}
// <WrapB<T> as Combine<'a>>::Ty normalizes to a type variable ?X
// with constraint `<T as Combine<'a>>::Ty == ?X`
struct WrapB<T>(T);
impl<'a, X, T> Combine<'a> for WrapB<T>
where
T: Combine<'a, Ty = X>,
{
type Ty = X;
}
// <WrapC<T> as Combine<'a>>::Ty normalizes to `&'a &'?x ()`
// with constraint `<T as Combine<'a>>::Ty == &'a &'?x ()`
struct WrapC<T>(T);
impl<'a, 'x: 'a, T> Combine<'a> for WrapC<T>
where
T: Combine<'a, Ty = &'a &'x ()>,
{
type Ty = &'a &'x ();
}
//==== Test implied bounds ======
fn test_wrap<'a, 'b, 'c1, 'c2, A, B>(
_: <WrapA<Box<A>> as Combine<'a>>::Ty, // normalized: &'a A
_: <WrapB<Box<B>> as Combine<'b>>::Ty, // normalized: &'b B
_: <WrapC<Box<&'c1 ()>> as Combine<'c2>>::Ty, // normalized: &'c2 &'c1 ()
) {
None::<&'a A>;
None::<&'b B>;
None::<&'c2 &'c1 ()>;
}
fn main() {}

View File

@ -1,4 +1,8 @@
// check-pass
// known-bug: #89515
//
// The trait solver cannot deal with ambiguous marker trait impls
// if there are lifetimes involved. As we must not special-case any
// regions this does not work, even with 'static
#![feature(marker_trait_attr)]
#[marker]

View File

@ -0,0 +1,31 @@
error[E0283]: type annotations needed: cannot satisfy `&'static (): Marker`
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:17
|
LL | impl Marker for &'static () {}
| ^^^^^^^^^^^
|
note: multiple `impl`s satisfying `&'static (): Marker` found
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:1
|
LL | impl Marker for &'static () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl Marker for &'static () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed: cannot satisfy `&'static (): Marker`
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:12:17
|
LL | impl Marker for &'static () {}
| ^^^^^^^^^^^
|
note: multiple `impl`s satisfying `&'static (): Marker` found
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:1
|
LL | impl Marker for &'static () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl Marker for &'static () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0283`.

View File

@ -1,9 +1,17 @@
// check-pass
// known-bug: #109481
//
// While the `T: Copy` is always applicable when checking
// that the impl `impl<T: Copy> F for T {}` is well formed,
// the old trait solver can only approximate this by checking
// that there are no inference variables in the obligation and
// no region constraints in the evaluation result.
//
// Because of this we end up with ambiguity here.
#![feature(marker_trait_attr)]
#[marker]
pub trait F {}
impl<T> F for T where T: Copy {}
impl<T> F for T where T: 'static {}
impl<T: Copy> F for T {}
impl<T: 'static> F for T {}
fn main() {}

View File

@ -0,0 +1,14 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/overlapping-impl-1-modulo-regions.rs:14:21
|
LL | impl<T: Copy> F for T {}
| ^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
LL | impl<T: Copy + 'static> F for T {}
| +++++++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0310`.