Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-01-29 05:25:22 +00:00
commit 667da1e3bd
508 changed files with 8982 additions and 3424 deletions

View file

@ -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",
]

View file

@ -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(),

View file

@ -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(

View file

@ -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);

View file

@ -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,
},

View file

@ -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();

View file

@ -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 {

View file

@ -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,

View file

@ -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)
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)]

View file

@ -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,

View file

@ -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)?;

View file

@ -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" }

View file

@ -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;
}
}
}

View file

@ -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(),

View file

@ -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));

View file

@ -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;
}

View file

@ -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`.
///

View file

@ -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,

View file

@ -15,6 +15,7 @@ TrivialTypeTraversalImpls! {
SourceScopeLocalData,
UserTypeAnnotationIndex,
BorrowKind,
RawPtrKind,
CastKind,
BasicBlock,
SwitchTargets,

View file

@ -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);
}

View file

@ -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)?)))

View file

@ -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)
}

View file

@ -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()
}

View file

@ -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(

View file

@ -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()

View file

@ -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

View file

@ -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),
))),
};

View file

@ -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

View file

@ -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 {:?}",

View file

@ -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)]

View file

@ -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);

View file

@ -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],

View file

@ -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 {

View file

@ -2184,8 +2184,10 @@ symbols! {
vec_macro,
vec_new,
vec_pop,
vec_reserve,
vec_with_capacity,
vecdeque_iter,
vecdeque_reserve,
vector,
version,
vfp2,

View file

@ -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 `()`.

View file

@ -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));
}
}
}

View file

@ -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) => {

View file

@ -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![];

View file

@ -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,
)?

View file

@ -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))
}
}

View file

@ -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)
}
}

View file

@ -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,
));

View file

@ -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)
})
}

View file

@ -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)
})
}

View file

@ -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>(

View file

@ -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,

View file

@ -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)",
}
}

View file

@ -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) => {

View file

@ -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
///

View file

@ -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();

View file

@ -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() }
}

View file

@ -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() }
}
}

View file

@ -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.

View file

@ -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) {

View file

@ -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,
{

View file

@ -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;

View file

@ -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>

View file

@ -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.

View file

@ -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,
{

View file

@ -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,

View file

@ -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>,

View file

@ -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>,
{

View file

@ -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;

View file

@ -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");

View file

@ -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")]

View file

@ -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)
}
}

View file

@ -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;

View file

@ -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

View file

@ -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`");

View file

@ -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;

View file

@ -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> {

View file

@ -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;

View file

@ -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);
}

View file

@ -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",
)

View file

@ -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.
///

View file

@ -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

View file

@ -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]

View file

@ -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]

View file

@ -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"]

View file

@ -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"]

View file

@ -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,

View file

@ -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)
}

View file

@ -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,

View file

@ -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.",
},
];

View file

@ -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)
/// ```

View file

@ -20,6 +20,7 @@ RUN yum upgrade -y && \
gcc-c++ \
git \
glibc-devel \
glibc-static \
libedit-devel \
libstdc++-devel \
make \

View file

@ -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 \

View file

@ -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:

View file

@ -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

View file

@ -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)

View 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) }}'

View file

@ -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

View file

@ -1,6 +1,12 @@
name: Lintcheck
on: pull_request
on:
pull_request:
paths-ignore:
- 'book/**'
- 'util/**'
- 'tests/**'
- '*.md'
env:
RUST_BACKTRACE: 1

View file

@ -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

View file

@ -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

View file

@ -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