Auto merge of #3736 - rust-lang:rustup-2024-07-06, r=RalfJung
Automatic Rustup
This commit is contained in:
commit
d358f5dcf9
226 changed files with 4962 additions and 2961 deletions
10
Cargo.lock
10
Cargo.lock
|
|
@ -4168,8 +4168,10 @@ dependencies = [
|
|||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_next_trait_solver",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_type_ir",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
|
@ -6356,9 +6358,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.57.0"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ccb96113d6277ba543c0f77e1c5494af8094bf9daf9b85acdc3f1b620e7c7b4"
|
||||
checksum = "91cd28d93c692351f3a6e5615567c56756e330bee1c99c6bdd57bfc5ab15f589"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"rayon",
|
||||
|
|
@ -6379,9 +6381,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-metadata"
|
||||
version = "0.57.0"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8308d076825b9d9e5abc64f8113e96d02b2aeeba869b20fdd65c7e70cda13dfc"
|
||||
checksum = "2e837f3c3012cfe9e7086302a93f441a7999439be1ad4c530d55d2f6d2921809"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ pub enum GenericArgs {
|
|||
AngleBracketed(AngleBracketedArgs),
|
||||
/// The `(A, B)` and `C` in `Foo(A, B) -> C`.
|
||||
Parenthesized(ParenthesizedArgs),
|
||||
/// `(..)` in return type notation
|
||||
/// `(..)` in return type notation.
|
||||
ParenthesizedElided(Span),
|
||||
}
|
||||
|
||||
|
|
@ -197,11 +197,11 @@ impl GenericArgs {
|
|||
/// Concrete argument in the sequence of generic args.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum GenericArg {
|
||||
/// `'a` in `Foo<'a>`
|
||||
/// `'a` in `Foo<'a>`.
|
||||
Lifetime(Lifetime),
|
||||
/// `Bar` in `Foo<Bar>`
|
||||
/// `Bar` in `Foo<Bar>`.
|
||||
Type(P<Ty>),
|
||||
/// `1` in `Foo<1>`
|
||||
/// `1` in `Foo<1>`.
|
||||
Const(AnonConst),
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +355,7 @@ pub enum GenericParamKind {
|
|||
ty: P<Ty>,
|
||||
/// Span of the `const` keyword.
|
||||
kw_span: Span,
|
||||
/// Optional default value for the const generic param
|
||||
/// Optional default value for the const generic param.
|
||||
default: Option<AnonConst>,
|
||||
},
|
||||
}
|
||||
|
|
@ -714,6 +714,7 @@ pub enum ByRef {
|
|||
}
|
||||
|
||||
impl ByRef {
|
||||
#[must_use]
|
||||
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
|
||||
if let ByRef::Yes(old_mutbl) = &mut self {
|
||||
*old_mutbl = cmp::min(*old_mutbl, mutbl);
|
||||
|
|
@ -832,7 +833,7 @@ pub enum PatKind {
|
|||
/// only one rest pattern may occur in the pattern sequences.
|
||||
Rest,
|
||||
|
||||
// A never pattern `!`
|
||||
// A never pattern `!`.
|
||||
Never,
|
||||
|
||||
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
|
||||
|
|
@ -1121,9 +1122,9 @@ impl LocalKind {
|
|||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Arm {
|
||||
pub attrs: AttrVec,
|
||||
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`
|
||||
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`.
|
||||
pub pat: P<Pat>,
|
||||
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
|
||||
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`.
|
||||
pub guard: Option<P<Expr>>,
|
||||
/// Match arm body. Omitted if the pattern is a never pattern.
|
||||
pub body: Option<P<Expr>>,
|
||||
|
|
@ -1354,12 +1355,12 @@ pub struct Closure {
|
|||
pub fn_arg_span: Span,
|
||||
}
|
||||
|
||||
/// Limit types of a range (inclusive or exclusive)
|
||||
/// Limit types of a range (inclusive or exclusive).
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
|
||||
pub enum RangeLimits {
|
||||
/// Inclusive at the beginning, exclusive at the end
|
||||
/// Inclusive at the beginning, exclusive at the end.
|
||||
HalfOpen,
|
||||
/// Inclusive at the beginning and end
|
||||
/// Inclusive at the beginning and end.
|
||||
Closed,
|
||||
}
|
||||
|
||||
|
|
@ -1400,9 +1401,9 @@ pub struct StructExpr {
|
|||
pub enum ExprKind {
|
||||
/// An array (e.g, `[a, b, c, d]`).
|
||||
Array(ThinVec<P<Expr>>),
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
/// Allow anonymous constants from an inline `const` block.
|
||||
ConstBlock(AnonConst),
|
||||
/// A function call
|
||||
/// A function call.
|
||||
///
|
||||
/// The first field resolves to the function itself,
|
||||
/// and the second field is the list of arguments.
|
||||
|
|
@ -1456,7 +1457,7 @@ pub enum ExprKind {
|
|||
/// A block (`'label: { ... }`).
|
||||
Block(P<Block>, Option<Label>),
|
||||
/// An `async` block (`async move { ... }`),
|
||||
/// or a `gen` block (`gen move { ... }`)
|
||||
/// or a `gen` block (`gen move { ... }`).
|
||||
///
|
||||
/// The span is the "decl", which is the header before the body `{ }`
|
||||
/// including the `asyng`/`gen` keywords and possibly `move`.
|
||||
|
|
@ -2156,9 +2157,9 @@ pub enum TyKind {
|
|||
Never,
|
||||
/// A tuple (`(A, B, C, D,...)`).
|
||||
Tup(ThinVec<P<Ty>>),
|
||||
/// An anonymous struct type i.e. `struct { foo: Type }`
|
||||
/// An anonymous struct type i.e. `struct { foo: Type }`.
|
||||
AnonStruct(NodeId, ThinVec<FieldDef>),
|
||||
/// An anonymous union type i.e. `union { bar: Type }`
|
||||
/// An anonymous union type i.e. `union { bar: Type }`.
|
||||
AnonUnion(NodeId, ThinVec<FieldDef>),
|
||||
/// A path (`module::module::...::Type`), optionally
|
||||
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
||||
|
|
@ -2232,9 +2233,9 @@ pub enum TraitObjectSyntax {
|
|||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum PreciseCapturingArg {
|
||||
/// Lifetime parameter
|
||||
/// Lifetime parameter.
|
||||
Lifetime(Lifetime),
|
||||
/// Type or const parameter
|
||||
/// Type or const parameter.
|
||||
Arg(Path, NodeId),
|
||||
}
|
||||
|
||||
|
|
@ -2528,11 +2529,11 @@ pub enum Safety {
|
|||
/// Iterator`.
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
|
||||
pub enum CoroutineKind {
|
||||
/// `async`, which returns an `impl Future`
|
||||
/// `async`, which returns an `impl Future`.
|
||||
Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
/// `gen`, which returns an `impl Iterator`
|
||||
/// `gen`, which returns an `impl Iterator`.
|
||||
Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
/// `async gen`, which returns an `impl AsyncIterator`
|
||||
/// `async gen`, which returns an `impl AsyncIterator`.
|
||||
AsyncGen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
}
|
||||
|
||||
|
|
@ -2749,7 +2750,7 @@ pub struct Variant {
|
|||
pub data: VariantData,
|
||||
/// Explicit discriminant, e.g., `Foo = 1`.
|
||||
pub disr_expr: Option<AnonConst>,
|
||||
/// Is a macro placeholder
|
||||
/// Is a macro placeholder.
|
||||
pub is_placeholder: bool,
|
||||
}
|
||||
|
||||
|
|
@ -3023,19 +3024,19 @@ impl Item {
|
|||
/// `extern` qualifier on a function item or function type.
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
|
||||
pub enum Extern {
|
||||
/// No explicit extern keyword was used
|
||||
/// No explicit extern keyword was used.
|
||||
///
|
||||
/// E.g. `fn foo() {}`
|
||||
/// E.g. `fn foo() {}`.
|
||||
None,
|
||||
/// An explicit extern keyword was used, but with implicit ABI
|
||||
/// An explicit extern keyword was used, but with implicit ABI.
|
||||
///
|
||||
/// E.g. `extern fn foo() {}`
|
||||
/// E.g. `extern fn foo() {}`.
|
||||
///
|
||||
/// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
|
||||
/// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`).
|
||||
Implicit(Span),
|
||||
/// An explicit extern keyword was used with an explicit ABI
|
||||
/// An explicit extern keyword was used with an explicit ABI.
|
||||
///
|
||||
/// E.g. `extern "C" fn foo() {}`
|
||||
/// E.g. `extern "C" fn foo() {}`.
|
||||
Explicit(StrLit, Span),
|
||||
}
|
||||
|
||||
|
|
@ -3054,13 +3055,13 @@ impl Extern {
|
|||
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
|
||||
pub struct FnHeader {
|
||||
/// Whether this is `unsafe`, or has a default safety
|
||||
/// Whether this is `unsafe`, or has a default safety.
|
||||
pub safety: Safety,
|
||||
/// Whether this is `async`, `gen`, or nothing.
|
||||
pub coroutine_kind: Option<CoroutineKind>,
|
||||
/// The `const` keyword, if any
|
||||
pub constness: Const,
|
||||
/// The `extern` keyword and corresponding ABI string, if any
|
||||
/// The `extern` keyword and corresponding ABI string, if any.
|
||||
pub ext: Extern,
|
||||
}
|
||||
|
||||
|
|
@ -3254,7 +3255,7 @@ pub enum ItemKind {
|
|||
///
|
||||
/// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
|
||||
Trait(Box<Trait>),
|
||||
/// Trait alias
|
||||
/// Trait alias.
|
||||
///
|
||||
/// E.g., `trait Foo = Bar + Quux;`.
|
||||
TraitAlias(Generics, GenericBounds),
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
|||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::borrow_set::TwoPhaseActivation;
|
||||
use crate::borrowck_errors;
|
||||
|
|
@ -784,20 +785,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
/// binding declaration within every scope we inspect.
|
||||
struct Finder {
|
||||
hir_id: hir::HirId,
|
||||
found: bool,
|
||||
}
|
||||
impl<'hir> Visitor<'hir> for Finder {
|
||||
fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) -> Self::Result {
|
||||
if pat.hir_id == self.hir_id {
|
||||
self.found = true;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
hir::intravisit::walk_pat(self, pat);
|
||||
hir::intravisit::walk_pat(self, pat)
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
||||
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) -> Self::Result {
|
||||
if ex.hir_id == self.hir_id {
|
||||
self.found = true;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
hir::intravisit::walk_expr(self, ex);
|
||||
hir::intravisit::walk_expr(self, ex)
|
||||
}
|
||||
}
|
||||
// The immediate HIR parent of the moved expression. We'll look for it to be a call.
|
||||
|
|
@ -822,9 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
_ => continue,
|
||||
};
|
||||
if let Some(&hir_id) = local_hir_id {
|
||||
let mut finder = Finder { hir_id, found: false };
|
||||
finder.visit_expr(e);
|
||||
if finder.found {
|
||||
if (Finder { hir_id }).visit_expr(e).is_break() {
|
||||
// The current scope includes the declaration of the binding we're accessing, we
|
||||
// can't look up any further for loops.
|
||||
break;
|
||||
|
|
@ -839,9 +838,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::If(cond, ..), ..
|
||||
}) => {
|
||||
let mut finder = Finder { hir_id: expr.hir_id, found: false };
|
||||
finder.visit_expr(cond);
|
||||
if finder.found {
|
||||
if (Finder { hir_id: expr.hir_id }).visit_expr(cond).is_break() {
|
||||
// The expression where the move error happened is in a `while let`
|
||||
// condition Don't suggest clone as it will likely end in an
|
||||
// infinite loop.
|
||||
|
|
@ -1837,7 +1834,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
|
||||
pub struct Holds<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
holds: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
|
||||
|
|
@ -1845,7 +1841,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
if t == self.ty {
|
||||
self.holds = true;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
|
@ -1863,9 +1859,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
&& rcvr_ty == ty
|
||||
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
|
||||
&& let inner = inner.peel_refs()
|
||||
&& let mut v = (Holds { ty: inner, holds: false })
|
||||
&& let _ = v.visit_ty(local_ty)
|
||||
&& v.holds
|
||||
&& (Holds { ty: inner }).visit_ty(local_ty).is_break()
|
||||
&& let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
|
||||
{
|
||||
err.span_label(
|
||||
|
|
@ -4325,15 +4319,14 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
|
|||
}
|
||||
|
||||
/// Detect whether one of the provided spans is a statement nested within the top-most visited expr
|
||||
struct ReferencedStatementsVisitor<'a>(&'a [Span], bool);
|
||||
struct ReferencedStatementsVisitor<'a>(&'a [Span]);
|
||||
|
||||
impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> {
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
|
||||
impl<'v> Visitor<'v> for ReferencedStatementsVisitor<'_> {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
|
||||
match s.kind {
|
||||
hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => {
|
||||
self.1 = true;
|
||||
}
|
||||
_ => {}
|
||||
hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => ControlFlow::Break(()),
|
||||
_ => ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4375,9 +4368,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
hir::ExprKind::If(cond, body, None) => {
|
||||
// `if` expressions with no `else` that initialize the binding might be missing an
|
||||
// `else` arm.
|
||||
let mut v = ReferencedStatementsVisitor(self.spans, false);
|
||||
v.visit_expr(body);
|
||||
if v.1 {
|
||||
if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() {
|
||||
self.errors.push((
|
||||
cond.span,
|
||||
format!(
|
||||
|
|
@ -4394,11 +4385,9 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
hir::ExprKind::If(cond, body, Some(other)) => {
|
||||
// `if` expressions where the binding is only initialized in one of the two arms
|
||||
// might be missing a binding initialization.
|
||||
let mut a = ReferencedStatementsVisitor(self.spans, false);
|
||||
a.visit_expr(body);
|
||||
let mut b = ReferencedStatementsVisitor(self.spans, false);
|
||||
b.visit_expr(other);
|
||||
match (a.1, b.1) {
|
||||
let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break();
|
||||
let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break();
|
||||
match (a, b) {
|
||||
(true, true) | (false, false) => {}
|
||||
(true, false) => {
|
||||
if other.span.is_desugaring(DesugaringKind::WhileLoop) {
|
||||
|
|
@ -4437,11 +4426,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
// arms might be missing an initialization.
|
||||
let results: Vec<bool> = arms
|
||||
.iter()
|
||||
.map(|arm| {
|
||||
let mut v = ReferencedStatementsVisitor(self.spans, false);
|
||||
v.visit_arm(arm);
|
||||
v.1
|
||||
})
|
||||
.map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break())
|
||||
.collect();
|
||||
if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
|
||||
for (arm, seen) in arms.iter().zip(results) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_infer::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
|
||||
use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::infer::relate::{
|
||||
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
|
||||
};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
|
|
@ -522,7 +523,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx
|
|||
}
|
||||
}
|
||||
|
||||
impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.locations.span(self.type_checker.body)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ fn has_a_default_variant(item: &Annotatable) -> bool {
|
|||
if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
// no need to subrecurse.
|
||||
// no need to walk the variant, we are only looking for top level variants
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,9 +301,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
// The signed form of the intrinsic allows this. If we interpret the
|
||||
// difference as isize, we'll get the proper signed difference. If that
|
||||
// seems *positive*, they were more than isize::MAX apart.
|
||||
// seems *positive* or equal to isize::MIN, they were more than isize::MAX apart.
|
||||
let dist = val.to_target_isize(self)?;
|
||||
if dist >= 0 {
|
||||
if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() {
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_offset_from_underflow,
|
||||
name = intrinsic_name,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
A variable already borrowed as immutable was borrowed as mutable.
|
||||
A variable already borrowed with a certain mutability (either mutable or
|
||||
immutable) was borrowed again with a different mutability.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ fn foo(a: &mut i32) {
|
|||
```
|
||||
|
||||
To fix this error, ensure that you don't have any other references to the
|
||||
variable before trying to access it mutably:
|
||||
variable before trying to access it with a different mutability:
|
||||
|
||||
```
|
||||
fn bar(x: &mut i32) {}
|
||||
|
|
|
|||
|
|
@ -575,6 +575,8 @@ declare_features! (
|
|||
(unstable, raw_ref_op, "1.41.0", Some(64490)),
|
||||
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
|
||||
(incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
|
||||
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant
|
||||
(incomplete, ref_pat_eat_one_layer_2024_structural, "CURRENT_RUSTC_VERSION", Some(123076)),
|
||||
/// Allows using the `#[register_tool]` attribute.
|
||||
(unstable, register_tool, "1.41.0", Some(66079)),
|
||||
/// Allows the `#[repr(i128)]` attribute for enums.
|
||||
|
|
|
|||
|
|
@ -981,7 +981,7 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
.next()
|
||||
.unwrap_or(impl_err_span);
|
||||
|
||||
diag.span_suggestion(
|
||||
diag.span_suggestion_verbose(
|
||||
span,
|
||||
"change the self-receiver type to match the trait",
|
||||
sugg,
|
||||
|
|
@ -1005,12 +1005,12 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
}
|
||||
hir::FnRetTy::Return(hir_ty) => {
|
||||
let sugg = trait_sig.output();
|
||||
diag.span_suggestion(hir_ty.span, msg, sugg, ap);
|
||||
diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap);
|
||||
}
|
||||
};
|
||||
};
|
||||
} else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
|
||||
diag.span_suggestion(
|
||||
diag.span_suggestion_verbose(
|
||||
impl_err_span,
|
||||
"change the parameter type to match the trait",
|
||||
trait_ty,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
use hir::{
|
||||
intravisit::{self, Visitor},
|
||||
|
|
@ -87,14 +89,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
let mut in_param_ty = false;
|
||||
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
|
||||
if let Some(generics) = node.generics() {
|
||||
let mut visitor = AnonConstInParamTyDetector {
|
||||
in_param_ty: false,
|
||||
found_anon_const_in_param_ty: false,
|
||||
ct: hir_id,
|
||||
};
|
||||
let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id };
|
||||
|
||||
visitor.visit_generics(generics);
|
||||
in_param_ty = visitor.found_anon_const_in_param_ty;
|
||||
in_param_ty = visitor.visit_generics(generics).is_break();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -460,50 +457,45 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
struct LateBoundRegionsDetector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outer_index: ty::DebruijnIndex,
|
||||
has_late_bound_regions: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||
if self.has_late_bound_regions.is_some() {
|
||||
return;
|
||||
}
|
||||
type Result = ControlFlow<Span>;
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
|
||||
match ty.kind {
|
||||
hir::TyKind::BareFn(..) => {
|
||||
self.outer_index.shift_in(1);
|
||||
intravisit::walk_ty(self, ty);
|
||||
let res = intravisit::walk_ty(self, ty);
|
||||
self.outer_index.shift_out(1);
|
||||
res
|
||||
}
|
||||
_ => intravisit::walk_ty(self, ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
|
||||
if self.has_late_bound_regions.is_some() {
|
||||
return;
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow<Span> {
|
||||
self.outer_index.shift_in(1);
|
||||
intravisit::walk_poly_trait_ref(self, tr);
|
||||
let res = intravisit::walk_poly_trait_ref(self, tr);
|
||||
self.outer_index.shift_out(1);
|
||||
res
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
|
||||
if self.has_late_bound_regions.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow<Span> {
|
||||
match self.tcx.named_bound_var(lt.hir_id) {
|
||||
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
|
||||
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
|
||||
if debruijn < self.outer_index => {}
|
||||
if debruijn < self.outer_index =>
|
||||
{
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
Some(
|
||||
rbv::ResolvedArg::LateBound(..)
|
||||
| rbv::ResolvedArg::Free(..)
|
||||
| rbv::ResolvedArg::Error(_),
|
||||
)
|
||||
| None => {
|
||||
self.has_late_bound_regions = Some(lt.ident.span);
|
||||
}
|
||||
| None => ControlFlow::Break(lt.ident.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -513,11 +505,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
generics: &'tcx hir::Generics<'tcx>,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
) -> Option<Span> {
|
||||
let mut visitor = LateBoundRegionsDetector {
|
||||
tcx,
|
||||
outer_index: ty::INNERMOST,
|
||||
has_late_bound_regions: None,
|
||||
};
|
||||
let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST };
|
||||
for param in generics.params {
|
||||
if let GenericParamKind::Lifetime { .. } = param.kind {
|
||||
if tcx.is_late_bound(param.hir_id) {
|
||||
|
|
@ -525,8 +513,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
}
|
||||
}
|
||||
}
|
||||
visitor.visit_fn_decl(decl);
|
||||
visitor.has_late_bound_regions
|
||||
visitor.visit_fn_decl(decl).break_value()
|
||||
}
|
||||
|
||||
let decl = node.fn_decl()?;
|
||||
|
|
@ -536,26 +523,29 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
|
||||
struct AnonConstInParamTyDetector {
|
||||
in_param_ty: bool,
|
||||
found_anon_const_in_param_ty: bool,
|
||||
ct: HirId,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
|
||||
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
|
||||
if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
|
||||
{
|
||||
let prev = self.in_param_ty;
|
||||
self.in_param_ty = true;
|
||||
self.visit_ty(ty);
|
||||
let res = self.visit_ty(ty);
|
||||
self.in_param_ty = prev;
|
||||
res
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
|
||||
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result {
|
||||
if self.in_param_ty && self.ct == c.hir_id {
|
||||
self.found_anon_const_in_param_ty = true;
|
||||
} else {
|
||||
intravisit::walk_anon_const(self, c)
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
intravisit::walk_anon_const(self, c)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
|
||||
use rustc_middle::ty::{self, Region, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::Span;
|
||||
use rustc_type_ir::outlives::{push_outlives_components, Component};
|
||||
use smallvec::smallvec;
|
||||
|
||||
/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
|
||||
|
|
|
|||
|
|
@ -501,6 +501,7 @@ pub enum SuggestBoxing {
|
|||
#[suggestion(
|
||||
hir_typeck_suggest_ptr_null_mut,
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose",
|
||||
code = "core::ptr::null_mut()"
|
||||
)]
|
||||
pub struct SuggestPtrNullMut {
|
||||
|
|
|
|||
|
|
@ -1384,7 +1384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(format!("provide the argument{}", if plural { "s" } else { "" }))
|
||||
}
|
||||
SuggestionText::Remove(plural) => {
|
||||
err.multipart_suggestion(
|
||||
err.multipart_suggestion_verbose(
|
||||
format!("remove the extra argument{}", if plural { "s" } else { "" }),
|
||||
suggestions,
|
||||
Applicability::HasPlaceholders,
|
||||
|
|
|
|||
|
|
@ -104,8 +104,6 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
|
||||
type Result = ();
|
||||
|
||||
fn span(&self) -> Span {
|
||||
self.root_cause.span
|
||||
}
|
||||
|
|
|
|||
|
|
@ -838,8 +838,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
},
|
||||
) = ex.kind
|
||||
{
|
||||
err.span_suggestion(
|
||||
ex.span,
|
||||
let span = if let hir::Node::Expr(parent) =
|
||||
self.tcx.parent_hir_node(ex.hir_id)
|
||||
&& let hir::ExprKind::Cast(..) = parent.kind
|
||||
{
|
||||
// `-1 as usize` -> `usize::MAX`
|
||||
parent.span
|
||||
} else {
|
||||
ex.span
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"you may have meant the maximum value of `{actual}`",
|
||||
),
|
||||
|
|
|
|||
|
|
@ -328,8 +328,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
adjust_mode: AdjustMode,
|
||||
max_ref_mutbl: MutblCap,
|
||||
) -> (Ty<'tcx>, ByRef, MutblCap) {
|
||||
if let ByRef::Yes(Mutability::Mut) = def_br {
|
||||
debug_assert!(max_ref_mutbl == MutblCap::Mut);
|
||||
#[cfg(debug_assertions)]
|
||||
if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut {
|
||||
span_bug!(pat.span, "Pattern mutability cap violated!");
|
||||
}
|
||||
match adjust_mode {
|
||||
AdjustMode::Pass => (expected, def_br, max_ref_mutbl),
|
||||
|
|
@ -437,7 +438,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
if self.tcx.features().ref_pat_eat_one_layer_2024 {
|
||||
let features = self.tcx.features();
|
||||
if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural {
|
||||
def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
|
||||
if def_br == ByRef::Yes(Mutability::Not) {
|
||||
max_ref_mutbl = MutblCap::Not;
|
||||
|
|
@ -669,7 +671,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Determine the binding mode...
|
||||
let bm = match user_bind_annot {
|
||||
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
|
||||
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
|
||||
if pat.span.at_least_rust_2024()
|
||||
&& (self.tcx.features().ref_pat_eat_one_layer_2024
|
||||
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural)
|
||||
{
|
||||
if !self.tcx.features().mut_ref {
|
||||
feature_err(
|
||||
&self.tcx.sess,
|
||||
|
|
@ -2123,7 +2128,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
mut expected: Ty<'tcx>,
|
||||
mut pat_info: PatInfo<'tcx, '_>,
|
||||
) -> Ty<'tcx> {
|
||||
let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024;
|
||||
let tcx = self.tcx;
|
||||
let features = tcx.features();
|
||||
let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024;
|
||||
let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural;
|
||||
|
||||
let no_ref_mut_behind_and =
|
||||
ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural;
|
||||
let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and;
|
||||
|
||||
let pat_prefix_span =
|
||||
|
|
@ -2138,32 +2149,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pat_info.max_ref_mutbl = MutblCap::Mut;
|
||||
}
|
||||
|
||||
expected = self.try_structurally_resolve_type(pat.span, expected);
|
||||
if new_match_ergonomics {
|
||||
if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
|
||||
// ref pattern consumes inherited reference
|
||||
if !ref_pat_eat_one_layer_2024 && let ty::Ref(_, _, r_mutbl) = *expected.kind() {
|
||||
// Don't attempt to consume inherited reference
|
||||
pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
|
||||
} else {
|
||||
// ref pattern attempts to consume inherited reference
|
||||
if pat_mutbl > inh_mut {
|
||||
// Tried to match inherited `ref` with `&mut`
|
||||
if !ref_pat_eat_one_layer_2024_structural {
|
||||
let err_msg = "mismatched types";
|
||||
let err = if let Some(span) = pat_prefix_span {
|
||||
let mut err = self.dcx().struct_span_err(span, err_msg);
|
||||
err.code(E0308);
|
||||
err.note("cannot match inherited `&` with `&mut` pattern");
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"replace this `&mut` pattern with `&`",
|
||||
"&",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err
|
||||
} else {
|
||||
self.dcx().struct_span_err(pat.span, err_msg)
|
||||
};
|
||||
err.emit();
|
||||
|
||||
if pat_mutbl > inh_mut {
|
||||
// Tried to match inherited `ref` with `&mut`, which is an error
|
||||
let err_msg = "cannot match inherited `&` with `&mut` pattern";
|
||||
let err = if let Some(span) = pat_prefix_span {
|
||||
let mut err = self.dcx().struct_span_err(span, err_msg);
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"replace this `&mut` pattern with `&`",
|
||||
"&",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err
|
||||
pat_info.binding_mode = ByRef::No;
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.skipped_ref_pats_mut()
|
||||
.insert(pat.hir_id);
|
||||
self.check_pat(inner, expected, pat_info);
|
||||
return expected;
|
||||
}
|
||||
} else {
|
||||
self.dcx().struct_span_err(pat.span, err_msg)
|
||||
};
|
||||
err.emit();
|
||||
pat_info.binding_mode = ByRef::No;
|
||||
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
||||
self.check_pat(inner, expected, pat_info);
|
||||
return expected;
|
||||
}
|
||||
}
|
||||
|
||||
pat_info.binding_mode = ByRef::No;
|
||||
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
||||
self.check_pat(inner, expected, pat_info);
|
||||
return expected;
|
||||
}
|
||||
} else {
|
||||
// Reset binding mode on old editions
|
||||
|
|
@ -2178,8 +2206,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let tcx = self.tcx;
|
||||
expected = self.try_structurally_resolve_type(pat.span, expected);
|
||||
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
|
||||
Ok(()) => {
|
||||
// `demand::subtype` would be good enough, but using `eqtype` turns
|
||||
|
|
@ -2191,7 +2217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
debug!("check_pat_ref: expected={:?}", expected);
|
||||
match *expected.kind() {
|
||||
ty::Ref(_, r_ty, r_mutbl)
|
||||
if (new_match_ergonomics && r_mutbl >= pat_mutbl)
|
||||
if (no_ref_mut_behind_and && r_mutbl >= pat_mutbl)
|
||||
|| r_mutbl == pat_mutbl =>
|
||||
{
|
||||
if no_ref_mut_behind_and && r_mutbl == Mutability::Not {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_trait_selection::traits::{
|
|||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
|
||||
// Data shared between a "typeck root" and its nested bodies,
|
||||
/// Data shared between a "typeck root" and its nested bodies,
|
||||
/// e.g. closures defined within the function. For example:
|
||||
/// ```ignore (illustrative)
|
||||
/// fn foo() {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,10 @@ rustc_hir = { path = "../rustc_hir" }
|
|||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
172
compiler/rustc_infer/src/infer/context.rs
Normal file
172
compiler/rustc_infer/src/infer/context.rs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
///! Definition of `InferCtxtLike` from the librarified type layer.
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::InferCtxtLike;
|
||||
|
||||
use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin};
|
||||
|
||||
impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
|
||||
type Interner = TyCtxt<'tcx>;
|
||||
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn solver_mode(&self) -> ty::solve::SolverMode {
|
||||
match self.intercrate {
|
||||
true => SolverMode::Coherence,
|
||||
false => SolverMode::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex {
|
||||
self.universe()
|
||||
}
|
||||
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex {
|
||||
self.create_next_universe()
|
||||
}
|
||||
|
||||
fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> {
|
||||
match self.probe_ty_var(vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> {
|
||||
match self.probe_const_var(ct) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
|
||||
self.root_var(var)
|
||||
}
|
||||
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
|
||||
self.root_const_var(var)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> {
|
||||
match self.probe_ty_var(vid) {
|
||||
Ok(ty) => ty,
|
||||
Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
|
||||
self.opportunistic_resolve_int_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
|
||||
self.opportunistic_resolve_float_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> {
|
||||
match self.probe_const_var(vid) {
|
||||
Ok(ct) => ct,
|
||||
Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
|
||||
match self.probe_effect_var(vid) {
|
||||
Some(ct) => ct,
|
||||
None => {
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(self.root_effect_var(vid)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types()
|
||||
}
|
||||
|
||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||
self.next_ty_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn next_const_infer(&self) -> ty::Const<'tcx> {
|
||||
self.next_const_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
self.fresh_args_for_item(DUMMY_SP, def_id)
|
||||
}
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T {
|
||||
self.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.enter_forall(value, f)
|
||||
}
|
||||
|
||||
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
|
||||
}
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.at(&ObligationCause::dummy(), param_env)
|
||||
.eq_structurally_relating_aliases_no_trace(lhs, rhs)
|
||||
}
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.resolve_vars_if_possible(value)
|
||||
}
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
|
||||
self.probe(|_| probe())
|
||||
}
|
||||
|
||||
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
|
||||
self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
|
||||
}
|
||||
|
||||
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
|
||||
self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy());
|
||||
}
|
||||
}
|
||||
|
|
@ -1168,14 +1168,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let output1 = sig1.output();
|
||||
let output2 = sig2.output();
|
||||
let (x1, x2) = self.cmp(output1, output2);
|
||||
if !output1.is_unit() {
|
||||
let output_diff = x1 != x2;
|
||||
if !output1.is_unit() || output_diff {
|
||||
values.0.push_normal(" -> ");
|
||||
(values.0).0.extend(x1.0);
|
||||
}
|
||||
if !output2.is_unit() {
|
||||
if !output2.is_unit() || output_diff {
|
||||
values.1.push_normal(" -> ");
|
||||
(values.1).0.extend(x2.0);
|
||||
}
|
||||
|
||||
values
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ use type_variable::TypeVariableOrigin;
|
|||
|
||||
pub mod at;
|
||||
pub mod canonical;
|
||||
mod context;
|
||||
pub mod error_reporting;
|
||||
pub mod free_regions;
|
||||
mod freshen;
|
||||
|
|
|
|||
|
|
@ -1,266 +0,0 @@
|
|||
// The outlines relation `T: 'a` or `'a: 'b`. This code frequently
|
||||
// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
|
||||
// RFC for reference.
|
||||
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Component<'tcx> {
|
||||
Region(ty::Region<'tcx>),
|
||||
Param(ty::ParamTy),
|
||||
Placeholder(ty::PlaceholderType),
|
||||
UnresolvedInferenceVariable(ty::InferTy),
|
||||
|
||||
// Projections like `T::Foo` are tricky because a constraint like
|
||||
// `T::Foo: 'a` can be satisfied in so many ways. There may be a
|
||||
// where-clause that says `T::Foo: 'a`, or the defining trait may
|
||||
// include a bound like `type Foo: 'static`, or -- in the most
|
||||
// conservative way -- we can prove that `T: 'a` (more generally,
|
||||
// that all components in the projection outlive `'a`). This code
|
||||
// is not in a position to judge which is the best technique, so
|
||||
// we just product the projection as a component and leave it to
|
||||
// the consumer to decide (but see `EscapingProjection` below).
|
||||
Alias(ty::AliasTy<'tcx>),
|
||||
|
||||
// In the case where a projection has escaping regions -- meaning
|
||||
// regions bound within the type itself -- we always use
|
||||
// the most conservative rule, which requires that all components
|
||||
// outlive the bound. So for example if we had a type like this:
|
||||
//
|
||||
// for<'a> Trait1< <T as Trait2<'a,'b>>::Foo >
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// then the inner projection (underlined) has an escaping region
|
||||
// `'a`. We consider that outer trait `'c` to meet a bound if `'b`
|
||||
// outlives `'b: 'c`, and we don't consider whether the trait
|
||||
// declares that `Foo: 'static` etc. Therefore, we just return the
|
||||
// free components of such a projection (in this case, `'b`).
|
||||
//
|
||||
// However, in the future, we may want to get smarter, and
|
||||
// actually return a "higher-ranked projection" here. Therefore,
|
||||
// we mark that these components are part of an escaping
|
||||
// projection, so that implied bounds code can avoid relying on
|
||||
// them. This gives us room to improve the regionck reasoning in
|
||||
// the future without breaking backwards compat.
|
||||
EscapingAlias(Vec<Component<'tcx>>),
|
||||
}
|
||||
|
||||
/// Push onto `out` all the things that must outlive `'a` for the condition
|
||||
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
|
||||
pub fn push_outlives_components<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty0: Ty<'tcx>,
|
||||
out: &mut SmallVec<[Component<'tcx>; 4]>,
|
||||
) {
|
||||
let mut visited = SsoHashSet::new();
|
||||
compute_components(tcx, ty0, out, &mut visited);
|
||||
debug!("components({:?}) = {:?}", ty0, out);
|
||||
}
|
||||
|
||||
fn compute_components<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
out: &mut SmallVec<[Component<'tcx>; 4]>,
|
||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||
) {
|
||||
// Descend through the types, looking for the various "base"
|
||||
// components and collecting them into `out`. This is not written
|
||||
// with `collect()` because of the need to sometimes skip subtrees
|
||||
// in the `subtys` iterator (e.g., when encountering a
|
||||
// projection).
|
||||
match *ty.kind() {
|
||||
ty::FnDef(_, args) => {
|
||||
// HACK(eddyb) ignore lifetimes found shallowly in `args`.
|
||||
// This is inconsistent with `ty::Adt` (including all args)
|
||||
// and with `ty::Closure` (ignoring all args other than
|
||||
// upvars, of which a `ty::FnDef` doesn't have any), but
|
||||
// consistent with previous (accidental) behavior.
|
||||
// See https://github.com/rust-lang/rust/issues/70917
|
||||
// for further background and discussion.
|
||||
for child in args {
|
||||
match child.unpack() {
|
||||
GenericArgKind::Type(ty) => {
|
||||
compute_components(tcx, ty, out, visited);
|
||||
}
|
||||
GenericArgKind::Lifetime(_) => {}
|
||||
GenericArgKind::Const(_) => {
|
||||
compute_components_recursive(tcx, child, out, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Pat(element, _) |
|
||||
ty::Array(element, _) => {
|
||||
// Don't look into the len const as it doesn't affect regions
|
||||
compute_components(tcx, element, out, visited);
|
||||
}
|
||||
|
||||
ty::Closure(_, args) => {
|
||||
let tupled_ty = args.as_closure().tupled_upvars_ty();
|
||||
compute_components(tcx, tupled_ty, out, visited);
|
||||
}
|
||||
|
||||
ty::CoroutineClosure(_, args) => {
|
||||
let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty();
|
||||
compute_components(tcx, tupled_ty, out, visited);
|
||||
}
|
||||
|
||||
ty::Coroutine(_, args) => {
|
||||
// Same as the closure case
|
||||
let tupled_ty = args.as_coroutine().tupled_upvars_ty();
|
||||
compute_components(tcx, tupled_ty, out, visited);
|
||||
|
||||
// We ignore regions in the coroutine interior as we don't
|
||||
// want these to affect region inference
|
||||
}
|
||||
|
||||
// All regions are bound inside a witness
|
||||
ty::CoroutineWitness(..) => (),
|
||||
|
||||
// OutlivesTypeParameterEnv -- the actual checking that `X:'a`
|
||||
// is implied by the environment is done in regionck.
|
||||
ty::Param(p) => {
|
||||
out.push(Component::Param(p));
|
||||
}
|
||||
|
||||
ty::Placeholder(p) => {
|
||||
out.push(Component::Placeholder(p));
|
||||
}
|
||||
|
||||
// For projections, we prefer to generate an obligation like
|
||||
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
|
||||
// regionck more ways to prove that it holds. However,
|
||||
// regionck is not (at least currently) prepared to deal with
|
||||
// higher-ranked regions that may appear in the
|
||||
// trait-ref. Therefore, if we see any higher-ranked regions,
|
||||
// we simply fallback to the most restrictive rule, which
|
||||
// requires that `Pi: 'a` for all `i`.
|
||||
ty::Alias(_, alias_ty) => {
|
||||
if !alias_ty.has_escaping_bound_vars() {
|
||||
// best case: no escaping regions, so push the
|
||||
// projection and skip the subtree (thus generating no
|
||||
// constraints for Pi). This defers the choice between
|
||||
// the rules OutlivesProjectionEnv,
|
||||
// OutlivesProjectionTraitDef, and
|
||||
// OutlivesProjectionComponents to regionck.
|
||||
out.push(Component::Alias(alias_ty));
|
||||
} else {
|
||||
// fallback case: hard code
|
||||
// OutlivesProjectionComponents. Continue walking
|
||||
// through and constrain Pi.
|
||||
let mut subcomponents = smallvec![];
|
||||
let mut subvisited = SsoHashSet::new();
|
||||
compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited);
|
||||
out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
|
||||
}
|
||||
}
|
||||
|
||||
// We assume that inference variables are fully resolved.
|
||||
// So, if we encounter an inference variable, just record
|
||||
// the unresolved variable as a component.
|
||||
ty::Infer(infer_ty) => {
|
||||
out.push(Component::UnresolvedInferenceVariable(infer_ty));
|
||||
}
|
||||
|
||||
// Most types do not introduce any region binders, nor
|
||||
// involve any other subtle cases, and so the WF relation
|
||||
// simply constraints any regions referenced directly by
|
||||
// the type and then visits the types that are lexically
|
||||
// contained within. (The comments refer to relevant rules
|
||||
// from RFC1214.)
|
||||
ty::Bool | // OutlivesScalar
|
||||
ty::Char | // OutlivesScalar
|
||||
ty::Int(..) | // OutlivesScalar
|
||||
ty::Uint(..) | // OutlivesScalar
|
||||
ty::Float(..) | // OutlivesScalar
|
||||
ty::Never | // ...
|
||||
ty::Adt(..) | // OutlivesNominalType
|
||||
ty::Foreign(..) | // OutlivesNominalType
|
||||
ty::Str | // OutlivesScalar (ish)
|
||||
ty::Slice(..) | // ...
|
||||
ty::RawPtr(..) | // ...
|
||||
ty::Ref(..) | // OutlivesReference
|
||||
ty::Tuple(..) | // ...
|
||||
ty::FnPtr(_) | // OutlivesFunction (*)
|
||||
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
|
||||
ty::Bound(..) |
|
||||
ty::Error(_) => {
|
||||
// (*) Function pointers and trait objects are both binders.
|
||||
// In the RFC, this means we would add the bound regions to
|
||||
// the "bound regions list". In our representation, no such
|
||||
// list is maintained explicitly, because bound regions
|
||||
// themselves can be readily identified.
|
||||
compute_components_recursive(tcx, ty.into(), out, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect [Component]s for *all* the args of `parent`.
|
||||
///
|
||||
/// This should not be used to get the components of `parent` itself.
|
||||
/// Use [push_outlives_components] instead.
|
||||
pub(super) fn compute_alias_components_recursive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
alias_ty: Ty<'tcx>,
|
||||
out: &mut SmallVec<[Component<'tcx>; 4]>,
|
||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||
) {
|
||||
let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
|
||||
unreachable!("can only call `compute_alias_components_recursive` on an alias type")
|
||||
};
|
||||
let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] };
|
||||
for (index, child) in alias_ty.args.iter().enumerate() {
|
||||
if opt_variances.get(index) == Some(&ty::Bivariant) {
|
||||
continue;
|
||||
}
|
||||
if !visited.insert(child) {
|
||||
continue;
|
||||
}
|
||||
match child.unpack() {
|
||||
GenericArgKind::Type(ty) => {
|
||||
compute_components(tcx, ty, out, visited);
|
||||
}
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
// Ignore higher ranked regions.
|
||||
if !lt.is_bound() {
|
||||
out.push(Component::Region(lt));
|
||||
}
|
||||
}
|
||||
GenericArgKind::Const(_) => {
|
||||
compute_components_recursive(tcx, child, out, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect [Component]s for *all* the args of `parent`.
|
||||
///
|
||||
/// This should not be used to get the components of `parent` itself.
|
||||
/// Use [push_outlives_components] instead.
|
||||
fn compute_components_recursive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
parent: GenericArg<'tcx>,
|
||||
out: &mut SmallVec<[Component<'tcx>; 4]>,
|
||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||
) {
|
||||
for child in parent.walk_shallow(visited) {
|
||||
match child.unpack() {
|
||||
GenericArgKind::Type(ty) => {
|
||||
compute_components(tcx, ty, out, visited);
|
||||
}
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
// Ignore higher ranked regions.
|
||||
if !lt.is_bound() {
|
||||
out.push(Component::Region(lt));
|
||||
}
|
||||
}
|
||||
GenericArgKind::Const(_) => {
|
||||
compute_components_recursive(tcx, child, out, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ use crate::infer::lexical_region_resolve;
|
|||
use rustc_middle::traits::query::{NoSolution, OutlivesBound};
|
||||
use rustc_middle::ty;
|
||||
|
||||
pub mod components;
|
||||
pub mod env;
|
||||
pub mod for_liveness;
|
||||
pub mod obligations;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@
|
|||
//! might later infer `?U` to something like `&'b u32`, which would
|
||||
//! imply that `'b: 'a`.
|
||||
|
||||
use crate::infer::outlives::components::{push_outlives_components, Component};
|
||||
use crate::infer::outlives::env::RegionBoundPairs;
|
||||
use crate::infer::outlives::verify::VerifyBoundCx;
|
||||
use crate::infer::resolve::OpportunisticRegionResolver;
|
||||
|
|
@ -75,6 +74,7 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_type_ir::outlives::{push_outlives_components, Component};
|
||||
use smallvec::smallvec;
|
||||
|
||||
use super::env::OutlivesEnvironment;
|
||||
|
|
@ -291,7 +291,7 @@ where
|
|||
fn components_must_outlive(
|
||||
&mut self,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
components: &[Component<'tcx>],
|
||||
components: &[Component<TyCtxt<'tcx>>],
|
||||
region: ty::Region<'tcx>,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
|
|
@ -471,7 +471,7 @@ where
|
|||
// projection outlive; in some cases, this may add insufficient
|
||||
// edges into the inference graph, leading to inference failures
|
||||
// even though a satisfactory solution exists.
|
||||
let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default());
|
||||
let verify_bound = self.verify_bound.alias_bound(alias_ty);
|
||||
debug!("alias_must_outlive: pushing {:?}", verify_bound);
|
||||
self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use crate::infer::outlives::components::{compute_alias_components_recursive, Component};
|
||||
use crate::infer::outlives::env::RegionBoundPairs;
|
||||
use crate::infer::region_constraints::VerifyIfEq;
|
||||
use crate::infer::{GenericKind, VerifyBound};
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
use rustc_middle::ty::GenericArg;
|
||||
use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
|
||||
use rustc_type_ir::outlives::{compute_alias_components_recursive, Component};
|
||||
|
||||
use smallvec::smallvec;
|
||||
|
||||
|
|
@ -99,12 +97,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, visited))]
|
||||
pub fn alias_bound(
|
||||
&self,
|
||||
alias_ty: ty::AliasTy<'tcx>,
|
||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||
) -> VerifyBound<'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> {
|
||||
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
|
||||
|
||||
// Search the env for where clauses like `P: 'a`.
|
||||
|
|
@ -130,21 +124,17 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
// see the extensive comment in projection_must_outlive
|
||||
let recursive_bound = {
|
||||
let mut components = smallvec![];
|
||||
compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components, visited);
|
||||
self.bound_from_components(&components, visited)
|
||||
compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components);
|
||||
self.bound_from_components(&components)
|
||||
};
|
||||
|
||||
VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound)
|
||||
}
|
||||
|
||||
fn bound_from_components(
|
||||
&self,
|
||||
components: &[Component<'tcx>],
|
||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||
) -> VerifyBound<'tcx> {
|
||||
fn bound_from_components(&self, components: &[Component<TyCtxt<'tcx>>]) -> VerifyBound<'tcx> {
|
||||
let mut bounds = components
|
||||
.iter()
|
||||
.map(|component| self.bound_from_single_component(component, visited))
|
||||
.map(|component| self.bound_from_single_component(component))
|
||||
// Remove bounds that must hold, since they are not interesting.
|
||||
.filter(|bound| !bound.must_hold());
|
||||
|
||||
|
|
@ -158,8 +148,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
|
||||
fn bound_from_single_component(
|
||||
&self,
|
||||
component: &Component<'tcx>,
|
||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||
component: &Component<TyCtxt<'tcx>>,
|
||||
) -> VerifyBound<'tcx> {
|
||||
match *component {
|
||||
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
||||
|
|
@ -167,10 +156,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
Component::Placeholder(placeholder_ty) => {
|
||||
self.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty))
|
||||
}
|
||||
Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited),
|
||||
Component::EscapingAlias(ref components) => {
|
||||
self.bound_from_components(components, visited)
|
||||
}
|
||||
Component::Alias(alias_ty) => self.alias_bound(alias_ty),
|
||||
Component::EscapingAlias(ref components) => self.bound_from_components(components),
|
||||
Component::UnresolvedInferenceVariable(v) => {
|
||||
// Ignore this, we presume it will yield an error later, since
|
||||
// if a type variable is not resolved by this point it never
|
||||
|
|
|
|||
|
|
@ -18,11 +18,13 @@
|
|||
//! On success, the LUB/GLB operations return the appropriate bound. The
|
||||
//! return value of `Equate` or `Sub` shouldn't really be used.
|
||||
|
||||
pub use rustc_next_trait_solver::relate::combine::*;
|
||||
|
||||
use super::glb::Glb;
|
||||
use super::lub::Lub;
|
||||
use super::type_relating::TypeRelating;
|
||||
use super::RelateResult;
|
||||
use super::StructurallyRelateAliases;
|
||||
use super::{RelateResult, TypeRelation};
|
||||
use crate::infer::relate;
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
||||
use crate::traits::{Obligation, PredicateObligation};
|
||||
|
|
@ -32,7 +34,6 @@ use rustc_middle::traits::solve::Goal;
|
|||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
|
||||
use rustc_middle::ty::{IntType, UintType};
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CombineFields<'infcx, 'tcx> {
|
||||
|
|
@ -76,7 +77,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
b: Ty<'tcx>,
|
||||
) -> RelateResult<'tcx, Ty<'tcx>>
|
||||
where
|
||||
R: PredicateEmittingRelation<'tcx>,
|
||||
R: PredicateEmittingRelation<InferCtxt<'tcx>>,
|
||||
{
|
||||
debug_assert!(!a.has_escaping_bound_vars());
|
||||
debug_assert!(!b.has_escaping_bound_vars());
|
||||
|
|
@ -171,7 +172,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
b: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>>
|
||||
where
|
||||
R: PredicateEmittingRelation<'tcx>,
|
||||
R: PredicateEmittingRelation<InferCtxt<'tcx>>,
|
||||
{
|
||||
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
|
||||
debug_assert!(!a.has_escaping_bound_vars());
|
||||
|
|
@ -323,30 +324,3 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PredicateEmittingRelation<'tcx>: TypeRelation<TyCtxt<'tcx>> {
|
||||
fn span(&self) -> Span;
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx>;
|
||||
|
||||
/// Whether aliases should be related structurally. This is pretty much
|
||||
/// always `No` unless you're equating in some specific locations of the
|
||||
/// new solver. See the comments in these use-cases for more details.
|
||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
|
||||
|
||||
/// Register obligations that must hold in order for this relation to hold
|
||||
fn register_goals(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
);
|
||||
|
||||
/// Register predicates that must hold in order for this relation to hold.
|
||||
/// This uses the default `param_env` of the obligation.
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
|
||||
);
|
||||
|
||||
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
|
||||
fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
|
||||
/// other usecases (i.e. setting the value of a type var).
|
||||
#[instrument(level = "debug", skip(self, relation))]
|
||||
pub fn instantiate_ty_var<R: PredicateEmittingRelation<'tcx>>(
|
||||
pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||
&self,
|
||||
relation: &mut R,
|
||||
target_is_expected: bool,
|
||||
|
|
@ -178,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
///
|
||||
/// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
|
||||
#[instrument(level = "debug", skip(self, relation))]
|
||||
pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<'tcx>>(
|
||||
pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||
&self,
|
||||
relation: &mut R,
|
||||
target_is_expected: bool,
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PredicateEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||
impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Glb<'_, '_, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.fields.trace.span()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Ty};
|
|||
///
|
||||
/// GLB moves "down" the lattice (to smaller values); LUB moves
|
||||
/// "up" the lattice (to bigger values).
|
||||
pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<'tcx> {
|
||||
pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> {
|
||||
fn infcx(&self) -> &'f InferCtxt<'tcx>;
|
||||
|
||||
fn cause(&self) -> &ObligationCause<'tcx>;
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PredicateEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||
impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Lub<'_, '_, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.fields.trace.span()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
//! (except for some relations used for diagnostics and heuristics in the compiler).
|
||||
//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc).
|
||||
|
||||
pub use rustc_middle::ty::relate::*;
|
||||
pub use rustc_middle::ty::relate::RelateResult;
|
||||
pub use rustc_next_trait_solver::relate::*;
|
||||
|
||||
pub use self::combine::CombineFields;
|
||||
pub use self::combine::PredicateEmittingRelation;
|
||||
|
||||
#[allow(hidden_glob_reexports)]
|
||||
pub(super) mod combine;
|
||||
mod generalize;
|
||||
mod glb;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::combine::CombineFields;
|
||||
use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
|
||||
use crate::infer::BoundRegionConversionTime::HigherRankedType;
|
||||
use crate::infer::{DefineOpaqueTypes, SubregionOrigin};
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
|
||||
use rustc_middle::traits::solve::Goal;
|
||||
use rustc_middle::ty::relate::{
|
||||
relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation,
|
||||
|
|
@ -296,7 +296,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PredicateEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
|
||||
impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.fields.trace.span()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use smallvec::smallvec;
|
||||
|
||||
use crate::infer::outlives::components::{push_outlives_components, Component};
|
||||
use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::ty::ToPolyTraitRef;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::Span;
|
||||
use rustc_type_ir::outlives::{push_outlives_components, Component};
|
||||
|
||||
pub fn anonymize_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
@ -82,7 +83,6 @@ pub struct Elaborator<'tcx, O> {
|
|||
enum Filter {
|
||||
All,
|
||||
OnlySelf,
|
||||
OnlySelfThatDefines(Ident),
|
||||
}
|
||||
|
||||
/// Describes how to elaborate an obligation into a sub-obligation.
|
||||
|
|
@ -252,12 +252,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Filter to only the supertraits of trait predicates that define the assoc_ty.
|
||||
pub fn filter_only_self_that_defines(mut self, assoc_ty: Ident) -> Self {
|
||||
self.mode = Filter::OnlySelfThatDefines(assoc_ty);
|
||||
self
|
||||
}
|
||||
|
||||
fn elaborate(&mut self, elaboratable: &O) {
|
||||
let tcx = self.visited.tcx;
|
||||
|
||||
|
|
@ -277,9 +271,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
|||
let predicates = match self.mode {
|
||||
Filter::All => tcx.explicit_implied_predicates_of(data.def_id()),
|
||||
Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()),
|
||||
Filter::OnlySelfThatDefines(ident) => {
|
||||
tcx.explicit_supertraits_containing_assoc_item((data.def_id(), ident))
|
||||
}
|
||||
};
|
||||
|
||||
let obligations =
|
||||
|
|
@ -405,14 +396,14 @@ impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> {
|
|||
pub fn supertraits<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
|
||||
) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> {
|
||||
elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits()
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
|
||||
) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> {
|
||||
elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
|
||||
.filter_only_self()
|
||||
.filter_to_traits()
|
||||
|
|
@ -427,17 +418,37 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
assoc_name: Ident,
|
||||
) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
|
||||
elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
|
||||
.filter_only_self_that_defines(assoc_name)
|
||||
.filter_to_traits()
|
||||
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
|
||||
let mut seen = FxHashSet::default();
|
||||
let mut stack: Vec<_> = trait_refs.collect();
|
||||
|
||||
std::iter::from_fn(move || {
|
||||
while let Some(trait_ref) = stack.pop() {
|
||||
if !seen.insert(tcx.anonymize_bound_vars(trait_ref)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stack.extend(
|
||||
tcx.explicit_supertraits_containing_assoc_item((trait_ref.def_id(), assoc_name))
|
||||
.instantiate_own_identity()
|
||||
.map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref))
|
||||
.filter_map(|clause| clause.as_trait_clause())
|
||||
// FIXME: Negative supertraits are elaborated here lol
|
||||
.map(|trait_pred| trait_pred.to_poly_trait_ref()),
|
||||
);
|
||||
|
||||
return Some(trait_ref);
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Other
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> {
|
||||
impl<'tcx> Elaborator<'tcx, ty::Clause<'tcx>> {
|
||||
fn filter_to_traits(self) -> FilterToTraits<Self> {
|
||||
FilterToTraits { base_iterator: self }
|
||||
}
|
||||
|
|
@ -449,7 +460,7 @@ pub struct FilterToTraits<I> {
|
|||
base_iterator: I,
|
||||
}
|
||||
|
||||
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
|
||||
impl<'tcx, I: Iterator<Item = ty::Clause<'tcx>>> Iterator for FilterToTraits<I> {
|
||||
type Item = ty::PolyTraitRef<'tcx>;
|
||||
|
||||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
||||
|
|
|
|||
|
|
@ -261,10 +261,16 @@ pub(super) fn unexpected_cfg_value(
|
|||
lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
|
||||
};
|
||||
|
||||
// We don't want to suggest adding values to well known names
|
||||
// since those are defined by rustc it-self. Users can still
|
||||
// do it if they want, but should not encourage them.
|
||||
let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name);
|
||||
// We don't want to encourage people to add values to a well-known names, as these are
|
||||
// defined by rustc/Rust itself. Users can still do this if they wish, but should not be
|
||||
// encouraged to do so.
|
||||
let can_suggest_adding_value = !sess.psess.check_config.well_known_names.contains(&name)
|
||||
// Except when working on rustc or the standard library itself, in which case we want to
|
||||
// suggest adding these cfgs to the "normal" place because of bootstraping reasons. As a
|
||||
// basic heuristic, we use the "cheat" unstable feature enable method and the
|
||||
// non-ui-testing enabled option.
|
||||
|| (matches!(sess.psess.unstable_features, rustc_feature::UnstableFeatures::Cheat)
|
||||
&& !sess.opts.unstable_opts.ui_testing);
|
||||
|
||||
let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
|
||||
|
||||
|
|
@ -275,14 +281,14 @@ pub(super) fn unexpected_cfg_value(
|
|||
} else {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
|
||||
}
|
||||
} else if !is_cfg_a_well_know_name {
|
||||
} else if can_suggest_adding_value {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_value::InvocationHelp::Cargo(help)
|
||||
} else {
|
||||
let help = if !is_cfg_a_well_know_name {
|
||||
let help = if can_suggest_adding_value {
|
||||
Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
//! For all the gory details, see the provider of the `dependency_formats`
|
||||
//! query.
|
||||
|
||||
// FIXME: move this file to rustc_metadata::dependency_format, but
|
||||
// this will introduce circular dependency between rustc_metadata and rustc_middle
|
||||
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_session::config::CrateType;
|
||||
|
||||
/// A list of dependencies for a certain crate type.
|
||||
///
|
||||
/// The length of this vector is the same as the number of external crates used.
|
||||
/// The value is None if the crate does not need to be linked (it was found
|
||||
/// statically in another dylib), or Some(kind) if it needs to be linked as
|
||||
/// `kind` (either static or dynamic).
|
||||
pub type DependencyList = Vec<Linkage>;
|
||||
|
||||
/// A mapping of all required dependencies for a particular flavor of output.
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ pub enum CoverageKind {
|
|||
SpanMarker,
|
||||
|
||||
/// Marks its enclosing basic block with an ID that can be referred to by
|
||||
/// side data in [`BranchInfo`].
|
||||
/// side data in [`CoverageInfoHi`].
|
||||
///
|
||||
/// Should be erased before codegen (at some point after `InstrumentCoverage`).
|
||||
BlockMarker { id: BlockMarkerId },
|
||||
|
|
@ -274,10 +274,15 @@ pub struct FunctionCoverageInfo {
|
|||
pub mcdc_num_condition_bitmaps: usize,
|
||||
}
|
||||
|
||||
/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR.
|
||||
/// Coverage information for a function, recorded during MIR building and
|
||||
/// attached to the corresponding `mir::Body`. Used by the `InstrumentCoverage`
|
||||
/// MIR pass.
|
||||
///
|
||||
/// ("Hi" indicates that this is "high-level" information collected at the
|
||||
/// THIR/MIR boundary, before the MIR-based coverage instrumentation pass.)
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct BranchInfo {
|
||||
pub struct CoverageInfoHi {
|
||||
/// 1 more than the highest-numbered [`CoverageKind::BlockMarker`] that was
|
||||
/// injected into the MIR body. This makes it possible to allocate per-ID
|
||||
/// data structures without having to scan the entire body first.
|
||||
|
|
|
|||
|
|
@ -430,11 +430,12 @@ pub struct Body<'tcx> {
|
|||
|
||||
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
|
||||
/// Branch coverage information collected during MIR building, to be used by
|
||||
/// the `InstrumentCoverage` pass.
|
||||
/// Coverage information collected from THIR/MIR during MIR building,
|
||||
/// to be used by the `InstrumentCoverage` pass.
|
||||
///
|
||||
/// Only present if branch coverage is enabled and this function is eligible.
|
||||
pub coverage_branch_info: Option<Box<coverage::BranchInfo>>,
|
||||
/// Only present if coverage is enabled and this function is eligible.
|
||||
/// Boxed to limit space overhead in non-coverage builds.
|
||||
pub coverage_info_hi: Option<Box<coverage::CoverageInfoHi>>,
|
||||
|
||||
/// Per-function coverage information added by the `InstrumentCoverage`
|
||||
/// pass, to be used in conjunction with the coverage statements injected
|
||||
|
|
@ -484,7 +485,7 @@ impl<'tcx> Body<'tcx> {
|
|||
is_polymorphic: false,
|
||||
injection_phase: None,
|
||||
tainted_by_errors,
|
||||
coverage_branch_info: None,
|
||||
coverage_info_hi: None,
|
||||
function_coverage_info: None,
|
||||
};
|
||||
body.is_polymorphic = body.has_non_region_param();
|
||||
|
|
@ -515,7 +516,7 @@ impl<'tcx> Body<'tcx> {
|
|||
is_polymorphic: false,
|
||||
injection_phase: None,
|
||||
tainted_by_errors: None,
|
||||
coverage_branch_info: None,
|
||||
coverage_info_hi: None,
|
||||
function_coverage_info: None,
|
||||
};
|
||||
body.is_polymorphic = body.has_non_region_param();
|
||||
|
|
|
|||
|
|
@ -473,8 +473,8 @@ pub fn write_mir_intro<'tcx>(
|
|||
// Add an empty line before the first block is printed.
|
||||
writeln!(w)?;
|
||||
|
||||
if let Some(branch_info) = &body.coverage_branch_info {
|
||||
write_coverage_branch_info(branch_info, w)?;
|
||||
if let Some(coverage_info_hi) = &body.coverage_info_hi {
|
||||
write_coverage_info_hi(coverage_info_hi, w)?;
|
||||
}
|
||||
if let Some(function_coverage_info) = &body.function_coverage_info {
|
||||
write_function_coverage_info(function_coverage_info, w)?;
|
||||
|
|
@ -483,18 +483,26 @@ pub fn write_mir_intro<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_coverage_branch_info(
|
||||
branch_info: &coverage::BranchInfo,
|
||||
fn write_coverage_info_hi(
|
||||
coverage_info_hi: &coverage::CoverageInfoHi,
|
||||
w: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
let coverage::BranchInfo { branch_spans, mcdc_branch_spans, mcdc_decision_spans, .. } =
|
||||
branch_info;
|
||||
let coverage::CoverageInfoHi {
|
||||
num_block_markers: _,
|
||||
branch_spans,
|
||||
mcdc_branch_spans,
|
||||
mcdc_decision_spans,
|
||||
} = coverage_info_hi;
|
||||
|
||||
// Only add an extra trailing newline if we printed at least one thing.
|
||||
let mut did_print = false;
|
||||
|
||||
for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans {
|
||||
writeln!(
|
||||
w,
|
||||
"{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
|
||||
)?;
|
||||
did_print = true;
|
||||
}
|
||||
|
||||
for coverage::MCDCBranchSpan {
|
||||
|
|
@ -510,6 +518,7 @@ fn write_coverage_branch_info(
|
|||
"{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?}, depth: {decision_depth:?} }} => {span:?}",
|
||||
condition_info.map(|info| info.condition_id)
|
||||
)?;
|
||||
did_print = true;
|
||||
}
|
||||
|
||||
for coverage::MCDCDecisionSpan { span, num_conditions, end_markers, decision_depth } in
|
||||
|
|
@ -519,10 +528,10 @@ fn write_coverage_branch_info(
|
|||
w,
|
||||
"{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}"
|
||||
)?;
|
||||
did_print = true;
|
||||
}
|
||||
|
||||
if !branch_spans.is_empty() || !mcdc_branch_spans.is_empty() || !mcdc_decision_spans.is_empty()
|
||||
{
|
||||
if did_print {
|
||||
writeln!(w)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,13 @@ pub struct Expr<'tcx> {
|
|||
pub kind: ExprKind,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::ExprConst<TyCtxt<'tcx>> for Expr<'tcx> {
|
||||
fn args(self) -> ty::GenericArgsRef<'tcx> {
|
||||
self.args
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Expr<'tcx> {
|
||||
pub fn new_binop(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ use std::ops::{Bound, Deref};
|
|||
impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type DefId = DefId;
|
||||
type LocalDefId = LocalDefId;
|
||||
type Span = Span;
|
||||
|
||||
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
||||
|
||||
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
|
||||
|
|
|
|||
|
|
@ -10,18 +10,6 @@ use crate::ty::{self as ty, Ty, TyCtxt};
|
|||
|
||||
pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
|
||||
|
||||
/// Whether aliases should be related structurally or not. Used
|
||||
/// to adjust the behavior of generalization and combine.
|
||||
///
|
||||
/// This should always be `No` unless in a few special-cases when
|
||||
/// instantiating canonical responses and in the new solver. Each
|
||||
/// such case should have a comment explaining why it is used.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum StructurallyRelateAliases {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> {
|
||||
#[inline]
|
||||
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
|
|
|
|||
|
|
@ -78,23 +78,6 @@ impl<'tcx> GenericArg<'tcx> {
|
|||
pub fn walk(self) -> TypeWalker<'tcx> {
|
||||
TypeWalker::new(self)
|
||||
}
|
||||
|
||||
/// Iterator that walks the immediate children of `self`. Hence
|
||||
/// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
|
||||
/// (but not `i32`, like `walk`).
|
||||
///
|
||||
/// Iterator only walks items once.
|
||||
/// It accepts visited set, updates it with all visited types
|
||||
/// and skips any types that are already there.
|
||||
pub fn walk_shallow(
|
||||
self,
|
||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||
) -> impl Iterator<Item = GenericArg<'tcx>> {
|
||||
let mut stack = SmallVec::new();
|
||||
push_inner(&mut stack, self);
|
||||
stack.retain(|a| visited.insert(*a));
|
||||
stack.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Ty<'tcx> {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::assert_matches::assert_matches;
|
|||
use std::collections::hash_map::Entry;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
|
||||
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind};
|
||||
use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp};
|
||||
use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -13,16 +13,25 @@ use crate::build::{Builder, CFG};
|
|||
|
||||
mod mcdc;
|
||||
|
||||
pub(crate) struct BranchInfoBuilder {
|
||||
/// Collects coverage-related information during MIR building, to eventually be
|
||||
/// turned into a function's [`CoverageInfoHi`] when MIR building is complete.
|
||||
pub(crate) struct CoverageInfoBuilder {
|
||||
/// Maps condition expressions to their enclosing `!`, for better instrumentation.
|
||||
nots: FxHashMap<ExprId, NotInfo>,
|
||||
|
||||
markers: BlockMarkerGen,
|
||||
branch_spans: Vec<BranchSpan>,
|
||||
|
||||
/// Present if branch coverage is enabled.
|
||||
branch_info: Option<BranchInfo>,
|
||||
/// Present if MC/DC coverage is enabled.
|
||||
mcdc_info: Option<MCDCInfoBuilder>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BranchInfo {
|
||||
branch_spans: Vec<BranchSpan>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct NotInfo {
|
||||
/// When visiting the associated expression as a branch condition, treat this
|
||||
|
|
@ -62,20 +71,20 @@ impl BlockMarkerGen {
|
|||
}
|
||||
}
|
||||
|
||||
impl BranchInfoBuilder {
|
||||
/// Creates a new branch info builder, but only if branch coverage instrumentation
|
||||
impl CoverageInfoBuilder {
|
||||
/// Creates a new coverage info builder, but only if coverage instrumentation
|
||||
/// is enabled and `def_id` represents a function that is eligible for coverage.
|
||||
pub(crate) fn new_if_enabled(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Self> {
|
||||
if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) {
|
||||
Some(Self {
|
||||
nots: FxHashMap::default(),
|
||||
markers: BlockMarkerGen::default(),
|
||||
branch_spans: vec![],
|
||||
mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
if !tcx.sess.instrument_coverage() || !tcx.is_eligible_for_coverage(def_id) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
nots: FxHashMap::default(),
|
||||
markers: BlockMarkerGen::default(),
|
||||
branch_info: tcx.sess.instrument_coverage_branch().then(BranchInfo::default),
|
||||
mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new),
|
||||
})
|
||||
}
|
||||
|
||||
/// Unary `!` expressions inside an `if` condition are lowered by lowering
|
||||
|
|
@ -88,6 +97,12 @@ impl BranchInfoBuilder {
|
|||
pub(crate) fn visit_unary_not(&mut self, thir: &Thir<'_>, unary_not: ExprId) {
|
||||
assert_matches!(thir[unary_not].kind, ExprKind::Unary { op: UnOp::Not, .. });
|
||||
|
||||
// The information collected by this visitor is only needed when branch
|
||||
// coverage or higher is enabled.
|
||||
if self.branch_info.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.visit_with_not_info(
|
||||
thir,
|
||||
unary_not,
|
||||
|
|
@ -137,40 +152,40 @@ impl BranchInfoBuilder {
|
|||
false_block,
|
||||
inject_block_marker,
|
||||
);
|
||||
} else {
|
||||
let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
|
||||
let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
|
||||
|
||||
self.branch_spans.push(BranchSpan {
|
||||
span: source_info.span,
|
||||
true_marker,
|
||||
false_marker,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail out if branch coverage is not enabled.
|
||||
let Some(branch_info) = self.branch_info.as_mut() else { return };
|
||||
|
||||
let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
|
||||
let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
|
||||
|
||||
branch_info.branch_spans.push(BranchSpan {
|
||||
span: source_info.span,
|
||||
true_marker,
|
||||
false_marker,
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> {
|
||||
let Self {
|
||||
nots: _,
|
||||
markers: BlockMarkerGen { num_block_markers },
|
||||
branch_spans,
|
||||
mcdc_info,
|
||||
} = self;
|
||||
pub(crate) fn into_done(self) -> Box<CoverageInfoHi> {
|
||||
let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } =
|
||||
self;
|
||||
|
||||
if num_block_markers == 0 {
|
||||
assert!(branch_spans.is_empty());
|
||||
return None;
|
||||
}
|
||||
let branch_spans =
|
||||
branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default();
|
||||
|
||||
let (mcdc_decision_spans, mcdc_branch_spans) =
|
||||
mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default();
|
||||
|
||||
Some(Box::new(mir::coverage::BranchInfo {
|
||||
// For simplicity, always return an info struct (without Option), even
|
||||
// if there's nothing interesting in it.
|
||||
Box::new(CoverageInfoHi {
|
||||
num_block_markers,
|
||||
branch_spans,
|
||||
mcdc_branch_spans,
|
||||
mcdc_decision_spans,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +199,7 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
block: &mut BasicBlock,
|
||||
) {
|
||||
// Bail out if condition coverage is not enabled for this function.
|
||||
let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
|
||||
let Some(coverage_info) = self.coverage_info.as_mut() else { return };
|
||||
if !self.tcx.sess.instrument_coverage_condition() {
|
||||
return;
|
||||
};
|
||||
|
|
@ -224,7 +239,7 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
);
|
||||
|
||||
// Separate path for handling branches when MC/DC is enabled.
|
||||
branch_info.register_two_way_branch(
|
||||
coverage_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
|
|
@ -247,12 +262,12 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
mut then_block: BasicBlock,
|
||||
mut else_block: BasicBlock,
|
||||
) {
|
||||
// Bail out if branch coverage is not enabled for this function.
|
||||
let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
|
||||
// Bail out if coverage is not enabled for this function.
|
||||
let Some(coverage_info) = self.coverage_info.as_mut() else { return };
|
||||
|
||||
// If this condition expression is nested within one or more `!` expressions,
|
||||
// replace it with the enclosing `!` collected by `visit_unary_not`.
|
||||
if let Some(&NotInfo { enclosing_not, is_flipped }) = branch_info.nots.get(&expr_id) {
|
||||
if let Some(&NotInfo { enclosing_not, is_flipped }) = coverage_info.nots.get(&expr_id) {
|
||||
expr_id = enclosing_not;
|
||||
if is_flipped {
|
||||
std::mem::swap(&mut then_block, &mut else_block);
|
||||
|
|
@ -261,7 +276,7 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
|
||||
let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
|
||||
|
||||
branch_info.register_two_way_branch(
|
||||
coverage_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
|
|
@ -280,13 +295,11 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
true_block: BasicBlock,
|
||||
false_block: BasicBlock,
|
||||
) {
|
||||
// Bail out if branch coverage is not enabled for this function.
|
||||
let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
|
||||
|
||||
// FIXME(#124144) This may need special handling when MC/DC is enabled.
|
||||
// Bail out if coverage is not enabled for this function.
|
||||
let Some(coverage_info) = self.coverage_info.as_mut() else { return };
|
||||
|
||||
let source_info = SourceInfo { span: pattern.span, scope: self.source_scope };
|
||||
branch_info.register_two_way_branch(
|
||||
coverage_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
|
|
|
|||
|
|
@ -250,24 +250,24 @@ impl MCDCInfoBuilder {
|
|||
|
||||
impl Builder<'_, '_> {
|
||||
pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) {
|
||||
if let Some(branch_info) = self.coverage_branch_info.as_mut()
|
||||
&& let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
|
||||
if let Some(coverage_info) = self.coverage_info.as_mut()
|
||||
&& let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
|
||||
{
|
||||
mcdc_info.state.record_conditions(logical_op, span);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) {
|
||||
if let Some(branch_info) = self.coverage_branch_info.as_mut()
|
||||
&& let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
|
||||
if let Some(coverage_info) = self.coverage_info.as_mut()
|
||||
&& let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
|
||||
{
|
||||
mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default());
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) {
|
||||
if let Some(branch_info) = self.coverage_branch_info.as_mut()
|
||||
&& let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
|
||||
if let Some(coverage_info) = self.coverage_info.as_mut()
|
||||
&& let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
|
||||
{
|
||||
if mcdc_info.state.decision_ctx_stack.pop().is_none() {
|
||||
bug!("Unexpected empty decision stack");
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ pub(super) fn build_custom_mir<'tcx>(
|
|||
tainted_by_errors: None,
|
||||
injection_phase: None,
|
||||
pass_count: 0,
|
||||
coverage_branch_info: None,
|
||||
coverage_info_hi: None,
|
||||
function_coverage_info: None,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -160,8 +160,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// Improve branch coverage instrumentation by noting conditions
|
||||
// nested within one or more `!` expressions.
|
||||
// (Skipped if branch coverage is not enabled.)
|
||||
if let Some(branch_info) = this.coverage_branch_info.as_mut() {
|
||||
branch_info.visit_unary_not(this.thir, expr_id);
|
||||
if let Some(coverage_info) = this.coverage_info.as_mut() {
|
||||
coverage_info.visit_unary_not(this.thir, expr_id);
|
||||
}
|
||||
|
||||
let local_scope = this.local_scope();
|
||||
|
|
|
|||
|
|
@ -218,8 +218,8 @@ struct Builder<'a, 'tcx> {
|
|||
lint_level_roots_cache: GrowableBitSet<hir::ItemLocalId>,
|
||||
|
||||
/// Collects additional coverage information during MIR building.
|
||||
/// Only present if branch coverage is enabled and this function is eligible.
|
||||
coverage_branch_info: Option<coverageinfo::BranchInfoBuilder>,
|
||||
/// Only present if coverage is enabled and this function is eligible.
|
||||
coverage_info: Option<coverageinfo::CoverageInfoBuilder>,
|
||||
}
|
||||
|
||||
type CaptureMap<'tcx> = SortedIndexMultiMap<usize, HirId, Capture<'tcx>>;
|
||||
|
|
@ -773,7 +773,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
unit_temp: None,
|
||||
var_debug_info: vec![],
|
||||
lint_level_roots_cache: GrowableBitSet::new_empty(),
|
||||
coverage_branch_info: coverageinfo::BranchInfoBuilder::new_if_enabled(tcx, def),
|
||||
coverage_info: coverageinfo::CoverageInfoBuilder::new_if_enabled(tcx, def),
|
||||
};
|
||||
|
||||
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
||||
|
|
@ -802,7 +802,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.coroutine,
|
||||
None,
|
||||
);
|
||||
body.coverage_branch_info = self.coverage_branch_info.and_then(|b| b.into_done());
|
||||
body.coverage_info_hi = self.coverage_info.map(|b| b.into_done());
|
||||
body
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ use std::collections::BTreeSet;
|
|||
use rustc_data_structures::graph::DirectedGraph;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind};
|
||||
use rustc_middle::mir::coverage::{
|
||||
BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind,
|
||||
};
|
||||
use rustc_middle::mir::{self, BasicBlock, StatementKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -157,12 +159,12 @@ impl ExtractedMappings {
|
|||
}
|
||||
|
||||
fn resolve_block_markers(
|
||||
branch_info: &mir::coverage::BranchInfo,
|
||||
coverage_info_hi: &CoverageInfoHi,
|
||||
mir_body: &mir::Body<'_>,
|
||||
) -> IndexVec<BlockMarkerId, Option<BasicBlock>> {
|
||||
let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
|
||||
None,
|
||||
branch_info.num_block_markers,
|
||||
coverage_info_hi.num_block_markers,
|
||||
);
|
||||
|
||||
// Fill out the mapping from block marker IDs to their enclosing blocks.
|
||||
|
|
@ -188,11 +190,11 @@ pub(super) fn extract_branch_pairs(
|
|||
hir_info: &ExtractedHirInfo,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
) -> Vec<BranchPair> {
|
||||
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] };
|
||||
let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return vec![] };
|
||||
|
||||
let block_markers = resolve_block_markers(branch_info, mir_body);
|
||||
let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
|
||||
|
||||
branch_info
|
||||
coverage_info_hi
|
||||
.branch_spans
|
||||
.iter()
|
||||
.filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| {
|
||||
|
|
@ -222,9 +224,9 @@ pub(super) fn extract_mcdc_mappings(
|
|||
mcdc_branches: &mut impl Extend<MCDCBranch>,
|
||||
mcdc_decisions: &mut impl Extend<MCDCDecision>,
|
||||
) {
|
||||
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return };
|
||||
let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return };
|
||||
|
||||
let block_markers = resolve_block_markers(branch_info, mir_body);
|
||||
let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
|
||||
|
||||
let bcb_from_marker =
|
||||
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
|
||||
|
|
@ -243,7 +245,7 @@ pub(super) fn extract_mcdc_mappings(
|
|||
Some((span, true_bcb, false_bcb))
|
||||
};
|
||||
|
||||
mcdc_branches.extend(branch_info.mcdc_branch_spans.iter().filter_map(
|
||||
mcdc_branches.extend(coverage_info_hi.mcdc_branch_spans.iter().filter_map(
|
||||
|&mir::coverage::MCDCBranchSpan {
|
||||
span: raw_span,
|
||||
condition_info,
|
||||
|
|
@ -257,7 +259,7 @@ pub(super) fn extract_mcdc_mappings(
|
|||
},
|
||||
));
|
||||
|
||||
mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map(
|
||||
mcdc_decisions.extend(coverage_info_hi.mcdc_decision_spans.iter().filter_map(
|
||||
|decision: &mir::coverage::MCDCDecisionSpan| {
|
||||
let span = unexpand_into_body_span(decision.span, body_span)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,16 +33,16 @@ use std::fmt;
|
|||
/// as it would allow running a destructor on a place behind a reference:
|
||||
///
|
||||
/// ```text
|
||||
// fn drop_term<T>(t: &mut T) {
|
||||
// mir! {
|
||||
// {
|
||||
// Drop(*t, exit)
|
||||
// }
|
||||
// exit = {
|
||||
// Return()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
/// fn drop_term<T>(t: &mut T) {
|
||||
/// mir! {
|
||||
/// {
|
||||
/// Drop(*t, exit)
|
||||
/// }
|
||||
/// exit = {
|
||||
/// Return()
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub struct ElaborateDrops;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
|||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use rustc_type_ir::{
|
||||
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner,
|
||||
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike,
|
||||
Interner,
|
||||
};
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode};
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
|
||||
pub trait SolverDelegate: Sized {
|
||||
pub trait SolverDelegate:
|
||||
Deref<Target: InferCtxtLike<Interner = <Self as SolverDelegate>::Interner>> + Sized
|
||||
{
|
||||
type Interner: Interner;
|
||||
fn cx(&self) -> Self::Interner;
|
||||
fn cx(&self) -> Self::Interner {
|
||||
(**self).cx()
|
||||
}
|
||||
|
||||
type Span: Copy;
|
||||
|
||||
fn solver_mode(&self) -> SolverMode;
|
||||
|
||||
fn build_with_canonical<V>(
|
||||
cx: Self::Interner,
|
||||
solver_mode: SolverMode,
|
||||
|
|
@ -21,82 +23,12 @@ pub trait SolverDelegate: Sized {
|
|||
where
|
||||
V: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex;
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_float_var(
|
||||
&self,
|
||||
vid: ty::FloatVid,
|
||||
) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_ct_var(
|
||||
&self,
|
||||
vid: ty::ConstVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_effect_var(
|
||||
&self,
|
||||
vid: ty::EffectVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_lt_var(
|
||||
&self,
|
||||
vid: ty::RegionVid,
|
||||
) -> <Self::Interner as Interner>::Region;
|
||||
|
||||
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
|
||||
|
||||
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
||||
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
||||
fn fresh_args_for_item(
|
||||
&self,
|
||||
def_id: <Self::Interner as Interner>::DefId,
|
||||
) -> <Self::Interner as Interner>::GenericArgs;
|
||||
|
||||
fn fresh_var_for_kind_with_span(
|
||||
&self,
|
||||
arg: <Self::Interner as Interner>::GenericArg,
|
||||
span: Self::Span,
|
||||
) -> <Self::Interner as Interner>::GenericArg;
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
) -> T;
|
||||
|
||||
fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U;
|
||||
|
||||
fn relate<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
|
||||
|
||||
// FIXME: Uplift the leak check into this crate.
|
||||
fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>;
|
||||
|
||||
|
|
@ -112,18 +44,6 @@ pub trait SolverDelegate: Sized {
|
|||
unevaluated: ty::UnevaluatedConst<Self::Interner>,
|
||||
) -> Option<<Self::Interner as Interner>::Const>;
|
||||
|
||||
fn sub_regions(
|
||||
&self,
|
||||
sub: <Self::Interner as Interner>::Region,
|
||||
sup: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
|
||||
fn register_ty_outlives(
|
||||
&self,
|
||||
ty: <Self::Interner as Interner>::Ty,
|
||||
r: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
|
||||
// FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`!
|
||||
fn well_formed_goals(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@
|
|||
|
||||
pub mod canonicalizer;
|
||||
pub mod delegate;
|
||||
pub mod relate;
|
||||
pub mod resolve;
|
||||
pub mod solve;
|
||||
|
|
|
|||
15
compiler/rustc_next_trait_solver/src/relate.rs
Normal file
15
compiler/rustc_next_trait_solver/src/relate.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
pub use rustc_type_ir::relate::*;
|
||||
|
||||
pub mod combine;
|
||||
|
||||
/// Whether aliases should be related structurally or not. Used
|
||||
/// to adjust the behavior of generalization and combine.
|
||||
///
|
||||
/// This should always be `No` unless in a few special-cases when
|
||||
/// instantiating canonical responses and in the new solver. Each
|
||||
/// such case should have a comment explaining why it is used.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum StructurallyRelateAliases {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
34
compiler/rustc_next_trait_solver/src/relate/combine.rs
Normal file
34
compiler/rustc_next_trait_solver/src/relate/combine.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
pub use rustc_type_ir::relate::*;
|
||||
use rustc_type_ir::solve::Goal;
|
||||
use rustc_type_ir::{InferCtxtLike, Interner, Upcast};
|
||||
|
||||
use super::StructurallyRelateAliases;
|
||||
|
||||
pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
|
||||
TypeRelation<I>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
fn span(&self) -> I::Span;
|
||||
|
||||
fn param_env(&self) -> I::ParamEnv;
|
||||
|
||||
/// Whether aliases should be related structurally. This is pretty much
|
||||
/// always `No` unless you're equating in some specific locations of the
|
||||
/// new solver. See the comments in these use-cases for more details.
|
||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
|
||||
|
||||
/// Register obligations that must hold in order for this relation to hold
|
||||
fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
|
||||
|
||||
/// Register predicates that must hold in order for this relation to hold.
|
||||
/// This uses the default `param_env` of the obligation.
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
|
||||
);
|
||||
|
||||
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
|
||||
fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ use crate::delegate::SolverDelegate;
|
|||
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EAGER RESOLUTION
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use std::iter;
|
|||
use rustc_index::IndexVec;
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner};
|
||||
use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
use crate::canonicalizer::{CanonicalizeMode, Canonicalizer};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
|||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use rustc_type_ir::{self as ty, CanonicalVarValues, Interner};
|
||||
use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner};
|
||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use rustc_type_ir::Interner;
|
||||
use rustc_type_ir::{InferCtxtLike, Interner};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
|
|
|
|||
|
|
@ -277,7 +277,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
pats: &[hir::PatField<'_>],
|
||||
) {
|
||||
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
ty::Adt(adt, _) => {
|
||||
self.check_def_id(adt.did());
|
||||
adt.variant_of_res(res)
|
||||
}
|
||||
_ => span_bug!(lhs.span, "non-ADT in struct pattern"),
|
||||
};
|
||||
for pat in pats {
|
||||
|
|
@ -297,7 +300,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
dotdot: hir::DotDotPos,
|
||||
) {
|
||||
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
ty::Adt(adt, _) => {
|
||||
self.check_def_id(adt.did());
|
||||
adt.variant_of_res(res)
|
||||
}
|
||||
_ => {
|
||||
self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
|
||||
return;
|
||||
|
|
@ -402,31 +408,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// don't ignore impls for Enums and pub Structs whose methods don't have self receiver,
|
||||
// cause external crate may call such methods to construct values of these types
|
||||
if let Some(local_impl_of) = impl_of.as_local()
|
||||
&& let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(fn_sig) =
|
||||
self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
|
||||
&& matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
|
||||
&& let TyKind::Path(hir::QPath::Resolved(_, path)) =
|
||||
self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind
|
||||
&& let Res::Def(def_kind, did) = path.res
|
||||
{
|
||||
match def_kind {
|
||||
// for example, #[derive(Default)] pub struct T(i32);
|
||||
// external crate can call T::default() to construct T,
|
||||
// so that don't ignore impl Default for pub Enum and Structs
|
||||
DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => {
|
||||
return false;
|
||||
}
|
||||
// don't ignore impl Default for Enums,
|
||||
// cause we don't know which variant is constructed
|
||||
DefKind::Enum => return false,
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
|
||||
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
|
||||
{
|
||||
|
|
@ -690,6 +671,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
|||
self.handle_field_pattern_match(pat, res, fields);
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
if let ty::Adt(adt, _) = self.typeck_results().node_type(pat.hir_id).kind() {
|
||||
self.check_def_id(adt.did());
|
||||
}
|
||||
let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
|
||||
self.handle_res(res);
|
||||
}
|
||||
|
|
@ -845,7 +829,7 @@ fn check_item<'tcx>(
|
|||
// mark the method live if the self_ty is public,
|
||||
// or the method is public and may construct self
|
||||
if tcx.visibility(local_def_id).is_public()
|
||||
&& (ty_and_all_fields_are_public || may_construct_self)
|
||||
&& (ty_and_all_fields_are_public || (ty_is_public && may_construct_self))
|
||||
{
|
||||
// if the impl item is public,
|
||||
// and the ty may be constructed or can be constructed in foreign crates,
|
||||
|
|
|
|||
|
|
@ -1513,6 +1513,7 @@ symbols! {
|
|||
recursion_limit,
|
||||
reexport_test_harness_main,
|
||||
ref_pat_eat_one_layer_2024,
|
||||
ref_pat_eat_one_layer_2024_structural,
|
||||
ref_pat_everywhere,
|
||||
ref_unwind_safe_trait,
|
||||
reference,
|
||||
|
|
|
|||
|
|
@ -1,21 +1,18 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
|
||||
use rustc_infer::infer::canonical::{
|
||||
Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues,
|
||||
};
|
||||
use rustc_infer::infer::{
|
||||
BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt,
|
||||
};
|
||||
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_infer::traits::{ObligationCause, Reveal};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode};
|
||||
|
||||
use crate::traits::coherence::trait_ref_is_knowable;
|
||||
|
|
@ -48,13 +45,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
|
||||
type Span = Span;
|
||||
|
||||
fn solver_mode(&self) -> ty::solve::SolverMode {
|
||||
match self.intercrate {
|
||||
true => SolverMode::Coherence,
|
||||
false => SolverMode::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_with_canonical<V>(
|
||||
interner: TyCtxt<'tcx>,
|
||||
solver_mode: SolverMode,
|
||||
|
|
@ -74,104 +64,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
(SolverDelegate(infcx), value, vars)
|
||||
}
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex {
|
||||
self.0.universe()
|
||||
}
|
||||
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex {
|
||||
self.0.create_next_universe()
|
||||
}
|
||||
|
||||
fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> {
|
||||
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
|
||||
// ty infers will give you the universe of the var it resolved to not the universe
|
||||
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
|
||||
// try to print out `?0.1` it will just print `?0`.
|
||||
match self.0.probe_ty_var(vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
match self.0.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> {
|
||||
// Same issue as with `universe_of_ty`
|
||||
match self.0.probe_const_var(ct) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
|
||||
self.0.root_var(var)
|
||||
}
|
||||
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
|
||||
self.0.root_const_var(var)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> {
|
||||
match self.0.probe_ty_var(vid) {
|
||||
Ok(ty) => ty,
|
||||
Err(_) => Ty::new_var(self.0.tcx, self.0.root_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
|
||||
self.0.opportunistic_resolve_int_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
|
||||
self.0.opportunistic_resolve_float_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> {
|
||||
match self.0.probe_const_var(vid) {
|
||||
Ok(ct) => ct,
|
||||
Err(_) => ty::Const::new_var(self.0.tcx, self.0.root_const_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
|
||||
match self.0.probe_effect_var(vid) {
|
||||
Some(ct) => ct,
|
||||
None => ty::Const::new_infer(
|
||||
self.0.tcx,
|
||||
ty::InferConst::EffectVar(self.0.root_effect_var(vid)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.0
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.0.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.0.defining_opaque_types()
|
||||
}
|
||||
|
||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||
self.0.next_ty_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn next_const_infer(&self) -> ty::Const<'tcx> {
|
||||
self.0.next_const_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
self.0.fresh_args_for_item(DUMMY_SP, def_id)
|
||||
}
|
||||
|
||||
fn fresh_var_for_kind_with_span(
|
||||
&self,
|
||||
arg: ty::GenericArg<'tcx>,
|
||||
|
|
@ -186,57 +78,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
}
|
||||
}
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T {
|
||||
self.0.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.0.enter_forall(value, f)
|
||||
}
|
||||
|
||||
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
|
||||
}
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.0
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq_structurally_relating_aliases_no_trace(lhs, rhs)
|
||||
}
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.0.resolve_vars_if_possible(value)
|
||||
}
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
|
||||
self.0.probe(|_| probe())
|
||||
}
|
||||
|
||||
fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> {
|
||||
self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
|
||||
}
|
||||
|
|
@ -265,14 +106,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
}
|
||||
}
|
||||
|
||||
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
|
||||
self.0.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
|
||||
}
|
||||
|
||||
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
|
||||
self.0.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy());
|
||||
}
|
||||
|
||||
fn well_formed_goals(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
|
|
|||
|
|
@ -805,10 +805,11 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
|
|||
.unwrap()
|
||||
.contains(&data.trait_ref(self.tcx).def_id);
|
||||
|
||||
// only walk contained types if it's not a super trait
|
||||
if is_supertrait_of_current_trait {
|
||||
ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
|
||||
t.super_visit_with(self) // POSSIBLY reporting an error
|
||||
}
|
||||
}
|
||||
_ => t.super_visit_with(self), // walk contained types, if any
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use crate::traits::wf;
|
|||
use crate::traits::ObligationCtxt;
|
||||
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_infer::traits::query::OutlivesBound;
|
||||
use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
|
||||
|
|
@ -12,6 +11,7 @@ use rustc_middle::traits::ObligationCause;
|
|||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_type_ir::outlives::{push_outlives_components, Component};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||
|
|
@ -284,7 +284,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
|||
/// those relationships.
|
||||
fn implied_bounds_from_components<'tcx>(
|
||||
sub_region: ty::Region<'tcx>,
|
||||
sup_components: SmallVec<[Component<'tcx>; 4]>,
|
||||
sup_components: SmallVec<[Component<TyCtxt<'tcx>>; 4]>,
|
||||
) -> Vec<OutlivesBound<'tcx>> {
|
||||
sup_components
|
||||
.into_iter()
|
||||
|
|
|
|||
|
|
@ -640,8 +640,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
||||
type Result = ();
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
|
||||
|
||||
|
|
|
|||
93
compiler/rustc_type_ir/src/infer_ctxt.rs
Normal file
93
compiler/rustc_type_ir/src/infer_ctxt.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use crate::fold::TypeFoldable;
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::{Goal, NoSolution, SolverMode};
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
pub trait InferCtxtLike {
|
||||
type Interner: Interner;
|
||||
fn cx(&self) -> Self::Interner;
|
||||
|
||||
fn solver_mode(&self) -> SolverMode;
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex;
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_float_var(
|
||||
&self,
|
||||
vid: ty::FloatVid,
|
||||
) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_ct_var(
|
||||
&self,
|
||||
vid: ty::ConstVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_effect_var(
|
||||
&self,
|
||||
vid: ty::EffectVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_lt_var(
|
||||
&self,
|
||||
vid: ty::RegionVid,
|
||||
) -> <Self::Interner as Interner>::Region;
|
||||
|
||||
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
|
||||
|
||||
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
||||
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
||||
fn fresh_args_for_item(
|
||||
&self,
|
||||
def_id: <Self::Interner as Interner>::DefId,
|
||||
) -> <Self::Interner as Interner>::GenericArgs;
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
) -> T;
|
||||
|
||||
fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U;
|
||||
|
||||
fn relate<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
|
||||
|
||||
fn sub_regions(
|
||||
&self,
|
||||
sub: <Self::Interner as Interner>::Region,
|
||||
sup: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
|
||||
fn register_ty_outlives(
|
||||
&self,
|
||||
ty: <Self::Interner as Interner>::Ty,
|
||||
r: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
}
|
||||
|
|
@ -232,6 +232,10 @@ pub trait Region<I: Interner<Region = Self>>:
|
|||
fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
|
||||
|
||||
fn new_static(interner: I) -> Self;
|
||||
|
||||
fn is_bound(self) -> bool {
|
||||
matches!(self.kind(), ty::ReBound(..))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Const<I: Interner<Const = Self>>:
|
||||
|
|
@ -272,6 +276,10 @@ pub trait Const<I: Interner<Const = Self>>:
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ExprConst<I: Interner<ExprConst = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
|
||||
fn args(self) -> I::GenericArgs;
|
||||
}
|
||||
|
||||
pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
|
||||
fn count(&self) -> usize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ pub trait Interner:
|
|||
{
|
||||
type DefId: DefId<Self>;
|
||||
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
|
||||
type Span: Copy + Debug + Hash + Eq;
|
||||
|
||||
type GenericArgs: GenericArgs<Self>;
|
||||
type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>;
|
||||
|
|
@ -109,7 +110,7 @@ pub trait Interner:
|
|||
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
|
||||
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
type ValueConst: Copy + Debug + Hash + Eq;
|
||||
type ExprConst: Copy + Debug + Hash + Eq + Relate<Self>;
|
||||
type ExprConst: ExprConst<Self>;
|
||||
|
||||
// Kinds of regions
|
||||
type Region: Region<Self>;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ pub mod inherent;
|
|||
pub mod ir_print;
|
||||
pub mod lang_items;
|
||||
pub mod lift;
|
||||
pub mod outlives;
|
||||
pub mod relate;
|
||||
pub mod solve;
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ mod const_kind;
|
|||
mod effects;
|
||||
mod flags;
|
||||
mod generic_arg;
|
||||
mod infer_ctxt;
|
||||
mod interner;
|
||||
mod opaque_ty;
|
||||
mod predicate;
|
||||
|
|
@ -56,6 +58,7 @@ pub use const_kind::*;
|
|||
pub use effects::*;
|
||||
pub use flags::*;
|
||||
pub use generic_arg::*;
|
||||
pub use infer_ctxt::*;
|
||||
pub use interner::*;
|
||||
pub use opaque_ty::*;
|
||||
pub use predicate::*;
|
||||
|
|
|
|||
228
compiler/rustc_type_ir/src/outlives.rs
Normal file
228
compiler/rustc_type_ir/src/outlives.rs
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
//! The outlives relation `T: 'a` or `'a: 'b`. This code frequently
|
||||
//! refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
|
||||
//! RFC for reference.
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::data_structures::SsoHashSet;
|
||||
use crate::inherent::*;
|
||||
use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, TypeVisitor};
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(Debug(bound = ""))]
|
||||
pub enum Component<I: Interner> {
|
||||
Region(I::Region),
|
||||
Param(I::ParamTy),
|
||||
Placeholder(I::PlaceholderTy),
|
||||
UnresolvedInferenceVariable(ty::InferTy),
|
||||
|
||||
// Projections like `T::Foo` are tricky because a constraint like
|
||||
// `T::Foo: 'a` can be satisfied in so many ways. There may be a
|
||||
// where-clause that says `T::Foo: 'a`, or the defining trait may
|
||||
// include a bound like `type Foo: 'static`, or -- in the most
|
||||
// conservative way -- we can prove that `T: 'a` (more generally,
|
||||
// that all components in the projection outlive `'a`). This code
|
||||
// is not in a position to judge which is the best technique, so
|
||||
// we just product the projection as a component and leave it to
|
||||
// the consumer to decide (but see `EscapingProjection` below).
|
||||
Alias(ty::AliasTy<I>),
|
||||
|
||||
// In the case where a projection has escaping regions -- meaning
|
||||
// regions bound within the type itself -- we always use
|
||||
// the most conservative rule, which requires that all components
|
||||
// outlive the bound. So for example if we had a type like this:
|
||||
//
|
||||
// for<'a> Trait1< <T as Trait2<'a,'b>>::Foo >
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// then the inner projection (underlined) has an escaping region
|
||||
// `'a`. We consider that outer trait `'c` to meet a bound if `'b`
|
||||
// outlives `'b: 'c`, and we don't consider whether the trait
|
||||
// declares that `Foo: 'static` etc. Therefore, we just return the
|
||||
// free components of such a projection (in this case, `'b`).
|
||||
//
|
||||
// However, in the future, we may want to get smarter, and
|
||||
// actually return a "higher-ranked projection" here. Therefore,
|
||||
// we mark that these components are part of an escaping
|
||||
// projection, so that implied bounds code can avoid relying on
|
||||
// them. This gives us room to improve the regionck reasoning in
|
||||
// the future without breaking backwards compat.
|
||||
EscapingAlias(Vec<Component<I>>),
|
||||
}
|
||||
|
||||
/// Push onto `out` all the things that must outlive `'a` for the condition
|
||||
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
|
||||
pub fn push_outlives_components<I: Interner>(
|
||||
tcx: I,
|
||||
ty: I::Ty,
|
||||
out: &mut SmallVec<[Component<I>; 4]>,
|
||||
) {
|
||||
ty.visit_with(&mut OutlivesCollector { tcx, out, visited: Default::default() });
|
||||
}
|
||||
|
||||
struct OutlivesCollector<'a, I: Interner> {
|
||||
tcx: I,
|
||||
out: &'a mut SmallVec<[Component<I>; 4]>,
|
||||
visited: SsoHashSet<I::Ty>,
|
||||
}
|
||||
|
||||
impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
|
||||
fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
|
||||
if !self.visited.insert(ty) {
|
||||
return;
|
||||
}
|
||||
// Descend through the types, looking for the various "base"
|
||||
// components and collecting them into `out`. This is not written
|
||||
// with `collect()` because of the need to sometimes skip subtrees
|
||||
// in the `subtys` iterator (e.g., when encountering a
|
||||
// projection).
|
||||
match ty.kind() {
|
||||
ty::FnDef(_, args) => {
|
||||
// HACK(eddyb) ignore lifetimes found shallowly in `args`.
|
||||
// This is inconsistent with `ty::Adt` (including all args)
|
||||
// and with `ty::Closure` (ignoring all args other than
|
||||
// upvars, of which a `ty::FnDef` doesn't have any), but
|
||||
// consistent with previous (accidental) behavior.
|
||||
// See https://github.com/rust-lang/rust/issues/70917
|
||||
// for further background and discussion.
|
||||
for child in args.iter() {
|
||||
match child.kind() {
|
||||
ty::GenericArgKind::Lifetime(_) => {}
|
||||
ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) => {
|
||||
child.visit_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Closure(_, args) => {
|
||||
args.as_closure().tupled_upvars_ty().visit_with(self);
|
||||
}
|
||||
|
||||
ty::CoroutineClosure(_, args) => {
|
||||
args.as_coroutine_closure().tupled_upvars_ty().visit_with(self);
|
||||
}
|
||||
|
||||
ty::Coroutine(_, args) => {
|
||||
args.as_coroutine().tupled_upvars_ty().visit_with(self);
|
||||
|
||||
// We ignore regions in the coroutine interior as we don't
|
||||
// want these to affect region inference
|
||||
}
|
||||
|
||||
// All regions are bound inside a witness, and we don't emit
|
||||
// higher-ranked outlives components currently.
|
||||
ty::CoroutineWitness(..) => {}
|
||||
|
||||
// OutlivesTypeParameterEnv -- the actual checking that `X:'a`
|
||||
// is implied by the environment is done in regionck.
|
||||
ty::Param(p) => {
|
||||
self.out.push(Component::Param(p));
|
||||
}
|
||||
|
||||
ty::Placeholder(p) => {
|
||||
self.out.push(Component::Placeholder(p));
|
||||
}
|
||||
|
||||
// For projections, we prefer to generate an obligation like
|
||||
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
|
||||
// regionck more ways to prove that it holds. However,
|
||||
// regionck is not (at least currently) prepared to deal with
|
||||
// higher-ranked regions that may appear in the
|
||||
// trait-ref. Therefore, if we see any higher-ranked regions,
|
||||
// we simply fallback to the most restrictive rule, which
|
||||
// requires that `Pi: 'a` for all `i`.
|
||||
ty::Alias(_, alias_ty) => {
|
||||
if !alias_ty.has_escaping_bound_vars() {
|
||||
// best case: no escaping regions, so push the
|
||||
// projection and skip the subtree (thus generating no
|
||||
// constraints for Pi). This defers the choice between
|
||||
// the rules OutlivesProjectionEnv,
|
||||
// OutlivesProjectionTraitDef, and
|
||||
// OutlivesProjectionComponents to regionck.
|
||||
self.out.push(Component::Alias(alias_ty));
|
||||
} else {
|
||||
// fallback case: hard code
|
||||
// OutlivesProjectionComponents. Continue walking
|
||||
// through and constrain Pi.
|
||||
let mut subcomponents = smallvec![];
|
||||
compute_alias_components_recursive(self.tcx, ty, &mut subcomponents);
|
||||
self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
|
||||
}
|
||||
}
|
||||
|
||||
// We assume that inference variables are fully resolved.
|
||||
// So, if we encounter an inference variable, just record
|
||||
// the unresolved variable as a component.
|
||||
ty::Infer(infer_ty) => {
|
||||
self.out.push(Component::UnresolvedInferenceVariable(infer_ty));
|
||||
}
|
||||
|
||||
// Most types do not introduce any region binders, nor
|
||||
// involve any other subtle cases, and so the WF relation
|
||||
// simply constraints any regions referenced directly by
|
||||
// the type and then visits the types that are lexically
|
||||
// contained within.
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Str
|
||||
| ty::Never
|
||||
| ty::Error(_) => {
|
||||
// Trivial
|
||||
}
|
||||
|
||||
ty::Bound(_, _) => {
|
||||
// FIXME: Bound vars matter here!
|
||||
}
|
||||
|
||||
ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Tuple(_) => {
|
||||
ty.super_visit_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, lt: I::Region) -> Self::Result {
|
||||
if !lt.is_bound() {
|
||||
self.out.push(Component::Region(lt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect [Component]s for *all* the args of `parent`.
|
||||
///
|
||||
/// This should not be used to get the components of `parent` itself.
|
||||
/// Use [push_outlives_components] instead.
|
||||
pub fn compute_alias_components_recursive<I: Interner>(
|
||||
tcx: I,
|
||||
alias_ty: I::Ty,
|
||||
out: &mut SmallVec<[Component<I>; 4]>,
|
||||
) {
|
||||
let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
|
||||
unreachable!("can only call `compute_alias_components_recursive` on an alias type")
|
||||
};
|
||||
|
||||
let opt_variances =
|
||||
if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None };
|
||||
|
||||
let mut visitor = OutlivesCollector { tcx, out, visited: Default::default() };
|
||||
|
||||
for (index, child) in alias_ty.args.iter().enumerate() {
|
||||
if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) {
|
||||
continue;
|
||||
}
|
||||
child.visit_with(&mut visitor);
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,6 @@ use crate::ascii::Char as AsciiChar;
|
|||
/// ```
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
|
||||
pub trait Default: Sized {
|
||||
/// Returns the "default value" for a type.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -517,7 +517,10 @@ impl Display for Arguments<'_> {
|
|||
///
|
||||
/// let origin = Point { x: 0, y: 0 };
|
||||
///
|
||||
/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
|
||||
/// assert_eq!(
|
||||
/// format!("The origin is: {origin:?}"),
|
||||
/// "The origin is: Point { x: 0, y: 0 }",
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// Manually implementing:
|
||||
|
|
@ -541,7 +544,10 @@ impl Display for Arguments<'_> {
|
|||
///
|
||||
/// let origin = Point { x: 0, y: 0 };
|
||||
///
|
||||
/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
|
||||
/// assert_eq!(
|
||||
/// format!("The origin is: {origin:?}"),
|
||||
/// "The origin is: Point { x: 0, y: 0 }",
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// There are a number of helper methods on the [`Formatter`] struct to help you with manual
|
||||
|
|
@ -582,11 +588,11 @@ impl Display for Arguments<'_> {
|
|||
///
|
||||
/// let origin = Point { x: 0, y: 0 };
|
||||
///
|
||||
/// assert_eq!(format!("The origin is: {origin:#?}"),
|
||||
/// "The origin is: Point {
|
||||
/// let expected = "The origin is: Point {
|
||||
/// x: 0,
|
||||
/// y: 0,
|
||||
/// }");
|
||||
/// }";
|
||||
/// assert_eq!(format!("The origin is: {origin:#?}"), expected);
|
||||
/// ```
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -738,8 +744,10 @@ pub trait Display {
|
|||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!("(1.987, 2.983)",
|
||||
/// format!("{}", Position { longitude: 1.987, latitude: 2.983, }));
|
||||
/// assert_eq!(
|
||||
/// "(1.987, 2.983)",
|
||||
/// format!("{}", Position { longitude: 1.987, latitude: 2.983, }),
|
||||
/// );
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result;
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ pub mod panicking;
|
|||
#[unstable(feature = "core_pattern_types", issue = "none")]
|
||||
pub mod pat;
|
||||
pub mod pin;
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub mod range;
|
||||
pub mod result;
|
||||
pub mod sync;
|
||||
|
||||
|
|
|
|||
|
|
@ -390,37 +390,26 @@ impl<T: ?Sized> *const T {
|
|||
if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer.
|
||||
/// Adds an offset to a pointer.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_offset`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
|
|
@ -611,8 +600,7 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * `self` and `origin` must either
|
||||
///
|
||||
|
|
@ -623,26 +611,10 @@ impl<T: ?Sized> *const T {
|
|||
/// * The distance between the pointers, in bytes, must be an exact multiple
|
||||
/// of the size of `T`.
|
||||
///
|
||||
/// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
|
||||
///
|
||||
/// * The distance being in bounds cannot rely on "wrapping around" the address space.
|
||||
///
|
||||
/// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
|
||||
/// address space, so two pointers within some value of any Rust type `T` will always satisfy
|
||||
/// the last two conditions. The standard library also generally ensures that allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
|
||||
/// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
|
||||
/// always satisfies the last two conditions.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such a large allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
|
||||
/// such large allocations either.)
|
||||
/// As a consequence, the absolute distance between the pointers, in bytes, computed on
|
||||
/// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
|
||||
/// implied by the in-bounds requirement, and the fact that no allocated object can be larger
|
||||
/// than `isize::MAX` bytes.
|
||||
///
|
||||
/// The requirement for pointers to be derived from the same allocated object is primarily
|
||||
/// needed for `const`-compatibility: the distance between pointers into *different* allocated
|
||||
|
|
@ -879,37 +851,26 @@ impl<T: ?Sized> *const T {
|
|||
}
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
|
||||
/// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a `usize`.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_add`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
|
|
@ -963,7 +924,7 @@ impl<T: ?Sized> *const T {
|
|||
unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for
|
||||
/// Subtracts an offset from a pointer (convenience for
|
||||
/// `.offset((count as isize).wrapping_neg())`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
|
|
@ -971,30 +932,19 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset cannot exceed `isize::MAX` **bytes**.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_sub`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
|
|
|
|||
|
|
@ -404,37 +404,26 @@ impl<T: ?Sized> *mut T {
|
|||
if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer.
|
||||
/// Adds an offset to a pointer.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_offset`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
|
|
@ -836,8 +825,7 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * `self` and `origin` must either
|
||||
///
|
||||
|
|
@ -848,26 +836,10 @@ impl<T: ?Sized> *mut T {
|
|||
/// * The distance between the pointers, in bytes, must be an exact multiple
|
||||
/// of the size of `T`.
|
||||
///
|
||||
/// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
|
||||
///
|
||||
/// * The distance being in bounds cannot rely on "wrapping around" the address space.
|
||||
///
|
||||
/// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
|
||||
/// address space, so two pointers within some value of any Rust type `T` will always satisfy
|
||||
/// the last two conditions. The standard library also generally ensures that allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
|
||||
/// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
|
||||
/// always satisfies the last two conditions.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such a large allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
|
||||
/// such large allocations either.)
|
||||
/// As a consequence, the absolute distance between the pointers, in bytes, computed on
|
||||
/// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
|
||||
/// implied by the in-bounds requirement, and the fact that no allocated object can be larger
|
||||
/// than `isize::MAX` bytes.
|
||||
///
|
||||
/// The requirement for pointers to be derived from the same allocated object is primarily
|
||||
/// needed for `const`-compatibility: the distance between pointers into *different* allocated
|
||||
|
|
@ -1020,37 +992,26 @@ impl<T: ?Sized> *mut T {
|
|||
unsafe { (self as *const T).sub_ptr(origin) }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
|
||||
/// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a `usize`.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_add`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
|
|
@ -1104,7 +1065,7 @@ impl<T: ?Sized> *mut T {
|
|||
unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for
|
||||
/// Subtracts an offset from a pointer (convenience for
|
||||
/// `.offset((count as isize).wrapping_neg())`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
|
|
@ -1112,30 +1073,19 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset cannot exceed `isize::MAX` **bytes**.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// Consider using [`wrapping_sub`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
|
|
|
|||
|
|
@ -476,36 +476,26 @@ impl<T: ?Sized> NonNull<T> {
|
|||
unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer.
|
||||
/// Adds an offset to a pointer.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// [allocated object]: crate::ptr#allocated-object
|
||||
///
|
||||
|
|
@ -562,36 +552,26 @@ impl<T: ?Sized> NonNull<T> {
|
|||
unsafe { NonNull { pointer: self.pointer.byte_offset(count) } }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
|
||||
/// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a `usize`.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// [allocated object]: crate::ptr#allocated-object
|
||||
///
|
||||
|
|
@ -649,7 +629,7 @@ impl<T: ?Sized> NonNull<T> {
|
|||
unsafe { NonNull { pointer: self.pointer.byte_add(count) } }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for
|
||||
/// Subtracts an offset from a pointer (convenience for
|
||||
/// `.offset((count as isize).wrapping_neg())`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
|
|
@ -657,29 +637,19 @@ impl<T: ?Sized> NonNull<T> {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
|
||||
///
|
||||
/// * The computed offset cannot exceed `isize::MAX` **bytes**.
|
||||
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
|
||||
/// [allocated object], and the entire memory range between `self` and the result must be in
|
||||
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
|
||||
/// of the address space.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec`
|
||||
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
|
||||
/// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such an allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
|
||||
/// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
|
||||
/// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
|
||||
/// safe.
|
||||
///
|
||||
/// [allocated object]: crate::ptr#allocated-object
|
||||
///
|
||||
|
|
@ -761,38 +731,21 @@ impl<T: ?Sized> NonNull<T> {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
/// If any of the following conditions are violated, the result is Undefined Behavior:
|
||||
///
|
||||
/// * Both `self` and `origin` must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * `self` and `origin` must either
|
||||
///
|
||||
/// * Both pointers must be *derived from* a pointer to the same object.
|
||||
/// (See below for an example.)
|
||||
/// * both be *derived from* a pointer to the same [allocated object], and the memory range between
|
||||
/// the two pointers must be either empty or in bounds of that object. (See below for an example.)
|
||||
/// * or both be derived from an integer literal/constant, and point to the same address.
|
||||
///
|
||||
/// * The distance between the pointers, in bytes, must be an exact multiple
|
||||
/// of the size of `T`.
|
||||
///
|
||||
/// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
|
||||
///
|
||||
/// * The distance being in bounds cannot rely on "wrapping around" the address space.
|
||||
///
|
||||
/// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
|
||||
/// address space, so two pointers within some value of any Rust type `T` will always satisfy
|
||||
/// the last two conditions. The standard library also generally ensures that allocations
|
||||
/// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
|
||||
/// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
|
||||
/// always satisfies the last two conditions.
|
||||
///
|
||||
/// Most platforms fundamentally can't even construct such a large allocation.
|
||||
/// For instance, no known 64-bit platform can ever serve a request
|
||||
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
|
||||
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
|
||||
/// more than `isize::MAX` bytes with things like Physical Address
|
||||
/// Extension. As such, memory acquired directly from allocators or memory
|
||||
/// mapped files *may* be too large to handle with this function.
|
||||
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
|
||||
/// such large allocations either.)
|
||||
/// As a consequence, the absolute distance between the pointers, in bytes, computed on
|
||||
/// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
|
||||
/// implied by the in-bounds requirement, and the fact that no allocated object can be larger
|
||||
/// than `isize::MAX` bytes.
|
||||
///
|
||||
/// The requirement for pointers to be derived from the same allocated object is primarily
|
||||
/// needed for `const`-compatibility: the distance between pointers into *different* allocated
|
||||
|
|
|
|||
494
library/core/src/range.rs
Normal file
494
library/core/src/range.rs
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
//! # Experimental replacement range types
|
||||
//!
|
||||
//! The types within this module are meant to replace the existing
|
||||
//! `Range`, `RangeInclusive`, and `RangeFrom` types in a future edition.
|
||||
//!
|
||||
//! ```
|
||||
//! #![feature(new_range_api)]
|
||||
//! use core::range::{Range, RangeFrom, RangeInclusive};
|
||||
//!
|
||||
//! let arr = [0, 1, 2, 3, 4];
|
||||
//! assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]);
|
||||
//! assert_eq!(arr[ .. 3 ], [0, 1, 2 ]);
|
||||
//! assert_eq!(arr[ ..=3 ], [0, 1, 2, 3 ]);
|
||||
//! assert_eq!(arr[ RangeFrom::from(1.. )], [ 1, 2, 3, 4]);
|
||||
//! assert_eq!(arr[ Range::from(1..3 )], [ 1, 2 ]);
|
||||
//! assert_eq!(arr[RangeInclusive::from(1..=3)], [ 1, 2, 3 ]);
|
||||
//! ```
|
||||
|
||||
use crate::fmt;
|
||||
use crate::hash::Hash;
|
||||
|
||||
mod iter;
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub mod legacy;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use crate::ops::{Bound, OneSidedRange, RangeBounds, RangeFull, RangeTo, RangeToInclusive};
|
||||
|
||||
use Bound::{Excluded, Included, Unbounded};
|
||||
|
||||
#[doc(inline)]
|
||||
pub use crate::iter::Step;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive};
|
||||
|
||||
/// A (half-open) range bounded inclusively below and exclusively above
|
||||
/// (`start..end` in a future edition).
|
||||
///
|
||||
/// The range `start..end` contains all values with `start <= x < end`.
|
||||
/// It is empty if `start >= end`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::Range;
|
||||
///
|
||||
/// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 });
|
||||
/// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum());
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub struct Range<Idx> {
|
||||
/// The lower bound of the range (inclusive).
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub start: Idx,
|
||||
/// The upper bound of the range (exclusive).
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub end: Idx,
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.start.fmt(fmt)?;
|
||||
write!(fmt, "..")?;
|
||||
self.end.fmt(fmt)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: Step> Range<Idx> {
|
||||
/// Create an iterator over the elements within this range.
|
||||
///
|
||||
/// Shorthand for `.clone().into_iter()`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::Range;
|
||||
///
|
||||
/// let mut i = Range::from(3..9).iter().map(|n| n*n);
|
||||
/// assert_eq!(i.next(), Some(9));
|
||||
/// assert_eq!(i.next(), Some(16));
|
||||
/// assert_eq!(i.next(), Some(25));
|
||||
/// ```
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[inline]
|
||||
pub fn iter(&self) -> IterRange<Idx> {
|
||||
self.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: PartialOrd<Idx>> Range<Idx> {
|
||||
/// Returns `true` if `item` is contained in the range.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::Range;
|
||||
///
|
||||
/// assert!(!Range::from(3..5).contains(&2));
|
||||
/// assert!( Range::from(3..5).contains(&3));
|
||||
/// assert!( Range::from(3..5).contains(&4));
|
||||
/// assert!(!Range::from(3..5).contains(&5));
|
||||
///
|
||||
/// assert!(!Range::from(3..3).contains(&3));
|
||||
/// assert!(!Range::from(3..2).contains(&3));
|
||||
///
|
||||
/// assert!( Range::from(0.0..1.0).contains(&0.5));
|
||||
/// assert!(!Range::from(0.0..1.0).contains(&f32::NAN));
|
||||
/// assert!(!Range::from(0.0..f32::NAN).contains(&0.5));
|
||||
/// assert!(!Range::from(f32::NAN..1.0).contains(&0.5));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
Idx: PartialOrd<U>,
|
||||
U: ?Sized + PartialOrd<Idx>,
|
||||
{
|
||||
<Self as RangeBounds<Idx>>::contains(self, item)
|
||||
}
|
||||
|
||||
/// Returns `true` if the range contains no items.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::Range;
|
||||
///
|
||||
/// assert!(!Range::from(3..5).is_empty());
|
||||
/// assert!( Range::from(3..3).is_empty());
|
||||
/// assert!( Range::from(3..2).is_empty());
|
||||
/// ```
|
||||
///
|
||||
/// The range is empty if either side is incomparable:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::Range;
|
||||
///
|
||||
/// assert!(!Range::from(3.0..5.0).is_empty());
|
||||
/// assert!( Range::from(3.0..f32::NAN).is_empty());
|
||||
/// assert!( Range::from(f32::NAN..5.0).is_empty());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
!(self.start < self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> RangeBounds<T> for Range<T> {
|
||||
fn start_bound(&self) -> Bound<&T> {
|
||||
Included(&self.start)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&T> {
|
||||
Excluded(&self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> RangeBounds<T> for Range<&T> {
|
||||
fn start_bound(&self) -> Bound<&T> {
|
||||
Included(self.start)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&T> {
|
||||
Excluded(self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<Range<T>> for legacy::Range<T> {
|
||||
#[inline]
|
||||
fn from(value: Range<T>) -> Self {
|
||||
Self { start: value.start, end: value.end }
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<legacy::Range<T>> for Range<T> {
|
||||
#[inline]
|
||||
fn from(value: legacy::Range<T>) -> Self {
|
||||
Self { start: value.start, end: value.end }
|
||||
}
|
||||
}
|
||||
|
||||
/// A range bounded inclusively below and above (`start..=end`).
|
||||
///
|
||||
/// The `RangeInclusive` `start..=end` contains all values with `x >= start`
|
||||
/// and `x <= end`. It is empty unless `start <= end`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `start..=end` syntax is a `RangeInclusive`:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::RangeInclusive;
|
||||
///
|
||||
/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 });
|
||||
/// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum());
|
||||
/// ```
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub struct RangeInclusive<Idx> {
|
||||
/// The lower bound of the range (inclusive).
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub start: Idx,
|
||||
/// The upper bound of the range (inclusive).
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub end: Idx,
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.start.fmt(fmt)?;
|
||||
write!(fmt, "..=")?;
|
||||
self.end.fmt(fmt)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
||||
/// Returns `true` if `item` is contained in the range.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::RangeInclusive;
|
||||
///
|
||||
/// assert!(!RangeInclusive::from(3..=5).contains(&2));
|
||||
/// assert!( RangeInclusive::from(3..=5).contains(&3));
|
||||
/// assert!( RangeInclusive::from(3..=5).contains(&4));
|
||||
/// assert!( RangeInclusive::from(3..=5).contains(&5));
|
||||
/// assert!(!RangeInclusive::from(3..=5).contains(&6));
|
||||
///
|
||||
/// assert!( RangeInclusive::from(3..=3).contains(&3));
|
||||
/// assert!(!RangeInclusive::from(3..=2).contains(&3));
|
||||
///
|
||||
/// assert!( RangeInclusive::from(0.0..=1.0).contains(&1.0));
|
||||
/// assert!(!RangeInclusive::from(0.0..=1.0).contains(&f32::NAN));
|
||||
/// assert!(!RangeInclusive::from(0.0..=f32::NAN).contains(&0.0));
|
||||
/// assert!(!RangeInclusive::from(f32::NAN..=1.0).contains(&1.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
Idx: PartialOrd<U>,
|
||||
U: ?Sized + PartialOrd<Idx>,
|
||||
{
|
||||
<Self as RangeBounds<Idx>>::contains(self, item)
|
||||
}
|
||||
|
||||
/// Returns `true` if the range contains no items.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::RangeInclusive;
|
||||
///
|
||||
/// assert!(!RangeInclusive::from(3..=5).is_empty());
|
||||
/// assert!(!RangeInclusive::from(3..=3).is_empty());
|
||||
/// assert!( RangeInclusive::from(3..=2).is_empty());
|
||||
/// ```
|
||||
///
|
||||
/// The range is empty if either side is incomparable:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::RangeInclusive;
|
||||
///
|
||||
/// assert!(!RangeInclusive::from(3.0..=5.0).is_empty());
|
||||
/// assert!( RangeInclusive::from(3.0..=f32::NAN).is_empty());
|
||||
/// assert!( RangeInclusive::from(f32::NAN..=5.0).is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
!(self.start <= self.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: Step> RangeInclusive<Idx> {
|
||||
/// Create an iterator over the elements within this range.
|
||||
///
|
||||
/// Shorthand for `.clone().into_iter()`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::RangeInclusive;
|
||||
///
|
||||
/// let mut i = RangeInclusive::from(3..=8).iter().map(|n| n*n);
|
||||
/// assert_eq!(i.next(), Some(9));
|
||||
/// assert_eq!(i.next(), Some(16));
|
||||
/// assert_eq!(i.next(), Some(25));
|
||||
/// ```
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[inline]
|
||||
pub fn iter(&self) -> IterRangeInclusive<Idx> {
|
||||
self.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl RangeInclusive<usize> {
|
||||
/// Converts to an exclusive `Range` for `SliceIndex` implementations.
|
||||
/// The caller is responsible for dealing with `end == usize::MAX`.
|
||||
#[inline]
|
||||
pub(crate) const fn into_slice_range(self) -> Range<usize> {
|
||||
Range { start: self.start, end: self.end + 1 }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> RangeBounds<T> for RangeInclusive<T> {
|
||||
fn start_bound(&self) -> Bound<&T> {
|
||||
Included(&self.start)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&T> {
|
||||
Included(&self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> RangeBounds<T> for RangeInclusive<&T> {
|
||||
fn start_bound(&self) -> Bound<&T> {
|
||||
Included(self.start)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&T> {
|
||||
Included(self.end)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
|
||||
#[inline]
|
||||
fn from(value: RangeInclusive<T>) -> Self {
|
||||
Self::new(value.start, value.end)
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
|
||||
#[inline]
|
||||
fn from(value: legacy::RangeInclusive<T>) -> Self {
|
||||
assert!(
|
||||
!value.exhausted,
|
||||
"attempted to convert from an exhausted `legacy::RangeInclusive` (unspecified behavior)"
|
||||
);
|
||||
|
||||
let (start, end) = value.into_inner();
|
||||
RangeInclusive { start, end }
|
||||
}
|
||||
}
|
||||
|
||||
/// A range only bounded inclusively below (`start..`).
|
||||
///
|
||||
/// The `RangeFrom` `start..` contains all values with `x >= start`.
|
||||
///
|
||||
/// *Note*: Overflow in the [`Iterator`] implementation (when the contained
|
||||
/// data type reaches its numerical limit) is allowed to panic, wrap, or
|
||||
/// saturate. This behavior is defined by the implementation of the [`Step`]
|
||||
/// trait. For primitive integers, this follows the normal rules, and respects
|
||||
/// the overflow checks profile (panic in debug, wrap in release). Note also
|
||||
/// that overflow happens earlier than you might assume: the overflow happens
|
||||
/// in the call to `next` that yields the maximum value, as the range must be
|
||||
/// set to a state to yield the next value.
|
||||
///
|
||||
/// [`Step`]: crate::iter::Step
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `start..` syntax is a `RangeFrom`:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::RangeFrom;
|
||||
///
|
||||
/// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 });
|
||||
/// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
|
||||
/// ```
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub struct RangeFrom<Idx> {
|
||||
/// The lower bound of the range (inclusive).
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub start: Idx,
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.start.fmt(fmt)?;
|
||||
write!(fmt, "..")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: Step> RangeFrom<Idx> {
|
||||
/// Create an iterator over the elements within this range.
|
||||
///
|
||||
/// Shorthand for `.clone().into_iter()`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::RangeFrom;
|
||||
///
|
||||
/// let mut i = RangeFrom::from(3..).iter().map(|n| n*n);
|
||||
/// assert_eq!(i.next(), Some(9));
|
||||
/// assert_eq!(i.next(), Some(16));
|
||||
/// assert_eq!(i.next(), Some(25));
|
||||
/// ```
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[inline]
|
||||
pub fn iter(&self) -> IterRangeFrom<Idx> {
|
||||
self.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
|
||||
/// Returns `true` if `item` is contained in the range.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_range_api)]
|
||||
/// use core::range::RangeFrom;
|
||||
///
|
||||
/// assert!(!RangeFrom::from(3..).contains(&2));
|
||||
/// assert!( RangeFrom::from(3..).contains(&3));
|
||||
/// assert!( RangeFrom::from(3..).contains(&1_000_000_000));
|
||||
///
|
||||
/// assert!( RangeFrom::from(0.0..).contains(&0.5));
|
||||
/// assert!(!RangeFrom::from(0.0..).contains(&f32::NAN));
|
||||
/// assert!(!RangeFrom::from(f32::NAN..).contains(&0.5));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
pub fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
Idx: PartialOrd<U>,
|
||||
U: ?Sized + PartialOrd<Idx>,
|
||||
{
|
||||
<Self as RangeBounds<Idx>>::contains(self, item)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> RangeBounds<T> for RangeFrom<T> {
|
||||
fn start_bound(&self) -> Bound<&T> {
|
||||
Included(&self.start)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&T> {
|
||||
Unbounded
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> RangeBounds<T> for RangeFrom<&T> {
|
||||
fn start_bound(&self) -> Bound<&T> {
|
||||
Included(self.start)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&T> {
|
||||
Unbounded
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<RangeFrom<T>> for legacy::RangeFrom<T> {
|
||||
#[inline]
|
||||
fn from(value: RangeFrom<T>) -> Self {
|
||||
Self { start: value.start }
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<legacy::RangeFrom<T>> for RangeFrom<T> {
|
||||
#[inline]
|
||||
fn from(value: legacy::RangeFrom<T>) -> Self {
|
||||
Self { start: value.start }
|
||||
}
|
||||
}
|
||||
340
library/core/src/range/iter.rs
Normal file
340
library/core/src/range/iter.rs
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
use crate::num::NonZero;
|
||||
use crate::range::{legacy, Range, RangeFrom, RangeInclusive};
|
||||
|
||||
use crate::iter::{
|
||||
FusedIterator, Step, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, TrustedStep,
|
||||
};
|
||||
|
||||
/// By-value [`Range`] iterator.
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IterRange<A>(legacy::Range<A>);
|
||||
|
||||
impl<A> IterRange<A> {
|
||||
/// Returns the remainder of the range being iterated over.
|
||||
pub fn remainder(self) -> Range<A> {
|
||||
Range { start: self.0.start, end: self.0.end }
|
||||
}
|
||||
}
|
||||
|
||||
/// Safety: This macro must only be used on types that are `Copy` and result in ranges
|
||||
/// which have an exact `size_hint()` where the upper bound must not be `None`.
|
||||
macro_rules! unsafe_range_trusted_random_access_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "trusted_random_access", issue = "none")]
|
||||
unsafe impl TrustedRandomAccess for IterRange<$t> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "trusted_random_access", issue = "none")]
|
||||
unsafe impl TrustedRandomAccessNoCoerce for IterRange<$t> {
|
||||
const MAY_HAVE_SIDE_EFFECT: bool = false;
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
unsafe_range_trusted_random_access_impl! {
|
||||
usize u8 u16
|
||||
isize i8 i16
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
unsafe_range_trusted_random_access_impl! {
|
||||
u32 i32
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
unsafe_range_trusted_random_access_impl! {
|
||||
u32 i32
|
||||
u64 i64
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> Iterator for IterRange<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
self.0.next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
self.0.count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, n: usize) -> Option<A> {
|
||||
self.0.nth(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(self) -> Option<A> {
|
||||
self.0.last()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn min(self) -> Option<A>
|
||||
where
|
||||
A: Ord,
|
||||
{
|
||||
self.0.min()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn max(self) -> Option<A>
|
||||
where
|
||||
A: Ord,
|
||||
{
|
||||
self.0.max()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_sorted(self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
self.0.advance_by(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
|
||||
where
|
||||
Self: TrustedRandomAccessNoCoerce,
|
||||
{
|
||||
// SAFETY: The TrustedRandomAccess contract requires that callers only pass an index
|
||||
// that is in bounds.
|
||||
// Additionally Self: TrustedRandomAccess is only implemented for Copy types
|
||||
// which means even repeated reads of the same index would be safe.
|
||||
unsafe { Step::forward_unchecked(self.0.start.clone(), idx) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> DoubleEndedIterator for IterRange<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
self.0.next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, n: usize) -> Option<A> {
|
||||
self.0.nth_back(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
self.0.advance_back_by(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: TrustedStep> TrustedLen for IterRange<A> {}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> FusedIterator for IterRange<A> {}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> IntoIterator for Range<A> {
|
||||
type Item = A;
|
||||
type IntoIter = IterRange<A>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IterRange(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// By-value [`RangeInclusive`] iterator.
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IterRangeInclusive<A>(legacy::RangeInclusive<A>);
|
||||
|
||||
impl<A: Step> IterRangeInclusive<A> {
|
||||
/// Returns the remainder of the range being iterated over.
|
||||
///
|
||||
/// If the iterator is exhausted or empty, returns `None`.
|
||||
pub fn remainder(self) -> Option<RangeInclusive<A>> {
|
||||
if self.0.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(RangeInclusive { start: self.0.start, end: self.0.end })
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_random_access", issue = "none")]
|
||||
impl<A: Step> Iterator for IterRangeInclusive<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
self.0.next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
self.0.count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, n: usize) -> Option<A> {
|
||||
self.0.nth(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(self) -> Option<A> {
|
||||
self.0.last()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn min(self) -> Option<A>
|
||||
where
|
||||
A: Ord,
|
||||
{
|
||||
self.0.min()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn max(self) -> Option<A>
|
||||
where
|
||||
A: Ord,
|
||||
{
|
||||
self.0.max()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_sorted(self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
self.0.advance_by(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> DoubleEndedIterator for IterRangeInclusive<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
self.0.next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, n: usize) -> Option<A> {
|
||||
self.0.nth_back(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
self.0.advance_back_by(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: TrustedStep> TrustedLen for IterRangeInclusive<A> {}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> FusedIterator for IterRangeInclusive<A> {}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> IntoIterator for RangeInclusive<A> {
|
||||
type Item = A;
|
||||
type IntoIter = IterRangeInclusive<A>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IterRangeInclusive(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
// These macros generate `ExactSizeIterator` impls for various range types.
|
||||
//
|
||||
// * `ExactSizeIterator::len` is required to always return an exact `usize`,
|
||||
// so no range can be longer than `usize::MAX`.
|
||||
// * For integer types in `Range<_>` this is the case for types narrower than or as wide as `usize`.
|
||||
// For integer types in `RangeInclusive<_>`
|
||||
// this is the case for types *strictly narrower* than `usize`
|
||||
// since e.g. `(0..=u64::MAX).len()` would be `u64::MAX + 1`.
|
||||
macro_rules! range_exact_iter_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl ExactSizeIterator for IterRange<$t> { }
|
||||
)*)
|
||||
}
|
||||
|
||||
macro_rules! range_incl_exact_iter_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl ExactSizeIterator for IterRangeInclusive<$t> { }
|
||||
)*)
|
||||
}
|
||||
|
||||
range_exact_iter_impl! {
|
||||
usize u8 u16
|
||||
isize i8 i16
|
||||
}
|
||||
|
||||
range_incl_exact_iter_impl! {
|
||||
u8
|
||||
i8
|
||||
}
|
||||
|
||||
/// By-value [`RangeFrom`] iterator.
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IterRangeFrom<A>(legacy::RangeFrom<A>);
|
||||
|
||||
impl<A> IterRangeFrom<A> {
|
||||
/// Returns the remainder of the range being iterated over.
|
||||
pub fn remainder(self) -> RangeFrom<A> {
|
||||
RangeFrom { start: self.0.start }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_random_access", issue = "none")]
|
||||
impl<A: Step> Iterator for IterRangeFrom<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
self.0.next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, n: usize) -> Option<A> {
|
||||
self.0.nth(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: TrustedStep> TrustedLen for IterRangeFrom<A> {}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> FusedIterator for IterRangeFrom<A> {}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<A: Step> IntoIterator for RangeFrom<A> {
|
||||
type Item = A;
|
||||
type IntoIter = IterRangeFrom<A>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IterRangeFrom(self.into())
|
||||
}
|
||||
}
|
||||
10
library/core/src/range/legacy.rs
Normal file
10
library/core/src/range/legacy.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
//! # Legacy range types
|
||||
//!
|
||||
//! The types within this module will be replaced by the types
|
||||
//! [`Range`], [`RangeInclusive`], and [`RangeFrom`] in the parent
|
||||
//! module, [`core::range`].
|
||||
//!
|
||||
//! The types here are equivalent to those in [`core::ops`].
|
||||
|
||||
#[doc(inline)]
|
||||
pub use crate::ops::{Range, RangeFrom, RangeInclusive};
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use crate::intrinsics::const_eval_select;
|
||||
use crate::ops;
|
||||
use crate::range;
|
||||
use crate::ub_checks::assert_unsafe_precondition;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -147,7 +148,8 @@ const unsafe fn get_offset_len_mut_noubcheck<T>(
|
|||
}
|
||||
|
||||
mod private_slice_index {
|
||||
use super::ops;
|
||||
use super::{ops, range};
|
||||
|
||||
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
||||
pub trait Sealed {}
|
||||
|
||||
|
|
@ -168,6 +170,13 @@ mod private_slice_index {
|
|||
#[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")]
|
||||
impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl Sealed for range::Range<usize> {}
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl Sealed for range::RangeInclusive<usize> {}
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl Sealed for range::RangeFrom<usize> {}
|
||||
|
||||
impl Sealed for ops::IndexRange {}
|
||||
}
|
||||
|
||||
|
|
@ -473,6 +482,43 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::Range<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
fn get(self, slice: &[T]) -> Option<&[T]> {
|
||||
ops::Range::from(self).get(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
|
||||
ops::Range::from(self).get_mut(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
|
||||
unsafe { ops::Range::from(self).get_unchecked(slice) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
|
||||
unsafe { ops::Range::from(self).get_unchecked_mut(slice) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn index(self, slice: &[T]) -> &[T] {
|
||||
ops::Range::from(self).index(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
|
||||
ops::Range::from(self).index_mut(slice)
|
||||
}
|
||||
}
|
||||
|
||||
/// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
|
||||
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
|
||||
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
||||
|
|
@ -559,6 +605,43 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
fn get(self, slice: &[T]) -> Option<&[T]> {
|
||||
ops::RangeFrom::from(self).get(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
|
||||
ops::RangeFrom::from(self).get_mut(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
|
||||
unsafe { ops::RangeFrom::from(self).get_unchecked(slice) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
|
||||
unsafe { ops::RangeFrom::from(self).get_unchecked_mut(slice) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index(self, slice: &[T]) -> &[T] {
|
||||
ops::RangeFrom::from(self).index(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
|
||||
ops::RangeFrom::from(self).index_mut(slice)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
|
||||
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
|
||||
|
|
@ -643,6 +726,43 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
fn get(self, slice: &[T]) -> Option<&[T]> {
|
||||
ops::RangeInclusive::from(self).get(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
|
||||
ops::RangeInclusive::from(self).get_mut(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
|
||||
unsafe { ops::RangeInclusive::from(self).get_unchecked(slice) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
|
||||
unsafe { ops::RangeInclusive::from(self).get_unchecked_mut(slice) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index(self, slice: &[T]) -> &[T] {
|
||||
ops::RangeInclusive::from(self).index(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
|
||||
ops::RangeInclusive::from(self).index_mut(slice)
|
||||
}
|
||||
}
|
||||
|
||||
/// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
||||
|
|
@ -780,7 +900,7 @@ where
|
|||
|
||||
/// Performs bounds-checking of a range without panicking.
|
||||
///
|
||||
/// This is a version of [`range`] that returns [`None`] instead of panicking.
|
||||
/// This is a version of [`range()`] that returns [`None`] instead of panicking.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::cmp::Ordering;
|
|||
use crate::intrinsics::unchecked_sub;
|
||||
use crate::ops;
|
||||
use crate::ptr;
|
||||
use crate::range;
|
||||
use crate::slice::SliceIndex;
|
||||
use crate::ub_checks::assert_unsafe_precondition;
|
||||
|
||||
|
|
@ -261,6 +262,108 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::Range<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
if self.start <= self.end
|
||||
&& slice.is_char_boundary(self.start)
|
||||
&& slice.is_char_boundary(self.end)
|
||||
{
|
||||
// SAFETY: just checked that `start` and `end` are on a char boundary,
|
||||
// and we are passing in a safe reference, so the return value will also be one.
|
||||
// We also checked char boundaries, so this is valid UTF-8.
|
||||
Some(unsafe { &*self.get_unchecked(slice) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
|
||||
if self.start <= self.end
|
||||
&& slice.is_char_boundary(self.start)
|
||||
&& slice.is_char_boundary(self.end)
|
||||
{
|
||||
// SAFETY: just checked that `start` and `end` are on a char boundary.
|
||||
// We know the pointer is unique because we got it from `slice`.
|
||||
Some(unsafe { &mut *self.get_unchecked_mut(slice) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
|
||||
let slice = slice as *const [u8];
|
||||
|
||||
assert_unsafe_precondition!(
|
||||
// We'd like to check that the bounds are on char boundaries,
|
||||
// but there's not really a way to do so without reading
|
||||
// behind the pointer, which has aliasing implications.
|
||||
// It's also not possible to move this check up to
|
||||
// `str::get_unchecked` without adding a special function
|
||||
// to `SliceIndex` just for this.
|
||||
check_library_ub,
|
||||
"str::get_unchecked requires that the range is within the string slice",
|
||||
(
|
||||
start: usize = self.start,
|
||||
end: usize = self.end,
|
||||
len: usize = slice.len()
|
||||
) => end >= start && end <= len,
|
||||
);
|
||||
|
||||
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
|
||||
// which satisfies all the conditions for `add`.
|
||||
unsafe {
|
||||
let new_len = unchecked_sub(self.end, self.start);
|
||||
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
|
||||
let slice = slice as *mut [u8];
|
||||
|
||||
assert_unsafe_precondition!(
|
||||
check_library_ub,
|
||||
"str::get_unchecked_mut requires that the range is within the string slice",
|
||||
(
|
||||
start: usize = self.start,
|
||||
end: usize = self.end,
|
||||
len: usize = slice.len()
|
||||
) => end >= start && end <= len,
|
||||
);
|
||||
|
||||
// SAFETY: see comments for `get_unchecked`.
|
||||
unsafe {
|
||||
let new_len = unchecked_sub(self.end, self.start);
|
||||
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn index(self, slice: &str) -> &Self::Output {
|
||||
let (start, end) = (self.start, self.end);
|
||||
match self.get(slice) {
|
||||
Some(s) => s,
|
||||
None => super::slice_error_fail(slice, start, end),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
// cannot reuse `get` as above, because of NLL trouble
|
||||
if self.start <= self.end
|
||||
&& slice.is_char_boundary(self.start)
|
||||
&& slice.is_char_boundary(self.end)
|
||||
{
|
||||
// SAFETY: just checked that `start` and `end` are on a char boundary,
|
||||
// and we are passing in a safe reference, so the return value will also be one.
|
||||
unsafe { &mut *self.get_unchecked_mut(slice) }
|
||||
} else {
|
||||
super::slice_error_fail(slice, self.start, self.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements substring slicing for arbitrary bounds.
|
||||
///
|
||||
/// Returns a slice of the given string bounded by the byte indices
|
||||
|
|
@ -453,6 +556,61 @@ unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::RangeFrom<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
if slice.is_char_boundary(self.start) {
|
||||
// SAFETY: just checked that `start` is on a char boundary,
|
||||
// and we are passing in a safe reference, so the return value will also be one.
|
||||
Some(unsafe { &*self.get_unchecked(slice) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
|
||||
if slice.is_char_boundary(self.start) {
|
||||
// SAFETY: just checked that `start` is on a char boundary,
|
||||
// and we are passing in a safe reference, so the return value will also be one.
|
||||
Some(unsafe { &mut *self.get_unchecked_mut(slice) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
|
||||
let len = (slice as *const [u8]).len();
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
|
||||
unsafe { (self.start..len).get_unchecked(slice) }
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
|
||||
let len = (slice as *mut [u8]).len();
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
|
||||
unsafe { (self.start..len).get_unchecked_mut(slice) }
|
||||
}
|
||||
#[inline]
|
||||
fn index(self, slice: &str) -> &Self::Output {
|
||||
let (start, end) = (self.start, slice.len());
|
||||
match self.get(slice) {
|
||||
Some(s) => s,
|
||||
None => super::slice_error_fail(slice, start, end),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
||||
if slice.is_char_boundary(self.start) {
|
||||
// SAFETY: just checked that `start` is on a char boundary,
|
||||
// and we are passing in a safe reference, so the return value will also be one.
|
||||
unsafe { &mut *self.get_unchecked_mut(slice) }
|
||||
} else {
|
||||
super::slice_error_fail(slice, self.start, slice.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut
|
||||
/// self[begin ..= end]`.
|
||||
///
|
||||
|
|
@ -507,6 +665,43 @@ unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::RangeInclusive<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
if self.end == usize::MAX { None } else { self.into_slice_range().get(slice) }
|
||||
}
|
||||
#[inline]
|
||||
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
|
||||
if self.end == usize::MAX { None } else { self.into_slice_range().get_mut(slice) }
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
|
||||
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
|
||||
unsafe { self.into_slice_range().get_unchecked(slice) }
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
|
||||
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
|
||||
unsafe { self.into_slice_range().get_unchecked_mut(slice) }
|
||||
}
|
||||
#[inline]
|
||||
fn index(self, slice: &str) -> &Self::Output {
|
||||
if self.end == usize::MAX {
|
||||
str_index_overflow_fail();
|
||||
}
|
||||
self.into_slice_range().index(slice)
|
||||
}
|
||||
#[inline]
|
||||
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
||||
if self.end == usize::MAX {
|
||||
str_index_overflow_fail();
|
||||
}
|
||||
self.into_slice_range().index_mut(slice)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements substring slicing with syntax `&self[..= end]` or `&mut
|
||||
/// self[..= end]`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -36,18 +36,14 @@ use core::panic::PanicPayload;
|
|||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "emscripten")] {
|
||||
#[path = "emcc.rs"]
|
||||
mod real_imp;
|
||||
mod imp;
|
||||
} else if #[cfg(target_os = "hermit")] {
|
||||
#[path = "hermit.rs"]
|
||||
mod real_imp;
|
||||
mod imp;
|
||||
} else if #[cfg(target_os = "l4re")] {
|
||||
// L4Re is unix family but does not yet support unwinding.
|
||||
#[path = "dummy.rs"]
|
||||
mod real_imp;
|
||||
} else if #[cfg(all(target_env = "msvc", not(target_arch = "arm")))] {
|
||||
// LLVM does not support unwinding on 32 bit ARM msvc (thumbv7a-pc-windows-msvc)
|
||||
#[path = "seh.rs"]
|
||||
mod real_imp;
|
||||
mod imp;
|
||||
} else if #[cfg(any(
|
||||
all(target_family = "windows", target_env = "gnu"),
|
||||
target_os = "psp",
|
||||
|
|
@ -58,7 +54,16 @@ cfg_if::cfg_if! {
|
|||
target_family = "wasm",
|
||||
))] {
|
||||
#[path = "gcc.rs"]
|
||||
mod real_imp;
|
||||
mod imp;
|
||||
} else if #[cfg(miri)] {
|
||||
// Use the Miri runtime on Windows as miri doesn't support funclet based unwinding,
|
||||
// only landingpad based unwinding. Also use the Miri runtime on unsupported platforms.
|
||||
#[path = "miri.rs"]
|
||||
mod imp;
|
||||
} else if #[cfg(all(target_env = "msvc", not(target_arch = "arm")))] {
|
||||
// LLVM does not support unwinding on 32 bit ARM msvc (thumbv7a-pc-windows-msvc)
|
||||
#[path = "seh.rs"]
|
||||
mod imp;
|
||||
} else {
|
||||
// Targets that don't support unwinding.
|
||||
// - os=none ("bare metal" targets)
|
||||
|
|
@ -67,20 +72,7 @@ cfg_if::cfg_if! {
|
|||
// - nvptx64-nvidia-cuda
|
||||
// - arch=avr
|
||||
#[path = "dummy.rs"]
|
||||
mod real_imp;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(miri)] {
|
||||
// Use the Miri runtime.
|
||||
// We still need to also load the normal runtime above, as rustc expects certain lang
|
||||
// items from there to be defined.
|
||||
#[path = "miri.rs"]
|
||||
mod imp;
|
||||
} else {
|
||||
// Use the real runtime.
|
||||
use real_imp as imp;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1519,6 +1519,74 @@ impl PathBuf {
|
|||
true
|
||||
}
|
||||
|
||||
/// Append [`self.extension`] with `extension`.
|
||||
///
|
||||
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
|
||||
/// returns `true` and updates the extension otherwise.
|
||||
///
|
||||
/// # Caveats
|
||||
///
|
||||
/// The appended `extension` may contain dots and will be used in its entirety,
|
||||
/// but only the part after the final dot will be reflected in
|
||||
/// [`self.extension`].
|
||||
///
|
||||
/// See the examples below.
|
||||
///
|
||||
/// [`self.file_name`]: Path::file_name
|
||||
/// [`self.extension`]: Path::extension
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(path_add_extension)]
|
||||
///
|
||||
/// use std::path::{Path, PathBuf};
|
||||
///
|
||||
/// let mut p = PathBuf::from("/feel/the");
|
||||
///
|
||||
/// p.add_extension("formatted");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted"), p.as_path());
|
||||
///
|
||||
/// p.add_extension("dark.side");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path());
|
||||
///
|
||||
/// p.set_extension("cookie");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path());
|
||||
///
|
||||
/// p.set_extension("");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
|
||||
///
|
||||
/// p.add_extension("");
|
||||
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
|
||||
/// ```
|
||||
#[unstable(feature = "path_add_extension", issue = "127292")]
|
||||
pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
|
||||
self._add_extension(extension.as_ref())
|
||||
}
|
||||
|
||||
fn _add_extension(&mut self, extension: &OsStr) -> bool {
|
||||
let file_name = match self.file_name() {
|
||||
None => return false,
|
||||
Some(f) => f.as_encoded_bytes(),
|
||||
};
|
||||
|
||||
let new = extension;
|
||||
if !new.is_empty() {
|
||||
// truncate until right after the file name
|
||||
// this is necessary for trimming the trailing slash
|
||||
let end_file_name = file_name[file_name.len()..].as_ptr().addr();
|
||||
let start = self.inner.as_encoded_bytes().as_ptr().addr();
|
||||
self.inner.truncate(end_file_name.wrapping_sub(start));
|
||||
|
||||
// append the new extension
|
||||
self.inner.reserve_exact(new.len() + 1);
|
||||
self.inner.push(OsStr::new("."));
|
||||
self.inner.push(new);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Yields a mutable reference to the underlying [`OsString`] instance.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -2656,6 +2724,32 @@ impl Path {
|
|||
new_path
|
||||
}
|
||||
|
||||
/// Creates an owned [`PathBuf`] like `self` but with the extension added.
|
||||
///
|
||||
/// See [`PathBuf::add_extension`] for more details.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(path_add_extension)]
|
||||
///
|
||||
/// use std::path::{Path, PathBuf};
|
||||
///
|
||||
/// let path = Path::new("foo.rs");
|
||||
/// assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt"));
|
||||
///
|
||||
/// let path = Path::new("foo.tar.gz");
|
||||
/// assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz"));
|
||||
/// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz"));
|
||||
/// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
|
||||
/// ```
|
||||
#[unstable(feature = "path_add_extension", issue = "127292")]
|
||||
pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
|
||||
let mut new_path = self.to_path_buf();
|
||||
new_path.add_extension(extension);
|
||||
new_path
|
||||
}
|
||||
|
||||
/// Produces an iterator over the [`Component`]s of the path.
|
||||
///
|
||||
/// When parsing the path, there is a small amount of normalization:
|
||||
|
|
|
|||
|
|
@ -1401,6 +1401,37 @@ pub fn test_set_extension() {
|
|||
tfe!("/", "foo", "/", false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_add_extension() {
|
||||
macro_rules! tfe (
|
||||
($path:expr, $ext:expr, $expected:expr, $output:expr) => ({
|
||||
let mut p = PathBuf::from($path);
|
||||
let output = p.add_extension($ext);
|
||||
assert!(p.to_str() == Some($expected) && output == $output,
|
||||
"adding extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
|
||||
$path, $ext, $expected, $output,
|
||||
p.to_str().unwrap(), output);
|
||||
});
|
||||
);
|
||||
|
||||
tfe!("foo", "txt", "foo.txt", true);
|
||||
tfe!("foo.bar", "txt", "foo.bar.txt", true);
|
||||
tfe!("foo.bar.baz", "txt", "foo.bar.baz.txt", true);
|
||||
tfe!(".test", "txt", ".test.txt", true);
|
||||
tfe!("foo.txt", "", "foo.txt", true);
|
||||
tfe!("foo", "", "foo", true);
|
||||
tfe!("", "foo", "", false);
|
||||
tfe!(".", "foo", ".", false);
|
||||
tfe!("foo/", "bar", "foo.bar", true);
|
||||
tfe!("foo/.", "bar", "foo.bar", true);
|
||||
tfe!("..", "foo", "..", false);
|
||||
tfe!("foo/..", "bar", "foo/..", false);
|
||||
tfe!("/", "foo", "/", false);
|
||||
|
||||
// edge cases
|
||||
tfe!("/foo.ext////", "bar", "/foo.ext.bar", true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_with_extension() {
|
||||
macro_rules! twe (
|
||||
|
|
@ -1441,6 +1472,49 @@ pub fn test_with_extension() {
|
|||
twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.aaa_aaa_aaa");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_with_added_extension() {
|
||||
macro_rules! twe (
|
||||
($input:expr, $extension:expr, $expected:expr) => ({
|
||||
let input = Path::new($input);
|
||||
let output = input.with_added_extension($extension);
|
||||
|
||||
assert!(
|
||||
output.to_str() == Some($expected),
|
||||
"calling Path::new({:?}).with_added_extension({:?}): Expected {:?}, got {:?}",
|
||||
$input, $extension, $expected, output,
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
twe!("foo", "txt", "foo.txt");
|
||||
twe!("foo.bar", "txt", "foo.bar.txt");
|
||||
twe!("foo.bar.baz", "txt", "foo.bar.baz.txt");
|
||||
twe!(".test", "txt", ".test.txt");
|
||||
twe!("foo.txt", "", "foo.txt");
|
||||
twe!("foo", "", "foo");
|
||||
twe!("", "foo", "");
|
||||
twe!(".", "foo", ".");
|
||||
twe!("foo/", "bar", "foo.bar");
|
||||
twe!("foo/.", "bar", "foo.bar");
|
||||
twe!("..", "foo", "..");
|
||||
twe!("foo/..", "bar", "foo/..");
|
||||
twe!("/", "foo", "/");
|
||||
|
||||
// edge cases
|
||||
twe!("/foo.ext////", "bar", "/foo.ext.bar");
|
||||
|
||||
// New extension is smaller than file name
|
||||
twe!("aaa_aaa_aaa", "bbb_bbb", "aaa_aaa_aaa.bbb_bbb");
|
||||
// New extension is greater than file name
|
||||
twe!("bbb_bbb", "aaa_aaa_aaa", "bbb_bbb.aaa_aaa_aaa");
|
||||
|
||||
// New extension is smaller than previous extension
|
||||
twe!("ccc.aaa_aaa_aaa", "bbb_bbb", "ccc.aaa_aaa_aaa.bbb_bbb");
|
||||
// New extension is greater than previous extension
|
||||
twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.bbb_bbb.aaa_aaa_aaa");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq_receivers() {
|
||||
use crate::borrow::Cow;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_vo
|
|||
use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
|
||||
use crate::ptr;
|
||||
|
||||
mod windows_targets;
|
||||
|
||||
mod windows_sys;
|
||||
pub use windows_sys::*;
|
||||
|
||||
|
|
@ -504,11 +506,8 @@ if #[cfg(not(target_vendor = "uwp"))] {
|
|||
#[cfg(target_arch = "arm")]
|
||||
pub enum CONTEXT {}
|
||||
}}
|
||||
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32;
|
||||
}
|
||||
// WSAStartup is only redefined here so that we can override WSADATA for Arm32
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32);
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[repr(C)]
|
||||
pub struct WSADATA {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
--out windows_sys.rs
|
||||
--config flatten std
|
||||
--config flatten sys
|
||||
--filter
|
||||
!Windows.Win32.Foundation.INVALID_HANDLE_VALUE
|
||||
Windows.Wdk.Storage.FileSystem.FILE_COMPLETE_IF_OPLOCKED
|
||||
|
|
|
|||
|
|
@ -1,843 +1,136 @@
|
|||
// Bindings generated by `windows-bindgen` 0.57.0
|
||||
// Bindings generated by `windows-bindgen` 0.58.0
|
||||
|
||||
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
pub fn OpenProcessToken(
|
||||
processhandle: HANDLE,
|
||||
desiredaccess: TOKEN_ACCESS_MASK,
|
||||
tokenhandle: *mut HANDLE,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
#[link_name = "SystemFunction036"]
|
||||
pub fn RtlGenRandom(randombuffer: *mut core::ffi::c_void, randombufferlength: u32) -> BOOLEAN;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn AcquireSRWLockShared(srwlock: *mut SRWLOCK);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CancelIo(hfile: HANDLE) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CloseHandle(hobject: HANDLE) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CompareStringOrdinal(
|
||||
lpstring1: PCWSTR,
|
||||
cchcount1: i32,
|
||||
lpstring2: PCWSTR,
|
||||
cchcount2: i32,
|
||||
bignorecase: BOOL,
|
||||
) -> COMPARESTRING_RESULT;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CopyFileExW(
|
||||
lpexistingfilename: PCWSTR,
|
||||
lpnewfilename: PCWSTR,
|
||||
lpprogressroutine: LPPROGRESS_ROUTINE,
|
||||
lpdata: *const core::ffi::c_void,
|
||||
pbcancel: *mut BOOL,
|
||||
dwcopyflags: u32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateDirectoryW(
|
||||
lppathname: PCWSTR,
|
||||
lpsecurityattributes: *const SECURITY_ATTRIBUTES,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateEventW(
|
||||
lpeventattributes: *const SECURITY_ATTRIBUTES,
|
||||
bmanualreset: BOOL,
|
||||
binitialstate: BOOL,
|
||||
lpname: PCWSTR,
|
||||
) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateFileW(
|
||||
lpfilename: PCWSTR,
|
||||
dwdesiredaccess: u32,
|
||||
dwsharemode: FILE_SHARE_MODE,
|
||||
lpsecurityattributes: *const SECURITY_ATTRIBUTES,
|
||||
dwcreationdisposition: FILE_CREATION_DISPOSITION,
|
||||
dwflagsandattributes: FILE_FLAGS_AND_ATTRIBUTES,
|
||||
htemplatefile: HANDLE,
|
||||
) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateHardLinkW(
|
||||
lpfilename: PCWSTR,
|
||||
lpexistingfilename: PCWSTR,
|
||||
lpsecurityattributes: *const SECURITY_ATTRIBUTES,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateNamedPipeW(
|
||||
lpname: PCWSTR,
|
||||
dwopenmode: FILE_FLAGS_AND_ATTRIBUTES,
|
||||
dwpipemode: NAMED_PIPE_MODE,
|
||||
nmaxinstances: u32,
|
||||
noutbuffersize: u32,
|
||||
ninbuffersize: u32,
|
||||
ndefaulttimeout: u32,
|
||||
lpsecurityattributes: *const SECURITY_ATTRIBUTES,
|
||||
) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateProcessW(
|
||||
lpapplicationname: PCWSTR,
|
||||
lpcommandline: PWSTR,
|
||||
lpprocessattributes: *const SECURITY_ATTRIBUTES,
|
||||
lpthreadattributes: *const SECURITY_ATTRIBUTES,
|
||||
binherithandles: BOOL,
|
||||
dwcreationflags: PROCESS_CREATION_FLAGS,
|
||||
lpenvironment: *const core::ffi::c_void,
|
||||
lpcurrentdirectory: PCWSTR,
|
||||
lpstartupinfo: *const STARTUPINFOW,
|
||||
lpprocessinformation: *mut PROCESS_INFORMATION,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateSymbolicLinkW(
|
||||
lpsymlinkfilename: PCWSTR,
|
||||
lptargetfilename: PCWSTR,
|
||||
dwflags: SYMBOLIC_LINK_FLAGS,
|
||||
) -> BOOLEAN;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateThread(
|
||||
lpthreadattributes: *const SECURITY_ATTRIBUTES,
|
||||
dwstacksize: usize,
|
||||
lpstartaddress: LPTHREAD_START_ROUTINE,
|
||||
lpparameter: *const core::ffi::c_void,
|
||||
dwcreationflags: THREAD_CREATION_FLAGS,
|
||||
lpthreadid: *mut u32,
|
||||
) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn CreateWaitableTimerExW(
|
||||
lptimerattributes: *const SECURITY_ATTRIBUTES,
|
||||
lptimername: PCWSTR,
|
||||
dwflags: u32,
|
||||
dwdesiredaccess: u32,
|
||||
) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn DeviceIoControl(
|
||||
hdevice: HANDLE,
|
||||
dwiocontrolcode: u32,
|
||||
lpinbuffer: *const core::ffi::c_void,
|
||||
ninbuffersize: u32,
|
||||
lpoutbuffer: *mut core::ffi::c_void,
|
||||
noutbuffersize: u32,
|
||||
lpbytesreturned: *mut u32,
|
||||
lpoverlapped: *mut OVERLAPPED,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn DuplicateHandle(
|
||||
hsourceprocesshandle: HANDLE,
|
||||
hsourcehandle: HANDLE,
|
||||
htargetprocesshandle: HANDLE,
|
||||
lptargethandle: *mut HANDLE,
|
||||
dwdesiredaccess: u32,
|
||||
binherithandle: BOOL,
|
||||
dwoptions: DUPLICATE_HANDLE_OPTIONS,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn ExitProcess(uexitcode: u32) -> !;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn FindClose(hfindfile: HANDLE) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn FindFirstFileW(lpfilename: PCWSTR, lpfindfiledata: *mut WIN32_FIND_DATAW) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn FindNextFileW(hfindfile: HANDLE, lpfindfiledata: *mut WIN32_FIND_DATAW) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn FlushFileBuffers(hfile: HANDLE) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn FormatMessageW(
|
||||
dwflags: FORMAT_MESSAGE_OPTIONS,
|
||||
lpsource: *const core::ffi::c_void,
|
||||
dwmessageid: u32,
|
||||
dwlanguageid: u32,
|
||||
lpbuffer: PWSTR,
|
||||
nsize: u32,
|
||||
arguments: *const *const i8,
|
||||
) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn FreeEnvironmentStringsW(penv: PCWSTR) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetActiveProcessorCount(groupnumber: u16) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetCommandLineW() -> PCWSTR;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetConsoleMode(hconsolehandle: HANDLE, lpmode: *mut CONSOLE_MODE) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetCurrentDirectoryW(nbufferlength: u32, lpbuffer: PWSTR) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetCurrentProcess() -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetCurrentProcessId() -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetCurrentThread() -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetEnvironmentStringsW() -> PWSTR;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetEnvironmentVariableW(lpname: PCWSTR, lpbuffer: PWSTR, nsize: u32) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetExitCodeProcess(hprocess: HANDLE, lpexitcode: *mut u32) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetFileAttributesW(lpfilename: PCWSTR) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetFileInformationByHandle(
|
||||
hfile: HANDLE,
|
||||
lpfileinformation: *mut BY_HANDLE_FILE_INFORMATION,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetFileInformationByHandleEx(
|
||||
hfile: HANDLE,
|
||||
fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
|
||||
lpfileinformation: *mut core::ffi::c_void,
|
||||
dwbuffersize: u32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetFileType(hfile: HANDLE) -> FILE_TYPE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetFinalPathNameByHandleW(
|
||||
hfile: HANDLE,
|
||||
lpszfilepath: PWSTR,
|
||||
cchfilepath: u32,
|
||||
dwflags: GETFINALPATHNAMEBYHANDLE_FLAGS,
|
||||
) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetFullPathNameW(
|
||||
lpfilename: PCWSTR,
|
||||
nbufferlength: u32,
|
||||
lpbuffer: PWSTR,
|
||||
lpfilepart: *mut PWSTR,
|
||||
) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetLastError() -> WIN32_ERROR;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetModuleFileNameW(hmodule: HMODULE, lpfilename: PWSTR, nsize: u32) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetModuleHandleA(lpmodulename: PCSTR) -> HMODULE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetModuleHandleW(lpmodulename: PCWSTR) -> HMODULE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetOverlappedResult(
|
||||
hfile: HANDLE,
|
||||
lpoverlapped: *const OVERLAPPED,
|
||||
lpnumberofbytestransferred: *mut u32,
|
||||
bwait: BOOL,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetProcessId(process: HANDLE) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetStdHandle(nstdhandle: STD_HANDLE) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetSystemDirectoryW(lpbuffer: PWSTR, usize: u32) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetSystemInfo(lpsysteminfo: *mut SYSTEM_INFO);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime: *mut FILETIME);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetTempPathW(nbufferlength: u32, lpbuffer: PWSTR) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetWindowsDirectoryW(lpbuffer: PWSTR, usize: u32) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn InitOnceBeginInitialize(
|
||||
lpinitonce: *mut INIT_ONCE,
|
||||
dwflags: u32,
|
||||
fpending: *mut BOOL,
|
||||
lpcontext: *mut *mut core::ffi::c_void,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn InitOnceComplete(
|
||||
lpinitonce: *mut INIT_ONCE,
|
||||
dwflags: u32,
|
||||
lpcontext: *const core::ffi::c_void,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn InitializeProcThreadAttributeList(
|
||||
lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
|
||||
dwattributecount: u32,
|
||||
dwflags: u32,
|
||||
lpsize: *mut usize,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn LocalFree(hmem: HLOCAL) -> HLOCAL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn MoveFileExW(
|
||||
lpexistingfilename: PCWSTR,
|
||||
lpnewfilename: PCWSTR,
|
||||
dwflags: MOVE_FILE_FLAGS,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn MultiByteToWideChar(
|
||||
codepage: u32,
|
||||
dwflags: MULTI_BYTE_TO_WIDE_CHAR_FLAGS,
|
||||
lpmultibytestr: PCSTR,
|
||||
cbmultibyte: i32,
|
||||
lpwidecharstr: PWSTR,
|
||||
cchwidechar: i32,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn QueryPerformanceCounter(lpperformancecount: *mut i64) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn QueryPerformanceFrequency(lpfrequency: *mut i64) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn ReadConsoleW(
|
||||
hconsoleinput: HANDLE,
|
||||
lpbuffer: *mut core::ffi::c_void,
|
||||
nnumberofcharstoread: u32,
|
||||
lpnumberofcharsread: *mut u32,
|
||||
pinputcontrol: *const CONSOLE_READCONSOLE_CONTROL,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn ReadFile(
|
||||
hfile: HANDLE,
|
||||
lpbuffer: *mut u8,
|
||||
nnumberofbytestoread: u32,
|
||||
lpnumberofbytesread: *mut u32,
|
||||
lpoverlapped: *mut OVERLAPPED,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn ReadFileEx(
|
||||
hfile: HANDLE,
|
||||
lpbuffer: *mut u8,
|
||||
nnumberofbytestoread: u32,
|
||||
lpoverlapped: *mut OVERLAPPED,
|
||||
lpcompletionroutine: LPOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn ReleaseSRWLockShared(srwlock: *mut SRWLOCK);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn RemoveDirectoryW(lppathname: PCWSTR) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetCurrentDirectoryW(lppathname: PCWSTR) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetEnvironmentVariableW(lpname: PCWSTR, lpvalue: PCWSTR) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetFileAttributesW(
|
||||
lpfilename: PCWSTR,
|
||||
dwfileattributes: FILE_FLAGS_AND_ATTRIBUTES,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetFileInformationByHandle(
|
||||
hfile: HANDLE,
|
||||
fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
|
||||
lpfileinformation: *const core::ffi::c_void,
|
||||
dwbuffersize: u32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetFilePointerEx(
|
||||
hfile: HANDLE,
|
||||
lidistancetomove: i64,
|
||||
lpnewfilepointer: *mut i64,
|
||||
dwmovemethod: SET_FILE_POINTER_MOVE_METHOD,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetFileTime(
|
||||
hfile: HANDLE,
|
||||
lpcreationtime: *const FILETIME,
|
||||
lplastaccesstime: *const FILETIME,
|
||||
lplastwritetime: *const FILETIME,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetHandleInformation(hobject: HANDLE, dwmask: u32, dwflags: HANDLE_FLAGS) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetLastError(dwerrcode: WIN32_ERROR);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SetWaitableTimer(
|
||||
htimer: HANDLE,
|
||||
lpduetime: *const i64,
|
||||
lperiod: i32,
|
||||
pfncompletionroutine: PTIMERAPCROUTINE,
|
||||
lpargtocompletionroutine: *const core::ffi::c_void,
|
||||
fresume: BOOL,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn Sleep(dwmilliseconds: u32);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SleepConditionVariableSRW(
|
||||
conditionvariable: *mut CONDITION_VARIABLE,
|
||||
srwlock: *mut SRWLOCK,
|
||||
dwmilliseconds: u32,
|
||||
flags: u32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SleepEx(dwmilliseconds: u32, balertable: BOOL) -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn SwitchToThread() -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn TerminateProcess(hprocess: HANDLE, uexitcode: u32) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn TlsAlloc() -> u32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn TlsFree(dwtlsindex: u32) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn TlsGetValue(dwtlsindex: u32) -> *mut core::ffi::c_void;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn TlsSetValue(dwtlsindex: u32, lptlsvalue: *const core::ffi::c_void) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn TryAcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> BOOLEAN;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn TryAcquireSRWLockShared(srwlock: *mut SRWLOCK) -> BOOLEAN;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn UpdateProcThreadAttribute(
|
||||
lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
|
||||
dwflags: u32,
|
||||
attribute: usize,
|
||||
lpvalue: *const core::ffi::c_void,
|
||||
cbsize: usize,
|
||||
lppreviousvalue: *mut core::ffi::c_void,
|
||||
lpreturnsize: *const usize,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WaitForMultipleObjects(
|
||||
ncount: u32,
|
||||
lphandles: *const HANDLE,
|
||||
bwaitall: BOOL,
|
||||
dwmilliseconds: u32,
|
||||
) -> WAIT_EVENT;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WAIT_EVENT;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WakeAllConditionVariable(conditionvariable: *mut CONDITION_VARIABLE);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WakeConditionVariable(conditionvariable: *mut CONDITION_VARIABLE);
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WideCharToMultiByte(
|
||||
codepage: u32,
|
||||
dwflags: u32,
|
||||
lpwidecharstr: PCWSTR,
|
||||
cchwidechar: i32,
|
||||
lpmultibytestr: PSTR,
|
||||
cbmultibyte: i32,
|
||||
lpdefaultchar: PCSTR,
|
||||
lpuseddefaultchar: *mut BOOL,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WriteConsoleW(
|
||||
hconsoleoutput: HANDLE,
|
||||
lpbuffer: *const core::ffi::c_void,
|
||||
nnumberofcharstowrite: u32,
|
||||
lpnumberofcharswritten: *mut u32,
|
||||
lpreserved: *const core::ffi::c_void,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WriteFileEx(
|
||||
hfile: HANDLE,
|
||||
lpbuffer: *const u8,
|
||||
nnumberofbytestowrite: u32,
|
||||
lpoverlapped: *mut OVERLAPPED,
|
||||
lpcompletionroutine: LPOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "ntdll")]
|
||||
extern "system" {
|
||||
pub fn NtCreateFile(
|
||||
filehandle: *mut HANDLE,
|
||||
desiredaccess: FILE_ACCESS_RIGHTS,
|
||||
objectattributes: *const OBJECT_ATTRIBUTES,
|
||||
iostatusblock: *mut IO_STATUS_BLOCK,
|
||||
allocationsize: *const i64,
|
||||
fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
|
||||
shareaccess: FILE_SHARE_MODE,
|
||||
createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
|
||||
createoptions: NTCREATEFILE_CREATE_OPTIONS,
|
||||
eabuffer: *const core::ffi::c_void,
|
||||
ealength: u32,
|
||||
) -> NTSTATUS;
|
||||
}
|
||||
#[link(name = "ntdll")]
|
||||
extern "system" {
|
||||
pub fn NtReadFile(
|
||||
filehandle: HANDLE,
|
||||
event: HANDLE,
|
||||
apcroutine: PIO_APC_ROUTINE,
|
||||
apccontext: *const core::ffi::c_void,
|
||||
iostatusblock: *mut IO_STATUS_BLOCK,
|
||||
buffer: *mut core::ffi::c_void,
|
||||
length: u32,
|
||||
byteoffset: *const i64,
|
||||
key: *const u32,
|
||||
) -> NTSTATUS;
|
||||
}
|
||||
#[link(name = "ntdll")]
|
||||
extern "system" {
|
||||
pub fn NtWriteFile(
|
||||
filehandle: HANDLE,
|
||||
event: HANDLE,
|
||||
apcroutine: PIO_APC_ROUTINE,
|
||||
apccontext: *const core::ffi::c_void,
|
||||
iostatusblock: *mut IO_STATUS_BLOCK,
|
||||
buffer: *const core::ffi::c_void,
|
||||
length: u32,
|
||||
byteoffset: *const i64,
|
||||
key: *const u32,
|
||||
) -> NTSTATUS;
|
||||
}
|
||||
#[link(name = "ntdll")]
|
||||
extern "system" {
|
||||
pub fn RtlNtStatusToDosError(status: NTSTATUS) -> u32;
|
||||
}
|
||||
#[link(name = "userenv")]
|
||||
extern "system" {
|
||||
pub fn GetUserProfileDirectoryW(
|
||||
htoken: HANDLE,
|
||||
lpprofiledir: PWSTR,
|
||||
lpcchsize: *mut u32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn WSACleanup() -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn WSADuplicateSocketW(
|
||||
s: SOCKET,
|
||||
dwprocessid: u32,
|
||||
lpprotocolinfo: *mut WSAPROTOCOL_INFOW,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn WSAGetLastError() -> WSA_ERROR;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn WSARecv(
|
||||
s: SOCKET,
|
||||
lpbuffers: *const WSABUF,
|
||||
dwbuffercount: u32,
|
||||
lpnumberofbytesrecvd: *mut u32,
|
||||
lpflags: *mut u32,
|
||||
lpoverlapped: *mut OVERLAPPED,
|
||||
lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn WSASend(
|
||||
s: SOCKET,
|
||||
lpbuffers: *const WSABUF,
|
||||
dwbuffercount: u32,
|
||||
lpnumberofbytessent: *mut u32,
|
||||
dwflags: u32,
|
||||
lpoverlapped: *mut OVERLAPPED,
|
||||
lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn WSASocketW(
|
||||
af: i32,
|
||||
r#type: i32,
|
||||
protocol: i32,
|
||||
lpprotocolinfo: *const WSAPROTOCOL_INFOW,
|
||||
g: u32,
|
||||
dwflags: u32,
|
||||
) -> SOCKET;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn accept(s: SOCKET, addr: *mut SOCKADDR, addrlen: *mut i32) -> SOCKET;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn bind(s: SOCKET, name: *const SOCKADDR, namelen: i32) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn closesocket(s: SOCKET) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn connect(s: SOCKET, name: *const SOCKADDR, namelen: i32) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn freeaddrinfo(paddrinfo: *const ADDRINFOA);
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn getaddrinfo(
|
||||
pnodename: PCSTR,
|
||||
pservicename: PCSTR,
|
||||
phints: *const ADDRINFOA,
|
||||
ppresult: *mut *mut ADDRINFOA,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn getpeername(s: SOCKET, name: *mut SOCKADDR, namelen: *mut i32) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn getsockname(s: SOCKET, name: *mut SOCKADDR, namelen: *mut i32) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn getsockopt(s: SOCKET, level: i32, optname: i32, optval: PSTR, optlen: *mut i32) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn ioctlsocket(s: SOCKET, cmd: i32, argp: *mut u32) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn listen(s: SOCKET, backlog: i32) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn recv(s: SOCKET, buf: PSTR, len: i32, flags: SEND_RECV_FLAGS) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn recvfrom(
|
||||
s: SOCKET,
|
||||
buf: PSTR,
|
||||
len: i32,
|
||||
flags: i32,
|
||||
from: *mut SOCKADDR,
|
||||
fromlen: *mut i32,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn select(
|
||||
nfds: i32,
|
||||
readfds: *mut FD_SET,
|
||||
writefds: *mut FD_SET,
|
||||
exceptfds: *mut FD_SET,
|
||||
timeout: *const TIMEVAL,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn send(s: SOCKET, buf: PCSTR, len: i32, flags: SEND_RECV_FLAGS) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn sendto(
|
||||
s: SOCKET,
|
||||
buf: PCSTR,
|
||||
len: i32,
|
||||
flags: i32,
|
||||
to: *const SOCKADDR,
|
||||
tolen: i32,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn setsockopt(s: SOCKET, level: i32, optname: i32, optval: PCSTR, optlen: i32) -> i32;
|
||||
}
|
||||
#[link(name = "ws2_32")]
|
||||
extern "system" {
|
||||
pub fn shutdown(s: SOCKET, how: WINSOCK_SHUTDOWN_HOW) -> i32;
|
||||
}
|
||||
windows_targets::link!("advapi32.dll" "system" fn OpenProcessToken(processhandle : HANDLE, desiredaccess : TOKEN_ACCESS_MASK, tokenhandle : *mut HANDLE) -> BOOL);
|
||||
windows_targets::link!("advapi32.dll" "system" "SystemFunction036" fn RtlGenRandom(randombuffer : *mut core::ffi::c_void, randombufferlength : u32) -> BOOLEAN);
|
||||
windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockExclusive(srwlock : *mut SRWLOCK));
|
||||
windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockShared(srwlock : *mut SRWLOCK));
|
||||
windows_targets::link!("kernel32.dll" "system" fn CancelIo(hfile : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CompareStringOrdinal(lpstring1 : PCWSTR, cchcount1 : i32, lpstring2 : PCWSTR, cchcount2 : i32, bignorecase : BOOL) -> COMPARESTRING_RESULT);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CopyFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, lpprogressroutine : LPPROGRESS_ROUTINE, lpdata : *const core::ffi::c_void, pbcancel : *mut BOOL, dwcopyflags : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateDirectoryW(lppathname : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateFileW(lpfilename : PCWSTR, dwdesiredaccess : u32, dwsharemode : FILE_SHARE_MODE, lpsecurityattributes : *const SECURITY_ATTRIBUTES, dwcreationdisposition : FILE_CREATION_DISPOSITION, dwflagsandattributes : FILE_FLAGS_AND_ATTRIBUTES, htemplatefile : HANDLE) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateHardLinkW(lpfilename : PCWSTR, lpexistingfilename : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateNamedPipeW(lpname : PCWSTR, dwopenmode : FILE_FLAGS_AND_ATTRIBUTES, dwpipemode : NAMED_PIPE_MODE, nmaxinstances : u32, noutbuffersize : u32, ninbuffersize : u32, ndefaulttimeout : u32, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateProcessW(lpapplicationname : PCWSTR, lpcommandline : PWSTR, lpprocessattributes : *const SECURITY_ATTRIBUTES, lpthreadattributes : *const SECURITY_ATTRIBUTES, binherithandles : BOOL, dwcreationflags : PROCESS_CREATION_FLAGS, lpenvironment : *const core::ffi::c_void, lpcurrentdirectory : PCWSTR, lpstartupinfo : *const STARTUPINFOW, lpprocessinformation : *mut PROCESS_INFORMATION) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateSymbolicLinkW(lpsymlinkfilename : PCWSTR, lptargetfilename : PCWSTR, dwflags : SYMBOLIC_LINK_FLAGS) -> BOOLEAN);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateThread(lpthreadattributes : *const SECURITY_ATTRIBUTES, dwstacksize : usize, lpstartaddress : LPTHREAD_START_ROUTINE, lpparameter : *const core::ffi::c_void, dwcreationflags : THREAD_CREATION_FLAGS, lpthreadid : *mut u32) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateWaitableTimerExW(lptimerattributes : *const SECURITY_ATTRIBUTES, lptimername : PCWSTR, dwflags : u32, dwdesiredaccess : u32) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn DeleteFileW(lpfilename : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn DeleteProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST));
|
||||
windows_targets::link!("kernel32.dll" "system" fn DeviceIoControl(hdevice : HANDLE, dwiocontrolcode : u32, lpinbuffer : *const core::ffi::c_void, ninbuffersize : u32, lpoutbuffer : *mut core::ffi::c_void, noutbuffersize : u32, lpbytesreturned : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn DuplicateHandle(hsourceprocesshandle : HANDLE, hsourcehandle : HANDLE, htargetprocesshandle : HANDLE, lptargethandle : *mut HANDLE, dwdesiredaccess : u32, binherithandle : BOOL, dwoptions : DUPLICATE_HANDLE_OPTIONS) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ExitProcess(uexitcode : u32) -> !);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FindClose(hfindfile : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FindFirstFileW(lpfilename : PCWSTR, lpfindfiledata : *mut WIN32_FIND_DATAW) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FindNextFileW(hfindfile : HANDLE, lpfindfiledata : *mut WIN32_FIND_DATAW) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FlushFileBuffers(hfile : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FreeEnvironmentStringsW(penv : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetActiveProcessorCount(groupnumber : u16) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCommandLineW() -> PCWSTR);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetConsoleMode(hconsolehandle : HANDLE, lpmode : *mut CONSOLE_MODE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentThread() -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentStringsW() -> PWSTR);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentVariableW(lpname : PCWSTR, lpbuffer : PWSTR, nsize : u32) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : HANDLE, lpexitcode : *mut u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleW(lpmodulename : PCWSTR) -> HMODULE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetOverlappedResult(hfile : HANDLE, lpoverlapped : *const OVERLAPPED, lpnumberofbytestransferred : *mut u32, bwait : BOOL) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcessId(process : HANDLE) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetStdHandle(nstdhandle : STD_HANDLE) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetSystemDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *mut SYSTEM_INFO));
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceFrequency(lpfrequency : *mut i64) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReadConsoleW(hconsoleinput : HANDLE, lpbuffer : *mut core::ffi::c_void, nnumberofcharstoread : u32, lpnumberofcharsread : *mut u32, pinputcontrol : *const CONSOLE_READCONSOLE_CONTROL) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReadFile(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpnumberofbytesread : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReadFileEx(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockExclusive(srwlock : *mut SRWLOCK));
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockShared(srwlock : *mut SRWLOCK));
|
||||
windows_targets::link!("kernel32.dll" "system" fn RemoveDirectoryW(lppathname : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetFileInformationByHandle(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *const core::ffi::c_void, dwbuffersize : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetLastError(dwerrcode : WIN32_ERROR));
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetWaitableTimer(htimer : HANDLE, lpduetime : *const i64, lperiod : i32, pfncompletionroutine : PTIMERAPCROUTINE, lpargtocompletionroutine : *const core::ffi::c_void, fresume : BOOL) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32));
|
||||
windows_targets::link!("kernel32.dll" "system" fn SleepConditionVariableSRW(conditionvariable : *mut CONDITION_VARIABLE, srwlock : *mut SRWLOCK, dwmilliseconds : u32, flags : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SleepEx(dwmilliseconds : u32, balertable : BOOL) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SwitchToThread() -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TerminateProcess(hprocess : HANDLE, uexitcode : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TlsAlloc() -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TlsFree(dwtlsindex : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32) -> *mut core::ffi::c_void);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> BOOLEAN);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> BOOLEAN);
|
||||
windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WakeAllConditionVariable(conditionvariable : *mut CONDITION_VARIABLE));
|
||||
windows_targets::link!("kernel32.dll" "system" fn WakeConditionVariable(conditionvariable : *mut CONDITION_VARIABLE));
|
||||
windows_targets::link!("kernel32.dll" "system" fn WideCharToMultiByte(codepage : u32, dwflags : u32, lpwidecharstr : PCWSTR, cchwidechar : i32, lpmultibytestr : PSTR, cbmultibyte : i32, lpdefaultchar : PCSTR, lpuseddefaultchar : *mut BOOL) -> i32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WriteConsoleW(hconsoleoutput : HANDLE, lpbuffer : PCWSTR, nnumberofcharstowrite : u32, lpnumberofcharswritten : *mut u32, lpreserved : *const core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WriteFileEx(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL);
|
||||
windows_targets::link!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
|
||||
windows_targets::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_targets::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
|
||||
windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSACleanup() -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSADuplicateSocketW(s : SOCKET, dwprocessid : u32, lpprotocolinfo : *mut WSAPROTOCOL_INFOW) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSARecv(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytesrecvd : *mut u32, lpflags : *mut u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSASend(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytessent : *mut u32, dwflags : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSASocketW(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOW, g : u32, dwflags : u32) -> SOCKET);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn accept(s : SOCKET, addr : *mut SOCKADDR, addrlen : *mut i32) -> SOCKET);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn bind(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn closesocket(s : SOCKET) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn connect(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn freeaddrinfo(paddrinfo : *const ADDRINFOA));
|
||||
windows_targets::link!("ws2_32.dll" "system" fn getaddrinfo(pnodename : PCSTR, pservicename : PCSTR, phints : *const ADDRINFOA, ppresult : *mut *mut ADDRINFOA) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn getpeername(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn getsockname(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn getsockopt(s : SOCKET, level : i32, optname : i32, optval : PSTR, optlen : *mut i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn ioctlsocket(s : SOCKET, cmd : i32, argp : *mut u32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn listen(s : SOCKET, backlog : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn recv(s : SOCKET, buf : PSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn recvfrom(s : SOCKET, buf : PSTR, len : i32, flags : i32, from : *mut SOCKADDR, fromlen : *mut i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn select(nfds : i32, readfds : *mut FD_SET, writefds : *mut FD_SET, exceptfds : *mut FD_SET, timeout : *const TIMEVAL) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn send(s : SOCKET, buf : PCSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn sendto(s : SOCKET, buf : PCSTR, len : i32, flags : i32, to : *const SOCKADDR, tolen : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn setsockopt(s : SOCKET, level : i32, optname : i32, optval : PCSTR, optlen : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32);
|
||||
pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32;
|
||||
pub type ADDRESS_FAMILY = u16;
|
||||
#[repr(C)]
|
||||
|
|
@ -3991,3 +3284,4 @@ pub struct XSAVE_FORMAT {
|
|||
pub Reserved4: [u8; 224],
|
||||
}
|
||||
// ignore-tidy-filelength
|
||||
use super::windows_targets;
|
||||
|
|
|
|||
24
library/std/src/sys/pal/windows/c/windows_targets.rs
Normal file
24
library/std/src/sys/pal/windows/c/windows_targets.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//! Provides the `link!` macro used by the generated windows bindings.
|
||||
//!
|
||||
//! This is a simple wrapper around an `extern` block with a `#[link]` attribute.
|
||||
//! It's very roughly equivalent to the windows-targets crate.
|
||||
|
||||
pub macro link {
|
||||
($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
|
||||
// Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't
|
||||
// have in this repo. So instead we always link kernel32.lib and add the rest of the import
|
||||
// libraries below by using an empty extern block. This works because extern blocks are not
|
||||
// connected to the library given in the #[link] attribute.
|
||||
#[link(name = "kernel32")]
|
||||
extern $abi {
|
||||
$(#[link_name=$link_name])?
|
||||
pub fn $($function)*;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[link(name = "advapi32")]
|
||||
#[link(name = "ntdll")]
|
||||
#[link(name = "userenv")]
|
||||
#[link(name = "ws2_32")]
|
||||
extern "C" {}
|
||||
|
|
@ -232,13 +232,7 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
|
|||
debug_assert!(data.len() < u32::MAX as usize);
|
||||
let mut written = 0;
|
||||
cvt(unsafe {
|
||||
c::WriteConsoleW(
|
||||
handle,
|
||||
data.as_ptr() as c::LPCVOID,
|
||||
data.len() as u32,
|
||||
&mut written,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
c::WriteConsoleW(handle, data.as_ptr(), data.len() as u32, &mut written, ptr::null_mut())
|
||||
})?;
|
||||
Ok(written as usize)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,8 +93,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
|
|||
docker --version
|
||||
|
||||
REGISTRY=ghcr.io
|
||||
# PR CI runs on rust-lang, but we want to use the cache from rust-lang-ci
|
||||
REGISTRY_USERNAME=rust-lang-ci
|
||||
REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER}
|
||||
# Tag used to push the final Docker image, so that it can be pulled by e.g. rustup
|
||||
IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum}
|
||||
# Tag used to cache the Docker build
|
||||
|
|
|
|||
|
|
@ -91,21 +91,17 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]:
|
|||
if ctx.event_name == "pull_request":
|
||||
return PRRunType()
|
||||
elif ctx.event_name == "push":
|
||||
old_bors_try_build = (
|
||||
ctx.ref in ("refs/heads/try", "refs/heads/try-perf") and
|
||||
ctx.repository == "rust-lang-ci/rust"
|
||||
try_build = ctx.ref in (
|
||||
"refs/heads/try",
|
||||
"refs/heads/try-perf",
|
||||
"refs/heads/automation/bors/try"
|
||||
)
|
||||
new_bors_try_build = (
|
||||
ctx.ref == "refs/heads/automation/bors/try" and
|
||||
ctx.repository == "rust-lang/rust"
|
||||
)
|
||||
try_build = old_bors_try_build or new_bors_try_build
|
||||
|
||||
if try_build:
|
||||
jobs = get_custom_jobs(ctx)
|
||||
return TryRunType(custom_jobs=jobs)
|
||||
|
||||
if ctx.ref == "refs/heads/auto" and ctx.repository == "rust-lang-ci/rust":
|
||||
if ctx.ref == "refs/heads/auto":
|
||||
return AutoRunType()
|
||||
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -3293,10 +3293,9 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
|||
}
|
||||
// call after consuming `{`
|
||||
decodeList() {
|
||||
const cb = "}".charCodeAt(0);
|
||||
let c = this.string.charCodeAt(this.offset);
|
||||
const ret = [];
|
||||
while (c !== cb) {
|
||||
while (c !== 125) { // 125 = "}"
|
||||
ret.push(this.decode());
|
||||
c = this.string.charCodeAt(this.offset);
|
||||
}
|
||||
|
|
@ -3305,14 +3304,13 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
|||
}
|
||||
// consumes and returns a list or integer
|
||||
decode() {
|
||||
const [ob, la] = ["{", "`"].map(c => c.charCodeAt(0));
|
||||
let n = 0;
|
||||
let c = this.string.charCodeAt(this.offset);
|
||||
if (c === ob) {
|
||||
if (c === 123) { // 123 = "{"
|
||||
this.offset += 1;
|
||||
return this.decodeList();
|
||||
}
|
||||
while (c < la) {
|
||||
while (c < 96) { // 96 = "`"
|
||||
n = (n << 4) | (c & 0xF);
|
||||
this.offset += 1;
|
||||
c = this.string.charCodeAt(this.offset);
|
||||
|
|
@ -3325,15 +3323,14 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
|||
}
|
||||
next() {
|
||||
const c = this.string.charCodeAt(this.offset);
|
||||
const [zero, ua, la] = ["0", "@", "`"].map(c => c.charCodeAt(0));
|
||||
// sixteen characters after "0" are backref
|
||||
if (c >= zero && c < ua) {
|
||||
if (c >= 48 && c < 64) { // 48 = "0", 64 = "@"
|
||||
this.offset += 1;
|
||||
return this.backrefQueue[c - zero];
|
||||
return this.backrefQueue[c - 48];
|
||||
}
|
||||
// special exception: 0 doesn't use backref encoding
|
||||
// it's already one character, and it's always nullish
|
||||
if (c === la) {
|
||||
if (c === 96) { // 96 = "`"
|
||||
this.offset += 1;
|
||||
return this.cons(0);
|
||||
}
|
||||
|
|
@ -3472,7 +3469,6 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
|||
searchIndex = [];
|
||||
searchIndexDeprecated = new Map();
|
||||
searchIndexEmptyDesc = new Map();
|
||||
const charA = "A".charCodeAt(0);
|
||||
let currentIndex = 0;
|
||||
let id = 0;
|
||||
|
||||
|
|
@ -3639,7 +3635,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
|||
// object defined above.
|
||||
const row = {
|
||||
crate,
|
||||
ty: itemTypes.charCodeAt(i) - charA,
|
||||
ty: itemTypes.charCodeAt(i) - 65, // 65 = "A"
|
||||
name: itemNames[i],
|
||||
path,
|
||||
descShard,
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit e6a6470d1eb4c88fee4b1ea98cd8e0ac4a181c16
|
||||
Subproject commit c54cff0e6e4d1a0d0a2df7c1ce3d96cdd554763e
|
||||
|
|
@ -4,4 +4,4 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies.windows-bindgen]
|
||||
version = "0.57.0"
|
||||
version = "0.58.0"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
let mut f = std::fs::File::options().append(true).open("windows_sys.rs")?;
|
||||
writeln!(&mut f, "// ignore-tidy-filelength")?;
|
||||
writeln!(&mut f, "use super::windows_targets;")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[
|
|||
// This is being used in the sense of 'inclusive range', not a markdown link
|
||||
("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
|
||||
("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
|
||||
("core/range/legacy/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
|
||||
("std/range/legacy/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
|
||||
("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
|
||||
("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
|
||||
("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
51917ba8f215f76e9d3fa8e77cd0a781bb28dab7
|
||||
51917e2e69702e5752bce6a4f3bfd285d0f4ae39
|
||||
|
|
|
|||
|
|
@ -758,6 +758,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_null(dest)?;
|
||||
}
|
||||
|
||||
"_Unwind_RaiseException" => {
|
||||
// This is not formally part of POSIX, but it is very wide-spread on POSIX systems.
|
||||
// It was originally specified as part of the Itanium C++ ABI:
|
||||
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw.
|
||||
// MinGW implements _Unwind_RaiseException on top of SEH exceptions.
|
||||
if this.tcx.sess.target.env != "gnu" {
|
||||
throw_unsup_format!(
|
||||
"`_Unwind_RaiseException` is not supported on non-MinGW Windows",
|
||||
);
|
||||
}
|
||||
// This function looks and behaves excatly like miri_start_unwind.
|
||||
let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?;
|
||||
this.handle_miri_start_unwind(payload)?;
|
||||
return Ok(EmulateItemResult::NeedsUnwind);
|
||||
}
|
||||
|
||||
_ => return Ok(EmulateItemResult::NotSupported),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,11 +75,12 @@ impl Command {
|
|||
/// Generic command arguments provider. Prefer specific helper methods if possible.
|
||||
/// Note that for some executables, arguments might be platform specific. For C/C++
|
||||
/// compilers, arguments might be platform *and* compiler specific.
|
||||
pub fn args<S>(&mut self, args: &[S]) -> &mut Self
|
||||
pub fn args<S, V>(&mut self, args: V) -> &mut Self
|
||||
where
|
||||
S: AsRef<ffi::OsStr>,
|
||||
V: AsRef<[S]>,
|
||||
{
|
||||
self.cmd.args(args);
|
||||
self.cmd.args(args.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -261,6 +261,47 @@ pub fn test_while_readonly<P: AsRef<Path>, F: FnOnce() + std::panic::UnwindSafe>
|
|||
success.unwrap();
|
||||
}
|
||||
|
||||
/// Browse the directory `path` non-recursively and return all files which respect the parameters
|
||||
/// outlined by `closure`.
|
||||
#[track_caller]
|
||||
pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
|
||||
path: P,
|
||||
filter: F,
|
||||
) -> Vec<PathBuf> {
|
||||
let mut matching_files = Vec::new();
|
||||
for entry in fs_wrapper::read_dir(path) {
|
||||
let entry = entry.expect("failed to read directory entry.");
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_file() && filter(&path) {
|
||||
matching_files.push(path);
|
||||
}
|
||||
}
|
||||
matching_files
|
||||
}
|
||||
|
||||
/// Returns true if the filename at `path` starts with `prefix`.
|
||||
pub fn has_prefix<P: AsRef<Path>>(path: P, prefix: &str) -> bool {
|
||||
path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix))
|
||||
}
|
||||
|
||||
/// Returns true if the filename at `path` has the extension `extension`.
|
||||
pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool {
|
||||
path.as_ref().extension().is_some_and(|ext| ext == extension)
|
||||
}
|
||||
|
||||
/// Returns true if the filename at `path` does not contain `expected`.
|
||||
pub fn not_contains<P: AsRef<Path>>(path: P, expected: &str) -> bool {
|
||||
!path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected))
|
||||
}
|
||||
|
||||
/// Returns true if the filename at `path` is not in `expected`.
|
||||
pub fn filename_not_in_denylist<P: AsRef<Path>>(path: P, expected: &[String]) -> bool {
|
||||
path.as_ref()
|
||||
.file_name()
|
||||
.is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned()))
|
||||
}
|
||||
|
||||
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
|
||||
/// available on the platform!
|
||||
#[track_caller]
|
||||
|
|
|
|||
|
|
@ -241,11 +241,3 @@ impl Parse for QueryGroup {
|
|||
Ok(QueryGroup { group_path })
|
||||
}
|
||||
}
|
||||
|
||||
struct Nothing;
|
||||
|
||||
impl Parse for Nothing {
|
||||
fn parse(_input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
Ok(Nothing)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue