Auto merge of #3736 - rust-lang:rustup-2024-07-06, r=RalfJung

Automatic Rustup
This commit is contained in:
bors 2024-07-06 08:30:54 +00:00
commit d358f5dcf9
226 changed files with 4962 additions and 2961 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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());
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,5 +6,6 @@
pub mod canonicalizer;
pub mod delegate;
pub mod relate;
pub mod resolve;
pub mod solve;

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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" {}

View file

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

View file

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

View file

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

View file

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

View file

@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies.windows-bindgen]
version = "0.57.0"
version = "0.58.0"

View file

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

View file

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

View file

@ -1 +1 @@
51917ba8f215f76e9d3fa8e77cd0a781bb28dab7
51917e2e69702e5752bce6a4f3bfd285d0f4ae39

View file

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

View file

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

View file

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

View file

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