Merge from rustc
This commit is contained in:
commit
667da1e3bd
508 changed files with 8982 additions and 3424 deletions
|
|
@ -1859,7 +1859,6 @@ checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
|||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
"rustc-rayon",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
@ -3240,11 +3239,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-rayon"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710"
|
||||
checksum = "2cd9fb077db982d7ceb42a90471e5a69a990b58f71e06f0d8340bb2cf35eb751"
|
||||
dependencies = [
|
||||
"either",
|
||||
"indexmap",
|
||||
"rustc-rayon-core",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
|||
let (infcx, key, _) =
|
||||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
|
||||
type_op_ascribe_user_type_with_span(&ocx, key, cause.span).ok()?;
|
||||
let diag = try_extract_error_from_fulfill_cx(
|
||||
&ocx,
|
||||
mbcx.mir_def_id(),
|
||||
|
|
|
|||
|
|
@ -1284,15 +1284,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
&Rvalue::RawPtr(mutability, place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (
|
||||
&Rvalue::RawPtr(kind, place) => {
|
||||
let access_kind = match kind {
|
||||
RawPtrKind::Mut => (
|
||||
Deep,
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
kind: MutBorrowKind::Default,
|
||||
})),
|
||||
),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
RawPtrKind::FakeForPtrMetadata => {
|
||||
(Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
|
||||
}
|
||||
};
|
||||
|
||||
self.access_place(
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@ use std::ops::ControlFlow;
|
|||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{
|
||||
self, BasicBlock, Body, BorrowKind, FakeBorrowKind, InlineAsmOperand, Location, Mutability,
|
||||
NonDivergingIntrinsic, Operand, Place, Rvalue, Statement, StatementKind, Terminator,
|
||||
TerminatorKind,
|
||||
};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -60,7 +56,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
|
||||
self.consume_operand(location, op);
|
||||
}
|
||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
|
||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
|
||||
src,
|
||||
dst,
|
||||
count,
|
||||
|
|
@ -273,15 +269,18 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
self.access_place(location, place, access_kind, LocalMutationIsAllowed::No);
|
||||
}
|
||||
|
||||
&Rvalue::RawPtr(mutability, place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (
|
||||
&Rvalue::RawPtr(kind, place) => {
|
||||
let access_kind = match kind {
|
||||
RawPtrKind::Mut => (
|
||||
Deep,
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
kind: mir::MutBorrowKind::Default,
|
||||
kind: MutBorrowKind::Default,
|
||||
})),
|
||||
),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
RawPtrKind::FakeForPtrMetadata => {
|
||||
(Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
|
||||
}
|
||||
};
|
||||
|
||||
self.access_place(location, place, access_kind, LocalMutationIsAllowed::No);
|
||||
|
|
|
|||
|
|
@ -349,8 +349,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
let tcx = self.tcx();
|
||||
let maybe_uneval = match constant.const_ {
|
||||
Const::Ty(_, ct) => match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(_) => {
|
||||
bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct)
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
Some(UnevaluatedConst { def: uv.def, args: uv.args, promoted: None })
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
&mut self,
|
||||
name: &str,
|
||||
params: Vec<AbiParam>,
|
||||
returns: Vec<AbiParam>,
|
||||
mut returns: Vec<AbiParam>,
|
||||
args: &[Value],
|
||||
) -> Cow<'_, [Value]> {
|
||||
// Pass i128 arguments by-ref on Windows.
|
||||
|
|
@ -150,15 +150,19 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
(params, args.into())
|
||||
};
|
||||
|
||||
// Return i128 using a return area pointer on Windows and s390x.
|
||||
let adjust_ret_param =
|
||||
if self.tcx.sess.target.is_like_windows || self.tcx.sess.target.arch == "s390x" {
|
||||
returns.len() == 1 && returns[0].value_type == types::I128
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let ret_single_i128 = returns.len() == 1 && returns[0].value_type == types::I128;
|
||||
if ret_single_i128 && self.tcx.sess.target.is_like_windows {
|
||||
// Return i128 using the vector ABI on Windows
|
||||
returns[0].value_type = types::I64X2;
|
||||
|
||||
if adjust_ret_param {
|
||||
let ret = self.lib_call_unadjusted(name, params, returns, &args)[0];
|
||||
|
||||
// FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
|
||||
let ret_ptr = self.create_stack_slot(16, 16);
|
||||
ret_ptr.store(self, ret, MemFlags::trusted());
|
||||
Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())])
|
||||
} else if ret_single_i128 && self.tcx.sess.target.arch == "s390x" {
|
||||
// Return i128 using a return area pointer on s390x.
|
||||
let mut params = params;
|
||||
let mut args = args.to_vec();
|
||||
|
||||
|
|
|
|||
|
|
@ -96,25 +96,9 @@ pub(crate) fn clif_int_or_float_cast(
|
|||
},
|
||||
);
|
||||
|
||||
if fx.tcx.sess.target.is_like_windows {
|
||||
let ret = fx.lib_call(
|
||||
&name,
|
||||
vec![AbiParam::new(from_ty)],
|
||||
vec![AbiParam::new(types::I64X2)],
|
||||
&[from],
|
||||
)[0];
|
||||
// FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
|
||||
let ret_ptr = fx.create_stack_slot(16, 16);
|
||||
ret_ptr.store(fx, ret, MemFlags::trusted());
|
||||
ret_ptr.load(fx, types::I128, MemFlags::trusted())
|
||||
} else {
|
||||
fx.lib_call(
|
||||
&name,
|
||||
vec![AbiParam::new(from_ty)],
|
||||
vec![AbiParam::new(types::I128)],
|
||||
&[from],
|
||||
)[0]
|
||||
}
|
||||
fx.lib_call(&name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(types::I128)], &[
|
||||
from,
|
||||
])[0]
|
||||
} else if to_ty == types::I8 || to_ty == types::I16 {
|
||||
// FIXME implement fcvt_to_*int_sat.i8/i16
|
||||
let val = if to_signed {
|
||||
|
|
|
|||
|
|
@ -33,28 +33,14 @@ pub(crate) fn maybe_codegen<'tcx>(
|
|||
(BinOp::Rem, true) => "__modti3",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if fx.tcx.sess.target.is_like_windows {
|
||||
let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
|
||||
let ret = fx.lib_call(
|
||||
name,
|
||||
vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
|
||||
vec![AbiParam::new(types::I64X2)],
|
||||
&args,
|
||||
)[0];
|
||||
// FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
|
||||
let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
|
||||
ret_place.to_ptr().store(fx, ret, MemFlags::trusted());
|
||||
Some(ret_place.to_cvalue(fx))
|
||||
} else {
|
||||
let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
|
||||
let ret_val = fx.lib_call(
|
||||
name,
|
||||
vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
|
||||
vec![AbiParam::new(types::I128)],
|
||||
&args,
|
||||
)[0];
|
||||
Some(CValue::by_val(ret_val, lhs.layout()))
|
||||
}
|
||||
let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
|
||||
let ret_val = fx.lib_call(
|
||||
name,
|
||||
vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
|
||||
vec![AbiParam::new(types::I128)],
|
||||
&args,
|
||||
)[0];
|
||||
Some(CValue::by_val(ret_val, lhs.layout()))
|
||||
}
|
||||
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
|
||||
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
|
||||
|
|
|
|||
|
|
@ -612,9 +612,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mir::Rvalue::CopyForDeref(place) => {
|
||||
self.codegen_operand(bx, &mir::Operand::Copy(place))
|
||||
}
|
||||
mir::Rvalue::RawPtr(mutability, place) => {
|
||||
let mk_ptr =
|
||||
move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability);
|
||||
mir::Rvalue::RawPtr(kind, place) => {
|
||||
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
|
||||
Ty::new_ptr(tcx, ty, kind.to_mutbl_lossy())
|
||||
};
|
||||
self.codegen_place_to_pointer(bx, place, mk_ptr)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ const_eval_uninhabited_enum_variant_read =
|
|||
const_eval_uninhabited_enum_variant_written =
|
||||
writing discriminant of an uninhabited enum variant
|
||||
|
||||
const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
|
||||
const_eval_unmarked_const_item_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
|
||||
.help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
|
||||
const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable
|
||||
.help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)
|
||||
|
|
@ -414,6 +414,7 @@ const_eval_unreachable_unwind =
|
|||
|
||||
const_eval_unsized_local = unsized locals are not supported
|
||||
const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
|
||||
const_eval_unstable_const_trait = `{$def_path}` is not yet stable as a const trait
|
||||
const_eval_unstable_in_stable_exposed =
|
||||
const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
|
||||
.is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use std::ops::Deref;
|
|||
|
||||
use rustc_attr_parsing::{ConstStability, StabilityLevel};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
|
|
@ -29,7 +30,7 @@ use super::ops::{self, NonConstOp, Status};
|
|||
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
||||
use super::resolver::FlowSensitiveAnalysis;
|
||||
use super::{ConstCx, Qualif};
|
||||
use crate::check_consts::is_safe_to_expose_on_stable_const_fn;
|
||||
use crate::check_consts::is_fn_or_trait_safe_to_expose_on_stable;
|
||||
use crate::errors;
|
||||
|
||||
type QualifResults<'mir, 'tcx, Q> =
|
||||
|
|
@ -470,6 +471,88 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
self.tcx.crate_level_attribute_injection_span(self.tcx.local_def_id_to_hir_id(id))
|
||||
})
|
||||
}
|
||||
|
||||
/// Check the const stability of the given item (fn or trait).
|
||||
fn check_callee_stability(&mut self, def_id: DefId) {
|
||||
match self.tcx.lookup_const_stability(def_id) {
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
|
||||
// All good.
|
||||
}
|
||||
None => {
|
||||
// This doesn't need a separate const-stability check -- const-stability equals
|
||||
// regular stability, and regular stability is checked separately.
|
||||
// However, we *do* have to worry about *recursive* const stability.
|
||||
if self.enforce_recursive_const_stability()
|
||||
&& !is_fn_or_trait_safe_to_expose_on_stable(self.tcx, def_id)
|
||||
{
|
||||
self.dcx().emit_err(errors::UnmarkedConstItemExposed {
|
||||
span: self.span,
|
||||
def_path: self.tcx.def_path_str(def_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(ConstStability {
|
||||
level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
|
||||
feature,
|
||||
..
|
||||
}) => {
|
||||
// An unstable const fn/trait with a feature gate.
|
||||
let callee_safe_to_expose_on_stable =
|
||||
is_fn_or_trait_safe_to_expose_on_stable(self.tcx, def_id);
|
||||
|
||||
// We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
|
||||
// the callee is safe to expose, to avoid bypassing recursive stability.
|
||||
// This is not ideal since it means the user sees an error, not the macro
|
||||
// author, but that's also the case if one forgets to set
|
||||
// `#[allow_internal_unstable]` in the first place. Note that this cannot be
|
||||
// integrated in the check below since we want to enforce
|
||||
// `callee_safe_to_expose_on_stable` even if
|
||||
// `!self.enforce_recursive_const_stability()`.
|
||||
if (self.span.allows_unstable(feature)
|
||||
|| implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
|
||||
&& callee_safe_to_expose_on_stable
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't use `check_op` to check whether the feature is enabled because
|
||||
// the logic is a bit different than elsewhere: local functions don't need
|
||||
// the feature gate, and there might be an "implied" gate that also suffices
|
||||
// to allow this.
|
||||
let feature_enabled = def_id.is_local()
|
||||
|| self.tcx.features().enabled(feature)
|
||||
|| implied_feature.is_some_and(|f| self.tcx.features().enabled(f))
|
||||
|| {
|
||||
// When we're compiling the compiler itself we may pull in
|
||||
// crates from crates.io, but those crates may depend on other
|
||||
// crates also pulled in from crates.io. We want to ideally be
|
||||
// able to compile everything without requiring upstream
|
||||
// modifications, so in the case that this looks like a
|
||||
// `rustc_private` crate (e.g., a compiler crate) and we also have
|
||||
// the `-Z force-unstable-if-unmarked` flag present (we're
|
||||
// compiling a compiler crate), then let this missing feature
|
||||
// annotation slide.
|
||||
// This matches what we do in `eval_stability_allow_unstable` for
|
||||
// regular stability.
|
||||
feature == sym::rustc_private
|
||||
&& issue == NonZero::new(27812)
|
||||
&& self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
|
||||
};
|
||||
// Even if the feature is enabled, we still need check_op to double-check
|
||||
// this if the callee is not safe to expose on stable.
|
||||
if !feature_enabled || !callee_safe_to_expose_on_stable {
|
||||
self.check_op(ops::CallUnstable {
|
||||
def_id,
|
||||
feature,
|
||||
feature_enabled,
|
||||
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
|
||||
suggestion_span: self.crate_inject_span(),
|
||||
is_function_call: self.tcx.def_kind(def_id) != DefKind::Trait,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
|
|
@ -518,7 +601,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
|
||||
Rvalue::Ref(_, BorrowKind::Mut { .. }, place)
|
||||
| Rvalue::RawPtr(Mutability::Mut, place) => {
|
||||
| Rvalue::RawPtr(RawPtrKind::Mut, place) => {
|
||||
// Inside mutable statics, we allow arbitrary mutable references.
|
||||
// We've allowed `static mut FOO = &mut [elements];` for a long time (the exact
|
||||
// reasons why are lost to history), and there is no reason to restrict that to
|
||||
|
|
@ -536,7 +619,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
|
||||
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
|
||||
| Rvalue::RawPtr(Mutability::Not, place) => {
|
||||
| Rvalue::RawPtr(RawPtrKind::Const, place) => {
|
||||
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
|
||||
self.ccx,
|
||||
&mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
|
||||
|
|
@ -548,6 +631,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place) => {
|
||||
// These are only inserted for slice length, so the place must already be indirect.
|
||||
// This implies we do not have to worry about whether the borrow escapes.
|
||||
assert!(place.is_indirect(), "fake borrows are always indirect");
|
||||
}
|
||||
|
||||
Rvalue::Cast(
|
||||
CastKind::PointerCoercion(
|
||||
PointerCoercion::MutToConstPointer
|
||||
|
|
@ -586,12 +675,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
) => {}
|
||||
Rvalue::ShallowInitBox(_, _) => {}
|
||||
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
Rvalue::UnaryOp(op, operand) => {
|
||||
let ty = operand.ty(self.body, self.tcx);
|
||||
if is_int_bool_float_or_char(ty) {
|
||||
// Int, bool, float, and char operations are fine.
|
||||
} else {
|
||||
span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty);
|
||||
match op {
|
||||
UnOp::Not | UnOp::Neg => {
|
||||
if is_int_bool_float_or_char(ty) {
|
||||
// Int, bool, float, and char operations are fine.
|
||||
} else {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"non-primitive type in `Rvalue::UnaryOp{op:?}`: {ty:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
UnOp::PtrMetadata => {
|
||||
// Getting the metadata from a pointer is always const.
|
||||
// We already validated the type is valid in the validator.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -716,8 +816,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
span: *fn_span,
|
||||
call_source,
|
||||
});
|
||||
// FIXME(const_trait_impl): do a more fine-grained check whether this
|
||||
// particular trait can be const-stably called.
|
||||
self.check_callee_stability(trait_did);
|
||||
} else {
|
||||
// Not even a const trait.
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
|
|
@ -793,7 +892,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// fallback body is safe to expose on stable.
|
||||
let is_const_stable = intrinsic.const_stable
|
||||
|| (!intrinsic.must_be_overridden
|
||||
&& is_safe_to_expose_on_stable_const_fn(tcx, callee));
|
||||
&& is_fn_or_trait_safe_to_expose_on_stable(tcx, callee));
|
||||
match tcx.lookup_const_stability(callee) {
|
||||
None => {
|
||||
// This doesn't need a separate const-stability check -- const-stability equals
|
||||
|
|
@ -842,83 +941,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
|
||||
// Finally, stability for regular function calls -- this is the big one.
|
||||
match tcx.lookup_const_stability(callee) {
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
|
||||
// All good.
|
||||
}
|
||||
None => {
|
||||
// This doesn't need a separate const-stability check -- const-stability equals
|
||||
// regular stability, and regular stability is checked separately.
|
||||
// However, we *do* have to worry about *recursive* const stability.
|
||||
if self.enforce_recursive_const_stability()
|
||||
&& !is_safe_to_expose_on_stable_const_fn(tcx, callee)
|
||||
{
|
||||
self.dcx().emit_err(errors::UnmarkedConstFnExposed {
|
||||
span: self.span,
|
||||
def_path: self.tcx.def_path_str(callee),
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(ConstStability {
|
||||
level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
|
||||
feature,
|
||||
..
|
||||
}) => {
|
||||
// An unstable const fn with a feature gate.
|
||||
let callee_safe_to_expose_on_stable =
|
||||
is_safe_to_expose_on_stable_const_fn(tcx, callee);
|
||||
|
||||
// We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
|
||||
// the callee is safe to expose, to avoid bypassing recursive stability.
|
||||
// This is not ideal since it means the user sees an error, not the macro
|
||||
// author, but that's also the case if one forgets to set
|
||||
// `#[allow_internal_unstable]` in the first place. Note that this cannot be
|
||||
// integrated in the check below since we want to enforce
|
||||
// `callee_safe_to_expose_on_stable` even if
|
||||
// `!self.enforce_recursive_const_stability()`.
|
||||
if (self.span.allows_unstable(feature)
|
||||
|| implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
|
||||
&& callee_safe_to_expose_on_stable
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't use `check_op` to check whether the feature is enabled because
|
||||
// the logic is a bit different than elsewhere: local functions don't need
|
||||
// the feature gate, and there might be an "implied" gate that also suffices
|
||||
// to allow this.
|
||||
let feature_enabled = callee.is_local()
|
||||
|| tcx.features().enabled(feature)
|
||||
|| implied_feature.is_some_and(|f| tcx.features().enabled(f))
|
||||
|| {
|
||||
// When we're compiling the compiler itself we may pull in
|
||||
// crates from crates.io, but those crates may depend on other
|
||||
// crates also pulled in from crates.io. We want to ideally be
|
||||
// able to compile everything without requiring upstream
|
||||
// modifications, so in the case that this looks like a
|
||||
// `rustc_private` crate (e.g., a compiler crate) and we also have
|
||||
// the `-Z force-unstable-if-unmarked` flag present (we're
|
||||
// compiling a compiler crate), then let this missing feature
|
||||
// annotation slide.
|
||||
// This matches what we do in `eval_stability_allow_unstable` for
|
||||
// regular stability.
|
||||
feature == sym::rustc_private
|
||||
&& issue == NonZero::new(27812)
|
||||
&& tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
|
||||
};
|
||||
// Even if the feature is enabled, we still need check_op to double-check
|
||||
// this if the callee is not safe to expose on stable.
|
||||
if !feature_enabled || !callee_safe_to_expose_on_stable {
|
||||
self.check_op(ops::FnCallUnstable {
|
||||
def_id: callee,
|
||||
feature,
|
||||
feature_enabled,
|
||||
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
|
||||
suggestion_span: self.crate_inject_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
self.check_callee_stability(callee);
|
||||
}
|
||||
|
||||
// Forbid all `Drop` terminators unless the place being dropped is a local with no
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
|
|||
self.const_kind == Some(hir::ConstContext::ConstFn)
|
||||
&& (self.tcx.features().staged_api()
|
||||
|| self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked)
|
||||
&& is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id())
|
||||
&& is_fn_or_trait_safe_to_expose_on_stable(self.tcx, self.def_id().to_def_id())
|
||||
}
|
||||
|
||||
fn is_async(&self) -> bool {
|
||||
|
|
@ -84,28 +84,14 @@ pub fn rustc_allow_const_fn_unstable(
|
|||
attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate)
|
||||
}
|
||||
|
||||
/// Returns `true` if the given `const fn` is "safe to expose on stable".
|
||||
///
|
||||
/// Panics if the given `DefId` does not refer to a `const fn`.
|
||||
/// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable".
|
||||
///
|
||||
/// This is relevant within a `staged_api` crate. Unlike with normal features, the use of unstable
|
||||
/// const features *recursively* taints the functions that use them. This is to avoid accidentally
|
||||
/// exposing e.g. the implementation of an unstable const intrinsic on stable. So we partition the
|
||||
/// world into two functions: those that are safe to expose on stable (and hence may not use
|
||||
/// unstable features, not even recursively), and those that are not.
|
||||
pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
// A default body in a `#[const_trait]` is not const-stable because const trait fns currently
|
||||
// cannot be const-stable. These functions can't be called from anything stable, so we shouldn't
|
||||
// restrict them to only call const-stable functions.
|
||||
if tcx.is_const_default_method(def_id) {
|
||||
// FIXME(const_trait_impl): we have to eventually allow some of these if these things can ever be stable.
|
||||
// They should probably behave like regular `const fn` for that...
|
||||
return false;
|
||||
}
|
||||
|
||||
// Const-stability is only relevant for `const fn`.
|
||||
assert!(tcx.is_const_fn(def_id));
|
||||
|
||||
pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
match tcx.lookup_const_stability(def_id) {
|
||||
None => {
|
||||
// In a `staged_api` crate, we do enforce recursive const stability for all unmarked
|
||||
|
|
|
|||
|
|
@ -377,11 +377,11 @@ fn build_error_for_const_call<'tcx>(
|
|||
err
|
||||
}
|
||||
|
||||
/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
|
||||
/// A call to an `#[unstable]` const fn, `#[rustc_const_unstable]` function or trait.
|
||||
///
|
||||
/// Contains the name of the feature that would allow the use of this function.
|
||||
/// Contains the name of the feature that would allow the use of this function/trait.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FnCallUnstable {
|
||||
pub(crate) struct CallUnstable {
|
||||
pub def_id: DefId,
|
||||
pub feature: Symbol,
|
||||
/// If this is true, then the feature is enabled, but we need to still check if it is safe to
|
||||
|
|
@ -389,24 +389,33 @@ pub(crate) struct FnCallUnstable {
|
|||
pub feature_enabled: bool,
|
||||
pub safe_to_expose_on_stable: bool,
|
||||
pub suggestion_span: Option<Span>,
|
||||
/// true if `def_id` is the function we are calling, false if `def_id` is an unstable trait.
|
||||
pub is_function_call: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
||||
impl<'tcx> NonConstOp<'tcx> for CallUnstable {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable {
|
||||
gate: self.feature,
|
||||
gate_already_checked: self.feature_enabled,
|
||||
safe_to_expose_on_stable: self.safe_to_expose_on_stable,
|
||||
is_function_call: true,
|
||||
is_function_call: self.is_function_call,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
assert!(!self.feature_enabled);
|
||||
let mut err = ccx.dcx().create_err(errors::UnstableConstFn {
|
||||
span,
|
||||
def_path: ccx.tcx.def_path_str(self.def_id),
|
||||
});
|
||||
let mut err = if self.is_function_call {
|
||||
ccx.dcx().create_err(errors::UnstableConstFn {
|
||||
span,
|
||||
def_path: ccx.tcx.def_path_str(self.def_id),
|
||||
})
|
||||
} else {
|
||||
ccx.dcx().create_err(errors::UnstableConstTrait {
|
||||
span,
|
||||
def_path: ccx.tcx.def_path_str(self.def_id),
|
||||
})
|
||||
};
|
||||
// FIXME: make this translatable
|
||||
let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature);
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
|
|
|
|||
|
|
@ -121,6 +121,14 @@ pub(crate) struct UnstableConstFn {
|
|||
pub def_path: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unstable_const_trait)]
|
||||
pub(crate) struct UnstableConstTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def_path: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unstable_intrinsic)]
|
||||
pub(crate) struct UnstableIntrinsic {
|
||||
|
|
@ -139,9 +147,9 @@ pub(crate) struct UnstableIntrinsic {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unmarked_const_fn_exposed)]
|
||||
#[diag(const_eval_unmarked_const_item_exposed)]
|
||||
#[help]
|
||||
pub(crate) struct UnmarkedConstFnExposed {
|
||||
pub(crate) struct UnmarkedConstItemExposed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def_path: String,
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.write_immediate(*val, &dest)?;
|
||||
}
|
||||
|
||||
RawPtr(_, place) => {
|
||||
RawPtr(kind, place) => {
|
||||
// Figure out whether this is an addr_of of an already raw place.
|
||||
let place_base_raw = if place.is_indirect_first_projection() {
|
||||
let ty = self.frame().body.local_decls[place.local].ty;
|
||||
|
|
@ -250,8 +250,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let src = self.eval_place(place)?;
|
||||
let place = self.force_allocation(&src)?;
|
||||
let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
|
||||
if !place_base_raw {
|
||||
// If this was not already raw, it needs retagging.
|
||||
if !place_base_raw && !kind.is_fake() {
|
||||
// If this was not already raw, it needs retagging -- except for "fake"
|
||||
// raw borrows whose defining property is that they do not get retagged.
|
||||
val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?;
|
||||
}
|
||||
self.write_immediate(*val, &dest)?;
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ bitflags = "2.4.1"
|
|||
either = "1.0"
|
||||
elsa = "=1.7.1"
|
||||
ena = "0.14.3"
|
||||
indexmap = { version = "2.4.0", features = ["rustc-rayon"] }
|
||||
indexmap = "2.4.0"
|
||||
jobserver_crate = { version = "0.1.28", package = "jobserver" }
|
||||
measureme = "11"
|
||||
rustc-hash = "2.0.0"
|
||||
rustc-rayon = "0.5.0"
|
||||
rustc-rayon = { version = "0.5.1", features = ["indexmap"] }
|
||||
rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
rustc_graphviz = { path = "../rustc_graphviz" }
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
/// Given the expected type, figures out what it can about this closure we
|
||||
/// are about to type check:
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
fn deduce_closure_signature(
|
||||
&self,
|
||||
expected_ty: Ty<'tcx>,
|
||||
|
|
@ -378,6 +378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
bound_predicate.rebind(proj_predicate),
|
||||
),
|
||||
);
|
||||
|
||||
// Make sure that we didn't infer a signature that mentions itself.
|
||||
// This can happen when we elaborate certain supertrait bounds that
|
||||
// mention projections containing the `Self` type. See #105401.
|
||||
|
|
@ -395,8 +396,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
|
||||
expected_sig = inferred_sig;
|
||||
|
||||
// Don't infer a closure signature from a goal that names the closure type as this will
|
||||
// (almost always) lead to occurs check errors later in type checking.
|
||||
if self.next_trait_solver()
|
||||
&& let Some(inferred_sig) = inferred_sig
|
||||
{
|
||||
// In the new solver it is difficult to explicitly normalize the inferred signature as we
|
||||
// would have to manually handle universes and rewriting bound vars and placeholders back
|
||||
// and forth.
|
||||
//
|
||||
// Instead we take advantage of the fact that we relating an inference variable with an alias
|
||||
// will only instantiate the variable if the alias is rigid(*not quite). Concretely we:
|
||||
// - Create some new variable `?sig`
|
||||
// - Equate `?sig` with the unnormalized signature, e.g. `fn(<Foo<?x> as Trait>::Assoc)`
|
||||
// - Depending on whether `<Foo<?x> as Trait>::Assoc` is rigid, ambiguous or normalizeable,
|
||||
// we will either wind up with `?sig=<Foo<?x> as Trait>::Assoc/?y/ConcreteTy` respectively.
|
||||
//
|
||||
// *: In cases where there are ambiguous aliases in the signature that make use of bound vars
|
||||
// they will wind up present in `?sig` even though they are non-rigid.
|
||||
//
|
||||
// This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty`
|
||||
// even though the normalized form may not name `expected_ty`. However, this matches the existing
|
||||
// behaviour of the old solver and would be technically a breaking change to fix.
|
||||
let generalized_fnptr_sig = self.next_ty_var(span);
|
||||
let inferred_fnptr_sig = Ty::new_fn_ptr(self.tcx, inferred_sig.sig);
|
||||
self.demand_eqtype(span, inferred_fnptr_sig, generalized_fnptr_sig);
|
||||
|
||||
let resolved_sig = self.resolve_vars_if_possible(generalized_fnptr_sig);
|
||||
|
||||
if resolved_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
|
||||
expected_sig = Some(ExpectedSig {
|
||||
cause_span: inferred_sig.cause_span,
|
||||
sig: resolved_sig.fn_sig(self.tcx),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
|
||||
expected_sig = inferred_sig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use rustc_span::Span;
|
|||
use rustc_trait_selection::solve::inspect::{
|
||||
InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor,
|
||||
};
|
||||
use rustc_type_ir::solve::GoalSource;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::FnCtxt;
|
||||
|
|
@ -119,7 +120,21 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
|
|||
fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
|
||||
let tcx = self.fcx.tcx;
|
||||
let goal = inspect_goal.goal();
|
||||
if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) {
|
||||
if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty)
|
||||
// We do not push the instantiated forms of goals as it would cause any
|
||||
// aliases referencing bound vars to go from having escaping bound vars to
|
||||
// being able to be normalized to an inference variable.
|
||||
//
|
||||
// This is mostly just a hack as arbitrary nested goals could still contain
|
||||
// such aliases while having a different `GoalSource`. Closure signature inference
|
||||
// however can't really handle *every* higher ranked `Fn` goal also being present
|
||||
// in the form of `?c: Fn<(<?x as Trait<'!a>>::Assoc)`.
|
||||
//
|
||||
// This also just better matches the behaviour of the old solver where we do not
|
||||
// encounter instantiated forms of goals, only nested goals that referred to bound
|
||||
// vars from instantiated goals.
|
||||
&& !matches!(inspect_goal.source(), GoalSource::InstantiateHigherRanked)
|
||||
{
|
||||
self.obligations_for_self_ty.push(traits::Obligation::new(
|
||||
tcx,
|
||||
self.root_cause.clone(),
|
||||
|
|
|
|||
|
|
@ -797,7 +797,6 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(function_sections, Some(false));
|
||||
tracked!(human_readable_cgu_names, true);
|
||||
tracked!(incremental_ignore_spans, true);
|
||||
tracked!(inline_in_all_cgus, Some(true));
|
||||
tracked!(inline_mir, Some(true));
|
||||
tracked!(inline_mir_hint_threshold, Some(123));
|
||||
tracked!(inline_mir_threshold, Some(123));
|
||||
|
|
|
|||
|
|
@ -91,13 +91,8 @@ impl<'tcx> MonoItem<'tcx> {
|
|||
}
|
||||
|
||||
pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
|
||||
let generate_cgu_internal_copies = tcx
|
||||
.sess
|
||||
.opts
|
||||
.unstable_opts
|
||||
.inline_in_all_cgus
|
||||
.unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No)
|
||||
&& !tcx.sess.link_dead_code();
|
||||
let generate_cgu_internal_copies =
|
||||
(tcx.sess.opts.optimize != OptLevel::No) && !tcx.sess.link_dead_code();
|
||||
|
||||
match *self {
|
||||
MonoItem::Fn(ref instance) => {
|
||||
|
|
@ -121,8 +116,8 @@ impl<'tcx> MonoItem<'tcx> {
|
|||
}
|
||||
|
||||
// At this point we don't have explicit linkage and we're an
|
||||
// inlined function. If we're inlining into all CGUs then we'll
|
||||
// be creating a local copy per CGU.
|
||||
// inlined function. If this crate's build settings permit,
|
||||
// we'll be creating a local copy per CGU.
|
||||
if generate_cgu_internal_copies {
|
||||
return InstantiationMode::LocalCopy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,6 +180,59 @@ pub enum BorrowKind {
|
|||
Mut { kind: MutBorrowKind },
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable)]
|
||||
pub enum RawPtrKind {
|
||||
Mut,
|
||||
Const,
|
||||
/// Creates a raw pointer to a place that will only be used to access its metadata,
|
||||
/// not the data behind the pointer. Note that this limitation is *not* enforced
|
||||
/// by the validator.
|
||||
///
|
||||
/// The borrow checker allows overlap of these raw pointers with references to the
|
||||
/// data. This is sound even if the pointer is "misused" since any such use is anyway
|
||||
/// unsafe. In terms of the operational semantics (i.e., Miri), this is equivalent
|
||||
/// to `RawPtrKind::Mut`, but will never incur a retag.
|
||||
FakeForPtrMetadata,
|
||||
}
|
||||
|
||||
impl From<Mutability> for RawPtrKind {
|
||||
fn from(other: Mutability) -> Self {
|
||||
match other {
|
||||
Mutability::Mut => RawPtrKind::Mut,
|
||||
Mutability::Not => RawPtrKind::Const,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawPtrKind {
|
||||
pub fn is_fake(self) -> bool {
|
||||
match self {
|
||||
RawPtrKind::Mut | RawPtrKind::Const => false,
|
||||
RawPtrKind::FakeForPtrMetadata => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_mutbl_lossy(self) -> Mutability {
|
||||
match self {
|
||||
RawPtrKind::Mut => Mutability::Mut,
|
||||
RawPtrKind::Const => Mutability::Not,
|
||||
|
||||
// We have no type corresponding to a fake borrow, so use
|
||||
// `*const` as an approximation.
|
||||
RawPtrKind::FakeForPtrMetadata => Mutability::Not,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptr_str(self) -> &'static str {
|
||||
match self {
|
||||
RawPtrKind::Mut => "mut",
|
||||
RawPtrKind::Const => "const",
|
||||
RawPtrKind::FakeForPtrMetadata => "const (fake)",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable)]
|
||||
pub enum MutBorrowKind {
|
||||
|
|
@ -1356,7 +1409,7 @@ pub enum Rvalue<'tcx> {
|
|||
///
|
||||
/// Like with references, the semantics of this operation are heavily dependent on the aliasing
|
||||
/// model.
|
||||
RawPtr(Mutability, Place<'tcx>),
|
||||
RawPtr(RawPtrKind, Place<'tcx>),
|
||||
|
||||
/// Yields the length of the place, as a `usize`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -206,9 +206,9 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
let place_ty = place.ty(local_decls, tcx).ty;
|
||||
Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy())
|
||||
}
|
||||
Rvalue::RawPtr(mutability, ref place) => {
|
||||
Rvalue::RawPtr(kind, ref place) => {
|
||||
let place_ty = place.ty(local_decls, tcx).ty;
|
||||
Ty::new_ptr(tcx, place_ty, mutability)
|
||||
Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy())
|
||||
}
|
||||
Rvalue::Len(..) => tcx.types.usize,
|
||||
Rvalue::Cast(.., ty) => ty,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ TrivialTypeTraversalImpls! {
|
|||
SourceScopeLocalData,
|
||||
UserTypeAnnotationIndex,
|
||||
BorrowKind,
|
||||
RawPtrKind,
|
||||
CastKind,
|
||||
BasicBlock,
|
||||
SwitchTargets,
|
||||
|
|
|
|||
|
|
@ -685,12 +685,15 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
Rvalue::RawPtr(m, path) => {
|
||||
let ctx = match m {
|
||||
Mutability::Mut => PlaceContext::MutatingUse(
|
||||
RawPtrKind::Mut => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::RawBorrow
|
||||
),
|
||||
Mutability::Not => PlaceContext::NonMutatingUse(
|
||||
RawPtrKind::Const => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::RawBorrow
|
||||
),
|
||||
RawPtrKind::FakeForPtrMetadata => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::Inspect
|
||||
),
|
||||
};
|
||||
self.visit_place(path, ctx, location);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
|
||||
),
|
||||
ExprKind::RawBorrow { mutability, arg } => Ok(
|
||||
Rvalue::RawPtr(*mutability, self.parse_place(*arg)?)
|
||||
Rvalue::RawPtr((*mutability).into(), self.parse_place(*arg)?)
|
||||
),
|
||||
ExprKind::Binary { op, lhs, rhs } => Ok(
|
||||
Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
|
||||
|
|
|
|||
|
|
@ -630,6 +630,69 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
block.and(base_place.index(idx))
|
||||
}
|
||||
|
||||
/// Given a place that's either an array or a slice, returns an operand
|
||||
/// with the length of the array/slice.
|
||||
///
|
||||
/// For arrays it'll be `Operand::Constant` with the actual length;
|
||||
/// For slices it'll be `Operand::Move` of a local using `PtrMetadata`.
|
||||
fn len_of_slice_or_array(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
source_info: SourceInfo,
|
||||
) -> Operand<'tcx> {
|
||||
let place_ty = place.ty(&self.local_decls, self.tcx).ty;
|
||||
match place_ty.kind() {
|
||||
ty::Array(_elem_ty, len_const) => {
|
||||
// We know how long an array is, so just use that as a constant
|
||||
// directly -- no locals needed. We do need one statement so
|
||||
// that borrow- and initialization-checking consider it used,
|
||||
// though. FIXME: Do we really *need* to count this as a use?
|
||||
// Could partial array tracking work off something else instead?
|
||||
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForIndex, place);
|
||||
let const_ = Const::Ty(self.tcx.types.usize, *len_const);
|
||||
Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ }))
|
||||
}
|
||||
ty::Slice(_elem_ty) => {
|
||||
let ptr_or_ref = if let [PlaceElem::Deref] = place.projection[..]
|
||||
&& let local_ty = self.local_decls[place.local].ty
|
||||
&& local_ty.is_trivially_pure_clone_copy()
|
||||
{
|
||||
// It's extremely common that we have something that can be
|
||||
// directly passed to `PtrMetadata`, so avoid an unnecessary
|
||||
// temporary and statement in those cases. Note that we can
|
||||
// only do that for `Copy` types -- not `&mut [_]` -- because
|
||||
// the MIR we're building here needs to pass NLL later.
|
||||
Operand::Copy(Place::from(place.local))
|
||||
} else {
|
||||
let ptr_ty = Ty::new_imm_ptr(self.tcx, place_ty);
|
||||
let slice_ptr = self.temp(ptr_ty, span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
slice_ptr,
|
||||
Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place),
|
||||
);
|
||||
Operand::Move(slice_ptr)
|
||||
};
|
||||
|
||||
let len = self.temp(self.tcx.types.usize, span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
len,
|
||||
Rvalue::UnaryOp(UnOp::PtrMetadata, ptr_or_ref),
|
||||
);
|
||||
|
||||
Operand::Move(len)
|
||||
}
|
||||
_ => {
|
||||
span_bug!(span, "len called on place of type {place_ty:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds_check(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
|
|
@ -638,25 +701,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
expr_span: Span,
|
||||
source_info: SourceInfo,
|
||||
) -> BasicBlock {
|
||||
let usize_ty = self.tcx.types.usize;
|
||||
let bool_ty = self.tcx.types.bool;
|
||||
// bounds check:
|
||||
let len = self.temp(usize_ty, expr_span);
|
||||
let lt = self.temp(bool_ty, expr_span);
|
||||
let slice = slice.to_place(self);
|
||||
|
||||
// len = len(slice)
|
||||
self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.to_place(self)));
|
||||
let len = self.len_of_slice_or_array(block, slice, expr_span, source_info);
|
||||
|
||||
// lt = idx < len
|
||||
let bool_ty = self.tcx.types.bool;
|
||||
let lt = self.temp(bool_ty, expr_span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
lt,
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Lt,
|
||||
Box::new((Operand::Copy(Place::from(index)), Operand::Copy(len))),
|
||||
Box::new((Operand::Copy(Place::from(index)), len.to_copy())),
|
||||
),
|
||||
);
|
||||
let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
|
||||
let msg = BoundsCheck { len, index: Operand::Copy(Place::from(index)) };
|
||||
|
||||
// assert!(lt, "...")
|
||||
self.assert(block, Operand::Move(lt), true, msg, expr_span)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
hir::Mutability::Not => this.as_read_only_place(block, arg),
|
||||
hir::Mutability::Mut => this.as_place(block, arg),
|
||||
};
|
||||
let address_of = Rvalue::RawPtr(mutability, unpack!(block = place));
|
||||
let address_of = Rvalue::RawPtr(mutability.into(), unpack!(block = place));
|
||||
this.cfg.push_assign(block, source_info, destination, address_of);
|
||||
block.unit()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -700,7 +700,7 @@ where
|
|||
statements: vec![
|
||||
self.assign(
|
||||
ptr,
|
||||
Rvalue::RawPtr(Mutability::Mut, tcx.mk_place_index(self.place, cur)),
|
||||
Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_index(self.place, cur)),
|
||||
),
|
||||
self.assign(
|
||||
cur.into(),
|
||||
|
|
@ -816,7 +816,7 @@ where
|
|||
|
||||
let mut delegate_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(Place::from(array_ptr), Rvalue::RawPtr(Mutability::Mut, self.place)),
|
||||
self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)),
|
||||
self.assign(
|
||||
Place::from(slice_ptr),
|
||||
Rvalue::Cast(
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ enum AggregateTy<'tcx> {
|
|||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
enum AddressKind {
|
||||
Ref(BorrowKind),
|
||||
Address(Mutability),
|
||||
Address(RawPtrKind),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
|
|
@ -504,7 +504,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
mplace.layout.ty,
|
||||
bk.to_mutbl_lossy(),
|
||||
),
|
||||
AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl),
|
||||
AddressKind::Address(mutbl) => {
|
||||
Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl.to_mutbl_lossy())
|
||||
}
|
||||
};
|
||||
let layout = self.ecx.layout_of(ty).ok()?;
|
||||
ImmTy::from_immediate(pointer, layout).into()
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
|
|||
}
|
||||
ctx.simplify_bool_cmp(rvalue);
|
||||
ctx.simplify_ref_deref(rvalue);
|
||||
ctx.simplify_len(rvalue);
|
||||
ctx.simplify_ptr_aggregate(rvalue);
|
||||
ctx.simplify_cast(rvalue);
|
||||
ctx.simplify_repeated_aggregate(rvalue);
|
||||
|
|
@ -166,18 +165,6 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Transform `Len([_; N])` ==> `N`.
|
||||
fn simplify_len(&self, rvalue: &mut Rvalue<'tcx>) {
|
||||
if let Rvalue::Len(ref place) = *rvalue {
|
||||
let place_ty = place.ty(self.local_decls, self.tcx).ty;
|
||||
if let ty::Array(_, len) = *place_ty.kind() {
|
||||
let const_ = Const::Ty(self.tcx.types.usize, len);
|
||||
let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None };
|
||||
*rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform `Aggregate(RawPtr, [p, ()])` ==> `Cast(PtrToPtr, p)`.
|
||||
fn simplify_ptr_aggregate(&self, rvalue: &mut Rvalue<'tcx>) {
|
||||
if let Rvalue::Aggregate(box AggregateKind::RawPtr(pointee_ty, mutability), fields) = rvalue
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
|
|||
source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
dst,
|
||||
Rvalue::RawPtr(Mutability::Mut, *lhs),
|
||||
Rvalue::RawPtr(RawPtrKind::Mut, *lhs),
|
||||
))),
|
||||
};
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
|
|||
source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
src,
|
||||
Rvalue::RawPtr(Mutability::Not, *rhs),
|
||||
Rvalue::RawPtr(RawPtrKind::Const, *rhs),
|
||||
))),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,17 +2,11 @@ use std::iter;
|
|||
|
||||
use itertools::Itertools;
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_const_eval::interpret;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::mir::{
|
||||
BasicBlock, BasicBlockData, Body, CallSource, CastKind, CoercionSource, Const, ConstOperand,
|
||||
ConstValue, Local, LocalDecl, MirSource, Operand, Place, PlaceElem, RETURN_PLACE, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnwindAction,
|
||||
UnwindTerminateReason,
|
||||
};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::util::{AsyncDropGlueMorphology, Discr};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
|
@ -345,7 +339,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
|
|||
.tcx
|
||||
.mk_place_elems(&[PlaceElem::Deref, PlaceElem::Field(field, field_ty)]),
|
||||
};
|
||||
self.put_temp_rvalue(Rvalue::RawPtr(Mutability::Mut, place))
|
||||
self.put_temp_rvalue(Rvalue::RawPtr(RawPtrKind::Mut, place))
|
||||
}
|
||||
|
||||
/// If given Self is an enum puts `to_drop: *mut FieldTy` on top of
|
||||
|
|
@ -365,7 +359,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
|
|||
PlaceElem::Field(field, field_ty),
|
||||
]),
|
||||
};
|
||||
self.put_temp_rvalue(Rvalue::RawPtr(Mutability::Mut, place))
|
||||
self.put_temp_rvalue(Rvalue::RawPtr(RawPtrKind::Mut, place))
|
||||
}
|
||||
|
||||
/// If given Self is an enum puts `to_drop: *mut FieldTy` on top of
|
||||
|
|
|
|||
|
|
@ -1128,14 +1128,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
UnOp::PtrMetadata => {
|
||||
if !matches!(self.body.phase, MirPhase::Runtime(_)) {
|
||||
// It would probably be fine to support this in earlier phases, but at
|
||||
// the time of writing it's only ever introduced from intrinsic
|
||||
// lowering or other runtime-phase optimization passes, so earlier
|
||||
// things can just `bug!` on it.
|
||||
self.fail(location, "PtrMetadata should be in runtime MIR only");
|
||||
}
|
||||
|
||||
check_kinds!(
|
||||
a,
|
||||
"Cannot PtrMetadata non-pointer non-reference type {:?}",
|
||||
|
|
|
|||
|
|
@ -2830,9 +2830,10 @@ pub(crate) struct DynAfterMut {
|
|||
pub(crate) struct FnPointerCannotBeConst {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
|
||||
#[label]
|
||||
pub qualifier: Span,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -2840,9 +2841,10 @@ pub(crate) struct FnPointerCannotBeConst {
|
|||
pub(crate) struct FnPointerCannotBeAsync {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
|
||||
#[label]
|
||||
pub qualifier: Span,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -609,16 +609,58 @@ impl<'a> Parser<'a> {
|
|||
let span_start = self.token.span;
|
||||
let ast::FnHeader { ext, safety, constness, coroutine_kind } =
|
||||
self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
|
||||
let fn_start_lo = self.prev_token.span.lo();
|
||||
if self.may_recover() && self.token == TokenKind::Lt {
|
||||
self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
|
||||
}
|
||||
let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
|
||||
let whole_span = lo.to(self.prev_token.span);
|
||||
if let ast::Const::Yes(span) = constness {
|
||||
self.dcx().emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
|
||||
|
||||
// Order/parsing of "front matter" follows:
|
||||
// `<constness> <coroutine_kind> <safety> <extern> fn()`
|
||||
// ^ ^ ^ ^ ^
|
||||
// | | | | fn_start_lo
|
||||
// | | | ext_sp.lo
|
||||
// | | safety_sp.lo
|
||||
// | coroutine_sp.lo
|
||||
// const_sp.lo
|
||||
if let ast::Const::Yes(const_span) = constness {
|
||||
let next_token_lo = if let Some(
|
||||
ast::CoroutineKind::Async { span, .. }
|
||||
| ast::CoroutineKind::Gen { span, .. }
|
||||
| ast::CoroutineKind::AsyncGen { span, .. },
|
||||
) = coroutine_kind
|
||||
{
|
||||
span.lo()
|
||||
} else if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety {
|
||||
span.lo()
|
||||
} else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
|
||||
span.lo()
|
||||
} else {
|
||||
fn_start_lo
|
||||
};
|
||||
let sugg_span = const_span.with_hi(next_token_lo);
|
||||
self.dcx().emit_err(FnPointerCannotBeConst {
|
||||
span: whole_span,
|
||||
qualifier: const_span,
|
||||
suggestion: sugg_span,
|
||||
});
|
||||
}
|
||||
if let Some(ast::CoroutineKind::Async { span, .. }) = coroutine_kind {
|
||||
self.dcx().emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span });
|
||||
if let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind {
|
||||
let next_token_lo = if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety
|
||||
{
|
||||
span.lo()
|
||||
} else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
|
||||
span.lo()
|
||||
} else {
|
||||
fn_start_lo
|
||||
};
|
||||
let sugg_span = async_span.with_hi(next_token_lo);
|
||||
self.dcx().emit_err(FnPointerCannotBeAsync {
|
||||
span: whole_span,
|
||||
qualifier: async_span,
|
||||
suggestion: sugg_span,
|
||||
});
|
||||
}
|
||||
// FIXME(gen_blocks): emit a similar error for `gen fn()`
|
||||
let decl_span = span_start.to(self.prev_token.span);
|
||||
|
|
|
|||
|
|
@ -1870,8 +1870,6 @@ options! {
|
|||
"verify extended properties for incr. comp. (default: no):
|
||||
- hashes of green query instances
|
||||
- hash collisions of query keys"),
|
||||
inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"control whether `#[inline]` functions are in all CGUs"),
|
||||
inline_llvm: bool = (true, parse_bool, [TRACKED],
|
||||
"enable LLVM inlining (default: yes)"),
|
||||
inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
|
|
|
|||
|
|
@ -232,6 +232,18 @@ impl<'tcx> Stable<'tcx> for mir::Mutability {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for mir::RawPtrKind {
|
||||
type T = stable_mir::mir::RawPtrKind;
|
||||
fn stable(&self, _: &mut Tables<'_>) -> Self::T {
|
||||
use mir::RawPtrKind::*;
|
||||
match *self {
|
||||
Const => stable_mir::mir::RawPtrKind::Const,
|
||||
Mut => stable_mir::mir::RawPtrKind::Mut,
|
||||
FakeForPtrMetadata => stable_mir::mir::RawPtrKind::FakeForPtrMetadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for mir::BorrowKind {
|
||||
type T = stable_mir::mir::BorrowKind;
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
|
|
|
|||
|
|
@ -2184,8 +2184,10 @@ symbols! {
|
|||
vec_macro,
|
||||
vec_new,
|
||||
vec_pop,
|
||||
vec_reserve,
|
||||
vec_with_capacity,
|
||||
vecdeque_iter,
|
||||
vecdeque_reserve,
|
||||
vector,
|
||||
version,
|
||||
vfp2,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_abi::{BackendRepr, Float, Primitive};
|
||||
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi, Reg};
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
|
@ -6,7 +6,7 @@ use crate::spec::HasTargetSpec;
|
|||
// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
|
||||
|
||||
pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
let fixup = |a: &mut ArgAbi<'_, Ty>| {
|
||||
let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
|
||||
match a.layout.backend_repr {
|
||||
BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {}
|
||||
BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
|
||||
|
|
@ -23,11 +23,16 @@ pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
|
|||
// (probably what clang calls "illegal vectors").
|
||||
}
|
||||
BackendRepr::Scalar(scalar) => {
|
||||
// Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
|
||||
// with what LLVM expects.
|
||||
if a.layout.size.bytes() > 8
|
||||
if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
|
||||
// `i128` is returned in xmm0 by Clang and GCC
|
||||
// FIXME(#134288): This may change for the `-msvc` targets in the future.
|
||||
let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) };
|
||||
a.cast_to(reg);
|
||||
} else if a.layout.size.bytes() > 8
|
||||
&& !matches!(scalar.primitive(), Primitive::Float(Float::F128))
|
||||
{
|
||||
// Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
|
||||
// with what LLVM expects.
|
||||
a.make_indirect();
|
||||
} else {
|
||||
a.extend_integer_width_to(32);
|
||||
|
|
@ -37,8 +42,9 @@ pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
|
|||
};
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
fixup(&mut fn_abi.ret);
|
||||
fixup(&mut fn_abi.ret, true);
|
||||
}
|
||||
|
||||
for arg in fn_abi.args.iter_mut() {
|
||||
if arg.is_ignore() && arg.layout.is_zst() {
|
||||
// Windows ABIs do not talk about ZST since such types do not exist in MSVC.
|
||||
|
|
@ -49,7 +55,7 @@ pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
|
|||
arg.make_indirect_from_ignore();
|
||||
continue;
|
||||
}
|
||||
fixup(arg);
|
||||
fixup(arg, false);
|
||||
}
|
||||
// FIXME: We should likely also do something about ZST return types, similar to above.
|
||||
// However, that's non-trivial due to `()`.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ use rustc_span::{DUMMY_SP, Span};
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::{ObligationCause, ObligationCtxt};
|
||||
use crate::traits::query::normalize::QueryNormalizeExt;
|
||||
use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
|
||||
|
||||
/// This returns true if the type `ty` is "trivial" for
|
||||
/// dropck-outlives -- that is, if it doesn't require any types to
|
||||
|
|
@ -90,6 +91,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
pub fn compute_dropck_outlives_inner<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
|
||||
span: Span,
|
||||
) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
|
||||
let tcx = ocx.infcx.tcx;
|
||||
let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal;
|
||||
|
|
@ -135,7 +137,7 @@ pub fn compute_dropck_outlives_inner<'tcx>(
|
|||
// Set used to detect infinite recursion.
|
||||
let mut ty_set = FxHashSet::default();
|
||||
|
||||
let cause = ObligationCause::dummy();
|
||||
let cause = ObligationCause::dummy_with_span(span);
|
||||
let mut constraints = DropckConstraint::empty();
|
||||
while let Some((ty, depth)) = ty_stack.pop() {
|
||||
debug!(
|
||||
|
|
@ -171,18 +173,13 @@ pub fn compute_dropck_outlives_inner<'tcx>(
|
|||
// do not themselves define a destructor", more or less. We have
|
||||
// to push them onto the stack to be expanded.
|
||||
for ty in constraints.dtorck_types.drain(..) {
|
||||
let normalized_ty = ocx.normalize(&cause, param_env, ty);
|
||||
let Normalized { value: ty, obligations } =
|
||||
ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
|
||||
ocx.register_obligations(obligations);
|
||||
|
||||
let errors = ocx.select_where_possible();
|
||||
if !errors.is_empty() {
|
||||
debug!("failed to normalize dtorck type: {ty} ~> {errors:#?}");
|
||||
return Err(NoSolution);
|
||||
}
|
||||
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
|
||||
|
||||
let normalized_ty = ocx.infcx.resolve_vars_if_possible(normalized_ty);
|
||||
debug!("dropck_outlives: ty from dtorck_types = {:?}", normalized_ty);
|
||||
|
||||
match normalized_ty.kind() {
|
||||
match ty.kind() {
|
||||
// All parameters live for the duration of the
|
||||
// function.
|
||||
ty::Param(..) => {}
|
||||
|
|
@ -190,12 +187,12 @@ pub fn compute_dropck_outlives_inner<'tcx>(
|
|||
// A projection that we couldn't resolve - it
|
||||
// might have a destructor.
|
||||
ty::Alias(..) => {
|
||||
result.kinds.push(normalized_ty.into());
|
||||
result.kinds.push(ty.into());
|
||||
}
|
||||
|
||||
_ => {
|
||||
if ty_set.insert(normalized_ty) {
|
||||
ty_stack.push((normalized_ty, depth + 1));
|
||||
if ty_set.insert(ty) {
|
||||
ty_stack.push((ty, depth + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
type_op_ascribe_user_type_with_span(ocx, key, None)
|
||||
type_op_ascribe_user_type_with_span(ocx, key, span)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,11 +42,10 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
|
|||
pub fn type_op_ascribe_user_type_with_span<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
|
||||
span: Option<Span>,
|
||||
span: Span,
|
||||
) -> Result<(), NoSolution> {
|
||||
let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
|
||||
debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
|
||||
let span = span.unwrap_or(DUMMY_SP);
|
||||
match user_ty.kind {
|
||||
UserTypeKind::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
|
||||
UserTypeKind::TypeOf(def_id, user_args) => {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
|
|||
use rustc_middle::infer::canonical::CanonicalQueryResponse;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_type_ir::outlives::{Component, push_outlives_components};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
|
@ -45,11 +45,12 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
if ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
|
||||
compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty)
|
||||
compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty, span)
|
||||
} else {
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty)
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -58,13 +59,14 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
|
|||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
|
||||
let normalize_op = |ty| -> Result<_, NoSolution> {
|
||||
// We must normalize the type so we can compute the right outlives components.
|
||||
// for example, if we have some constrained param type like `T: Trait<Out = U>`,
|
||||
// and we know that `&'a T::Out` is WF, then we want to imply `U: 'a`.
|
||||
let ty = ocx
|
||||
.deeply_normalize(&ObligationCause::dummy(), param_env, ty)
|
||||
.deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty)
|
||||
.map_err(|_| NoSolution)?;
|
||||
if !ocx.select_all_or_error().is_empty() {
|
||||
return Err(NoSolution);
|
||||
|
|
@ -142,6 +144,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
|||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
|
||||
let tcx = ocx.infcx.tcx;
|
||||
|
||||
|
|
@ -171,8 +174,8 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
|||
// FIXME(@lcnr): It's not really "always fine", having fewer implied
|
||||
// bounds can be backward incompatible, e.g. #101951 was caused by
|
||||
// us not dealing with inference vars in `TypeOutlives` predicates.
|
||||
let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
|
||||
.unwrap_or_default();
|
||||
let obligations =
|
||||
wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, span).unwrap_or_default();
|
||||
|
||||
for obligation in obligations {
|
||||
debug!(?obligation);
|
||||
|
|
@ -255,7 +258,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
|||
// Need to manually normalize in the new solver as `wf::obligations` does not.
|
||||
if ocx.infcx.next_trait_solver() {
|
||||
ty_a = ocx
|
||||
.deeply_normalize(&ObligationCause::dummy(), param_env, ty_a)
|
||||
.deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty_a)
|
||||
.map_err(|_| NoSolution)?;
|
||||
}
|
||||
let mut components = smallvec![];
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution>;
|
||||
|
||||
fn fully_perform_into(
|
||||
|
|
@ -152,7 +153,7 @@ where
|
|||
if infcx.next_trait_solver() {
|
||||
return Ok(scrape_region_constraints(
|
||||
infcx,
|
||||
|ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self),
|
||||
|ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span),
|
||||
"query type op",
|
||||
span,
|
||||
)?
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use rustc_middle::traits::query::NoSolution;
|
|||
pub use rustc_middle::traits::query::type_op::Normalize;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
|
@ -29,9 +30,10 @@ where
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
// FIXME(-Znext-solver): shouldn't be using old normalizer
|
||||
Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value))
|
||||
Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
|
||||
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
|
@ -28,7 +29,8 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
compute_dropck_outlives_inner(ocx, key.param_env.and(key.value))
|
||||
compute_dropck_outlives_inner(ocx, key.param_env.and(key.value), span)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use rustc_middle::traits::ObligationCause;
|
|||
use rustc_middle::traits::query::NoSolution;
|
||||
pub use rustc_middle::traits::query::type_op::ProvePredicate;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
|
@ -57,10 +58,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
ocx.register_obligation(Obligation::new(
|
||||
ocx.infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
ObligationCause::dummy_with_span(span),
|
||||
key.param_env,
|
||||
key.value.predicate,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
|
||||
use rustc_middle::ty::{self, GenericArgs, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::dropck_outlives::{
|
||||
compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner,
|
||||
|
|
@ -24,7 +25,7 @@ fn dropck_outlives<'tcx>(
|
|||
debug!("dropck_outlives(goal={:#?})", canonical_goal);
|
||||
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| {
|
||||
compute_dropck_outlives_inner(ocx, goal)
|
||||
compute_dropck_outlives_inner(ocx, goal, DUMMY_SP)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use rustc_infer::traits::query::OutlivesBound;
|
|||
use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{
|
||||
compute_implied_outlives_bounds_compat_inner, compute_implied_outlives_bounds_inner,
|
||||
|
|
@ -28,7 +29,7 @@ fn implied_outlives_bounds_compat<'tcx>(
|
|||
> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
|
||||
let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts();
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty)
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty, DUMMY_SP)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +42,6 @@ fn implied_outlives_bounds<'tcx>(
|
|||
> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
|
||||
let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts();
|
||||
compute_implied_outlives_bounds_inner(ocx, param_env, ty)
|
||||
compute_implied_outlives_bounds_inner(ocx, param_env, ty, DUMMY_SP)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@ use rustc_infer::infer::canonical::{Canonical, CanonicalQueryInput, QueryRespons
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::{Clause, FnSig, ParamEnvAnd, PolyFnSig, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
|
||||
use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
|
||||
AscribeUserType, type_op_ascribe_user_type_with_span,
|
||||
};
|
||||
use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
|
||||
use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
|
||||
|
||||
pub(crate) fn provide(p: &mut Providers) {
|
||||
*p = Providers {
|
||||
|
|
@ -30,7 +32,7 @@ fn type_op_ascribe_user_type<'tcx>(
|
|||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
|
||||
type_op_ascribe_user_type_with_span(ocx, key, None)
|
||||
type_op_ascribe_user_type_with_span(ocx, key, DUMMY_SP)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +44,10 @@ where
|
|||
T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let (param_env, Normalize { value }) = key.into_parts();
|
||||
Ok(ocx.normalize(&ObligationCause::dummy(), param_env, value))
|
||||
let Normalized { value, obligations } =
|
||||
ocx.infcx.at(&ObligationCause::dummy(), param_env).query_normalize(value)?;
|
||||
ocx.register_obligations(obligations);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn type_op_normalize_ty<'tcx>(
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ pub enum Rvalue {
|
|||
///
|
||||
/// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
|
||||
/// `&raw v` or `addr_of!(v)`.
|
||||
AddressOf(Mutability, Place),
|
||||
AddressOf(RawPtrKind, Place),
|
||||
|
||||
/// Creates an aggregate value, like a tuple or struct.
|
||||
///
|
||||
|
|
@ -577,7 +577,7 @@ impl Rvalue {
|
|||
}
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
let place_ty = place.ty(locals)?;
|
||||
Ok(Ty::new_ptr(place_ty, *mutability))
|
||||
Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
|
||||
}
|
||||
Rvalue::Len(..) => Ok(Ty::usize_ty()),
|
||||
Rvalue::Cast(.., ty) => Ok(*ty),
|
||||
|
|
@ -903,6 +903,24 @@ impl BorrowKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum RawPtrKind {
|
||||
Mut,
|
||||
Const,
|
||||
FakeForPtrMetadata,
|
||||
}
|
||||
|
||||
impl RawPtrKind {
|
||||
pub fn to_mutable_lossy(self) -> Mutability {
|
||||
match self {
|
||||
RawPtrKind::Mut { .. } => Mutability::Mut,
|
||||
RawPtrKind::Const => Mutability::Not,
|
||||
// FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation.
|
||||
RawPtrKind::FakeForPtrMetadata => Mutability::Not,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum MutBorrowKind {
|
||||
Default,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ use std::{fmt, io, iter};
|
|||
use fmt::{Display, Formatter};
|
||||
|
||||
use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind};
|
||||
use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents};
|
||||
use crate::mir::{
|
||||
Operand, Place, RawPtrKind, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents,
|
||||
};
|
||||
use crate::ty::{AdtKind, IndexedVal, MirConst, Ty, TyConst};
|
||||
use crate::{Body, CrateDef, Mutability, with};
|
||||
|
||||
|
|
@ -325,7 +327,7 @@ fn pretty_ty_const(ct: &TyConst) -> String {
|
|||
fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
||||
match rval {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
write!(writer, "&raw {} {:?}", pretty_mut(*mutability), place)
|
||||
write!(writer, "&raw {} {:?}", pretty_raw_ptr_kind(*mutability), place)
|
||||
}
|
||||
Rvalue::Aggregate(aggregate_kind, operands) => {
|
||||
// FIXME: Add pretty_aggregate function that returns a pretty string
|
||||
|
|
@ -437,3 +439,11 @@ fn pretty_mut(mutability: Mutability) -> &'static str {
|
|||
Mutability::Mut => "mut ",
|
||||
}
|
||||
}
|
||||
|
||||
fn pretty_raw_ptr_kind(kind: RawPtrKind) -> &'static str {
|
||||
match kind {
|
||||
RawPtrKind::Const => "const",
|
||||
RawPtrKind::Mut => "mut",
|
||||
RawPtrKind::FakeForPtrMetadata => "const (fake)",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ pub trait MirVisitor {
|
|||
fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
|
||||
match rvalue {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
let pcx = PlaceContext { is_mut: *mutability == Mutability::Mut };
|
||||
let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
|
||||
self.visit_place(place, pcx, location);
|
||||
}
|
||||
Rvalue::Aggregate(_, operands) => {
|
||||
|
|
|
|||
|
|
@ -1115,6 +1115,8 @@ impl<T: ?Sized> Box<T> {
|
|||
/// memory problems. For example, a double-free may occur if the
|
||||
/// function is called twice on the same `NonNull` pointer.
|
||||
///
|
||||
/// The non-null pointer must point to a block of memory allocated by the global allocator.
|
||||
///
|
||||
/// The safety conditions are described in the [memory layout] section.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -1170,7 +1172,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
|||
/// memory problems. For example, a double-free may occur if the
|
||||
/// function is called twice on the same raw pointer.
|
||||
///
|
||||
/// The raw pointer must point to a block of memory allocated by `alloc`
|
||||
/// The raw pointer must point to a block of memory allocated by `alloc`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1225,6 +1227,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
|||
/// memory problems. For example, a double-free may occur if the
|
||||
/// function is called twice on the same raw pointer.
|
||||
///
|
||||
/// The non-null pointer must point to a block of memory allocated by `alloc`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl<K, V> Root<K, V> {
|
|||
/// a `BTreeMap`, both iterators should produce keys in strictly ascending
|
||||
/// order, each greater than all keys in the tree, including any keys
|
||||
/// already in the tree upon entry.
|
||||
pub fn append_from_sorted_iters<I, A: Allocator + Clone>(
|
||||
pub(super) fn append_from_sorted_iters<I, A: Allocator + Clone>(
|
||||
&mut self,
|
||||
left: I,
|
||||
right: I,
|
||||
|
|
@ -36,8 +36,12 @@ impl<K, V> Root<K, V> {
|
|||
/// Pushes all key-value pairs to the end of the tree, incrementing a
|
||||
/// `length` variable along the way. The latter makes it easier for the
|
||||
/// caller to avoid a leak when the iterator panicks.
|
||||
pub fn bulk_push<I, A: Allocator + Clone>(&mut self, iter: I, length: &mut usize, alloc: A)
|
||||
where
|
||||
pub(super) fn bulk_push<I, A: Allocator + Clone>(
|
||||
&mut self,
|
||||
iter: I,
|
||||
length: &mut usize,
|
||||
alloc: A,
|
||||
) where
|
||||
I: Iterator<Item = (K, V)>,
|
||||
{
|
||||
let mut cur_node = self.borrow_mut().last_leaf_edge().into_node();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use core::ptr::NonNull;
|
|||
/// the compiler to follow. A `DormantMutRef` allows you to check borrowing
|
||||
/// yourself, while still expressing its stacked nature, and encapsulating
|
||||
/// the raw pointer code needed to do this without undefined behavior.
|
||||
pub struct DormantMutRef<'a, T> {
|
||||
pub(super) struct DormantMutRef<'a, T> {
|
||||
ptr: NonNull<T>,
|
||||
_marker: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ impl<'a, T> DormantMutRef<'a, T> {
|
|||
/// Capture a unique borrow, and immediately reborrow it. For the compiler,
|
||||
/// the lifetime of the new reference is the same as the lifetime of the
|
||||
/// original reference, but you promise to use it for a shorter period.
|
||||
pub fn new(t: &'a mut T) -> (&'a mut T, Self) {
|
||||
pub(super) fn new(t: &'a mut T) -> (&'a mut T, Self) {
|
||||
let ptr = NonNull::from(t);
|
||||
// SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose
|
||||
// only this reference, so it is unique.
|
||||
|
|
@ -37,7 +37,7 @@ impl<'a, T> DormantMutRef<'a, T> {
|
|||
///
|
||||
/// The reborrow must have ended, i.e., the reference returned by `new` and
|
||||
/// all pointers and references derived from it, must not be used anymore.
|
||||
pub unsafe fn awaken(self) -> &'a mut T {
|
||||
pub(super) unsafe fn awaken(self) -> &'a mut T {
|
||||
// SAFETY: our own safety conditions imply this reference is again unique.
|
||||
unsafe { &mut *self.ptr.as_ptr() }
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ impl<'a, T> DormantMutRef<'a, T> {
|
|||
///
|
||||
/// The reborrow must have ended, i.e., the reference returned by `new` and
|
||||
/// all pointers and references derived from it, must not be used anymore.
|
||||
pub unsafe fn reborrow(&mut self) -> &'a mut T {
|
||||
pub(super) unsafe fn reborrow(&mut self) -> &'a mut T {
|
||||
// SAFETY: our own safety conditions imply this reference is again unique.
|
||||
unsafe { &mut *self.ptr.as_ptr() }
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ impl<'a, T> DormantMutRef<'a, T> {
|
|||
///
|
||||
/// The reborrow must have ended, i.e., the reference returned by `new` and
|
||||
/// all pointers and references derived from it, must not be used anymore.
|
||||
pub unsafe fn reborrow_shared(&self) -> &'a T {
|
||||
pub(super) unsafe fn reborrow_shared(&self) -> &'a T {
|
||||
// SAFETY: our own safety conditions imply this reference is again unique.
|
||||
unsafe { &*self.ptr.as_ptr() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use core::iter::Peekable;
|
|||
/// Used by [`BTreeMap::bulk_build_from_sorted_iter`][1].
|
||||
///
|
||||
/// [1]: crate::collections::BTreeMap::bulk_build_from_sorted_iter
|
||||
pub struct DedupSortedIter<K, V, I>
|
||||
pub(super) struct DedupSortedIter<K, V, I>
|
||||
where
|
||||
I: Iterator<Item = (K, V)>,
|
||||
{
|
||||
|
|
@ -17,7 +17,7 @@ impl<K, V, I> DedupSortedIter<K, V, I>
|
|||
where
|
||||
I: Iterator<Item = (K, V)>,
|
||||
{
|
||||
pub fn new(iter: I) -> Self {
|
||||
pub(super) fn new(iter: I) -> Self {
|
||||
Self { iter: iter.peekable() }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,10 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
|||
///
|
||||
/// This method does not expect ancestors to already be underfull upon entry
|
||||
/// and panics if it encounters an empty ancestor.
|
||||
pub fn fix_node_and_affected_ancestors<A: Allocator + Clone>(mut self, alloc: A) -> bool {
|
||||
pub(super) fn fix_node_and_affected_ancestors<A: Allocator + Clone>(
|
||||
mut self,
|
||||
alloc: A,
|
||||
) -> bool {
|
||||
loop {
|
||||
match self.fix_node_through_parent(alloc.clone()) {
|
||||
Ok(Some(parent)) => self = parent.forget_type(),
|
||||
|
|
@ -70,7 +73,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
|||
|
||||
impl<K, V> Root<K, V> {
|
||||
/// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty.
|
||||
pub fn fix_top<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
pub(super) fn fix_top<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
while self.height() > 0 && self.len() == 0 {
|
||||
self.pop_internal_level(alloc.clone());
|
||||
}
|
||||
|
|
@ -79,7 +82,7 @@ impl<K, V> Root<K, V> {
|
|||
/// Stocks up or merge away any underfull nodes on the right border of the
|
||||
/// tree. The other nodes, those that are not the root nor a rightmost edge,
|
||||
/// must already have at least MIN_LEN elements.
|
||||
pub fn fix_right_border<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
pub(super) fn fix_right_border<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
self.fix_top(alloc.clone());
|
||||
if self.len() > 0 {
|
||||
self.borrow_mut().last_kv().fix_right_border_of_right_edge(alloc.clone());
|
||||
|
|
@ -88,7 +91,7 @@ impl<K, V> Root<K, V> {
|
|||
}
|
||||
|
||||
/// The symmetric clone of `fix_right_border`.
|
||||
pub fn fix_left_border<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
pub(super) fn fix_left_border<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
self.fix_top(alloc.clone());
|
||||
if self.len() > 0 {
|
||||
self.borrow_mut().first_kv().fix_left_border_of_left_edge(alloc.clone());
|
||||
|
|
@ -99,7 +102,7 @@ impl<K, V> Root<K, V> {
|
|||
/// Stocks up any underfull nodes on the right border of the tree.
|
||||
/// The other nodes, those that are neither the root nor a rightmost edge,
|
||||
/// must be prepared to have up to MIN_LEN elements stolen.
|
||||
pub fn fix_right_border_of_plentiful(&mut self) {
|
||||
pub(super) fn fix_right_border_of_plentiful(&mut self) {
|
||||
let mut cur_node = self.borrow_mut();
|
||||
while let Internal(internal) = cur_node.force() {
|
||||
// Check if rightmost child is underfull.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use core::{intrinsics, mem, ptr};
|
|||
/// If a panic occurs in the `change` closure, the entire process will be aborted.
|
||||
#[allow(dead_code)] // keep as illustration and for future use
|
||||
#[inline]
|
||||
pub fn take_mut<T>(v: &mut T, change: impl FnOnce(T) -> T) {
|
||||
pub(super) fn take_mut<T>(v: &mut T, change: impl FnOnce(T) -> T) {
|
||||
replace(v, |value| (change(value), ()))
|
||||
}
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ pub fn take_mut<T>(v: &mut T, change: impl FnOnce(T) -> T) {
|
|||
///
|
||||
/// If a panic occurs in the `change` closure, the entire process will be aborted.
|
||||
#[inline]
|
||||
pub fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
|
||||
pub(super) fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
|
||||
struct PanicGuard;
|
||||
impl Drop for PanicGuard {
|
||||
fn drop(&mut self) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use core::iter::FusedIterator;
|
|||
|
||||
/// Core of an iterator that merges the output of two strictly ascending iterators,
|
||||
/// for instance a union or a symmetric difference.
|
||||
pub struct MergeIterInner<I: Iterator> {
|
||||
pub(super) struct MergeIterInner<I: Iterator> {
|
||||
a: I,
|
||||
b: I,
|
||||
peeked: Option<Peeked<I>>,
|
||||
|
|
@ -40,7 +40,7 @@ where
|
|||
|
||||
impl<I: Iterator> MergeIterInner<I> {
|
||||
/// Creates a new core for an iterator merging a pair of sources.
|
||||
pub fn new(a: I, b: I) -> Self {
|
||||
pub(super) fn new(a: I, b: I) -> Self {
|
||||
MergeIterInner { a, b, peeked: None }
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ impl<I: Iterator> MergeIterInner<I> {
|
|||
/// the sources are not strictly ascending). If neither returned option
|
||||
/// contains a value, iteration has finished and subsequent calls will
|
||||
/// return the same empty pair.
|
||||
pub fn nexts<Cmp: Fn(&I::Item, &I::Item) -> Ordering>(
|
||||
pub(super) fn nexts<Cmp: Fn(&I::Item, &I::Item) -> Ordering>(
|
||||
&mut self,
|
||||
cmp: Cmp,
|
||||
) -> (Option<I::Item>, Option<I::Item>)
|
||||
|
|
@ -85,7 +85,7 @@ impl<I: Iterator> MergeIterInner<I> {
|
|||
}
|
||||
|
||||
/// Returns a pair of upper bounds for the `size_hint` of the final iterator.
|
||||
pub fn lens(&self) -> (usize, usize)
|
||||
pub(super) fn lens(&self) -> (usize, usize)
|
||||
where
|
||||
I: ExactSizeIterator,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ mod append;
|
|||
mod borrow;
|
||||
mod dedup_sorted_iter;
|
||||
mod fix;
|
||||
pub mod map;
|
||||
pub(super) mod map;
|
||||
mod mem;
|
||||
mod merge_iter;
|
||||
mod navigate;
|
||||
mod node;
|
||||
mod remove;
|
||||
mod search;
|
||||
pub mod set;
|
||||
pub(super) mod set;
|
||||
mod set_val;
|
||||
mod split;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use super::node::{Handle, NodeRef, marker};
|
|||
use super::search::SearchBound;
|
||||
use crate::alloc::Allocator;
|
||||
// `front` and `back` are always both `None` or both `Some`.
|
||||
pub struct LeafRange<BorrowType, K, V> {
|
||||
pub(super) struct LeafRange<BorrowType, K, V> {
|
||||
front: Option<Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>>,
|
||||
back: Option<Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>>,
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ impl<B, K, V> Default for LeafRange<B, K, V> {
|
|||
}
|
||||
|
||||
impl<BorrowType, K, V> LeafRange<BorrowType, K, V> {
|
||||
pub fn none() -> Self {
|
||||
pub(super) fn none() -> Self {
|
||||
LeafRange { front: None, back: None }
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ impl<BorrowType, K, V> LeafRange<BorrowType, K, V> {
|
|||
}
|
||||
|
||||
/// Temporarily takes out another, immutable equivalent of the same range.
|
||||
pub fn reborrow(&self) -> LeafRange<marker::Immut<'_>, K, V> {
|
||||
pub(super) fn reborrow(&self) -> LeafRange<marker::Immut<'_>, K, V> {
|
||||
LeafRange {
|
||||
front: self.front.as_ref().map(|f| f.reborrow()),
|
||||
back: self.back.as_ref().map(|b| b.reborrow()),
|
||||
|
|
@ -44,24 +44,24 @@ impl<BorrowType, K, V> LeafRange<BorrowType, K, V> {
|
|||
|
||||
impl<'a, K, V> LeafRange<marker::Immut<'a>, K, V> {
|
||||
#[inline]
|
||||
pub fn next_checked(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
pub(super) fn next_checked(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
self.perform_next_checked(|kv| kv.into_kv())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
pub(super) fn next_back_checked(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
self.perform_next_back_checked(|kv| kv.into_kv())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> LeafRange<marker::ValMut<'a>, K, V> {
|
||||
#[inline]
|
||||
pub fn next_checked(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
pub(super) fn next_checked(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
self.perform_next_checked(|kv| unsafe { ptr::read(kv) }.into_kv_valmut())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
pub(super) fn next_back_checked(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
self.perform_next_back_checked(|kv| unsafe { ptr::read(kv) }.into_kv_valmut())
|
||||
}
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ impl<BorrowType, K, V> LazyLeafHandle<BorrowType, K, V> {
|
|||
}
|
||||
|
||||
// `front` and `back` are always both `None` or both `Some`.
|
||||
pub struct LazyLeafRange<BorrowType, K, V> {
|
||||
pub(super) struct LazyLeafRange<BorrowType, K, V> {
|
||||
front: Option<LazyLeafHandle<BorrowType, K, V>>,
|
||||
back: Option<LazyLeafHandle<BorrowType, K, V>>,
|
||||
}
|
||||
|
|
@ -142,12 +142,12 @@ impl<'a, K: 'a, V: 'a> Clone for LazyLeafRange<marker::Immut<'a>, K, V> {
|
|||
}
|
||||
|
||||
impl<BorrowType, K, V> LazyLeafRange<BorrowType, K, V> {
|
||||
pub fn none() -> Self {
|
||||
pub(super) fn none() -> Self {
|
||||
LazyLeafRange { front: None, back: None }
|
||||
}
|
||||
|
||||
/// Temporarily takes out another, immutable equivalent of the same range.
|
||||
pub fn reborrow(&self) -> LazyLeafRange<marker::Immut<'_>, K, V> {
|
||||
pub(super) fn reborrow(&self) -> LazyLeafRange<marker::Immut<'_>, K, V> {
|
||||
LazyLeafRange {
|
||||
front: self.front.as_ref().map(|f| f.reborrow()),
|
||||
back: self.back.as_ref().map(|b| b.reborrow()),
|
||||
|
|
@ -157,24 +157,24 @@ impl<BorrowType, K, V> LazyLeafRange<BorrowType, K, V> {
|
|||
|
||||
impl<'a, K, V> LazyLeafRange<marker::Immut<'a>, K, V> {
|
||||
#[inline]
|
||||
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
|
||||
pub(super) unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
|
||||
unsafe { self.init_front().unwrap().next_unchecked() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
|
||||
pub(super) unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
|
||||
unsafe { self.init_back().unwrap().next_back_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> LazyLeafRange<marker::ValMut<'a>, K, V> {
|
||||
#[inline]
|
||||
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
pub(super) unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
unsafe { self.init_front().unwrap().next_unchecked() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
pub(super) unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
unsafe { self.init_back().unwrap().next_back_unchecked() }
|
||||
}
|
||||
}
|
||||
|
|
@ -190,7 +190,7 @@ impl<K, V> LazyLeafRange<marker::Dying, K, V> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn deallocating_next_unchecked<A: Allocator + Clone>(
|
||||
pub(super) unsafe fn deallocating_next_unchecked<A: Allocator + Clone>(
|
||||
&mut self,
|
||||
alloc: A,
|
||||
) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> {
|
||||
|
|
@ -200,7 +200,7 @@ impl<K, V> LazyLeafRange<marker::Dying, K, V> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn deallocating_next_back_unchecked<A: Allocator + Clone>(
|
||||
pub(super) unsafe fn deallocating_next_back_unchecked<A: Allocator + Clone>(
|
||||
&mut self,
|
||||
alloc: A,
|
||||
) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> {
|
||||
|
|
@ -210,7 +210,7 @@ impl<K, V> LazyLeafRange<marker::Dying, K, V> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn deallocating_end<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
pub(super) fn deallocating_end<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
if let Some(front) = self.take_front() {
|
||||
front.deallocating_end(alloc)
|
||||
}
|
||||
|
|
@ -313,7 +313,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
|
|||
///
|
||||
/// The result is meaningful only if the tree is ordered by key, like the tree
|
||||
/// in a `BTreeMap` is.
|
||||
pub fn range_search<Q, R>(self, range: R) -> LeafRange<marker::Immut<'a>, K, V>
|
||||
pub(super) fn range_search<Q, R>(self, range: R) -> LeafRange<marker::Immut<'a>, K, V>
|
||||
where
|
||||
Q: ?Sized + Ord,
|
||||
K: Borrow<Q>,
|
||||
|
|
@ -324,7 +324,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
|
|||
}
|
||||
|
||||
/// Finds the pair of leaf edges delimiting an entire tree.
|
||||
pub fn full_range(self) -> LazyLeafRange<marker::Immut<'a>, K, V> {
|
||||
pub(super) fn full_range(self) -> LazyLeafRange<marker::Immut<'a>, K, V> {
|
||||
full_range(self, self)
|
||||
}
|
||||
}
|
||||
|
|
@ -339,7 +339,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::ValMut<'a>, K, V, marker::LeafOrInternal>
|
|||
///
|
||||
/// # Safety
|
||||
/// Do not use the duplicate handles to visit the same KV twice.
|
||||
pub fn range_search<Q, R>(self, range: R) -> LeafRange<marker::ValMut<'a>, K, V>
|
||||
pub(super) fn range_search<Q, R>(self, range: R) -> LeafRange<marker::ValMut<'a>, K, V>
|
||||
where
|
||||
Q: ?Sized + Ord,
|
||||
K: Borrow<Q>,
|
||||
|
|
@ -351,7 +351,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::ValMut<'a>, K, V, marker::LeafOrInternal>
|
|||
/// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree.
|
||||
/// The results are non-unique references allowing mutation (of values only), so must be used
|
||||
/// with care.
|
||||
pub fn full_range(self) -> LazyLeafRange<marker::ValMut<'a>, K, V> {
|
||||
pub(super) fn full_range(self) -> LazyLeafRange<marker::ValMut<'a>, K, V> {
|
||||
// We duplicate the root NodeRef here -- we will never visit the same KV
|
||||
// twice, and never end up with overlapping value references.
|
||||
let self2 = unsafe { ptr::read(&self) };
|
||||
|
|
@ -363,7 +363,7 @@ impl<K, V> NodeRef<marker::Dying, K, V, marker::LeafOrInternal> {
|
|||
/// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree.
|
||||
/// The results are non-unique references allowing massively destructive mutation, so must be
|
||||
/// used with the utmost care.
|
||||
pub fn full_range(self) -> LazyLeafRange<marker::Dying, K, V> {
|
||||
pub(super) fn full_range(self) -> LazyLeafRange<marker::Dying, K, V> {
|
||||
// We duplicate the root NodeRef here -- we will never access it in a way
|
||||
// that overlaps references obtained from the root.
|
||||
let self2 = unsafe { ptr::read(&self) };
|
||||
|
|
@ -377,7 +377,7 @@ impl<BorrowType: marker::BorrowType, K, V>
|
|||
/// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
|
||||
/// on the right side, which is either in the same leaf node or in an ancestor node.
|
||||
/// If the leaf edge is the last one in the tree, returns [`Result::Err`] with the root node.
|
||||
pub fn next_kv(
|
||||
pub(super) fn next_kv(
|
||||
self,
|
||||
) -> Result<
|
||||
Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
|
||||
|
|
@ -398,7 +398,7 @@ impl<BorrowType: marker::BorrowType, K, V>
|
|||
/// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
|
||||
/// on the left side, which is either in the same leaf node or in an ancestor node.
|
||||
/// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node.
|
||||
pub fn next_back_kv(
|
||||
pub(super) fn next_back_kv(
|
||||
self,
|
||||
) -> Result<
|
||||
Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
|
||||
|
|
@ -627,7 +627,9 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
|
|||
/// Returns the leftmost leaf edge in or underneath a node - in other words, the edge
|
||||
/// you need first when navigating forward (or last when navigating backward).
|
||||
#[inline]
|
||||
pub fn first_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
pub(super) fn first_leaf_edge(
|
||||
self,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
let mut node = self;
|
||||
loop {
|
||||
match node.force() {
|
||||
|
|
@ -640,7 +642,9 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
|
|||
/// Returns the rightmost leaf edge in or underneath a node - in other words, the edge
|
||||
/// you need last when navigating forward (or first when navigating backward).
|
||||
#[inline]
|
||||
pub fn last_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
pub(super) fn last_leaf_edge(
|
||||
self,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
let mut node = self;
|
||||
loop {
|
||||
match node.force() {
|
||||
|
|
@ -651,7 +655,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Position<BorrowType, K, V> {
|
||||
pub(super) enum Position<BorrowType, K, V> {
|
||||
Leaf(NodeRef<BorrowType, K, V, marker::Leaf>),
|
||||
Internal(NodeRef<BorrowType, K, V, marker::Internal>),
|
||||
InternalKV,
|
||||
|
|
@ -661,7 +665,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
|
|||
/// Visits leaf nodes and internal KVs in order of ascending keys, and also
|
||||
/// visits internal nodes as a whole in a depth first order, meaning that
|
||||
/// internal nodes precede their individual KVs and their child nodes.
|
||||
pub fn visit_nodes_in_order<F>(self, mut visit: F)
|
||||
pub(super) fn visit_nodes_in_order<F>(self, mut visit: F)
|
||||
where
|
||||
F: FnMut(Position<marker::Immut<'a>, K, V>),
|
||||
{
|
||||
|
|
@ -693,7 +697,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
|
|||
}
|
||||
|
||||
/// Calculates the number of elements in a (sub)tree.
|
||||
pub fn calc_length(self) -> usize {
|
||||
pub(super) fn calc_length(self) -> usize {
|
||||
let mut result = 0;
|
||||
self.visit_nodes_in_order(|pos| match pos {
|
||||
Position::Leaf(node) => result += node.len(),
|
||||
|
|
@ -708,7 +712,9 @@ impl<BorrowType: marker::BorrowType, K, V>
|
|||
Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>
|
||||
{
|
||||
/// Returns the leaf edge closest to a KV for forward navigation.
|
||||
pub fn next_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
pub(super) fn next_leaf_edge(
|
||||
self,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
match self.force() {
|
||||
Leaf(leaf_kv) => leaf_kv.right_edge(),
|
||||
Internal(internal_kv) => {
|
||||
|
|
@ -719,7 +725,7 @@ impl<BorrowType: marker::BorrowType, K, V>
|
|||
}
|
||||
|
||||
/// Returns the leaf edge closest to a KV for backward navigation.
|
||||
pub fn next_back_leaf_edge(
|
||||
pub(super) fn next_back_leaf_edge(
|
||||
self,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
match self.force() {
|
||||
|
|
@ -735,7 +741,7 @@ impl<BorrowType: marker::BorrowType, K, V>
|
|||
impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
/// Returns the leaf edge corresponding to the first point at which the
|
||||
/// given bound is true.
|
||||
pub fn lower_bound<Q: ?Sized>(
|
||||
pub(super) fn lower_bound<Q: ?Sized>(
|
||||
self,
|
||||
mut bound: SearchBound<&Q>,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>
|
||||
|
|
@ -758,7 +764,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
|
|||
|
||||
/// Returns the leaf edge corresponding to the last point at which the
|
||||
/// given bound is true.
|
||||
pub fn upper_bound<Q: ?Sized>(
|
||||
pub(super) fn upper_bound<Q: ?Sized>(
|
||||
self,
|
||||
mut bound: SearchBound<&Q>,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ use crate::alloc::{Allocator, Layout};
|
|||
use crate::boxed::Box;
|
||||
|
||||
const B: usize = 6;
|
||||
pub const CAPACITY: usize = 2 * B - 1;
|
||||
pub const MIN_LEN_AFTER_SPLIT: usize = B - 1;
|
||||
pub(super) const CAPACITY: usize = 2 * B - 1;
|
||||
pub(super) const MIN_LEN_AFTER_SPLIT: usize = B - 1;
|
||||
const KV_IDX_CENTER: usize = B - 1;
|
||||
const EDGE_IDX_LEFT_OF_CENTER: usize = B - 1;
|
||||
const EDGE_IDX_RIGHT_OF_CENTER: usize = B;
|
||||
|
|
@ -179,7 +179,7 @@ type BoxedNode<K, V> = NonNull<LeafNode<K, V>>;
|
|||
/// as the returned reference is used.
|
||||
/// The methods supporting insert bend this rule by returning a raw pointer,
|
||||
/// i.e., a reference without any lifetime.
|
||||
pub struct NodeRef<BorrowType, K, V, Type> {
|
||||
pub(super) struct NodeRef<BorrowType, K, V, Type> {
|
||||
/// The number of levels that the node and the level of leaves are apart, a
|
||||
/// constant of the node that cannot be entirely described by `Type`, and that
|
||||
/// the node itself does not store. We only need to store the height of the root
|
||||
|
|
@ -195,7 +195,7 @@ pub struct NodeRef<BorrowType, K, V, Type> {
|
|||
/// The root node of an owned tree.
|
||||
///
|
||||
/// Note that this does not have a destructor, and must be cleaned up manually.
|
||||
pub type Root<K, V> = NodeRef<marker::Owned, K, V, marker::LeafOrInternal>;
|
||||
pub(super) type Root<K, V> = NodeRef<marker::Owned, K, V, marker::LeafOrInternal>;
|
||||
|
||||
impl<'a, K: 'a, V: 'a, Type> Copy for NodeRef<marker::Immut<'a>, K, V, Type> {}
|
||||
impl<'a, K: 'a, V: 'a, Type> Clone for NodeRef<marker::Immut<'a>, K, V, Type> {
|
||||
|
|
@ -213,7 +213,7 @@ unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Owned, K, V, Type>
|
|||
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Dying, K, V, Type> {}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
|
||||
pub fn new_leaf<A: Allocator + Clone>(alloc: A) -> Self {
|
||||
pub(super) fn new_leaf<A: Allocator + Clone>(alloc: A) -> Self {
|
||||
Self::from_new_leaf(LeafNode::new(alloc))
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
|||
/// The number of edges is `len() + 1`.
|
||||
/// Note that, despite being safe, calling this function can have the side effect
|
||||
/// of invalidating mutable references that unsafe code has created.
|
||||
pub fn len(&self) -> usize {
|
||||
pub(super) fn len(&self) -> usize {
|
||||
// Crucially, we only access the `len` field here. If BorrowType is marker::ValMut,
|
||||
// there might be outstanding mutable references to values that we must not invalidate.
|
||||
unsafe { usize::from((*Self::as_leaf_ptr(self)).len) }
|
||||
|
|
@ -285,12 +285,12 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
|||
/// root on top, the number says at which elevation the node appears.
|
||||
/// If you picture trees with leaves on top, the number says how high
|
||||
/// the tree extends above the node.
|
||||
pub fn height(&self) -> usize {
|
||||
pub(super) fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
/// Temporarily takes out another, immutable reference to the same node.
|
||||
pub fn reborrow(&self) -> NodeRef<marker::Immut<'_>, K, V, Type> {
|
||||
pub(super) fn reborrow(&self) -> NodeRef<marker::Immut<'_>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +315,7 @@ impl<BorrowType: marker::BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type>
|
|||
///
|
||||
/// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should
|
||||
/// both, upon success, do nothing.
|
||||
pub fn ascend(
|
||||
pub(super) fn ascend(
|
||||
self,
|
||||
) -> Result<Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge>, Self> {
|
||||
const {
|
||||
|
|
@ -335,24 +335,24 @@ impl<BorrowType: marker::BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type>
|
|||
.ok_or(self)
|
||||
}
|
||||
|
||||
pub fn first_edge(self) -> Handle<Self, marker::Edge> {
|
||||
pub(super) fn first_edge(self) -> Handle<Self, marker::Edge> {
|
||||
unsafe { Handle::new_edge(self, 0) }
|
||||
}
|
||||
|
||||
pub fn last_edge(self) -> Handle<Self, marker::Edge> {
|
||||
pub(super) fn last_edge(self) -> Handle<Self, marker::Edge> {
|
||||
let len = self.len();
|
||||
unsafe { Handle::new_edge(self, len) }
|
||||
}
|
||||
|
||||
/// Note that `self` must be nonempty.
|
||||
pub fn first_kv(self) -> Handle<Self, marker::KV> {
|
||||
pub(super) fn first_kv(self) -> Handle<Self, marker::KV> {
|
||||
let len = self.len();
|
||||
assert!(len > 0);
|
||||
unsafe { Handle::new_kv(self, 0) }
|
||||
}
|
||||
|
||||
/// Note that `self` must be nonempty.
|
||||
pub fn last_kv(self) -> Handle<Self, marker::KV> {
|
||||
pub(super) fn last_kv(self) -> Handle<Self, marker::KV> {
|
||||
let len = self.len();
|
||||
assert!(len > 0);
|
||||
unsafe { Handle::new_kv(self, len - 1) }
|
||||
|
|
@ -381,7 +381,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
|
|||
}
|
||||
|
||||
/// Borrows a view into the keys stored in the node.
|
||||
pub fn keys(&self) -> &[K] {
|
||||
pub(super) fn keys(&self) -> &[K] {
|
||||
let leaf = self.into_leaf();
|
||||
unsafe { leaf.keys.get_unchecked(..usize::from(leaf.len)).assume_init_ref() }
|
||||
}
|
||||
|
|
@ -391,7 +391,7 @@ impl<K, V> NodeRef<marker::Dying, K, V, marker::LeafOrInternal> {
|
|||
/// Similar to `ascend`, gets a reference to a node's parent node, but also
|
||||
/// deallocates the current node in the process. This is unsafe because the
|
||||
/// current node will still be accessible despite being deallocated.
|
||||
pub unsafe fn deallocate_and_ascend<A: Allocator + Clone>(
|
||||
pub(super) unsafe fn deallocate_and_ascend<A: Allocator + Clone>(
|
||||
self,
|
||||
alloc: A,
|
||||
) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::Internal>, marker::Edge>> {
|
||||
|
|
@ -443,7 +443,7 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
|||
|
||||
/// Returns a dormant copy of this node with its lifetime erased which can
|
||||
/// be reawakened later.
|
||||
pub fn dormant(&self) -> NodeRef<marker::DormantMut, K, V, Type> {
|
||||
pub(super) fn dormant(&self) -> NodeRef<marker::DormantMut, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
|
@ -455,7 +455,7 @@ impl<K, V, Type> NodeRef<marker::DormantMut, K, V, Type> {
|
|||
///
|
||||
/// The reborrow must have ended, i.e., the reference returned by `new` and
|
||||
/// all pointers and references derived from it, must not be used anymore.
|
||||
pub unsafe fn awaken<'a>(self) -> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||
pub(super) unsafe fn awaken<'a>(self) -> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
|
@ -536,7 +536,7 @@ impl<'a, K, V, Type> NodeRef<marker::ValMut<'a>, K, V, Type> {
|
|||
|
||||
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||
/// Borrows exclusive access to the length of the node.
|
||||
pub fn len_mut(&mut self) -> &mut u16 {
|
||||
pub(super) fn len_mut(&mut self) -> &mut u16 {
|
||||
&mut self.as_leaf_mut().len
|
||||
}
|
||||
}
|
||||
|
|
@ -578,14 +578,14 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
|||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
/// Returns a new owned tree, with its own root node that is initially empty.
|
||||
pub fn new<A: Allocator + Clone>(alloc: A) -> Self {
|
||||
pub(super) fn new<A: Allocator + Clone>(alloc: A) -> Self {
|
||||
NodeRef::new_leaf(alloc).forget_type()
|
||||
}
|
||||
|
||||
/// Adds a new internal node with a single edge pointing to the previous root node,
|
||||
/// make that new node the root node, and return it. This increases the height by 1
|
||||
/// and is the opposite of `pop_internal_level`.
|
||||
pub fn push_internal_level<A: Allocator + Clone>(
|
||||
pub(super) fn push_internal_level<A: Allocator + Clone>(
|
||||
&mut self,
|
||||
alloc: A,
|
||||
) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
|
||||
|
|
@ -604,7 +604,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
|||
/// it will not invalidate other handles or references to the root node.
|
||||
///
|
||||
/// Panics if there is no internal level, i.e., if the root node is a leaf.
|
||||
pub fn pop_internal_level<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
pub(super) fn pop_internal_level<A: Allocator + Clone>(&mut self, alloc: A) {
|
||||
assert!(self.height > 0);
|
||||
|
||||
let top = self.node;
|
||||
|
|
@ -628,18 +628,18 @@ impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
|
|||
/// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe
|
||||
/// because the return value cannot be used to destroy the root, and there
|
||||
/// cannot be other references to the tree.
|
||||
pub fn borrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
|
||||
pub(super) fn borrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Slightly mutably borrows the owned root node.
|
||||
pub fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
|
||||
pub(super) fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Irreversibly transitions to a reference that permits traversal and offers
|
||||
/// destructive methods and little else.
|
||||
pub fn into_dying(self) -> NodeRef<marker::Dying, K, V, Type> {
|
||||
pub(super) fn into_dying(self) -> NodeRef<marker::Dying, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
|
@ -651,7 +651,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
|||
/// # Safety
|
||||
///
|
||||
/// The returned handle has an unbound lifetime.
|
||||
pub unsafe fn push_with_handle<'b>(
|
||||
pub(super) unsafe fn push_with_handle<'b>(
|
||||
&mut self,
|
||||
key: K,
|
||||
val: V,
|
||||
|
|
@ -672,7 +672,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
|||
|
||||
/// Adds a key-value pair to the end of the node, and returns
|
||||
/// the mutable reference of the inserted value.
|
||||
pub fn push(&mut self, key: K, val: V) -> *mut V {
|
||||
pub(super) fn push(&mut self, key: K, val: V) -> *mut V {
|
||||
// SAFETY: The unbound handle is no longer accessible.
|
||||
unsafe { self.push_with_handle(key, val).into_val_mut() }
|
||||
}
|
||||
|
|
@ -681,7 +681,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
|||
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
/// Adds a key-value pair, and an edge to go to the right of that pair,
|
||||
/// to the end of the node.
|
||||
pub fn push(&mut self, key: K, val: V, edge: Root<K, V>) {
|
||||
pub(super) fn push(&mut self, key: K, val: V, edge: Root<K, V>) {
|
||||
assert!(edge.height == self.height - 1);
|
||||
|
||||
let len = self.len_mut();
|
||||
|
|
@ -699,21 +699,21 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
|||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Leaf> {
|
||||
/// Removes any static information asserting that this node is a `Leaf` node.
|
||||
pub fn forget_type(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
pub(super) fn forget_type(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||
/// Removes any static information asserting that this node is an `Internal` node.
|
||||
pub fn forget_type(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
pub(super) fn forget_type(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
/// Checks whether a node is an `Internal` node or a `Leaf` node.
|
||||
pub fn force(
|
||||
pub(super) fn force(
|
||||
self,
|
||||
) -> ForceResult<
|
||||
NodeRef<BorrowType, K, V, marker::Leaf>,
|
||||
|
|
@ -737,7 +737,9 @@ impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
|||
|
||||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
/// Unsafely asserts to the compiler the static information that this node is a `Leaf`.
|
||||
pub unsafe fn cast_to_leaf_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
pub(super) unsafe fn cast_to_leaf_unchecked(
|
||||
self,
|
||||
) -> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
debug_assert!(self.height == 0);
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
|
@ -757,7 +759,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
|||
/// a child node, these represent the spaces where child pointers would go between the key-value
|
||||
/// pairs. For example, in a node with length 2, there would be 3 possible edge locations - one
|
||||
/// to the left of the node, one between the two pairs, and one at the right of the node.
|
||||
pub struct Handle<Node, Type> {
|
||||
pub(super) struct Handle<Node, Type> {
|
||||
node: Node,
|
||||
idx: usize,
|
||||
_marker: PhantomData<Type>,
|
||||
|
|
@ -774,12 +776,12 @@ impl<Node: Copy, Type> Clone for Handle<Node, Type> {
|
|||
|
||||
impl<Node, Type> Handle<Node, Type> {
|
||||
/// Retrieves the node that contains the edge or key-value pair this handle points to.
|
||||
pub fn into_node(self) -> Node {
|
||||
pub(super) fn into_node(self) -> Node {
|
||||
self.node
|
||||
}
|
||||
|
||||
/// Returns the position of this handle in the node.
|
||||
pub fn idx(&self) -> usize {
|
||||
pub(super) fn idx(&self) -> usize {
|
||||
self.idx
|
||||
}
|
||||
}
|
||||
|
|
@ -787,17 +789,17 @@ impl<Node, Type> Handle<Node, Type> {
|
|||
impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::KV> {
|
||||
/// Creates a new handle to a key-value pair in `node`.
|
||||
/// Unsafe because the caller must ensure that `idx < node.len()`.
|
||||
pub unsafe fn new_kv(node: NodeRef<BorrowType, K, V, NodeType>, idx: usize) -> Self {
|
||||
pub(super) unsafe fn new_kv(node: NodeRef<BorrowType, K, V, NodeType>, idx: usize) -> Self {
|
||||
debug_assert!(idx < node.len());
|
||||
|
||||
Handle { node, idx, _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub fn left_edge(self) -> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
|
||||
pub(super) fn left_edge(self) -> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
|
||||
unsafe { Handle::new_edge(self.node, self.idx) }
|
||||
}
|
||||
|
||||
pub fn right_edge(self) -> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
|
||||
pub(super) fn right_edge(self) -> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
|
||||
unsafe { Handle::new_edge(self.node, self.idx + 1) }
|
||||
}
|
||||
}
|
||||
|
|
@ -815,7 +817,9 @@ impl<BorrowType, K, V, NodeType, HandleType>
|
|||
Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
|
||||
{
|
||||
/// Temporarily takes out another immutable handle on the same location.
|
||||
pub fn reborrow(&self) -> Handle<NodeRef<marker::Immut<'_>, K, V, NodeType>, HandleType> {
|
||||
pub(super) fn reborrow(
|
||||
&self,
|
||||
) -> Handle<NodeRef<marker::Immut<'_>, K, V, NodeType>, HandleType> {
|
||||
// We can't use Handle::new_kv or Handle::new_edge because we don't know our type
|
||||
Handle { node: self.node.reborrow(), idx: self.idx, _marker: PhantomData }
|
||||
}
|
||||
|
|
@ -827,7 +831,7 @@ impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeT
|
|||
/// dangerous.
|
||||
///
|
||||
/// For details, see `NodeRef::reborrow_mut`.
|
||||
pub unsafe fn reborrow_mut(
|
||||
pub(super) unsafe fn reborrow_mut(
|
||||
&mut self,
|
||||
) -> Handle<NodeRef<marker::Mut<'_>, K, V, NodeType>, HandleType> {
|
||||
// We can't use Handle::new_kv or Handle::new_edge because we don't know our type
|
||||
|
|
@ -837,7 +841,9 @@ impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeT
|
|||
/// Returns a dormant copy of this handle which can be reawakened later.
|
||||
///
|
||||
/// See `DormantMutRef` for more details.
|
||||
pub fn dormant(&self) -> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> {
|
||||
pub(super) fn dormant(
|
||||
&self,
|
||||
) -> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> {
|
||||
Handle { node: self.node.dormant(), idx: self.idx, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
|
@ -849,7 +855,9 @@ impl<K, V, NodeType, HandleType> Handle<NodeRef<marker::DormantMut, K, V, NodeTy
|
|||
///
|
||||
/// The reborrow must have ended, i.e., the reference returned by `new` and
|
||||
/// all pointers and references derived from it, must not be used anymore.
|
||||
pub unsafe fn awaken<'a>(self) -> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> {
|
||||
pub(super) unsafe fn awaken<'a>(
|
||||
self,
|
||||
) -> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> {
|
||||
Handle { node: unsafe { self.node.awaken() }, idx: self.idx, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
|
@ -857,13 +865,15 @@ impl<K, V, NodeType, HandleType> Handle<NodeRef<marker::DormantMut, K, V, NodeTy
|
|||
impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
|
||||
/// Creates a new handle to an edge in `node`.
|
||||
/// Unsafe because the caller must ensure that `idx <= node.len()`.
|
||||
pub unsafe fn new_edge(node: NodeRef<BorrowType, K, V, NodeType>, idx: usize) -> Self {
|
||||
pub(super) unsafe fn new_edge(node: NodeRef<BorrowType, K, V, NodeType>, idx: usize) -> Self {
|
||||
debug_assert!(idx <= node.len());
|
||||
|
||||
Handle { node, idx, _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub fn left_kv(self) -> Result<Handle<NodeRef<BorrowType, K, V, NodeType>, marker::KV>, Self> {
|
||||
pub(super) fn left_kv(
|
||||
self,
|
||||
) -> Result<Handle<NodeRef<BorrowType, K, V, NodeType>, marker::KV>, Self> {
|
||||
if self.idx > 0 {
|
||||
Ok(unsafe { Handle::new_kv(self.node, self.idx - 1) })
|
||||
} else {
|
||||
|
|
@ -871,7 +881,9 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar
|
|||
}
|
||||
}
|
||||
|
||||
pub fn right_kv(self) -> Result<Handle<NodeRef<BorrowType, K, V, NodeType>, marker::KV>, Self> {
|
||||
pub(super) fn right_kv(
|
||||
self,
|
||||
) -> Result<Handle<NodeRef<BorrowType, K, V, NodeType>, marker::KV>, Self> {
|
||||
if self.idx < self.node.len() {
|
||||
Ok(unsafe { Handle::new_kv(self.node, self.idx) })
|
||||
} else {
|
||||
|
|
@ -880,7 +892,7 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar
|
|||
}
|
||||
}
|
||||
|
||||
pub enum LeftOrRight<T> {
|
||||
pub(super) enum LeftOrRight<T> {
|
||||
Left(T),
|
||||
Right(T),
|
||||
}
|
||||
|
|
@ -1034,7 +1046,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
|
|||
/// If the returned result is some `SplitResult`, the `left` field will be the root node.
|
||||
/// The returned pointer points to the inserted value, which in the case of `SplitResult`
|
||||
/// is in the `left` or `right` tree.
|
||||
pub fn insert_recursing<A: Allocator + Clone>(
|
||||
pub(super) fn insert_recursing<A: Allocator + Clone>(
|
||||
self,
|
||||
key: K,
|
||||
value: V,
|
||||
|
|
@ -1078,7 +1090,7 @@ impl<BorrowType: marker::BorrowType, K, V>
|
|||
///
|
||||
/// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should
|
||||
/// both, upon success, do nothing.
|
||||
pub fn descend(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
pub(super) fn descend(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
const {
|
||||
assert!(BorrowType::TRAVERSAL_PERMIT);
|
||||
}
|
||||
|
|
@ -1097,7 +1109,7 @@ impl<BorrowType: marker::BorrowType, K, V>
|
|||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Immut<'a>, K, V, NodeType>, marker::KV> {
|
||||
pub fn into_kv(self) -> (&'a K, &'a V) {
|
||||
pub(super) fn into_kv(self) -> (&'a K, &'a V) {
|
||||
debug_assert!(self.idx < self.node.len());
|
||||
let leaf = self.node.into_leaf();
|
||||
let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() };
|
||||
|
|
@ -1107,17 +1119,17 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Immut<'a>, K, V, NodeTyp
|
|||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
|
||||
pub fn key_mut(&mut self) -> &mut K {
|
||||
pub(super) fn key_mut(&mut self) -> &mut K {
|
||||
unsafe { self.node.key_area_mut(self.idx).assume_init_mut() }
|
||||
}
|
||||
|
||||
pub fn into_val_mut(self) -> &'a mut V {
|
||||
pub(super) fn into_val_mut(self) -> &'a mut V {
|
||||
debug_assert!(self.idx < self.node.len());
|
||||
let leaf = self.node.into_leaf_mut();
|
||||
unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
|
||||
}
|
||||
|
||||
pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) {
|
||||
pub(super) fn into_kv_mut(self) -> (&'a mut K, &'a mut V) {
|
||||
debug_assert!(self.idx < self.node.len());
|
||||
let leaf = self.node.into_leaf_mut();
|
||||
let k = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() };
|
||||
|
|
@ -1127,13 +1139,13 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
|
|||
}
|
||||
|
||||
impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, marker::KV> {
|
||||
pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) {
|
||||
pub(super) fn into_kv_valmut(self) -> (&'a K, &'a mut V) {
|
||||
unsafe { self.node.into_key_val_mut_at(self.idx) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
|
||||
pub fn kv_mut(&mut self) -> (&mut K, &mut V) {
|
||||
pub(super) fn kv_mut(&mut self) -> (&mut K, &mut V) {
|
||||
debug_assert!(self.idx < self.node.len());
|
||||
// We cannot call separate key and value methods, because calling the second one
|
||||
// invalidates the reference returned by the first.
|
||||
|
|
@ -1146,7 +1158,7 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
|
|||
}
|
||||
|
||||
/// Replaces the key and value that the KV handle refers to.
|
||||
pub fn replace_kv(&mut self, k: K, v: V) -> (K, V) {
|
||||
pub(super) fn replace_kv(&mut self, k: K, v: V) -> (K, V) {
|
||||
let (key, val) = self.kv_mut();
|
||||
(mem::replace(key, k), mem::replace(val, v))
|
||||
}
|
||||
|
|
@ -1156,7 +1168,7 @@ impl<K, V, NodeType> Handle<NodeRef<marker::Dying, K, V, NodeType>, marker::KV>
|
|||
/// Extracts the key and value that the KV handle refers to.
|
||||
/// # Safety
|
||||
/// The node that the handle refers to must not yet have been deallocated.
|
||||
pub unsafe fn into_key_val(mut self) -> (K, V) {
|
||||
pub(super) unsafe fn into_key_val(mut self) -> (K, V) {
|
||||
debug_assert!(self.idx < self.node.len());
|
||||
let leaf = self.node.as_leaf_dying();
|
||||
unsafe {
|
||||
|
|
@ -1170,7 +1182,7 @@ impl<K, V, NodeType> Handle<NodeRef<marker::Dying, K, V, NodeType>, marker::KV>
|
|||
/// # Safety
|
||||
/// The node that the handle refers to must not yet have been deallocated.
|
||||
#[inline]
|
||||
pub unsafe fn drop_key_val(mut self) {
|
||||
pub(super) unsafe fn drop_key_val(mut self) {
|
||||
// Run the destructor of the value even if the destructor of the key panics.
|
||||
struct Dropper<'a, T>(&'a mut MaybeUninit<T>);
|
||||
impl<T> Drop for Dropper<'_, T> {
|
||||
|
|
@ -1229,7 +1241,10 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
|
|||
/// - The key and value pointed to by this handle are extracted.
|
||||
/// - All the key-value pairs to the right of this handle are put into a newly
|
||||
/// allocated node.
|
||||
pub fn split<A: Allocator + Clone>(mut self, alloc: A) -> SplitResult<'a, K, V, marker::Leaf> {
|
||||
pub(super) fn split<A: Allocator + Clone>(
|
||||
mut self,
|
||||
alloc: A,
|
||||
) -> SplitResult<'a, K, V, marker::Leaf> {
|
||||
let mut new_node = LeafNode::new(alloc);
|
||||
|
||||
let kv = self.split_leaf_data(&mut new_node);
|
||||
|
|
@ -1240,7 +1255,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
|
|||
|
||||
/// Removes the key-value pair pointed to by this handle and returns it, along with the edge
|
||||
/// that the key-value pair collapsed into.
|
||||
pub fn remove(
|
||||
pub(super) fn remove(
|
||||
mut self,
|
||||
) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
|
||||
let old_len = self.node.len();
|
||||
|
|
@ -1261,7 +1276,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
|
|||
/// - The key and value pointed to by this handle are extracted.
|
||||
/// - All the edges and key-value pairs to the right of this handle are put into
|
||||
/// a newly allocated node.
|
||||
pub fn split<A: Allocator + Clone>(
|
||||
pub(super) fn split<A: Allocator + Clone>(
|
||||
mut self,
|
||||
alloc: A,
|
||||
) -> SplitResult<'a, K, V, marker::Internal> {
|
||||
|
|
@ -1285,14 +1300,14 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
|
|||
|
||||
/// Represents a session for evaluating and performing a balancing operation
|
||||
/// around an internal key-value pair.
|
||||
pub struct BalancingContext<'a, K, V> {
|
||||
pub(super) struct BalancingContext<'a, K, V> {
|
||||
parent: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::KV>,
|
||||
left_child: NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
|
||||
right_child: NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::KV> {
|
||||
pub fn consider_for_balancing(self) -> BalancingContext<'a, K, V> {
|
||||
pub(super) fn consider_for_balancing(self) -> BalancingContext<'a, K, V> {
|
||||
let self1 = unsafe { ptr::read(&self) };
|
||||
let self2 = unsafe { ptr::read(&self) };
|
||||
BalancingContext {
|
||||
|
|
@ -1318,7 +1333,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
|||
/// typically faster, since we only need to shift the node's N elements to
|
||||
/// the right, instead of shifting at least N of the sibling's elements to
|
||||
/// the left.
|
||||
pub fn choose_parent_kv(self) -> Result<LeftOrRight<BalancingContext<'a, K, V>>, Self> {
|
||||
pub(super) fn choose_parent_kv(self) -> Result<LeftOrRight<BalancingContext<'a, K, V>>, Self> {
|
||||
match unsafe { ptr::read(&self) }.ascend() {
|
||||
Ok(parent_edge) => match parent_edge.left_kv() {
|
||||
Ok(left_parent_kv) => Ok(LeftOrRight::Left(BalancingContext {
|
||||
|
|
@ -1341,25 +1356,25 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
|||
}
|
||||
|
||||
impl<'a, K, V> BalancingContext<'a, K, V> {
|
||||
pub fn left_child_len(&self) -> usize {
|
||||
pub(super) fn left_child_len(&self) -> usize {
|
||||
self.left_child.len()
|
||||
}
|
||||
|
||||
pub fn right_child_len(&self) -> usize {
|
||||
pub(super) fn right_child_len(&self) -> usize {
|
||||
self.right_child.len()
|
||||
}
|
||||
|
||||
pub fn into_left_child(self) -> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
pub(super) fn into_left_child(self) -> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
self.left_child
|
||||
}
|
||||
|
||||
pub fn into_right_child(self) -> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
pub(super) fn into_right_child(self) -> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
self.right_child
|
||||
}
|
||||
|
||||
/// Returns whether merging is possible, i.e., whether there is enough room
|
||||
/// in a node to combine the central KV with both adjacent child nodes.
|
||||
pub fn can_merge(&self) -> bool {
|
||||
pub(super) fn can_merge(&self) -> bool {
|
||||
self.left_child.len() + 1 + self.right_child.len() <= CAPACITY
|
||||
}
|
||||
}
|
||||
|
|
@ -1433,7 +1448,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
|||
/// the left child node and returns the shrunk parent node.
|
||||
///
|
||||
/// Panics unless we `.can_merge()`.
|
||||
pub fn merge_tracking_parent<A: Allocator + Clone>(
|
||||
pub(super) fn merge_tracking_parent<A: Allocator + Clone>(
|
||||
self,
|
||||
alloc: A,
|
||||
) -> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||
|
|
@ -1444,7 +1459,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
|||
/// the left child node and returns that child node.
|
||||
///
|
||||
/// Panics unless we `.can_merge()`.
|
||||
pub fn merge_tracking_child<A: Allocator + Clone>(
|
||||
pub(super) fn merge_tracking_child<A: Allocator + Clone>(
|
||||
self,
|
||||
alloc: A,
|
||||
) -> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
||||
|
|
@ -1456,7 +1471,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
|||
/// where the tracked child edge ended up,
|
||||
///
|
||||
/// Panics unless we `.can_merge()`.
|
||||
pub fn merge_tracking_child_edge<A: Allocator + Clone>(
|
||||
pub(super) fn merge_tracking_child_edge<A: Allocator + Clone>(
|
||||
self,
|
||||
track_edge_idx: LeftOrRight<usize>,
|
||||
alloc: A,
|
||||
|
|
@ -1479,7 +1494,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
|||
/// of the parent, while pushing the old parent key-value pair into the right child.
|
||||
/// Returns a handle to the edge in the right child corresponding to where the original
|
||||
/// edge specified by `track_right_edge_idx` ended up.
|
||||
pub fn steal_left(
|
||||
pub(super) fn steal_left(
|
||||
mut self,
|
||||
track_right_edge_idx: usize,
|
||||
) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::Edge> {
|
||||
|
|
@ -1491,7 +1506,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
|||
/// of the parent, while pushing the old parent key-value pair onto the left child.
|
||||
/// Returns a handle to the edge in the left child specified by `track_left_edge_idx`,
|
||||
/// which didn't move.
|
||||
pub fn steal_right(
|
||||
pub(super) fn steal_right(
|
||||
mut self,
|
||||
track_left_edge_idx: usize,
|
||||
) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::Edge> {
|
||||
|
|
@ -1500,7 +1515,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
|||
}
|
||||
|
||||
/// This does stealing similar to `steal_left` but steals multiple elements at once.
|
||||
pub fn bulk_steal_left(&mut self, count: usize) {
|
||||
pub(super) fn bulk_steal_left(&mut self, count: usize) {
|
||||
assert!(count > 0);
|
||||
unsafe {
|
||||
let left_node = &mut self.left_child;
|
||||
|
|
@ -1563,7 +1578,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
|||
}
|
||||
|
||||
/// The symmetric clone of `bulk_steal_left`.
|
||||
pub fn bulk_steal_right(&mut self, count: usize) {
|
||||
pub(super) fn bulk_steal_right(&mut self, count: usize) {
|
||||
assert!(count > 0);
|
||||
unsafe {
|
||||
let left_node = &mut self.left_child;
|
||||
|
|
@ -1628,7 +1643,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
|
|||
}
|
||||
|
||||
impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
pub fn forget_node_type(
|
||||
pub(super) fn forget_node_type(
|
||||
self,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::Edge> {
|
||||
unsafe { Handle::new_edge(self.node.forget_type(), self.idx) }
|
||||
|
|
@ -1636,7 +1651,7 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::E
|
|||
}
|
||||
|
||||
impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge> {
|
||||
pub fn forget_node_type(
|
||||
pub(super) fn forget_node_type(
|
||||
self,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::Edge> {
|
||||
unsafe { Handle::new_edge(self.node.forget_type(), self.idx) }
|
||||
|
|
@ -1644,7 +1659,7 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marke
|
|||
}
|
||||
|
||||
impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::KV> {
|
||||
pub fn forget_node_type(
|
||||
pub(super) fn forget_node_type(
|
||||
self,
|
||||
) -> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV> {
|
||||
unsafe { Handle::new_kv(self.node.forget_type(), self.idx) }
|
||||
|
|
@ -1653,7 +1668,7 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::K
|
|||
|
||||
impl<BorrowType, K, V, Type> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, Type> {
|
||||
/// Checks whether the underlying node is an `Internal` node or a `Leaf` node.
|
||||
pub fn force(
|
||||
pub(super) fn force(
|
||||
self,
|
||||
) -> ForceResult<
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, Type>,
|
||||
|
|
@ -1672,7 +1687,7 @@ impl<BorrowType, K, V, Type> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInte
|
|||
|
||||
impl<'a, K, V, Type> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, Type> {
|
||||
/// Unsafely asserts to the compiler the static information that the handle's node is a `Leaf`.
|
||||
pub unsafe fn cast_to_leaf_unchecked(
|
||||
pub(super) unsafe fn cast_to_leaf_unchecked(
|
||||
self,
|
||||
) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, Type> {
|
||||
let node = unsafe { self.node.cast_to_leaf_unchecked() };
|
||||
|
|
@ -1683,7 +1698,7 @@ impl<'a, K, V, Type> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInterna
|
|||
impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::Edge> {
|
||||
/// Move the suffix after `self` from one node to another one. `right` must be empty.
|
||||
/// The first edge of `right` remains unchanged.
|
||||
pub fn move_suffix(
|
||||
pub(super) fn move_suffix(
|
||||
&mut self,
|
||||
right: &mut NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
|
||||
) {
|
||||
|
|
@ -1726,13 +1741,13 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, ma
|
|||
}
|
||||
}
|
||||
|
||||
pub enum ForceResult<Leaf, Internal> {
|
||||
pub(super) enum ForceResult<Leaf, Internal> {
|
||||
Leaf(Leaf),
|
||||
Internal(Internal),
|
||||
}
|
||||
|
||||
/// Result of insertion, when a node needed to expand beyond its capacity.
|
||||
pub struct SplitResult<'a, K, V, NodeType> {
|
||||
pub(super) struct SplitResult<'a, K, V, NodeType> {
|
||||
// Altered node in existing tree with elements and edges that belong to the left of `kv`.
|
||||
pub left: NodeRef<marker::Mut<'a>, K, V, NodeType>,
|
||||
// Some key and value that existed before and were split off, to be inserted elsewhere.
|
||||
|
|
@ -1742,32 +1757,32 @@ pub struct SplitResult<'a, K, V, NodeType> {
|
|||
}
|
||||
|
||||
impl<'a, K, V> SplitResult<'a, K, V, marker::Leaf> {
|
||||
pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> {
|
||||
pub(super) fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> {
|
||||
SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> SplitResult<'a, K, V, marker::Internal> {
|
||||
pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> {
|
||||
pub(super) fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> {
|
||||
SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() }
|
||||
}
|
||||
}
|
||||
|
||||
pub mod marker {
|
||||
pub(super) mod marker {
|
||||
use core::marker::PhantomData;
|
||||
|
||||
pub enum Leaf {}
|
||||
pub enum Internal {}
|
||||
pub enum LeafOrInternal {}
|
||||
pub(crate) enum Leaf {}
|
||||
pub(crate) enum Internal {}
|
||||
pub(crate) enum LeafOrInternal {}
|
||||
|
||||
pub enum Owned {}
|
||||
pub enum Dying {}
|
||||
pub enum DormantMut {}
|
||||
pub struct Immut<'a>(PhantomData<&'a ()>);
|
||||
pub struct Mut<'a>(PhantomData<&'a mut ()>);
|
||||
pub struct ValMut<'a>(PhantomData<&'a mut ()>);
|
||||
pub(crate) enum Owned {}
|
||||
pub(crate) enum Dying {}
|
||||
pub(crate) enum DormantMut {}
|
||||
pub(crate) struct Immut<'a>(PhantomData<&'a ()>);
|
||||
pub(crate) struct Mut<'a>(PhantomData<&'a mut ()>);
|
||||
pub(crate) struct ValMut<'a>(PhantomData<&'a mut ()>);
|
||||
|
||||
pub trait BorrowType {
|
||||
pub(crate) trait BorrowType {
|
||||
/// If node references of this borrow type allow traversing to other
|
||||
/// nodes in the tree, this constant is set to `true`. It can be used
|
||||
/// for a compile-time assertion.
|
||||
|
|
@ -1786,8 +1801,8 @@ pub mod marker {
|
|||
impl<'a> BorrowType for ValMut<'a> {}
|
||||
impl BorrowType for DormantMut {}
|
||||
|
||||
pub enum KV {}
|
||||
pub enum Edge {}
|
||||
pub(crate) enum KV {}
|
||||
pub(crate) enum Edge {}
|
||||
}
|
||||
|
||||
/// Inserts a value into a slice of initialized elements followed by one uninitialized element.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::string::String;
|
|||
|
||||
impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
|
||||
// Asserts that the back pointer in each reachable node points to its parent.
|
||||
pub fn assert_back_pointers(self) {
|
||||
pub(crate) fn assert_back_pointers(self) {
|
||||
if let ForceResult::Internal(node) = self.force() {
|
||||
for idx in 0..=node.len() {
|
||||
let edge = unsafe { Handle::new_edge(node, idx) };
|
||||
|
|
@ -20,7 +20,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
|
|||
// Renders a multi-line display of the keys in order and in tree hierarchy,
|
||||
// picturing the tree growing sideways from its root on the left to its
|
||||
// leaves on the right.
|
||||
pub fn dump_keys(self) -> String
|
||||
pub(crate) fn dump_keys(self) -> String
|
||||
where
|
||||
K: Debug,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
|
|||
/// the leaf edge corresponding to that former pair. It's possible this empties
|
||||
/// a root node that is internal, which the caller should pop from the map
|
||||
/// holding the tree. The caller should also decrement the map's length.
|
||||
pub fn remove_kv_tracking<F: FnOnce(), A: Allocator + Clone>(
|
||||
pub(super) fn remove_kv_tracking<F: FnOnce(), A: Allocator + Clone>(
|
||||
self,
|
||||
handle_emptied_internal_root: F,
|
||||
alloc: A,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use SearchResult::*;
|
|||
use super::node::ForceResult::*;
|
||||
use super::node::{Handle, NodeRef, marker};
|
||||
|
||||
pub enum SearchBound<T> {
|
||||
pub(super) enum SearchBound<T> {
|
||||
/// An inclusive bound to look for, just like `Bound::Included(T)`.
|
||||
Included(T),
|
||||
/// An exclusive bound to look for, just like `Bound::Excluded(T)`.
|
||||
|
|
@ -20,7 +20,7 @@ pub enum SearchBound<T> {
|
|||
}
|
||||
|
||||
impl<T> SearchBound<T> {
|
||||
pub fn from_range(range_bound: Bound<T>) -> Self {
|
||||
pub(super) fn from_range(range_bound: Bound<T>) -> Self {
|
||||
match range_bound {
|
||||
Bound::Included(t) => Included(t),
|
||||
Bound::Excluded(t) => Excluded(t),
|
||||
|
|
@ -29,12 +29,12 @@ impl<T> SearchBound<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum SearchResult<BorrowType, K, V, FoundType, GoDownType> {
|
||||
pub(super) enum SearchResult<BorrowType, K, V, FoundType, GoDownType> {
|
||||
Found(Handle<NodeRef<BorrowType, K, V, FoundType>, marker::KV>),
|
||||
GoDown(Handle<NodeRef<BorrowType, K, V, GoDownType>, marker::Edge>),
|
||||
}
|
||||
|
||||
pub enum IndexResult {
|
||||
pub(super) enum IndexResult {
|
||||
KV(usize),
|
||||
Edge(usize),
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
|
|||
///
|
||||
/// The result is meaningful only if the tree is ordered by key, like the tree
|
||||
/// in a `BTreeMap` is.
|
||||
pub fn search_tree<Q: ?Sized>(
|
||||
pub(super) fn search_tree<Q: ?Sized>(
|
||||
mut self,
|
||||
key: &Q,
|
||||
) -> SearchResult<BorrowType, K, V, marker::LeafOrInternal, marker::Leaf>
|
||||
|
|
@ -80,7 +80,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
|
|||
/// As a diagnostic service, panics if the range specifies impossible bounds.
|
||||
///
|
||||
/// The result is meaningful only if the tree is ordered by key.
|
||||
pub fn search_tree_for_bifurcation<'r, Q: ?Sized, R>(
|
||||
pub(super) fn search_tree_for_bifurcation<'r, Q: ?Sized, R>(
|
||||
mut self,
|
||||
range: &'r R,
|
||||
) -> Result<
|
||||
|
|
@ -156,7 +156,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
|
|||
/// the matching child node, if `self` is an internal node.
|
||||
///
|
||||
/// The result is meaningful only if the tree is ordered by key.
|
||||
pub fn find_lower_bound_edge<'r, Q>(
|
||||
pub(super) fn find_lower_bound_edge<'r, Q>(
|
||||
self,
|
||||
bound: SearchBound<&'r Q>,
|
||||
) -> (Handle<Self, marker::Edge>, SearchBound<&'r Q>)
|
||||
|
|
@ -170,7 +170,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
|
|||
}
|
||||
|
||||
/// Clone of `find_lower_bound_edge` for the upper bound.
|
||||
pub fn find_upper_bound_edge<'r, Q>(
|
||||
pub(super) fn find_upper_bound_edge<'r, Q>(
|
||||
self,
|
||||
bound: SearchBound<&'r Q>,
|
||||
) -> (Handle<Self, marker::Edge>, SearchBound<&'r Q>)
|
||||
|
|
@ -192,7 +192,10 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
|||
///
|
||||
/// The result is meaningful only if the tree is ordered by key, like the tree
|
||||
/// in a `BTreeMap` is.
|
||||
pub fn search_node<Q: ?Sized>(self, key: &Q) -> SearchResult<BorrowType, K, V, Type, Type>
|
||||
pub(super) fn search_node<Q: ?Sized>(
|
||||
self,
|
||||
key: &Q,
|
||||
) -> SearchResult<BorrowType, K, V, Type, Type>
|
||||
where
|
||||
Q: Ord,
|
||||
K: Borrow<Q>,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use super::search::SearchResult::*;
|
|||
impl<K, V> Root<K, V> {
|
||||
/// Calculates the length of both trees that result from splitting up
|
||||
/// a given number of distinct key-value pairs.
|
||||
pub fn calc_split_length(
|
||||
pub(super) fn calc_split_length(
|
||||
total_num: usize,
|
||||
root_a: &Root<K, V>,
|
||||
root_b: &Root<K, V>,
|
||||
|
|
@ -31,7 +31,11 @@ impl<K, V> Root<K, V> {
|
|||
/// and if the ordering of `Q` corresponds to that of `K`.
|
||||
/// If `self` respects all `BTreeMap` tree invariants, then both
|
||||
/// `self` and the returned tree will respect those invariants.
|
||||
pub fn split_off<Q: ?Sized + Ord, A: Allocator + Clone>(&mut self, key: &Q, alloc: A) -> Self
|
||||
pub(super) fn split_off<Q: ?Sized + Ord, A: Allocator + Clone>(
|
||||
&mut self,
|
||||
key: &Q,
|
||||
alloc: A,
|
||||
) -> Self
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
|
|||
v.iter().cloned().collect()
|
||||
}
|
||||
|
||||
pub fn check_links<T>(list: &LinkedList<T>) {
|
||||
fn check_links<T>(list: &LinkedList<T>) {
|
||||
unsafe {
|
||||
let mut len = 0;
|
||||
let mut last_ptr: Option<&Node<T>> = None;
|
||||
|
|
|
|||
|
|
@ -823,6 +823,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
|
|||
/// assert!(buf.capacity() >= 11);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_reserve")]
|
||||
#[track_caller]
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
let new_cap = self.len.checked_add(additional).expect("capacity overflow");
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
#![warn(rustdoc::unescaped_backticks)]
|
||||
#![deny(ffi_unwind_calls)]
|
||||
#![warn(unreachable_pub)]
|
||||
//
|
||||
// Library features:
|
||||
// tidy-alphabetical-start
|
||||
|
|
@ -227,7 +228,7 @@ pub mod alloc;
|
|||
pub mod boxed;
|
||||
#[cfg(test)]
|
||||
mod boxed {
|
||||
pub use std::boxed::Box;
|
||||
pub(crate) use std::boxed::Box;
|
||||
}
|
||||
pub mod borrow;
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ impl<T> RawVec<T, Global> {
|
|||
/// `RawVec` with capacity `usize::MAX`. Useful for implementing
|
||||
/// delayed allocation.
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
pub(crate) const fn new() -> Self {
|
||||
Self::new_in(Global)
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ impl<T> RawVec<T, Global> {
|
|||
#[must_use]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
||||
Self { inner: RawVecInner::with_capacity(capacity, T::LAYOUT), _marker: PhantomData }
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ impl<T> RawVec<T, Global> {
|
|||
#[must_use]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn with_capacity_zeroed(capacity: usize) -> Self {
|
||||
pub(crate) fn with_capacity_zeroed(capacity: usize) -> Self {
|
||||
Self {
|
||||
inner: RawVecInner::with_capacity_zeroed_in(capacity, Global, T::LAYOUT),
|
||||
_marker: PhantomData,
|
||||
|
|
@ -172,7 +172,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
/// Like `new`, but parameterized over the choice of allocator for
|
||||
/// the returned `RawVec`.
|
||||
#[inline]
|
||||
pub const fn new_in(alloc: A) -> Self {
|
||||
pub(crate) const fn new_in(alloc: A) -> Self {
|
||||
Self { inner: RawVecInner::new_in(alloc, align_of::<T>()), _marker: PhantomData }
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
|
||||
pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self {
|
||||
Self {
|
||||
inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT),
|
||||
_marker: PhantomData,
|
||||
|
|
@ -191,7 +191,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
/// Like `try_with_capacity`, but parameterized over the choice of
|
||||
/// allocator for the returned `RawVec`.
|
||||
#[inline]
|
||||
pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
|
||||
pub(crate) fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
|
||||
match RawVecInner::try_with_capacity_in(capacity, alloc, T::LAYOUT) {
|
||||
Ok(inner) => Ok(Self { inner, _marker: PhantomData }),
|
||||
Err(e) => Err(e),
|
||||
|
|
@ -203,7 +203,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
|
||||
pub(crate) fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
|
||||
Self {
|
||||
inner: RawVecInner::with_capacity_zeroed_in(capacity, alloc, T::LAYOUT),
|
||||
_marker: PhantomData,
|
||||
|
|
@ -222,7 +222,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
///
|
||||
/// Note, that the requested capacity and `self.capacity()` could differ, as
|
||||
/// an allocator could overallocate and return a greater memory block than requested.
|
||||
pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>], A> {
|
||||
pub(crate) unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>], A> {
|
||||
// Sanity-check one half of the safety requirement (we cannot check the other half).
|
||||
debug_assert!(
|
||||
len <= self.capacity(),
|
||||
|
|
@ -247,7 +247,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
/// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
|
||||
/// guaranteed.
|
||||
#[inline]
|
||||
pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
|
||||
pub(crate) unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
|
||||
// SAFETY: Precondition passed to the caller
|
||||
unsafe {
|
||||
let ptr = ptr.cast();
|
||||
|
|
@ -265,7 +265,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
///
|
||||
/// See [`RawVec::from_raw_parts_in`].
|
||||
#[inline]
|
||||
pub unsafe fn from_nonnull_in(ptr: NonNull<T>, capacity: usize, alloc: A) -> Self {
|
||||
pub(crate) unsafe fn from_nonnull_in(ptr: NonNull<T>, capacity: usize, alloc: A) -> Self {
|
||||
// SAFETY: Precondition passed to the caller
|
||||
unsafe {
|
||||
let ptr = ptr.cast();
|
||||
|
|
@ -278,12 +278,12 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
/// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
|
||||
/// be careful.
|
||||
#[inline]
|
||||
pub const fn ptr(&self) -> *mut T {
|
||||
pub(crate) const fn ptr(&self) -> *mut T {
|
||||
self.inner.ptr()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn non_null(&self) -> NonNull<T> {
|
||||
pub(crate) fn non_null(&self) -> NonNull<T> {
|
||||
self.inner.non_null()
|
||||
}
|
||||
|
||||
|
|
@ -291,13 +291,13 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
///
|
||||
/// This will always be `usize::MAX` if `T` is zero-sized.
|
||||
#[inline]
|
||||
pub const fn capacity(&self) -> usize {
|
||||
pub(crate) const fn capacity(&self) -> usize {
|
||||
self.inner.capacity(size_of::<T>())
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the allocator backing this `RawVec`.
|
||||
#[inline]
|
||||
pub fn allocator(&self) -> &A {
|
||||
pub(crate) fn allocator(&self) -> &A {
|
||||
self.inner.allocator()
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn reserve(&mut self, len: usize, additional: usize) {
|
||||
pub(crate) fn reserve(&mut self, len: usize, additional: usize) {
|
||||
self.inner.reserve(len, additional, T::LAYOUT)
|
||||
}
|
||||
|
||||
|
|
@ -332,12 +332,16 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[inline(never)]
|
||||
#[track_caller]
|
||||
pub fn grow_one(&mut self) {
|
||||
pub(crate) fn grow_one(&mut self) {
|
||||
self.inner.grow_one(T::LAYOUT)
|
||||
}
|
||||
|
||||
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
|
||||
pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
||||
pub(crate) fn try_reserve(
|
||||
&mut self,
|
||||
len: usize,
|
||||
additional: usize,
|
||||
) -> Result<(), TryReserveError> {
|
||||
self.inner.try_reserve(len, additional, T::LAYOUT)
|
||||
}
|
||||
|
||||
|
|
@ -360,12 +364,12 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
/// Aborts on OOM.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[track_caller]
|
||||
pub fn reserve_exact(&mut self, len: usize, additional: usize) {
|
||||
pub(crate) fn reserve_exact(&mut self, len: usize, additional: usize) {
|
||||
self.inner.reserve_exact(len, additional, T::LAYOUT)
|
||||
}
|
||||
|
||||
/// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
|
||||
pub fn try_reserve_exact(
|
||||
pub(crate) fn try_reserve_exact(
|
||||
&mut self,
|
||||
len: usize,
|
||||
additional: usize,
|
||||
|
|
@ -386,7 +390,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
pub fn shrink_to_fit(&mut self, cap: usize) {
|
||||
pub(crate) fn shrink_to_fit(&mut self, cap: usize) {
|
||||
self.inner.shrink_to_fit(cap, T::LAYOUT)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ use crate::vec::Vec;
|
|||
// functions are actually methods that are in `impl [T]` but not in
|
||||
// `core::slice::SliceExt` - we need to supply these functions for the
|
||||
// `test_permutations` test
|
||||
#[allow(unreachable_pub)] // cfg(test) pub above
|
||||
pub(crate) mod hack {
|
||||
use core::alloc::Allocator;
|
||||
|
||||
|
|
|
|||
|
|
@ -2740,7 +2740,7 @@ impl<T: ?Sized> Weak<T> {
|
|||
/// # Safety
|
||||
///
|
||||
/// The pointer must have originated from the [`into_raw`] and must still own its potential
|
||||
/// weak reference.
|
||||
/// weak reference, and must point to a block of memory allocated by global allocator.
|
||||
///
|
||||
/// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this
|
||||
/// takes ownership of one weak reference currently represented as a raw pointer (the weak
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::fmt::Debug; // the `Debug` trait is the only thing we use from `crate
|
|||
/// Crash test dummies are identified and ordered by an id, so they can be used
|
||||
/// as keys in a BTreeMap.
|
||||
#[derive(Debug)]
|
||||
pub struct CrashTestDummy {
|
||||
pub(crate) struct CrashTestDummy {
|
||||
pub id: usize,
|
||||
cloned: AtomicUsize,
|
||||
dropped: AtomicUsize,
|
||||
|
|
@ -20,7 +20,7 @@ pub struct CrashTestDummy {
|
|||
|
||||
impl CrashTestDummy {
|
||||
/// Creates a crash test dummy design. The `id` determines order and equality of instances.
|
||||
pub fn new(id: usize) -> CrashTestDummy {
|
||||
pub(crate) fn new(id: usize) -> CrashTestDummy {
|
||||
CrashTestDummy {
|
||||
id,
|
||||
cloned: AtomicUsize::new(0),
|
||||
|
|
@ -31,34 +31,34 @@ impl CrashTestDummy {
|
|||
|
||||
/// Creates an instance of a crash test dummy that records what events it experiences
|
||||
/// and optionally panics.
|
||||
pub fn spawn(&self, panic: Panic) -> Instance<'_> {
|
||||
pub(crate) fn spawn(&self, panic: Panic) -> Instance<'_> {
|
||||
Instance { origin: self, panic }
|
||||
}
|
||||
|
||||
/// Returns how many times instances of the dummy have been cloned.
|
||||
pub fn cloned(&self) -> usize {
|
||||
pub(crate) fn cloned(&self) -> usize {
|
||||
self.cloned.load(SeqCst)
|
||||
}
|
||||
|
||||
/// Returns how many times instances of the dummy have been dropped.
|
||||
pub fn dropped(&self) -> usize {
|
||||
pub(crate) fn dropped(&self) -> usize {
|
||||
self.dropped.load(SeqCst)
|
||||
}
|
||||
|
||||
/// Returns how many times instances of the dummy have had their `query` member invoked.
|
||||
pub fn queried(&self) -> usize {
|
||||
pub(crate) fn queried(&self) -> usize {
|
||||
self.queried.load(SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Instance<'a> {
|
||||
pub(crate) struct Instance<'a> {
|
||||
origin: &'a CrashTestDummy,
|
||||
panic: Panic,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Panic {
|
||||
pub(crate) enum Panic {
|
||||
Never,
|
||||
InClone,
|
||||
InDrop,
|
||||
|
|
@ -66,12 +66,12 @@ pub enum Panic {
|
|||
}
|
||||
|
||||
impl Instance<'_> {
|
||||
pub fn id(&self) -> usize {
|
||||
pub(crate) fn id(&self) -> usize {
|
||||
self.origin.id
|
||||
}
|
||||
|
||||
/// Some anonymous query, the result of which is already given.
|
||||
pub fn query<R>(&self, result: R) -> R {
|
||||
pub(crate) fn query<R>(&self, result: R) -> R {
|
||||
self.origin.queried.fetch_add(1, SeqCst);
|
||||
if self.panic == Panic::InQuery {
|
||||
panic!("panic in `query`");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
pub mod crash_test;
|
||||
pub mod ord_chaos;
|
||||
pub mod rng;
|
||||
pub(crate) mod crash_test;
|
||||
pub(crate) mod ord_chaos;
|
||||
pub(crate) mod rng;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::ptr;
|
|||
|
||||
// Minimal type with an `Ord` implementation violating transitivity.
|
||||
#[derive(Debug)]
|
||||
pub enum Cyclic3 {
|
||||
pub(crate) enum Cyclic3 {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
|
|
@ -37,16 +37,16 @@ impl Eq for Cyclic3 {}
|
|||
|
||||
// Controls the ordering of values wrapped by `Governed`.
|
||||
#[derive(Debug)]
|
||||
pub struct Governor {
|
||||
pub(crate) struct Governor {
|
||||
flipped: Cell<bool>,
|
||||
}
|
||||
|
||||
impl Governor {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new() -> Self {
|
||||
Governor { flipped: Cell::new(false) }
|
||||
}
|
||||
|
||||
pub fn flip(&self) {
|
||||
pub(crate) fn flip(&self) {
|
||||
self.flipped.set(!self.flipped.get());
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ impl Governor {
|
|||
// (assuming that `T` respects total order), but can suddenly be made to invert
|
||||
// that total order.
|
||||
#[derive(Debug)]
|
||||
pub struct Governed<'a, T>(pub T, pub &'a Governor);
|
||||
pub(crate) struct Governed<'a, T>(pub T, pub &'a Governor);
|
||||
|
||||
impl<T: Ord> PartialOrd for Governed<'_, T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/// XorShiftRng
|
||||
pub struct DeterministicRng {
|
||||
pub(crate) struct DeterministicRng {
|
||||
count: usize,
|
||||
x: u32,
|
||||
y: u32,
|
||||
|
|
@ -8,12 +8,12 @@ pub struct DeterministicRng {
|
|||
}
|
||||
|
||||
impl DeterministicRng {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new() -> Self {
|
||||
DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
|
||||
}
|
||||
|
||||
/// Guarantees that each returned number is unique.
|
||||
pub fn next(&mut self) -> u32 {
|
||||
pub(crate) fn next(&mut self) -> u32 {
|
||||
self.count += 1;
|
||||
assert!(self.count <= 70029);
|
||||
let x = self.x;
|
||||
|
|
|
|||
|
|
@ -1267,6 +1267,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[track_caller]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")]
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
self.buf.reserve(self.len, additional);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ mod c_char_definition {
|
|||
// Section 2.1 "Basic Types" in MSP430 Embedded Application Binary
|
||||
// Interface says "The char type is unsigned by default".
|
||||
// https://www.ti.com/lit/an/slaa534a/slaa534a.pdf
|
||||
// Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945).
|
||||
// powerpc/powerpc64:
|
||||
// - PPC32 SysV: "Table 3-1 Scalar Types" in System V Application Binary Interface PowerPC
|
||||
// Processor Supplement says ANSI C char is unsigned byte
|
||||
|
|
@ -139,8 +138,10 @@ mod c_char_definition {
|
|||
// https://github.com/IBM/s390x-abi/releases/tag/v1.6.1
|
||||
// - z/OS: XL C/C++ Language Reference says: "By default, char behaves like an unsigned char."
|
||||
// https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-character-types
|
||||
// Xtensa:
|
||||
// - "The char type is unsigned by default for Xtensa processors."
|
||||
// xtensa:
|
||||
// Section 2.17.1 "Data Types and Alignment" of Xtensa LX Microprocessor Overview handbook
|
||||
// says "`char` type is unsigned by default".
|
||||
// https://loboris.eu/ESP32/Xtensa_lx%20Overview%20handbook.pdf
|
||||
//
|
||||
// On the following operating systems, c_char is signed by default, regardless of architecture.
|
||||
// Darwin (macOS, iOS, etc.):
|
||||
|
|
@ -150,11 +151,12 @@ mod c_char_definition {
|
|||
// Windows MSVC C++ Language Reference says "Microsoft-specific: Variables of type char
|
||||
// are promoted to int as if from type signed char by default, unless the /J compilation
|
||||
// option is used."
|
||||
// https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types)
|
||||
// L4RE:
|
||||
// https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types
|
||||
// L4Re:
|
||||
// The kernel builds with -funsigned-char on all targets (but useserspace follows the
|
||||
// architecture defaults). As we only have a target for userspace apps so there are no
|
||||
// special cases for L4RE below.
|
||||
// special cases for L4Re below.
|
||||
// https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240
|
||||
if #[cfg(all(
|
||||
not(windows),
|
||||
not(target_vendor = "apple"),
|
||||
|
|
@ -166,8 +168,8 @@ mod c_char_definition {
|
|||
target_arch = "msp430",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "riscv64",
|
||||
target_arch = "riscv32",
|
||||
target_arch = "riscv64",
|
||||
target_arch = "s390x",
|
||||
target_arch = "xtensa",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::fmt;
|
||||
|
||||
/// Creates a new iterator where each iteration calls the provided closure
|
||||
/// `F: FnMut() -> Option<T>`.
|
||||
/// Creates an iterator with the provided closure
|
||||
/// `F: FnMut() -> Option<T>` as its `[next](Iterator::next)` method.
|
||||
///
|
||||
/// The iterator will yield the `T`s returned from the closure.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1164,7 +1164,7 @@ impl AtomicBool {
|
|||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
|
|
@ -1203,6 +1203,125 @@ impl AtomicBool {
|
|||
}
|
||||
Err(prev)
|
||||
}
|
||||
|
||||
/// Fetches the value, and applies a function to it that returns an optional
|
||||
/// new value. Returns a `Result` of `Ok(previous_value)` if the function
|
||||
/// returned `Some(_)`, else `Err(previous_value)`.
|
||||
///
|
||||
/// See also: [`update`](`AtomicBool::update`).
|
||||
///
|
||||
/// Note: This may call the function multiple times if the value has been
|
||||
/// changed from other threads in the meantime, as long as the function
|
||||
/// returns `Some(_)`, but the function will have been applied only once to
|
||||
/// the stored value.
|
||||
///
|
||||
/// `try_update` takes two [`Ordering`] arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering for
|
||||
/// when the operation finally succeeds while the second describes the
|
||||
/// required ordering for loads. These correspond to the success and failure
|
||||
/// orderings of [`AtomicBool::compare_exchange`] respectively.
|
||||
///
|
||||
/// Using [`Acquire`] as success ordering makes the store part of this
|
||||
/// operation [`Relaxed`], and using [`Release`] makes the final successful
|
||||
/// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
|
||||
/// [`Acquire`] or [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(atomic_try_update)]
|
||||
/// use std::sync::atomic::{AtomicBool, Ordering};
|
||||
///
|
||||
/// let x = AtomicBool::new(false);
|
||||
/// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(false));
|
||||
/// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(false));
|
||||
/// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(true));
|
||||
/// assert_eq!(x.load(Ordering::SeqCst), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_try_update", issue = "135894")]
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub fn try_update(
|
||||
&self,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
f: impl FnMut(bool) -> Option<bool>,
|
||||
) -> Result<bool, bool> {
|
||||
// FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`;
|
||||
// when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`.
|
||||
self.fetch_update(set_order, fetch_order, f)
|
||||
}
|
||||
|
||||
/// Fetches the value, applies a function to it that it return a new value.
|
||||
/// The new value is stored and the old value is returned.
|
||||
///
|
||||
/// See also: [`try_update`](`AtomicBool::try_update`).
|
||||
///
|
||||
/// Note: This may call the function multiple times if the value has been changed from other threads in
|
||||
/// the meantime, but the function will have been applied only once to the stored value.
|
||||
///
|
||||
/// `update` takes two [`Ordering`] arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering for
|
||||
/// when the operation finally succeeds while the second describes the
|
||||
/// required ordering for loads. These correspond to the success and failure
|
||||
/// orderings of [`AtomicBool::compare_exchange`] respectively.
|
||||
///
|
||||
/// Using [`Acquire`] as success ordering makes the store part
|
||||
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
|
||||
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic operations on `u8`.
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(atomic_try_update)]
|
||||
///
|
||||
/// use std::sync::atomic::{AtomicBool, Ordering};
|
||||
///
|
||||
/// let x = AtomicBool::new(false);
|
||||
/// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| !x), false);
|
||||
/// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| !x), true);
|
||||
/// assert_eq!(x.load(Ordering::SeqCst), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_try_update", issue = "135894")]
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub fn update(
|
||||
&self,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
mut f: impl FnMut(bool) -> bool,
|
||||
) -> bool {
|
||||
let mut prev = self.load(fetch_order);
|
||||
loop {
|
||||
match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
|
||||
Ok(x) => break x,
|
||||
Err(next_prev) => prev = next_prev,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_has_atomic_load_store = "ptr")]
|
||||
|
|
@ -1684,7 +1803,7 @@ impl<T> AtomicPtr<T> {
|
|||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
|
|
@ -1732,6 +1851,137 @@ impl<T> AtomicPtr<T> {
|
|||
}
|
||||
Err(prev)
|
||||
}
|
||||
/// Fetches the value, and applies a function to it that returns an optional
|
||||
/// new value. Returns a `Result` of `Ok(previous_value)` if the function
|
||||
/// returned `Some(_)`, else `Err(previous_value)`.
|
||||
///
|
||||
/// See also: [`update`](`AtomicPtr::update`).
|
||||
///
|
||||
/// Note: This may call the function multiple times if the value has been
|
||||
/// changed from other threads in the meantime, as long as the function
|
||||
/// returns `Some(_)`, but the function will have been applied only once to
|
||||
/// the stored value.
|
||||
///
|
||||
/// `try_update` takes two [`Ordering`] arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering for
|
||||
/// when the operation finally succeeds while the second describes the
|
||||
/// required ordering for loads. These correspond to the success and failure
|
||||
/// orderings of [`AtomicPtr::compare_exchange`] respectively.
|
||||
///
|
||||
/// Using [`Acquire`] as success ordering makes the store part of this
|
||||
/// operation [`Relaxed`], and using [`Release`] makes the final successful
|
||||
/// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
|
||||
/// [`Acquire`] or [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on pointers.
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(atomic_try_update)]
|
||||
/// use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
///
|
||||
/// let ptr: *mut _ = &mut 5;
|
||||
/// let some_ptr = AtomicPtr::new(ptr);
|
||||
///
|
||||
/// let new: *mut _ = &mut 10;
|
||||
/// assert_eq!(some_ptr.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ptr));
|
||||
/// let result = some_ptr.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
|
||||
/// if x == ptr {
|
||||
/// Some(new)
|
||||
/// } else {
|
||||
/// None
|
||||
/// }
|
||||
/// });
|
||||
/// assert_eq!(result, Ok(ptr));
|
||||
/// assert_eq!(some_ptr.load(Ordering::SeqCst), new);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_try_update", issue = "135894")]
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub fn try_update(
|
||||
&self,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
f: impl FnMut(*mut T) -> Option<*mut T>,
|
||||
) -> Result<*mut T, *mut T> {
|
||||
// FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`;
|
||||
// when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`.
|
||||
self.fetch_update(set_order, fetch_order, f)
|
||||
}
|
||||
|
||||
/// Fetches the value, applies a function to it that it return a new value.
|
||||
/// The new value is stored and the old value is returned.
|
||||
///
|
||||
/// See also: [`try_update`](`AtomicPtr::try_update`).
|
||||
///
|
||||
/// Note: This may call the function multiple times if the value has been changed from other threads in
|
||||
/// the meantime, but the function will have been applied only once to the stored value.
|
||||
///
|
||||
/// `update` takes two [`Ordering`] arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering for
|
||||
/// when the operation finally succeeds while the second describes the
|
||||
/// required ordering for loads. These correspond to the success and failure
|
||||
/// orderings of [`AtomicPtr::compare_exchange`] respectively.
|
||||
///
|
||||
/// Using [`Acquire`] as success ordering makes the store part
|
||||
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
|
||||
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on pointers.
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(atomic_try_update)]
|
||||
///
|
||||
/// use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
///
|
||||
/// let ptr: *mut _ = &mut 5;
|
||||
/// let some_ptr = AtomicPtr::new(ptr);
|
||||
///
|
||||
/// let new: *mut _ = &mut 10;
|
||||
/// let result = some_ptr.update(Ordering::SeqCst, Ordering::SeqCst, |_| new);
|
||||
/// assert_eq!(result, ptr);
|
||||
/// assert_eq!(some_ptr.load(Ordering::SeqCst), new);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_try_update", issue = "135894")]
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub fn update(
|
||||
&self,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
mut f: impl FnMut(*mut T) -> *mut T,
|
||||
) -> *mut T {
|
||||
let mut prev = self.load(fetch_order);
|
||||
loop {
|
||||
match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
|
||||
Ok(x) => break x,
|
||||
Err(next_prev) => prev = next_prev,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Offsets the pointer's address by adding `val` (in units of `T`),
|
||||
/// returning the previous pointer.
|
||||
|
|
@ -2297,7 +2547,7 @@ macro_rules! atomic_int {
|
|||
$int_type,
|
||||
no = [
|
||||
"**Note:** This function is only available on targets where `",
|
||||
stringify!($int_type), "` has an alignment of ", $align, " bytes."
|
||||
stringify!($atomic_type), "` has the same alignment as `", stringify!($int_type), "`."
|
||||
],
|
||||
}]
|
||||
///
|
||||
|
|
@ -2875,7 +3125,7 @@ macro_rules! atomic_int {
|
|||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
|
||||
/// and suffers from the same drawbacks.
|
||||
|
|
@ -2913,6 +3163,127 @@ macro_rules! atomic_int {
|
|||
Err(prev)
|
||||
}
|
||||
|
||||
/// Fetches the value, and applies a function to it that returns an optional
|
||||
/// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
|
||||
/// `Err(previous_value)`.
|
||||
///
|
||||
#[doc = concat!("See also: [`update`](`", stringify!($atomic_type), "::update`).")]
|
||||
///
|
||||
/// Note: This may call the function multiple times if the value has been changed from other threads in
|
||||
/// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
|
||||
/// only once to the stored value.
|
||||
///
|
||||
/// `try_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
|
||||
/// The first describes the required ordering for when the operation finally succeeds while the second
|
||||
/// describes the required ordering for loads. These correspond to the success and failure orderings of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")]
|
||||
/// respectively.
|
||||
///
|
||||
/// Using [`Acquire`] as success ordering makes the store part
|
||||
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
|
||||
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
|
||||
///
|
||||
/// **Note**: This method is only available on platforms that support atomic operations on
|
||||
#[doc = concat!("[`", $s_int_type, "`].")]
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
|
||||
/// and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(atomic_try_update)]
|
||||
#[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
|
||||
///
|
||||
#[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")]
|
||||
/// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
|
||||
/// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
|
||||
/// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
|
||||
/// assert_eq!(x.load(Ordering::SeqCst), 9);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_try_update", issue = "135894")]
|
||||
#[$cfg_cas]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub fn try_update(
|
||||
&self,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
f: impl FnMut($int_type) -> Option<$int_type>,
|
||||
) -> Result<$int_type, $int_type> {
|
||||
// FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`;
|
||||
// when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`.
|
||||
self.fetch_update(set_order, fetch_order, f)
|
||||
}
|
||||
|
||||
/// Fetches the value, applies a function to it that it return a new value.
|
||||
/// The new value is stored and the old value is returned.
|
||||
///
|
||||
#[doc = concat!("See also: [`try_update`](`", stringify!($atomic_type), "::try_update`).")]
|
||||
///
|
||||
/// Note: This may call the function multiple times if the value has been changed from other threads in
|
||||
/// the meantime, but the function will have been applied only once to the stored value.
|
||||
///
|
||||
/// `update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
|
||||
/// The first describes the required ordering for when the operation finally succeeds while the second
|
||||
/// describes the required ordering for loads. These correspond to the success and failure orderings of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")]
|
||||
/// respectively.
|
||||
///
|
||||
/// Using [`Acquire`] as success ordering makes the store part
|
||||
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
|
||||
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
|
||||
///
|
||||
/// **Note**: This method is only available on platforms that support atomic operations on
|
||||
#[doc = concat!("[`", $s_int_type, "`].")]
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
|
||||
/// and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(atomic_try_update)]
|
||||
#[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
|
||||
///
|
||||
#[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")]
|
||||
/// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| x + 1), 7);
|
||||
/// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| x + 1), 8);
|
||||
/// assert_eq!(x.load(Ordering::SeqCst), 9);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_try_update", issue = "135894")]
|
||||
#[$cfg_cas]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub fn update(
|
||||
&self,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
mut f: impl FnMut($int_type) -> $int_type,
|
||||
) -> $int_type {
|
||||
let mut prev = self.load(fetch_order);
|
||||
loop {
|
||||
match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
|
||||
Ok(x) => break x,
|
||||
Err(next_prev) => prev = next_prev,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Maximum with the current value.
|
||||
///
|
||||
/// Finds the maximum of the current value and the argument `val`, and
|
||||
|
|
|
|||
|
|
@ -324,6 +324,20 @@ impl f128 {
|
|||
///
|
||||
/// The precision of this function is non-deterministic. This means it varies by platform,
|
||||
/// Rust version, and can even differ within the same execution from one invocation to the next.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f128)]
|
||||
/// # #[cfg(reliable_f128_math)] {
|
||||
///
|
||||
/// let x = 2.0_f128;
|
||||
/// let abs_difference = (x.powi(2) - (x * x)).abs();
|
||||
/// assert!(abs_difference <= f128::EPSILON);
|
||||
///
|
||||
/// assert_eq!(f128::powi(f128::NAN, 0), 1.0);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[rustc_allow_incoherent_impl]
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
|
|
@ -347,8 +361,10 @@ impl f128 {
|
|||
///
|
||||
/// let x = 2.0_f128;
|
||||
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
|
||||
///
|
||||
/// assert!(abs_difference <= f128::EPSILON);
|
||||
///
|
||||
/// assert_eq!(f128::powf(1.0, f128::NAN), 1.0);
|
||||
/// assert_eq!(f128::powf(f128::NAN, 0.0), 1.0);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -324,6 +324,20 @@ impl f16 {
|
|||
///
|
||||
/// The precision of this function is non-deterministic. This means it varies by platform,
|
||||
/// Rust version, and can even differ within the same execution from one invocation to the next.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f16)]
|
||||
/// # #[cfg(reliable_f16_math)] {
|
||||
///
|
||||
/// let x = 2.0_f16;
|
||||
/// let abs_difference = (x.powi(2) - (x * x)).abs();
|
||||
/// assert!(abs_difference <= f16::EPSILON);
|
||||
///
|
||||
/// assert_eq!(f16::powi(f16::NAN, 0), 1.0);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[rustc_allow_incoherent_impl]
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
|
|
@ -347,8 +361,10 @@ impl f16 {
|
|||
///
|
||||
/// let x = 2.0_f16;
|
||||
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
|
||||
///
|
||||
/// assert!(abs_difference <= f16::EPSILON);
|
||||
///
|
||||
/// assert_eq!(f16::powf(1.0, f16::NAN), 1.0);
|
||||
/// assert_eq!(f16::powf(f16::NAN, 0.0), 1.0);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -306,8 +306,9 @@ impl f32 {
|
|||
/// ```
|
||||
/// let x = 2.0_f32;
|
||||
/// let abs_difference = (x.powi(2) - (x * x)).abs();
|
||||
///
|
||||
/// assert!(abs_difference <= f32::EPSILON);
|
||||
///
|
||||
/// assert_eq!(f32::powi(f32::NAN, 0), 1.0);
|
||||
/// ```
|
||||
#[rustc_allow_incoherent_impl]
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
|
|
@ -329,8 +330,10 @@ impl f32 {
|
|||
/// ```
|
||||
/// let x = 2.0_f32;
|
||||
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
|
||||
///
|
||||
/// assert!(abs_difference <= f32::EPSILON);
|
||||
///
|
||||
/// assert_eq!(f32::powf(1.0, f32::NAN), 1.0);
|
||||
/// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0);
|
||||
/// ```
|
||||
#[rustc_allow_incoherent_impl]
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
|
|
|
|||
|
|
@ -306,8 +306,9 @@ impl f64 {
|
|||
/// ```
|
||||
/// let x = 2.0_f64;
|
||||
/// let abs_difference = (x.powi(2) - (x * x)).abs();
|
||||
/// assert!(abs_difference <= f64::EPSILON);
|
||||
///
|
||||
/// assert!(abs_difference < 1e-10);
|
||||
/// assert_eq!(f64::powi(f64::NAN, 0), 1.0);
|
||||
/// ```
|
||||
#[rustc_allow_incoherent_impl]
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
|
|
@ -329,8 +330,10 @@ impl f64 {
|
|||
/// ```
|
||||
/// let x = 2.0_f64;
|
||||
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
|
||||
/// assert!(abs_difference <= f64::EPSILON);
|
||||
///
|
||||
/// assert!(abs_difference < 1e-10);
|
||||
/// assert_eq!(f64::powf(1.0, f64::NAN), 1.0);
|
||||
/// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0);
|
||||
/// ```
|
||||
#[rustc_allow_incoherent_impl]
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ use std::{env, fs};
|
|||
use crate::core::build_steps::toolstate::ToolState;
|
||||
use crate::core::build_steps::{compile, llvm};
|
||||
use crate::core::builder;
|
||||
use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
|
||||
use crate::core::config::{DebuginfoLevel, TargetSelection};
|
||||
use crate::core::builder::{
|
||||
Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step, cargo_profile_var,
|
||||
};
|
||||
use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection};
|
||||
use crate::utils::channel::GitInfo;
|
||||
use crate::utils::exec::{BootstrapCommand, command};
|
||||
use crate::utils::helpers::{add_dylib_path, exe, t};
|
||||
|
|
@ -645,7 +647,7 @@ impl Step for Rustdoc {
|
|||
}
|
||||
|
||||
// NOTE: Never modify the rustflags here, it breaks the build cache for other tools!
|
||||
let cargo = prepare_tool_cargo(
|
||||
let mut cargo = prepare_tool_cargo(
|
||||
builder,
|
||||
build_compiler,
|
||||
Mode::ToolRustc,
|
||||
|
|
@ -656,6 +658,17 @@ impl Step for Rustdoc {
|
|||
features.as_slice(),
|
||||
);
|
||||
|
||||
// rustdoc is performance sensitive, so apply LTO to it.
|
||||
let lto = match builder.config.rust_lto {
|
||||
RustcLto::Off => Some("off"),
|
||||
RustcLto::Thin => Some("thin"),
|
||||
RustcLto::Fat => Some("fat"),
|
||||
RustcLto::ThinLocal => None,
|
||||
};
|
||||
if let Some(lto) = lto {
|
||||
cargo.env(cargo_profile_var("LTO", &builder.config), lto);
|
||||
}
|
||||
|
||||
let _guard = builder.msg_tool(
|
||||
Kind::Build,
|
||||
Mode::ToolRustc,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::core::config::flags::Color;
|
|||
use crate::utils::build_stamp;
|
||||
use crate::utils::helpers::{self, LldThreads, check_cfg_arg, linker_args, linker_flags};
|
||||
use crate::{
|
||||
BootstrapCommand, CLang, Compiler, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode,
|
||||
BootstrapCommand, CLang, Compiler, Config, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode,
|
||||
TargetSelection, command, prepare_behaviour_dump_dir, t,
|
||||
};
|
||||
|
||||
|
|
@ -484,10 +484,7 @@ impl Builder<'_> {
|
|||
build_stamp::clear_if_dirty(self, &my_out, &rustdoc);
|
||||
}
|
||||
|
||||
let profile_var = |name: &str| {
|
||||
let profile = if self.config.rust_optimize.is_release() { "RELEASE" } else { "DEV" };
|
||||
format!("CARGO_PROFILE_{}_{}", profile, name)
|
||||
};
|
||||
let profile_var = |name: &str| cargo_profile_var(name, &self.config);
|
||||
|
||||
// See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config
|
||||
// needs to not accidentally link to libLLVM in stage0/lib.
|
||||
|
|
@ -1232,3 +1229,8 @@ impl Builder<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cargo_profile_var(name: &str, config: &Config) -> String {
|
||||
let profile = if config.rust_optimize.is_release() { "RELEASE" } else { "DEV" };
|
||||
format!("CARGO_PROFILE_{}_{}", profile, name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::{env, fs};
|
|||
|
||||
use clap::ValueEnum;
|
||||
|
||||
pub use self::cargo::Cargo;
|
||||
pub use self::cargo::{Cargo, cargo_profile_var};
|
||||
pub use crate::Compiler;
|
||||
use crate::core::build_steps::{
|
||||
check, clean, clippy, compile, dist, doc, gcc, install, llvm, run, setup, test, tool, vendor,
|
||||
|
|
|
|||
|
|
@ -340,4 +340,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
|||
severity: ChangeSeverity::Info,
|
||||
summary: "Change the compiler profile to default to rust.debug-assertions = true",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 135832,
|
||||
severity: ChangeSeverity::Info,
|
||||
summary: "Rustdoc now respects the value of rust.lto.",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ pub fn output_result(cmd: &mut Command) -> Result<String, String> {
|
|||
/// Finds the remote for rust-lang/rust.
|
||||
/// For example for these remotes it will return `upstream`.
|
||||
/// ```text
|
||||
/// origin https://github.com/Nilstrieb/rust.git (fetch)
|
||||
/// origin https://github.com/Nilstrieb/rust.git (push)
|
||||
/// origin https://github.com/pietroalbani/rust.git (fetch)
|
||||
/// origin https://github.com/pietroalbani/rust.git (push)
|
||||
/// upstream https://github.com/rust-lang/rust (fetch)
|
||||
/// upstream https://github.com/rust-lang/rust (push)
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ RUN yum upgrade -y && \
|
|||
gcc-c++ \
|
||||
git \
|
||||
glibc-devel \
|
||||
glibc-static \
|
||||
libedit-devel \
|
||||
libstdc++-devel \
|
||||
make \
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ RUN yum upgrade -y && \
|
|||
git \
|
||||
glibc-devel.i686 \
|
||||
glibc-devel.x86_64 \
|
||||
glibc-static.i686 \
|
||||
glibc-static.x86_64 \
|
||||
libedit-devel \
|
||||
libstdc++-devel.i686 \
|
||||
libstdc++-devel.x86_64 \
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ envs:
|
|||
# builds)
|
||||
# - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain
|
||||
#
|
||||
# If you *want* these to happen however, temporarily uncomment it before triggering a try build.
|
||||
# If you *want* these to happen however, temporarily comment it before triggering a try build.
|
||||
DIST_TRY_BUILD: 1
|
||||
|
||||
auto:
|
||||
|
|
|
|||
2
src/tools/clippy/.github/deploy.sh
vendored
2
src/tools/clippy/.github/deploy.sh
vendored
|
|
@ -45,6 +45,8 @@ if [[ -n $TAG_NAME ]]; then
|
|||
git add "$TAG_NAME"
|
||||
# Update the symlink
|
||||
git add stable
|
||||
# Update the index.html file
|
||||
git add index.html
|
||||
git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}"
|
||||
elif [[ $BETA = "true" ]]; then
|
||||
if git diff --exit-code --quiet -- beta/; then
|
||||
|
|
|
|||
6
src/tools/clippy/.github/driver.sh
vendored
6
src/tools/clippy/.github/driver.sh
vendored
|
|
@ -47,9 +47,9 @@ unset CARGO_MANIFEST_DIR
|
|||
|
||||
# Run a lint and make sure it produces the expected output. It's also expected to exit with code 1
|
||||
# FIXME: How to match the clippy invocation in compile-test.rs?
|
||||
./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/box_default.rs 2>box_default.stderr && exit 1
|
||||
sed -e "/= help: for/d" box_default.stderr > normalized.stderr
|
||||
diff -u normalized.stderr tests/ui/box_default.stderr
|
||||
./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/string_to_string.rs 2>string_to_string.stderr && exit 1
|
||||
sed -e "/= help: for/d" string_to_string.stderr > normalized.stderr
|
||||
diff -u normalized.stderr tests/ui/string_to_string.stderr
|
||||
|
||||
# make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
|
||||
SYSROOT=$(rustc --print sysroot)
|
||||
|
|
|
|||
59
src/tools/clippy/.github/workflows/clippy_changelog.yml
vendored
Normal file
59
src/tools/clippy/.github/workflows/clippy_changelog.yml
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
name: Clippy changelog check
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, edited]
|
||||
|
||||
concurrency:
|
||||
# For a given workflow, if we push to the same PR, cancel all previous builds on that PR.
|
||||
# If the push is not attached to a PR, we will cancel all builds on the same branch.
|
||||
group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
# Run
|
||||
- name: Check Changelog
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/rust-lang/rust-clippy/pulls/$PR_NUMBER" | \
|
||||
python -c "import sys, json; print(json.load(sys.stdin)['body'])")
|
||||
output=$(awk '/^changelog:\s*\S/ && !/changelog: \[.*\]: your change/' <<< "$body" | sed "s/changelog:\s*//g")
|
||||
if [ -z "$output" ]; then
|
||||
echo "ERROR: pull request message must contain 'changelog: ...' with your changelog. Please add it."
|
||||
exit 1
|
||||
else
|
||||
echo "changelog: $output"
|
||||
fi
|
||||
env:
|
||||
PYTHONIOENCODING: 'utf-8'
|
||||
PR_NUMBER: '${{ github.event.number }}'
|
||||
|
||||
# We need to have the "conclusion" job also on PR CI, to make it possible
|
||||
# to add PRs to a merge queue.
|
||||
conclusion_changelog:
|
||||
needs: [ changelog ]
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
# when the workflow is canceled manually.
|
||||
#
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: Conclusion
|
||||
run: |
|
||||
# Print the dependent jobs to see them in the CI log
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful.
|
||||
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
34
src/tools/clippy/.github/workflows/clippy_mq.yml
vendored
34
src/tools/clippy/.github/workflows/clippy_mq.yml
vendored
|
|
@ -15,37 +15,7 @@ defaults:
|
|||
shell: bash
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
# Unsetting this would make so that any malicious package could get our Github Token
|
||||
persist-credentials: false
|
||||
|
||||
# Run
|
||||
- name: Check Changelog
|
||||
run: |
|
||||
MESSAGE=$(git log --format=%B -n 1)
|
||||
PR=$(echo "$MESSAGE" | grep -o "#[0-9]*" | head -1 | sed -e 's/^#//')
|
||||
body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/rust-lang/rust-clippy/pulls/$PR" | \
|
||||
python -c "import sys, json; print(json.load(sys.stdin)['body'])")
|
||||
output=$(grep "^changelog:\s*\S" <<< "$body" | sed "s/changelog:\s*//g") || {
|
||||
echo "ERROR: PR body must contain 'changelog: ...'"
|
||||
exit 1
|
||||
}
|
||||
if [[ "$output" = "none" ]]; then
|
||||
echo "WARNING: changelog is 'none'"
|
||||
else
|
||||
echo "changelog: $output"
|
||||
fi
|
||||
env:
|
||||
PYTHONIOENCODING: 'utf-8'
|
||||
base:
|
||||
needs: changelog
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
|
|
@ -119,7 +89,6 @@ jobs:
|
|||
OS: ${{ runner.os }}
|
||||
|
||||
metadata_collection:
|
||||
needs: changelog
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
@ -138,7 +107,6 @@ jobs:
|
|||
run: cargo collect-metadata
|
||||
|
||||
integration_build:
|
||||
needs: changelog
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
@ -228,7 +196,7 @@ jobs:
|
|||
INTEGRATION: ${{ matrix.integration }}
|
||||
|
||||
conclusion:
|
||||
needs: [ changelog, base, metadata_collection, integration_build, integration ]
|
||||
needs: [ base, metadata_collection, integration_build, integration ]
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
name: Lintcheck
|
||||
|
||||
on: pull_request
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'book/**'
|
||||
- 'util/**'
|
||||
- 'tests/**'
|
||||
- '*.md'
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
- name: Install mdbook
|
||||
run: |
|
||||
mkdir mdbook
|
||||
curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.34/mdbook-v0.4.34-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
|
||||
curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.43/mdbook-v0.4.43-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
|
||||
echo `pwd`/mdbook >> $GITHUB_PATH
|
||||
|
||||
# Run
|
||||
|
|
|
|||
|
|
@ -5533,6 +5533,7 @@ Released 2018-09-13
|
|||
[`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
|
||||
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
|
||||
[`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs
|
||||
[`doc_overindented_list_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items
|
||||
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
|
||||
[`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last
|
||||
[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
|
||||
|
|
@ -5762,11 +5763,13 @@ Released 2018-09-13
|
|||
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
|
||||
[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back
|
||||
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
|
||||
[`manual_ok_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_err
|
||||
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
|
||||
[`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison
|
||||
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
|
||||
[`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
|
||||
[`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
|
||||
[`manual_repeat_n`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n
|
||||
[`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain
|
||||
[`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate
|
||||
[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
|
||||
|
|
@ -5904,6 +5907,7 @@ Released 2018-09-13
|
|||
[`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg
|
||||
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
|
||||
[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
|
||||
[`non_std_lazy_statics`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_std_lazy_statics
|
||||
[`non_zero_suggestions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_zero_suggestions
|
||||
[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
|
||||
[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
|
||||
|
|
@ -6063,6 +6067,7 @@ Released 2018-09-13
|
|||
[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
|
||||
[`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref
|
||||
[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
|
||||
[`sliced_string_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#sliced_string_as_bytes
|
||||
[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
|
||||
[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
|
||||
[`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc
|
||||
|
|
@ -6172,12 +6177,14 @@ Released 2018-09-13
|
|||
[`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment
|
||||
[`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc
|
||||
[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
|
||||
[`unnecessary_semicolon`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_semicolon
|
||||
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
|
||||
[`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization
|
||||
[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
|
||||
[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
|
||||
[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
|
||||
[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
|
||||
[`unneeded_struct_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_struct_pattern
|
||||
[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
|
||||
[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns
|
||||
[`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable
|
||||
|
|
@ -6216,6 +6223,7 @@ Released 2018-09-13
|
|||
[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
|
||||
[`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
|
||||
[`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
|
||||
[`useless_nonzero_new_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_nonzero_new_unchecked
|
||||
[`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
|
||||
[`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
|
||||
[`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ currently. Between writing new lints, fixing issues, reviewing pull requests and
|
|||
responding to issues there may not always be enough time to stay on top of it
|
||||
all.
|
||||
|
||||
Our highest priority is fixing [crashes][l-crash] and [bugs][l-bug], for example
|
||||
Our highest priority is fixing [ICEs][I-ICE] and [bugs][C-bug], for example
|
||||
an ICE in a popular crate that many other crates depend on. We don't
|
||||
want Clippy to crash on your code and we want it to be as reliable as the
|
||||
suggestions from Rust compiler errors.
|
||||
|
|
@ -213,8 +213,8 @@ Or rather: before the sync this should be addressed,
|
|||
e.g. by removing a lint again, so it doesn't hit beta/stable.
|
||||
|
||||
[triage]: https://forge.rust-lang.org/release/triage-procedure.html
|
||||
[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash
|
||||
[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug
|
||||
[I-ICE]: https://github.com/rust-lang/rust-clippy/labels/I-ICE
|
||||
[C-bug]: https://github.com/rust-lang/rust-clippy/labels/C-bug
|
||||
[p-low]: https://github.com/rust-lang/rust-clippy/labels/P-low
|
||||
[p-medium]: https://github.com/rust-lang/rust-clippy/labels/P-medium
|
||||
[p-high]: https://github.com/rust-lang/rust-clippy/labels/P-high
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue