Merge from rustc
This commit is contained in:
commit
4a26aa4439
196 changed files with 2507 additions and 1673 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -44,13 +44,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let mut res = self.lower_res(base_res);
|
||||
|
||||
// When we have an `async` kw on a bound, map the trait it resolves to.
|
||||
let mut bound_modifier_allowed_features = None;
|
||||
if let Some(TraitBoundModifiers { asyncness: BoundAsyncness::Async(_), .. }) = modifiers {
|
||||
match res {
|
||||
Res::Def(DefKind::Trait, def_id) => {
|
||||
if let Some((async_def_id, features)) = self.map_trait_to_async_trait(def_id) {
|
||||
if let Some(async_def_id) = self.map_trait_to_async_trait(def_id) {
|
||||
res = Res::Def(DefKind::Trait, async_def_id);
|
||||
bound_modifier_allowed_features = Some(features);
|
||||
} else {
|
||||
self.dcx().emit_err(AsyncBoundOnlyForFnTraits { span: p.span });
|
||||
}
|
||||
|
|
@ -67,6 +65,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
// Ungate the `async_fn_traits` feature in the path if the trait is
|
||||
// named via either `async Fn*()` or `AsyncFn*()`.
|
||||
let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res
|
||||
&& self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some()
|
||||
{
|
||||
Some(self.allow_async_fn_traits.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let path_span_lo = p.span.shrink_to_lo();
|
||||
let proj_start = p.segments.len() - unresolved_segments;
|
||||
let path = self.arena.alloc(hir::Path {
|
||||
|
|
@ -506,14 +514,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
/// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one
|
||||
/// that is generic over `async`ness, if that's ever possible, or modify the
|
||||
/// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
|
||||
fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<(DefId, Lrc<[Symbol]>)> {
|
||||
fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<DefId> {
|
||||
let lang_items = self.tcx.lang_items();
|
||||
if Some(def_id) == lang_items.fn_trait() {
|
||||
Some((lang_items.async_fn_trait()?, self.allow_async_fn_traits.clone()))
|
||||
lang_items.async_fn_trait()
|
||||
} else if Some(def_id) == lang_items.fn_mut_trait() {
|
||||
Some((lang_items.async_fn_mut_trait()?, self.allow_async_fn_traits.clone()))
|
||||
lang_items.async_fn_mut_trait()
|
||||
} else if Some(def_id) == lang_items.fn_once_trait() {
|
||||
Some((lang_items.async_fn_once_trait()?, self.allow_async_fn_traits.clone()))
|
||||
lang_items.async_fn_once_trait()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use core::ops::ControlFlow;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::mut_visit::MutVisitor;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::visit::{AssocCtxt, Visitor};
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_ast::{mut_visit, visit};
|
||||
use rustc_ast::{Attribute, HasAttrs, HasTokens};
|
||||
|
|
@ -53,11 +53,8 @@ fn flat_map_annotatable(
|
|||
) -> Option<Annotatable> {
|
||||
match annotatable {
|
||||
Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item),
|
||||
Annotatable::TraitItem(item) => {
|
||||
vis.flat_map_trait_item(item).pop().map(Annotatable::TraitItem)
|
||||
}
|
||||
Annotatable::ImplItem(item) => {
|
||||
vis.flat_map_impl_item(item).pop().map(Annotatable::ImplItem)
|
||||
Annotatable::AssocItem(item, ctxt) => {
|
||||
Some(Annotatable::AssocItem(vis.flat_map_assoc_item(item, ctxt).pop()?, ctxt))
|
||||
}
|
||||
Annotatable::ForeignItem(item) => {
|
||||
vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)
|
||||
|
|
@ -106,8 +103,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
|||
|
||||
let res = match annotatable {
|
||||
Annotatable::Item(item) => CfgFinder.visit_item(item),
|
||||
Annotatable::TraitItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Trait),
|
||||
Annotatable::ImplItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Impl),
|
||||
Annotatable::AssocItem(item, ctxt) => CfgFinder.visit_assoc_item(item, *ctxt),
|
||||
Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
|
||||
Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
|
||||
Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
|
||||
|
|
@ -150,14 +146,16 @@ impl CfgEval<'_> {
|
|||
Annotatable::Item(_) => {
|
||||
|parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap()))
|
||||
}
|
||||
Annotatable::TraitItem(_) => |parser| {
|
||||
Ok(Annotatable::TraitItem(
|
||||
Annotatable::AssocItem(_, AssocCtxt::Trait) => |parser| {
|
||||
Ok(Annotatable::AssocItem(
|
||||
parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(),
|
||||
AssocCtxt::Trait,
|
||||
))
|
||||
},
|
||||
Annotatable::ImplItem(_) => |parser| {
|
||||
Ok(Annotatable::ImplItem(
|
||||
Annotatable::AssocItem(_, AssocCtxt::Impl) => |parser| {
|
||||
Ok(Annotatable::AssocItem(
|
||||
parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(),
|
||||
AssocCtxt::Impl,
|
||||
))
|
||||
},
|
||||
Annotatable::ForeignItem(_) => |parser| {
|
||||
|
|
@ -214,18 +212,18 @@ impl MutVisitor for CfgEval<'_> {
|
|||
#[instrument(level = "trace", skip(self))]
|
||||
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
|
||||
self.0.configure_expr(expr, false);
|
||||
mut_visit::noop_visit_expr(expr, self);
|
||||
mut_visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
|
||||
self.0.configure_expr(expr, true);
|
||||
mut_visit::noop_visit_expr(expr, self);
|
||||
mut_visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
|
||||
let mut expr = configure!(self, expr);
|
||||
mut_visit::noop_visit_expr(&mut expr, self);
|
||||
mut_visit::walk_expr(self, &mut expr);
|
||||
Some(expr)
|
||||
}
|
||||
|
||||
|
|
@ -233,53 +231,64 @@ impl MutVisitor for CfgEval<'_> {
|
|||
&mut self,
|
||||
param: ast::GenericParam,
|
||||
) -> SmallVec<[ast::GenericParam; 1]> {
|
||||
mut_visit::noop_flat_map_generic_param(configure!(self, param), self)
|
||||
let param = configure!(self, param);
|
||||
mut_visit::walk_flat_map_generic_param(self, param)
|
||||
}
|
||||
|
||||
fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
|
||||
mut_visit::noop_flat_map_stmt(configure!(self, stmt), self)
|
||||
let stmt = configure!(self, stmt);
|
||||
mut_visit::walk_flat_map_stmt(self, stmt)
|
||||
}
|
||||
|
||||
fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
||||
mut_visit::noop_flat_map_item(configure!(self, item), self)
|
||||
let item = configure!(self, item);
|
||||
mut_visit::walk_flat_map_item(self, item)
|
||||
}
|
||||
|
||||
fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
mut_visit::noop_flat_map_item(configure!(self, item), self)
|
||||
}
|
||||
|
||||
fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
mut_visit::noop_flat_map_item(configure!(self, item), self)
|
||||
fn flat_map_assoc_item(
|
||||
&mut self,
|
||||
item: P<ast::AssocItem>,
|
||||
_ctxt: AssocCtxt,
|
||||
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
let item = configure!(self, item);
|
||||
mut_visit::walk_flat_map_item(self, item)
|
||||
}
|
||||
|
||||
fn flat_map_foreign_item(
|
||||
&mut self,
|
||||
foreign_item: P<ast::ForeignItem>,
|
||||
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
|
||||
mut_visit::noop_flat_map_item(configure!(self, foreign_item), self)
|
||||
let foreign_item = configure!(self, foreign_item);
|
||||
mut_visit::walk_flat_map_item(self, foreign_item)
|
||||
}
|
||||
|
||||
fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
|
||||
mut_visit::noop_flat_map_arm(configure!(self, arm), self)
|
||||
let arm = configure!(self, arm);
|
||||
mut_visit::walk_flat_map_arm(self, arm)
|
||||
}
|
||||
|
||||
fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
|
||||
mut_visit::noop_flat_map_expr_field(configure!(self, field), self)
|
||||
let field = configure!(self, field);
|
||||
mut_visit::walk_flat_map_expr_field(self, field)
|
||||
}
|
||||
|
||||
fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
|
||||
mut_visit::noop_flat_map_pat_field(configure!(self, fp), self)
|
||||
let fp = configure!(self, fp);
|
||||
mut_visit::walk_flat_map_pat_field(self, fp)
|
||||
}
|
||||
|
||||
fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
|
||||
mut_visit::noop_flat_map_param(configure!(self, p), self)
|
||||
let p = configure!(self, p);
|
||||
mut_visit::walk_flat_map_param(self, p)
|
||||
}
|
||||
|
||||
fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
|
||||
mut_visit::noop_flat_map_field_def(configure!(self, sf), self)
|
||||
let sf = configure!(self, sf);
|
||||
mut_visit::walk_flat_map_field_def(self, sf)
|
||||
}
|
||||
|
||||
fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
|
||||
mut_visit::noop_flat_map_variant(configure!(self, variant), self)
|
||||
let variant = configure!(self, variant);
|
||||
mut_visit::walk_flat_map_variant(self, variant)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,15 +122,15 @@ impl TestHarnessGenerator<'_> {
|
|||
impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||
fn visit_crate(&mut self, c: &mut ast::Crate) {
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
noop_visit_crate(c, self);
|
||||
walk_crate(self, c);
|
||||
self.add_test_cases(ast::CRATE_NODE_ID, c.spans.inner_span, prev_tests);
|
||||
|
||||
// Create a main function to run our tests
|
||||
c.items.push(mk_main(&mut self.cx));
|
||||
}
|
||||
|
||||
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
||||
let mut item = i.into_inner();
|
||||
fn flat_map_item(&mut self, mut i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
||||
let item = &mut *i;
|
||||
if let Some(name) = get_test_name(&item) {
|
||||
debug!("this is a test item");
|
||||
|
||||
|
|
@ -144,13 +144,13 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
|||
item.kind
|
||||
{
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
noop_visit_item_kind(&mut item.kind, self);
|
||||
walk_item_kind(&mut item.kind, item.span, item.id, self);
|
||||
self.add_test_cases(item.id, span, prev_tests);
|
||||
} else {
|
||||
// But in those cases, we emit a lint to warn the user of these missing tests.
|
||||
walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
|
||||
}
|
||||
smallvec![P(item)]
|
||||
smallvec![i]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ struct EntryPointCleaner<'a> {
|
|||
impl<'a> MutVisitor for EntryPointCleaner<'a> {
|
||||
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
||||
self.depth += 1;
|
||||
let item = noop_flat_map_item(i, self).expect_one("noop did something");
|
||||
let item = walk_flat_map_item(self, i).expect_one("noop did something");
|
||||
self.depth -= 1;
|
||||
|
||||
// Remove any #[rustc_main] or #[start] from the AST so it doesn't
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaI
|
|||
pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) {
|
||||
let attrs: Option<&[Attribute]> = match item {
|
||||
Annotatable::Item(item) => Some(&item.attrs),
|
||||
Annotatable::TraitItem(item) => Some(&item.attrs),
|
||||
Annotatable::ImplItem(item) => Some(&item.attrs),
|
||||
Annotatable::AssocItem(item, _) => Some(&item.attrs),
|
||||
Annotatable::ForeignItem(item) => Some(&item.attrs),
|
||||
Annotatable::Expr(expr) => Some(&expr.attrs),
|
||||
Annotatable::Arm(arm) => Some(&arm.attrs),
|
||||
|
|
|
|||
|
|
@ -100,7 +100,33 @@ impl Qualif for HasMutInterior {
|
|||
}
|
||||
|
||||
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
!ty.is_freeze(cx.tcx, cx.param_env)
|
||||
// Avoid selecting for simple cases, such as builtin types.
|
||||
if ty.is_trivially_freeze() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We do not use `ty.is_freeze` here, because that requires revealing opaque types, which
|
||||
// requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error.
|
||||
// Instead we invoke an obligation context manually, and provide the opaque type inference settings
|
||||
// that allow the trait solver to just error out instead of cycling.
|
||||
let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span));
|
||||
|
||||
let obligation = Obligation::new(
|
||||
cx.tcx,
|
||||
ObligationCause::dummy_with_span(cx.body.span),
|
||||
cx.param_env,
|
||||
ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]),
|
||||
);
|
||||
|
||||
let infcx = cx
|
||||
.tcx
|
||||
.infer_ctxt()
|
||||
.with_opaque_type_inference(cx.body.source.def_id().expect_local())
|
||||
.build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
ocx.register_obligation(obligation);
|
||||
let errors = ocx.select_all_or_error();
|
||||
!errors.is_empty()
|
||||
}
|
||||
|
||||
fn in_adt_inherently<'tcx>(
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ use thin_vec::ThinVec;
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum Annotatable {
|
||||
Item(P<ast::Item>),
|
||||
TraitItem(P<ast::AssocItem>),
|
||||
ImplItem(P<ast::AssocItem>),
|
||||
AssocItem(P<ast::AssocItem>, AssocCtxt),
|
||||
ForeignItem(P<ast::ForeignItem>),
|
||||
Stmt(P<ast::Stmt>),
|
||||
Expr(P<ast::Expr>),
|
||||
|
|
@ -56,8 +55,7 @@ impl Annotatable {
|
|||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
Annotatable::Item(item) => item.span,
|
||||
Annotatable::TraitItem(trait_item) => trait_item.span,
|
||||
Annotatable::ImplItem(impl_item) => impl_item.span,
|
||||
Annotatable::AssocItem(assoc_item, _) => assoc_item.span,
|
||||
Annotatable::ForeignItem(foreign_item) => foreign_item.span,
|
||||
Annotatable::Stmt(stmt) => stmt.span,
|
||||
Annotatable::Expr(expr) => expr.span,
|
||||
|
|
@ -75,8 +73,7 @@ impl Annotatable {
|
|||
pub fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
|
||||
match self {
|
||||
Annotatable::Item(item) => item.visit_attrs(f),
|
||||
Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f),
|
||||
Annotatable::ImplItem(impl_item) => impl_item.visit_attrs(f),
|
||||
Annotatable::AssocItem(assoc_item, _) => assoc_item.visit_attrs(f),
|
||||
Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f),
|
||||
Annotatable::Stmt(stmt) => stmt.visit_attrs(f),
|
||||
Annotatable::Expr(expr) => expr.visit_attrs(f),
|
||||
|
|
@ -94,8 +91,7 @@ impl Annotatable {
|
|||
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) -> V::Result {
|
||||
match self {
|
||||
Annotatable::Item(item) => visitor.visit_item(item),
|
||||
Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait),
|
||||
Annotatable::ImplItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Impl),
|
||||
Annotatable::AssocItem(item, ctxt) => visitor.visit_assoc_item(item, *ctxt),
|
||||
Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item),
|
||||
Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt),
|
||||
Annotatable::Expr(expr) => visitor.visit_expr(expr),
|
||||
|
|
@ -113,9 +109,7 @@ impl Annotatable {
|
|||
pub fn to_tokens(&self) -> TokenStream {
|
||||
match self {
|
||||
Annotatable::Item(node) => TokenStream::from_ast(node),
|
||||
Annotatable::TraitItem(node) | Annotatable::ImplItem(node) => {
|
||||
TokenStream::from_ast(node)
|
||||
}
|
||||
Annotatable::AssocItem(node, _) => TokenStream::from_ast(node),
|
||||
Annotatable::ForeignItem(node) => TokenStream::from_ast(node),
|
||||
Annotatable::Stmt(node) => {
|
||||
assert!(!matches!(node.kind, ast::StmtKind::Empty));
|
||||
|
|
@ -142,14 +136,14 @@ impl Annotatable {
|
|||
|
||||
pub fn expect_trait_item(self) -> P<ast::AssocItem> {
|
||||
match self {
|
||||
Annotatable::TraitItem(i) => i,
|
||||
Annotatable::AssocItem(i, AssocCtxt::Trait) => i,
|
||||
_ => panic!("expected Item"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_impl_item(self) -> P<ast::AssocItem> {
|
||||
match self {
|
||||
Annotatable::ImplItem(i) => i,
|
||||
Annotatable::AssocItem(i, AssocCtxt::Impl) => i,
|
||||
_ => panic!("expected Item"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::errors::{
|
|||
};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{Delimiter, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, DelimSpacing, DelimSpan, Spacing};
|
||||
use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, Spacing};
|
||||
use rustc_ast::tokenstream::{LazyAttrTokenStream, TokenTree};
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
|
||||
|
|
@ -298,47 +298,47 @@ impl<'a> StripUnconfigured<'a> {
|
|||
cfg_attr: &Attribute,
|
||||
(item, item_span): (ast::AttrItem, Span),
|
||||
) -> Attribute {
|
||||
// We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
|
||||
// and producing an attribute of the form `#[attr]`. We
|
||||
// have captured tokens for `attr` itself, but we need to
|
||||
// synthesize tokens for the wrapper `#` and `[]`, which
|
||||
// we do below.
|
||||
// Convert `#[cfg_attr(pred, attr)]` to `#[attr]`.
|
||||
|
||||
// Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
|
||||
// for `attr` when we expand it to `#[attr]`
|
||||
// Use the `#` from `#[cfg_attr(pred, attr)]` in the result `#[attr]`.
|
||||
let mut orig_trees = cfg_attr.token_trees().into_iter();
|
||||
let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) =
|
||||
orig_trees.next().unwrap().clone()
|
||||
let Some(TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _)) =
|
||||
orig_trees.next()
|
||||
else {
|
||||
panic!("Bad tokens for attribute {cfg_attr:?}");
|
||||
};
|
||||
|
||||
// We don't really have a good span to use for the synthesized `[]`
|
||||
// in `#[attr]`, so just use the span of the `#` token.
|
||||
let bracket_group = AttrTokenTree::Delimited(
|
||||
DelimSpan::from_single(pound_token.span),
|
||||
DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
|
||||
Delimiter::Bracket,
|
||||
item.tokens
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
|
||||
.to_attr_token_stream(),
|
||||
);
|
||||
let trees = if cfg_attr.style == AttrStyle::Inner {
|
||||
// For inner attributes, we do the same thing for the `!` in `#![some_attr]`
|
||||
let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) =
|
||||
orig_trees.next().unwrap().clone()
|
||||
// For inner attributes, we do the same thing for the `!` in `#![attr]`.
|
||||
let mut trees = if cfg_attr.style == AttrStyle::Inner {
|
||||
let Some(TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _)) =
|
||||
orig_trees.next()
|
||||
else {
|
||||
panic!("Bad tokens for attribute {cfg_attr:?}");
|
||||
};
|
||||
vec![
|
||||
AttrTokenTree::Token(pound_token, Spacing::Joint),
|
||||
AttrTokenTree::Token(bang_token, Spacing::JointHidden),
|
||||
bracket_group,
|
||||
]
|
||||
} else {
|
||||
vec![AttrTokenTree::Token(pound_token, Spacing::JointHidden), bracket_group]
|
||||
vec![AttrTokenTree::Token(pound_token, Spacing::JointHidden)]
|
||||
};
|
||||
|
||||
// And the same thing for the `[`/`]` delimiters in `#[attr]`.
|
||||
let Some(TokenTree::Delimited(delim_span, delim_spacing, Delimiter::Bracket, _)) =
|
||||
orig_trees.next()
|
||||
else {
|
||||
panic!("Bad tokens for attribute {cfg_attr:?}");
|
||||
};
|
||||
trees.push(AttrTokenTree::Delimited(
|
||||
delim_span,
|
||||
delim_spacing,
|
||||
Delimiter::Bracket,
|
||||
item.tokens
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
|
||||
.to_attr_token_stream(),
|
||||
));
|
||||
|
||||
let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees)));
|
||||
let attr = attr::mk_attr_from_item(
|
||||
&self.sess.psess.attr_id_generator,
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ macro_rules! ast_fragments {
|
|||
AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
|
||||
$($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
|
||||
$($(AstFragment::$Kind(ast) =>
|
||||
ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
|
||||
ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast, $($args)*)),)?)*
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,13 +177,13 @@ ast_fragments! {
|
|||
}
|
||||
TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
||||
"trait item";
|
||||
many fn flat_map_trait_item;
|
||||
many fn flat_map_assoc_item;
|
||||
fn visit_assoc_item(AssocCtxt::Trait);
|
||||
fn make_trait_items;
|
||||
}
|
||||
ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
||||
"impl item";
|
||||
many fn flat_map_impl_item;
|
||||
many fn flat_map_assoc_item;
|
||||
fn visit_assoc_item(AssocCtxt::Impl);
|
||||
fn make_impl_items;
|
||||
}
|
||||
|
|
@ -833,7 +833,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
self.cx, deleg, &item, &suffixes, item.span, true,
|
||||
);
|
||||
fragment_kind.expect_from_annotatables(
|
||||
single_delegations.map(|item| Annotatable::ImplItem(P(item))),
|
||||
single_delegations.map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl)),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
@ -843,8 +843,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
|
||||
let kind = match item {
|
||||
Annotatable::Item(_)
|
||||
| Annotatable::TraitItem(_)
|
||||
| Annotatable::ImplItem(_)
|
||||
| Annotatable::AssocItem(..)
|
||||
| Annotatable::ForeignItem(_)
|
||||
| Annotatable::Crate(..) => return,
|
||||
Annotatable::Stmt(stmt) => {
|
||||
|
|
@ -1037,7 +1036,7 @@ pub(crate) fn ensure_complete_parse<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
|
||||
/// Wraps a call to `walk_*` / `walk_flat_map_*`
|
||||
/// for an AST node that supports attributes
|
||||
/// (see the `Annotatable` enum)
|
||||
/// This method assigns a `NodeId`, and sets that `NodeId`
|
||||
|
|
@ -1057,7 +1056,7 @@ pub(crate) fn ensure_complete_parse<'a>(
|
|||
/// * `id` is a mutable reference to the `NodeId` field
|
||||
/// of the current AST node.
|
||||
/// * `closure` is a closure that executes the
|
||||
/// `noop_visit_*` / `noop_flat_map_*` method
|
||||
/// `walk_*` / `walk_flat_map_*` method
|
||||
/// for the current AST node.
|
||||
macro_rules! assign_id {
|
||||
($self:ident, $id:expr, $closure:expr) => {{
|
||||
|
|
@ -1091,10 +1090,10 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
|
|||
fn descr() -> &'static str {
|
||||
unreachable!()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
|
||||
fn walk_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
|
||||
unreachable!()
|
||||
}
|
||||
fn noop_visit<V: MutVisitor>(&mut self, _visitor: &mut V) {
|
||||
fn walk<V: MutVisitor>(&mut self, _visitor: &mut V) {
|
||||
unreachable!()
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
|
|
@ -1118,12 +1117,12 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
|
|||
fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
|
||||
fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
|
||||
}
|
||||
fn wrap_flat_map_node_noop_flat_map(
|
||||
fn wrap_flat_map_node_walk_flat_map(
|
||||
node: Self,
|
||||
collector: &mut InvocationCollector<'_, '_>,
|
||||
noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
|
||||
walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
|
||||
) -> Result<Self::OutputTy, Self> {
|
||||
Ok(noop_flat_map(node, collector))
|
||||
Ok(walk_flat_map(node, collector))
|
||||
}
|
||||
fn expand_cfg_false(
|
||||
&mut self,
|
||||
|
|
@ -1149,8 +1148,8 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_items()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_item(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_item(visitor, self)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.kind, ItemKind::MacCall(..))
|
||||
|
|
@ -1177,13 +1176,13 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
|
||||
items.flatten().collect()
|
||||
}
|
||||
fn wrap_flat_map_node_noop_flat_map(
|
||||
fn wrap_flat_map_node_walk_flat_map(
|
||||
mut node: Self,
|
||||
collector: &mut InvocationCollector<'_, '_>,
|
||||
noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
|
||||
walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
|
||||
) -> Result<Self::OutputTy, Self> {
|
||||
if !matches!(node.kind, ItemKind::Mod(..)) {
|
||||
return Ok(noop_flat_map(node, collector));
|
||||
return Ok(walk_flat_map(node, collector));
|
||||
}
|
||||
|
||||
// Work around borrow checker not seeing through `P`'s deref.
|
||||
|
|
@ -1253,7 +1252,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
let orig_dir_ownership =
|
||||
mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership);
|
||||
|
||||
let res = Ok(noop_flat_map(node, collector));
|
||||
let res = Ok(walk_flat_map(node, collector));
|
||||
|
||||
collector.cx.current_expansion.dir_ownership = orig_dir_ownership;
|
||||
collector.cx.current_expansion.module = orig_module;
|
||||
|
|
@ -1288,13 +1287,13 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
|
|||
type ItemKind = AssocItemKind;
|
||||
const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
|
||||
fn to_annotatable(self) -> Annotatable {
|
||||
Annotatable::TraitItem(self.wrapped)
|
||||
Annotatable::AssocItem(self.wrapped, AssocCtxt::Trait)
|
||||
}
|
||||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_trait_items()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_item(self.wrapped, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_item(visitor, self.wrapped)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
||||
|
|
@ -1329,13 +1328,13 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
|
|||
type ItemKind = AssocItemKind;
|
||||
const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
|
||||
fn to_annotatable(self) -> Annotatable {
|
||||
Annotatable::ImplItem(self.wrapped)
|
||||
Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl)
|
||||
}
|
||||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_impl_items()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_item(self.wrapped, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_item(visitor, self.wrapped)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
||||
|
|
@ -1372,8 +1371,8 @@ impl InvocationCollectorNode for P<ast::ForeignItem> {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_foreign_items()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_item(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_item(visitor, self)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.kind, ForeignItemKind::MacCall(..))
|
||||
|
|
@ -1395,8 +1394,8 @@ impl InvocationCollectorNode for ast::Variant {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_variants()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_variant(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_variant(visitor, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1408,8 +1407,8 @@ impl InvocationCollectorNode for ast::FieldDef {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_field_defs()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_field_def(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_field_def(visitor, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1421,8 +1420,8 @@ impl InvocationCollectorNode for ast::PatField {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_pat_fields()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_pat_field(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_pat_field(visitor, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1434,8 +1433,8 @@ impl InvocationCollectorNode for ast::ExprField {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_expr_fields()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_expr_field(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_expr_field(visitor, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1447,8 +1446,8 @@ impl InvocationCollectorNode for ast::Param {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_params()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_param(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_param(visitor, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1460,8 +1459,8 @@ impl InvocationCollectorNode for ast::GenericParam {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_generic_params()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_generic_param(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_generic_param(visitor, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1473,8 +1472,8 @@ impl InvocationCollectorNode for ast::Arm {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_arms()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_arm(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_arm(visitor, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1487,8 +1486,8 @@ impl InvocationCollectorNode for ast::Stmt {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_stmts()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_flat_map_stmt(self, visitor)
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_stmt(visitor, self)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
match &self.kind {
|
||||
|
|
@ -1561,8 +1560,8 @@ impl InvocationCollectorNode for ast::Crate {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_crate()
|
||||
}
|
||||
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
noop_visit_crate(self, visitor)
|
||||
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
walk_crate(visitor, self)
|
||||
}
|
||||
fn expand_cfg_false(
|
||||
&mut self,
|
||||
|
|
@ -1587,8 +1586,8 @@ impl InvocationCollectorNode for P<ast::Ty> {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_ty()
|
||||
}
|
||||
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
noop_visit_ty(self, visitor)
|
||||
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
walk_ty(visitor, self)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.kind, ast::TyKind::MacCall(..))
|
||||
|
|
@ -1611,8 +1610,8 @@ impl InvocationCollectorNode for P<ast::Pat> {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_pat()
|
||||
}
|
||||
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
noop_visit_pat(self, visitor)
|
||||
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
walk_pat(visitor, self)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.kind, PatKind::MacCall(..))
|
||||
|
|
@ -1639,8 +1638,8 @@ impl InvocationCollectorNode for P<ast::Expr> {
|
|||
fn descr() -> &'static str {
|
||||
"an expression"
|
||||
}
|
||||
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
noop_visit_expr(self, visitor)
|
||||
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
walk_expr(visitor, self)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.kind, ExprKind::MacCall(..))
|
||||
|
|
@ -1665,8 +1664,8 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
fragment.make_opt_expr()
|
||||
}
|
||||
fn noop_flat_map<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
|
||||
noop_visit_expr(&mut self.wrapped, visitor);
|
||||
fn walk_flat_map<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_expr(visitor, &mut self.wrapped);
|
||||
Some(self.wrapped)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
|
|
@ -1705,8 +1704,8 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag>
|
|||
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
|
||||
AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag)
|
||||
}
|
||||
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
noop_visit_expr(&mut self.wrapped, visitor)
|
||||
fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
walk_expr(visitor, &mut self.wrapped)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
|
||||
|
|
@ -1993,9 +1992,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
let traitless_qself =
|
||||
matches!(&deleg.qself, Some(qself) if qself.position == 0);
|
||||
let item = match node.to_annotatable() {
|
||||
Annotatable::ImplItem(item) => item,
|
||||
Annotatable::AssocItem(item, AssocCtxt::Impl) => item,
|
||||
ann @ (Annotatable::Item(_)
|
||||
| Annotatable::TraitItem(_)
|
||||
| Annotatable::AssocItem(..)
|
||||
| Annotatable::Stmt(_)) => {
|
||||
let span = ann.span();
|
||||
self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span });
|
||||
|
|
@ -2016,12 +2015,12 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
);
|
||||
Node::flatten_outputs(single_delegations.map(|item| {
|
||||
let mut item = Node::from_item(item);
|
||||
assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
|
||||
assign_id!(self, item.node_id_mut(), || item.walk_flat_map(self))
|
||||
}))
|
||||
}
|
||||
None => {
|
||||
match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
|
||||
assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this))
|
||||
match Node::wrap_flat_map_node_walk_flat_map(node, self, |mut node, this| {
|
||||
assign_id!(this, node.node_id_mut(), || node.walk_flat_map(this))
|
||||
}) {
|
||||
Ok(output) => output,
|
||||
Err(returned_node) => {
|
||||
|
|
@ -2069,7 +2068,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
}
|
||||
None if node.delegation().is_some() => unreachable!(),
|
||||
None => {
|
||||
assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
|
||||
assign_id!(self, node.node_id_mut(), || node.walk(self))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -2081,12 +2080,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
self.flat_map_node(node)
|
||||
}
|
||||
|
||||
fn flat_map_trait_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag))
|
||||
}
|
||||
|
||||
fn flat_map_impl_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag))
|
||||
fn flat_map_assoc_item(
|
||||
&mut self,
|
||||
node: P<ast::AssocItem>,
|
||||
ctxt: AssocCtxt,
|
||||
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
match ctxt {
|
||||
AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)),
|
||||
AssocCtxt::Impl => self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)),
|
||||
}
|
||||
}
|
||||
|
||||
fn flat_map_foreign_item(
|
||||
|
|
@ -2145,11 +2147,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
self.cx.current_expansion.is_trailing_mac = true;
|
||||
// Don't use `assign_id` for this statement - it may get removed
|
||||
// entirely due to a `#[cfg]` on the contained expression
|
||||
let res = noop_flat_map_stmt(node, self);
|
||||
let res = walk_flat_map_stmt(self, node);
|
||||
self.cx.current_expansion.is_trailing_mac = false;
|
||||
res
|
||||
}
|
||||
_ => noop_flat_map_stmt(node, self),
|
||||
_ => walk_flat_map_stmt(self, node),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2193,7 +2195,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
&mut self.cx.current_expansion.dir_ownership,
|
||||
DirOwnership::UnownedViaBlock,
|
||||
);
|
||||
noop_visit_block(node, self);
|
||||
walk_block(self, node);
|
||||
self.cx.current_expansion.dir_ownership = orig_dir_ownership;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ pub(super) fn transcribe<'a>(
|
|||
// jump back out of the Delimited, pop the result_stack and add the new results back to
|
||||
// the previous results (from outside the Delimited).
|
||||
mbe::TokenTree::Delimited(mut span, spacing, delimited) => {
|
||||
mut_visit::visit_delim_span(&mut span, &mut marker);
|
||||
mut_visit::visit_delim_span(&mut marker, &mut span);
|
||||
stack.push(Frame::new_delimited(delimited, span, *spacing));
|
||||
result_stack.push(mem::take(&mut result));
|
||||
}
|
||||
|
|
@ -342,7 +342,7 @@ pub(super) fn transcribe<'a>(
|
|||
// preserve syntax context.
|
||||
mbe::TokenTree::Token(token) => {
|
||||
let mut token = token.clone();
|
||||
mut_visit::visit_token(&mut token, &mut marker);
|
||||
mut_visit::visit_token(&mut marker, &mut token);
|
||||
let tt = TokenTree::Token(token, Spacing::Alone);
|
||||
result.push(tt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use crate::expand::{AstFragment, AstFragmentKind};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::mut_visit::*;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::{self as ast, visit::AssocCtxt};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
|
@ -209,7 +209,7 @@ impl MutVisitor for PlaceholderExpander {
|
|||
if arm.is_placeholder {
|
||||
self.remove(arm.id).make_arms()
|
||||
} else {
|
||||
noop_flat_map_arm(arm, self)
|
||||
walk_flat_map_arm(self, arm)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ impl MutVisitor for PlaceholderExpander {
|
|||
if field.is_placeholder {
|
||||
self.remove(field.id).make_expr_fields()
|
||||
} else {
|
||||
noop_flat_map_expr_field(field, self)
|
||||
walk_flat_map_expr_field(self, field)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +225,7 @@ impl MutVisitor for PlaceholderExpander {
|
|||
if fp.is_placeholder {
|
||||
self.remove(fp.id).make_pat_fields()
|
||||
} else {
|
||||
noop_flat_map_pat_field(fp, self)
|
||||
walk_flat_map_pat_field(self, fp)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ impl MutVisitor for PlaceholderExpander {
|
|||
if param.is_placeholder {
|
||||
self.remove(param.id).make_generic_params()
|
||||
} else {
|
||||
noop_flat_map_generic_param(param, self)
|
||||
walk_flat_map_generic_param(self, param)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ impl MutVisitor for PlaceholderExpander {
|
|||
if p.is_placeholder {
|
||||
self.remove(p.id).make_params()
|
||||
} else {
|
||||
noop_flat_map_param(p, self)
|
||||
walk_flat_map_param(self, p)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ impl MutVisitor for PlaceholderExpander {
|
|||
if sf.is_placeholder {
|
||||
self.remove(sf.id).make_field_defs()
|
||||
} else {
|
||||
noop_flat_map_field_def(sf, self)
|
||||
walk_flat_map_field_def(self, sf)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -260,28 +260,31 @@ impl MutVisitor for PlaceholderExpander {
|
|||
if variant.is_placeholder {
|
||||
self.remove(variant.id).make_variants()
|
||||
} else {
|
||||
noop_flat_map_variant(variant, self)
|
||||
walk_flat_map_variant(self, variant)
|
||||
}
|
||||
}
|
||||
|
||||
fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
||||
match item.kind {
|
||||
ast::ItemKind::MacCall(_) => self.remove(item.id).make_items(),
|
||||
_ => noop_flat_map_item(item, self),
|
||||
_ => walk_flat_map_item(self, item),
|
||||
}
|
||||
}
|
||||
|
||||
fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
fn flat_map_assoc_item(
|
||||
&mut self,
|
||||
item: P<ast::AssocItem>,
|
||||
ctxt: AssocCtxt,
|
||||
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
match item.kind {
|
||||
ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_trait_items(),
|
||||
_ => noop_flat_map_item(item, self),
|
||||
}
|
||||
}
|
||||
|
||||
fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
match item.kind {
|
||||
ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_impl_items(),
|
||||
_ => noop_flat_map_item(item, self),
|
||||
ast::AssocItemKind::MacCall(_) => {
|
||||
let it = self.remove(item.id);
|
||||
match ctxt {
|
||||
AssocCtxt::Trait => it.make_trait_items(),
|
||||
AssocCtxt::Impl => it.make_impl_items(),
|
||||
}
|
||||
}
|
||||
_ => walk_flat_map_item(self, item),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -291,35 +294,35 @@ impl MutVisitor for PlaceholderExpander {
|
|||
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
|
||||
match item.kind {
|
||||
ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(),
|
||||
_ => noop_flat_map_item(item, self),
|
||||
_ => walk_flat_map_item(self, item),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
|
||||
match expr.kind {
|
||||
ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(),
|
||||
_ => noop_visit_expr(expr, self),
|
||||
_ => walk_expr(self, expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
|
||||
match expr.kind {
|
||||
ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(),
|
||||
_ => noop_visit_expr(expr, self),
|
||||
_ => walk_expr(self, expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
|
||||
match expr.kind {
|
||||
ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(),
|
||||
_ => noop_filter_map_expr(expr, self),
|
||||
_ => noop_filter_map_expr(self, expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
|
||||
let (style, mut stmts) = match stmt.kind {
|
||||
ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()),
|
||||
_ => return noop_flat_map_stmt(stmt, self),
|
||||
_ => return walk_flat_map_stmt(self, stmt),
|
||||
};
|
||||
|
||||
if style == ast::MacStmtStyle::Semicolon {
|
||||
|
|
@ -365,14 +368,14 @@ impl MutVisitor for PlaceholderExpander {
|
|||
fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
|
||||
match pat.kind {
|
||||
ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(),
|
||||
_ => noop_visit_pat(pat, self),
|
||||
_ => walk_pat(self, pat),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
|
||||
match ty.kind {
|
||||
ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(),
|
||||
_ => noop_visit_ty(ty, self),
|
||||
_ => walk_ty(self, ty),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,7 +383,7 @@ impl MutVisitor for PlaceholderExpander {
|
|||
if krate.is_placeholder {
|
||||
*krate = self.remove(krate.id).make_crate();
|
||||
} else {
|
||||
noop_visit_crate(krate, self)
|
||||
walk_crate(self, krate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -763,7 +763,7 @@ impl<'hir> Generics<'hir> {
|
|||
)
|
||||
}
|
||||
|
||||
fn span_for_predicate_removal(&self, pos: usize) -> Span {
|
||||
pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
|
||||
let predicate = &self.predicates[pos];
|
||||
let span = predicate.span();
|
||||
|
||||
|
|
@ -806,15 +806,21 @@ impl<'hir> Generics<'hir> {
|
|||
return self.span_for_predicate_removal(predicate_pos);
|
||||
}
|
||||
|
||||
let span = bounds[bound_pos].span();
|
||||
if bound_pos == 0 {
|
||||
// where T: ?Sized + Bar, Foo: Bar,
|
||||
// ^^^^^^^^^
|
||||
span.to(bounds[1].span().shrink_to_lo())
|
||||
let bound_span = bounds[bound_pos].span();
|
||||
if bound_pos < bounds.len() - 1 {
|
||||
// If there's another bound after the current bound
|
||||
// include the following '+' e.g.:
|
||||
//
|
||||
// `T: Foo + CurrentBound + Bar`
|
||||
// ^^^^^^^^^^^^^^^
|
||||
bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo())
|
||||
} else {
|
||||
// where T: Bar + ?Sized, Foo: Bar,
|
||||
// ^^^^^^^^^
|
||||
bounds[bound_pos - 1].span().shrink_to_hi().to(span)
|
||||
// If the current bound is the last bound
|
||||
// include the preceding '+' E.g.:
|
||||
//
|
||||
// `T: Foo + Bar + CurrentBound`
|
||||
// ^^^^^^^^^^^^^^^
|
||||
bound_span.with_lo(bounds[bound_pos - 1].span().hi())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -888,7 +888,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
let comma = if args.len() > 0 { ", " } else { "" };
|
||||
let trait_path = self.tcx.def_path_str(trait_def_id);
|
||||
let method_name = self.tcx.item_name(self.def_id);
|
||||
err.span_suggestion(
|
||||
err.span_suggestion_verbose(
|
||||
expr.span,
|
||||
msg,
|
||||
format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"),
|
||||
|
|
@ -939,18 +939,20 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
|
||||
let span_lo_redundant_lt_args = if self.num_expected_lifetime_args() == 0 {
|
||||
lt_arg_spans[0]
|
||||
} else {
|
||||
lt_arg_spans[self.num_expected_lifetime_args() - 1]
|
||||
};
|
||||
let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
|
||||
|
||||
let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
|
||||
let span_redundant_lt_args =
|
||||
span_lo_redundant_lt_args.shrink_to_hi().to(span_hi_redundant_lt_args);
|
||||
debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
|
||||
|
||||
let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
|
||||
let msg_lifetimes = format!(
|
||||
"remove {these} lifetime argument{s}",
|
||||
these = pluralize!("this", num_redundant_lt_args),
|
||||
s = pluralize!(num_redundant_lt_args),
|
||||
);
|
||||
let msg_lifetimes =
|
||||
format!("remove the lifetime argument{s}", s = pluralize!(num_redundant_lt_args));
|
||||
|
||||
err.span_suggestion(
|
||||
span_redundant_lt_args,
|
||||
|
|
@ -979,18 +981,22 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let span_lo_redundant_type_or_const_args =
|
||||
gen_arg_spans[self.num_expected_type_or_const_args()];
|
||||
if self.num_expected_type_or_const_args() == 0 {
|
||||
gen_arg_spans[0]
|
||||
} else {
|
||||
gen_arg_spans[self.num_expected_type_or_const_args() - 1]
|
||||
};
|
||||
let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
|
||||
let span_redundant_type_or_const_args = span_lo_redundant_type_or_const_args
|
||||
.shrink_to_hi()
|
||||
.to(span_hi_redundant_type_or_const_args);
|
||||
|
||||
let span_redundant_type_or_const_args =
|
||||
span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
|
||||
debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
|
||||
|
||||
let num_redundant_gen_args =
|
||||
gen_arg_spans.len() - self.num_expected_type_or_const_args();
|
||||
let msg_types_or_consts = format!(
|
||||
"remove {these} generic argument{s}",
|
||||
these = pluralize!("this", num_redundant_gen_args),
|
||||
"remove the unnecessary generic argument{s}",
|
||||
s = pluralize!(num_redundant_gen_args),
|
||||
);
|
||||
|
||||
|
|
@ -1036,7 +1042,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
.with_lo(self.path_segment.ident.span.hi());
|
||||
|
||||
let msg = format!(
|
||||
"remove these {}generics",
|
||||
"remove the unnecessary {}generics",
|
||||
if self.gen_args.parenthesized == hir::GenericArgsParentheses::ParenSugar {
|
||||
"parenthetical "
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1846,7 +1846,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
/// Determine if the associated item with the given DefId matches
|
||||
/// the desired name via a doc alias.
|
||||
fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
|
||||
let Some(name) = self.method_name else {
|
||||
let Some(method) = self.method_name else {
|
||||
return false;
|
||||
};
|
||||
let Some(local_def_id) = def_id.as_local() else {
|
||||
|
|
@ -1863,7 +1863,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
// #[rustc_confusables("foo", "bar"))]
|
||||
for n in confusables {
|
||||
if let Some(lit) = n.lit()
|
||||
&& name.as_str() == lit.symbol.as_str()
|
||||
&& method.name == lit.symbol
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1883,14 +1883,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
// #[doc(alias("foo", "bar"))]
|
||||
for n in nested {
|
||||
if let Some(lit) = n.lit()
|
||||
&& name.as_str() == lit.symbol.as_str()
|
||||
&& method.name == lit.symbol
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if let Some(meta) = v.meta_item()
|
||||
&& let Some(lit) = meta.name_value_literal()
|
||||
&& name.as_str() == lit.symbol.as_str()
|
||||
&& method.name == lit.symbol
|
||||
{
|
||||
// #[doc(alias = "foo")]
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1424,7 +1424,7 @@ declare_lint! {
|
|||
Deny,
|
||||
"detects missing fragment specifiers in unused `macro_rules!` patterns",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
|
||||
reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,31 +188,60 @@ fn suggest_changing_unsized_bound(
|
|||
continue;
|
||||
};
|
||||
|
||||
for (pos, bound) in predicate.bounds.iter().enumerate() {
|
||||
let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
|
||||
continue;
|
||||
};
|
||||
if poly.trait_ref.trait_def_id() != def_id {
|
||||
continue;
|
||||
}
|
||||
if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 {
|
||||
// For `impl ?Sized` with no other bounds, suggest `impl Sized` instead.
|
||||
let bound_span = bound.span();
|
||||
if bound_span.can_be_used_for_suggestions() {
|
||||
let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1));
|
||||
suggestions.push((
|
||||
let unsized_bounds = predicate
|
||||
.bounds
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, bound)| {
|
||||
if let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound
|
||||
&& poly.trait_ref.trait_def_id() == def_id
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if unsized_bounds.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut push_suggestion = |sp, msg| suggestions.push((sp, String::new(), msg));
|
||||
|
||||
if predicate.bounds.len() == unsized_bounds.len() {
|
||||
// All the bounds are unsized bounds, e.g.
|
||||
// `T: ?Sized + ?Sized` or `_: impl ?Sized + ?Sized`,
|
||||
// so in this case:
|
||||
// - if it's an impl trait predicate suggest changing the
|
||||
// the first bound to sized and removing the rest
|
||||
// - Otherwise simply suggest removing the entire predicate
|
||||
if predicate.origin == PredicateOrigin::ImplTrait {
|
||||
let first_bound = unsized_bounds[0].1;
|
||||
let first_bound_span = first_bound.span();
|
||||
if first_bound_span.can_be_used_for_suggestions() {
|
||||
let question_span =
|
||||
first_bound_span.with_hi(first_bound_span.lo() + BytePos(1));
|
||||
push_suggestion(
|
||||
question_span,
|
||||
String::new(),
|
||||
SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized,
|
||||
));
|
||||
);
|
||||
|
||||
for (pos, _) in unsized_bounds.iter().skip(1) {
|
||||
let sp = generics.span_for_bound_removal(where_pos, *pos);
|
||||
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let sp = generics.span_for_predicate_removal(where_pos);
|
||||
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
|
||||
}
|
||||
} else {
|
||||
// Some of the bounds are other than unsized.
|
||||
// So push separate removal suggestion for each unsized bound
|
||||
for (pos, _) in unsized_bounds {
|
||||
let sp = generics.span_for_bound_removal(where_pos, pos);
|
||||
suggestions.push((
|
||||
sp,
|
||||
String::new(),
|
||||
SuggestChangingConstraintsMessage::RemoveMaybeUnsized,
|
||||
));
|
||||
push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1268,7 +1268,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
///
|
||||
/// Returning true means the type is known to be `Freeze`. Returning
|
||||
/// `false` means nothing -- could be `Freeze`, might not be.
|
||||
fn is_trivially_freeze(self) -> bool {
|
||||
pub fn is_trivially_freeze(self) -> bool {
|
||||
match self.kind() {
|
||||
ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
|
|
|
|||
|
|
@ -528,12 +528,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
end_block.unit()
|
||||
}
|
||||
|
||||
/// Binds the variables and ascribes types for a given `match` arm or
|
||||
/// `let` binding.
|
||||
/// For a top-level `match` arm or a `let` binding, binds the variables and
|
||||
/// ascribes types, and also checks the match arm guard (if present).
|
||||
///
|
||||
/// Also check if the guard matches, if it's provided.
|
||||
/// `arm_scope` should be `Some` if and only if this is called for a
|
||||
/// `match` arm.
|
||||
///
|
||||
/// In the presence of or-patterns, a match arm might have multiple
|
||||
/// sub-branches representing different ways to match, with each sub-branch
|
||||
/// requiring its own bindings and its own copy of the guard. This method
|
||||
/// handles those sub-branches individually, and then has them jump together
|
||||
/// to a common block.
|
||||
///
|
||||
/// Returns a single block that the match arm can be lowered into.
|
||||
/// (For `let` bindings, this is the code that can use the bindings.)
|
||||
fn bind_pattern(
|
||||
&mut self,
|
||||
outer_source_info: SourceInfo,
|
||||
|
|
@ -638,12 +646,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
// Optimize the case of `let x: T = ...` to write directly
|
||||
// into `x` and then require that `T == typeof(x)`.
|
||||
//
|
||||
// Weirdly, this is needed to prevent the
|
||||
// `intrinsic-move-val.rs` test case from crashing. That
|
||||
// test works with uninitialized values in a rather
|
||||
// dubious way, so it may be that the test is kind of
|
||||
// broken.
|
||||
PatKind::AscribeUserType {
|
||||
subpattern:
|
||||
box Pat {
|
||||
|
|
@ -1022,7 +1024,8 @@ impl<'tcx> PatternExtraData<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A pattern in a form suitable for generating code.
|
||||
/// A pattern in a form suitable for lowering the match tree, with all irrefutable
|
||||
/// patterns simplified away, and or-patterns sorted to the end.
|
||||
///
|
||||
/// Here, "flat" indicates that the pattern's match pairs have been recursively
|
||||
/// simplified by [`Builder::simplify_match_pairs`]. They are not necessarily
|
||||
|
|
@ -1055,36 +1058,89 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
|
|||
ascriptions: Vec::new(),
|
||||
is_never: pattern.is_never_pattern(),
|
||||
};
|
||||
// Partly-flatten and sort the match pairs, while recording extra data.
|
||||
// Recursively remove irrefutable match pairs, while recording their
|
||||
// bindings/ascriptions, and sort or-patterns after other match pairs.
|
||||
cx.simplify_match_pairs(&mut match_pairs, &mut extra_data);
|
||||
|
||||
Self { match_pairs, extra_data }
|
||||
}
|
||||
}
|
||||
|
||||
/// Candidates are a generalization of (a) top-level match arms, and
|
||||
/// (b) sub-branches of or-patterns, allowing the match-lowering process to handle
|
||||
/// them both in a mostly-uniform way. For example, the list of candidates passed
|
||||
/// to [`Builder::match_candidates`] will often contain a mixture of top-level
|
||||
/// candidates and or-pattern subcandidates.
|
||||
///
|
||||
/// At the start of match lowering, there is one candidate for each match arm.
|
||||
/// During match lowering, arms with or-patterns will be expanded into a tree
|
||||
/// of candidates, where each "leaf" candidate represents one of the ways for
|
||||
/// the arm pattern to successfully match.
|
||||
#[derive(Debug)]
|
||||
struct Candidate<'pat, 'tcx> {
|
||||
/// For the candidate to match, all of these must be satisfied...
|
||||
// Invariant: all the match pairs are recursively simplified.
|
||||
// Invariant: or-patterns must be sorted at the end.
|
||||
///
|
||||
/// ---
|
||||
/// Initially contains a list of match pairs created by [`FlatPat`], but is
|
||||
/// subsequently mutated (in a queue-like way) while lowering the match tree.
|
||||
/// When this list becomes empty, the candidate is fully matched and becomes
|
||||
/// a leaf (see [`Builder::select_matched_candidate`]).
|
||||
///
|
||||
/// Key mutations include:
|
||||
///
|
||||
/// - When a match pair is fully satisfied by a test, it is removed from the
|
||||
/// list, and its subpairs are added instead (see [`Builder::sort_candidate`]).
|
||||
/// - During or-pattern expansion, any leading or-pattern is removed, and is
|
||||
/// converted into subcandidates (see [`Builder::expand_and_match_or_candidates`]).
|
||||
/// - After a candidate's subcandidates have been lowered, a copy of any remaining
|
||||
/// or-patterns is added to each leaf subcandidate
|
||||
/// (see [`Builder::test_remaining_match_pairs_after_or`]).
|
||||
///
|
||||
/// Invariants:
|
||||
/// - All [`TestCase::Irrefutable`] patterns have been removed by simplification.
|
||||
/// - All or-patterns ([`TestCase::Or`]) have been sorted to the end.
|
||||
match_pairs: Vec<MatchPairTree<'pat, 'tcx>>,
|
||||
|
||||
/// ...and if this is non-empty, one of these subcandidates also has to match...
|
||||
// Invariant: at the end of the algorithm, this must never contain a `is_never` candidate
|
||||
// because that would break binding consistency.
|
||||
///
|
||||
/// ---
|
||||
/// Initially a candidate has no subcandidates; they are added (and then immediately
|
||||
/// lowered) during or-pattern expansion. Their main function is to serve as _output_
|
||||
/// of match tree lowering, allowing later steps to see the leaf candidates that
|
||||
/// represent a match of the entire match arm.
|
||||
///
|
||||
/// A candidate no subcandidates is either incomplete (if it has match pairs left),
|
||||
/// or is a leaf in the match tree. A candidate with one or more subcandidates is
|
||||
/// an internal node in the match tree.
|
||||
///
|
||||
/// Invariant: at the end of match tree lowering, this must not contain an
|
||||
/// `is_never` candidate, because that would break binding consistency.
|
||||
/// - See [`Builder::remove_never_subcandidates`].
|
||||
subcandidates: Vec<Candidate<'pat, 'tcx>>,
|
||||
|
||||
/// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`.
|
||||
///
|
||||
/// ---
|
||||
/// For subcandidates, this is copied from the parent candidate, so it indicates
|
||||
/// whether the enclosing match arm has a guard.
|
||||
has_guard: bool,
|
||||
|
||||
/// If the candidate matches, bindings and ascriptions must be established.
|
||||
/// Holds extra pattern data that was prepared by [`FlatPat`], including bindings and
|
||||
/// ascriptions that must be established if this candidate succeeds.
|
||||
extra_data: PatternExtraData<'tcx>,
|
||||
|
||||
/// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from.
|
||||
// Invariant: it is `None` iff `subcandidates.is_empty()`.
|
||||
/// When setting `self.subcandidates`, we store here the span of the or-pattern they came from.
|
||||
///
|
||||
/// ---
|
||||
/// Invariant: it is `None` iff `subcandidates.is_empty()`.
|
||||
/// - FIXME: We sometimes don't unset this when clearing `subcandidates`.
|
||||
or_span: Option<Span>,
|
||||
|
||||
/// The block before the `bindings` have been established.
|
||||
///
|
||||
/// After the match tree has been lowered, [`Builder::lower_match_arms`]
|
||||
/// will use this as the start point for lowering bindings and guards, and
|
||||
/// then jump to a shared block containing the arm body.
|
||||
pre_binding_block: Option<BasicBlock>,
|
||||
|
||||
/// The block to branch to if the guard or a nested candidate fails to match.
|
||||
|
|
@ -1144,14 +1200,24 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
|
|||
|
||||
/// A depth-first traversal of the `Candidate` and all of its recursive
|
||||
/// subcandidates.
|
||||
///
|
||||
/// This signature is very generic, to support traversing candidate trees by
|
||||
/// reference or by value, and to allow a mutable "context" to be shared by the
|
||||
/// traversal callbacks. Most traversals can use the simpler
|
||||
/// [`Candidate::visit_leaves`] wrapper instead.
|
||||
fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
|
||||
candidate: C,
|
||||
context: &mut T,
|
||||
// Called when visiting a "leaf" candidate (with no subcandidates).
|
||||
visit_leaf: &mut impl FnMut(C, &mut T),
|
||||
// Called when visiting a "node" candidate (with one or more subcandidates).
|
||||
// Returns an iterator over the candidate's children (by value or reference).
|
||||
// Can perform setup before visiting the node's children.
|
||||
get_children: impl Copy + Fn(C, &mut T) -> I,
|
||||
// Called after visiting a "node" candidate's children.
|
||||
complete_children: impl Copy + Fn(&mut T),
|
||||
) where
|
||||
C: Borrow<Candidate<'pat, 'tcx>>,
|
||||
C: Borrow<Candidate<'pat, 'tcx>>, // Typically `Candidate` or `&mut Candidate`
|
||||
I: Iterator<Item = C>,
|
||||
{
|
||||
if candidate.borrow().subcandidates.is_empty() {
|
||||
|
|
@ -1182,6 +1248,24 @@ struct Ascription<'tcx> {
|
|||
variance: ty::Variance,
|
||||
}
|
||||
|
||||
/// Partial summary of a [`thir::Pat`], indicating what sort of test should be
|
||||
/// performed to match/reject the pattern, and what the desired test outcome is.
|
||||
/// This avoids having to perform a full match on [`thir::PatKind`] in some places,
|
||||
/// and helps [`TestKind::Switch`] and [`TestKind::SwitchInt`] know what target
|
||||
/// values to use.
|
||||
///
|
||||
/// Created by [`MatchPairTree::for_pattern`], and then inspected primarily by:
|
||||
/// - [`Builder::pick_test_for_match_pair`] (to choose a test)
|
||||
/// - [`Builder::sort_candidate`] (to see how the test interacts with a match pair)
|
||||
///
|
||||
/// Two variants are unlike the others and deserve special mention:
|
||||
///
|
||||
/// - [`Self::Irrefutable`] is only used temporarily when building a [`MatchPairTree`].
|
||||
/// They are then flattened away by [`Builder::simplify_match_pairs`], with any
|
||||
/// bindings/ascriptions incorporated into the enclosing [`FlatPat`].
|
||||
/// - [`Self::Or`] are not tested directly like the other variants. Instead they
|
||||
/// participate in or-pattern expansion, where they are transformed into subcandidates.
|
||||
/// - See [`Builder::expand_and_match_or_candidates`].
|
||||
#[derive(Debug, Clone)]
|
||||
enum TestCase<'pat, 'tcx> {
|
||||
Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
|
||||
|
|
@ -1224,6 +1308,12 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
|
|||
test_case: TestCase<'pat, 'tcx>,
|
||||
|
||||
/// ... and these subpairs must match.
|
||||
///
|
||||
/// ---
|
||||
/// Subpairs typically represent tests that can only be performed after their
|
||||
/// parent has succeeded. For example, the pattern `Some(3)` might have an
|
||||
/// outer match pair that tests for the variant `Some`, and then a subpair
|
||||
/// that tests its field for the value `3`.
|
||||
subpairs: Vec<Self>,
|
||||
|
||||
/// The pattern this was created from.
|
||||
|
|
@ -1234,15 +1324,22 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum TestKind<'tcx> {
|
||||
/// Test what enum variant a value is.
|
||||
///
|
||||
/// The subset of expected variants is not stored here; instead they are
|
||||
/// extracted from the [`TestCase`]s of the candidates participating in the
|
||||
/// test.
|
||||
Switch {
|
||||
/// The enum type being tested.
|
||||
adt_def: ty::AdtDef<'tcx>,
|
||||
},
|
||||
|
||||
/// Test what value an integer or `char` has.
|
||||
///
|
||||
/// The test's target values are not stored here; instead they are extracted
|
||||
/// from the [`TestCase`]s of the candidates participating in the test.
|
||||
SwitchInt,
|
||||
|
||||
/// Test what value a `bool` has.
|
||||
/// Test whether a `bool` is `true` or `false`.
|
||||
If,
|
||||
|
||||
/// Test for equality with value, possibly after an unsizing coercion to
|
||||
|
|
@ -1258,7 +1355,7 @@ enum TestKind<'tcx> {
|
|||
/// Test whether the value falls within an inclusive or exclusive range.
|
||||
Range(Box<PatRange<'tcx>>),
|
||||
|
||||
/// Test that the length of the slice is equal to `len`.
|
||||
/// Test that the length of the slice is `== len` or `>= len`.
|
||||
Len { len: u64, op: BinOp },
|
||||
|
||||
/// Call `Deref::deref[_mut]` on the value.
|
||||
|
|
@ -1385,20 +1482,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
/// The main match algorithm. It begins with a set of candidates `candidates` and has the job of
|
||||
/// generating code that branches to an appropriate block if the scrutinee matches one of these
|
||||
/// candidates. The
|
||||
/// candidates are sorted such that the first item in the list
|
||||
/// candidates are ordered such that the first item in the list
|
||||
/// has the highest priority. When a candidate is found to match
|
||||
/// the value, we will set and generate a branch to the appropriate
|
||||
/// pre-binding block.
|
||||
///
|
||||
/// If none of the candidates apply, we continue to the returned `otherwise_block`.
|
||||
///
|
||||
/// It might be surprising that the input can be non-exhaustive.
|
||||
/// Indeed, for matches, initially, it is not, because all matches are
|
||||
/// exhaustive in Rust. But during processing we sometimes divide
|
||||
/// up the list of candidates and recurse with a non-exhaustive
|
||||
/// list. This is how our lowering approach (called "backtracking
|
||||
/// automaton" in the literature) works.
|
||||
/// See [`Builder::test_candidates`] for more details.
|
||||
/// Note that while `match` expressions in the Rust language are exhaustive,
|
||||
/// candidate lists passed to this method are often _non-exhaustive_.
|
||||
/// For example, the match lowering process will frequently divide up the
|
||||
/// list of candidates, and recursively call this method with a non-exhaustive
|
||||
/// subset of candidates.
|
||||
/// See [`Builder::test_candidates`] for more details on this
|
||||
/// "backtracking automata" approach.
|
||||
///
|
||||
/// For an example of how we use `otherwise_block`, consider:
|
||||
/// ```
|
||||
|
|
@ -1478,14 +1575,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
return start_block;
|
||||
}
|
||||
[first, remaining @ ..] if first.match_pairs.is_empty() => {
|
||||
// The first candidate has satisfied all its match pairs; we link it up and continue
|
||||
// with the remaining candidates.
|
||||
// The first candidate has satisfied all its match pairs.
|
||||
// We record the blocks that will be needed by match arm lowering,
|
||||
// and then continue with the remaining candidates.
|
||||
let remainder_start = self.select_matched_candidate(first, start_block);
|
||||
remainder_start.and(remaining)
|
||||
}
|
||||
candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => {
|
||||
// If any candidate starts with an or-pattern, we have to expand the or-pattern before we
|
||||
// can proceed further.
|
||||
// If any candidate starts with an or-pattern, we want to expand or-patterns
|
||||
// before we do any more tests.
|
||||
//
|
||||
// The only candidate we strictly _need_ to expand here is the first one.
|
||||
// But by expanding other candidates as early as possible, we unlock more
|
||||
// opportunities to include them in test outcomes, making the match tree
|
||||
// smaller and simpler.
|
||||
self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates)
|
||||
}
|
||||
candidates => {
|
||||
|
|
@ -1588,6 +1691,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);
|
||||
|
||||
// Expand one level of or-patterns for each candidate in `candidates_to_expand`.
|
||||
// We take care to preserve the relative ordering of candidates, so that
|
||||
// or-patterns are expanded in their parent's relative position.
|
||||
let mut expanded_candidates = Vec::new();
|
||||
for candidate in candidates_to_expand.iter_mut() {
|
||||
if candidate.starts_with_or_pattern() {
|
||||
|
|
@ -1608,7 +1713,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Process the expanded candidates.
|
||||
// Recursively lower the part of the match tree represented by the
|
||||
// expanded candidates. This is where subcandidates actually get lowered!
|
||||
let remainder_start = self.match_candidates(
|
||||
span,
|
||||
scrutinee_span,
|
||||
|
|
@ -1628,6 +1734,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.remove_never_subcandidates(candidate);
|
||||
}
|
||||
}
|
||||
// It's important to perform the above simplifications _before_ dealing
|
||||
// with remaining match pairs, to avoid exponential blowup if possible
|
||||
// (for trivial or-patterns), and avoid useless work (for never patterns).
|
||||
if let Some(last_candidate) = candidates_to_expand.last_mut() {
|
||||
self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate);
|
||||
}
|
||||
|
|
@ -1808,6 +1917,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
.all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
|
||||
);
|
||||
|
||||
// Visit each leaf candidate within this subtree, add a copy of the remaining
|
||||
// match pairs to it, and then recursively lower the rest of the match tree
|
||||
// from that point.
|
||||
candidate.visit_leaves(|leaf_candidate| {
|
||||
// At this point the leaf's own match pairs have all been lowered
|
||||
// and removed, so `extend` and assignment are equivalent,
|
||||
|
|
@ -1860,17 +1972,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
(match_place, test)
|
||||
}
|
||||
|
||||
/// Given a test, we sort the input candidates into several buckets. If a candidate only matches
|
||||
/// in one of the branches of `test`, we move it there. If it could match in more than one of
|
||||
/// the branches of `test`, we stop sorting candidates.
|
||||
/// Given a test, we partition the input candidates into several buckets.
|
||||
/// If a candidate matches in exactly one of the branches of `test`
|
||||
/// (and no other branches), we put it into the corresponding bucket.
|
||||
/// If it could match in more than one of the branches of `test`, the test
|
||||
/// doesn't usefully apply to it, and we stop partitioning candidates.
|
||||
///
|
||||
/// Importantly, we also **mutate** the branched candidates to remove match pairs
|
||||
/// that are entailed by the outcome of the test, and add any sub-pairs of the
|
||||
/// removed pairs.
|
||||
///
|
||||
/// This returns a pair of
|
||||
/// - the candidates that weren't sorted;
|
||||
/// - for each possible outcome of the test, the candidates that match in that outcome.
|
||||
///
|
||||
/// Moreover, we transform the branched candidates to reflect the fact that we know which
|
||||
/// outcome of `test` occurred.
|
||||
///
|
||||
/// For example:
|
||||
/// ```
|
||||
/// # let (x, y, z) = (true, true, true);
|
||||
|
|
@ -1883,14 +1998,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
/// # ;
|
||||
/// ```
|
||||
///
|
||||
/// Assume we are testing on `x`. There are 2 overlapping candidate sets:
|
||||
/// - If the outcome is that `x` is true, candidates 0, 2, and 3
|
||||
/// - If the outcome is that `x` is false, candidates 1 and 2
|
||||
/// Assume we are testing on `x`. Conceptually, there are 2 overlapping candidate sets:
|
||||
/// - If the outcome is that `x` is true, candidates {0, 2, 3} are possible
|
||||
/// - If the outcome is that `x` is false, candidates {1, 2} are possible
|
||||
///
|
||||
/// Following our algorithm, candidate 0 is sorted into outcome `x == true`, candidate 1 goes
|
||||
/// into outcome `x == false`, and candidate 2 and 3 remain unsorted.
|
||||
/// Following our algorithm:
|
||||
/// - Candidate 0 is sorted into outcome `x == true`
|
||||
/// - Candidate 1 is sorted into outcome `x == false`
|
||||
/// - Candidate 2 remains unsorted, because testing `x` has no effect on it
|
||||
/// - Candidate 3 remains unsorted, because a previous candidate (2) was unsorted
|
||||
/// - This helps preserve the illusion that candidates are tested "in order"
|
||||
///
|
||||
/// The sorted candidates are transformed:
|
||||
/// The sorted candidates are mutated to remove entailed match pairs:
|
||||
/// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`;
|
||||
/// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`.
|
||||
fn sort_candidates<'b, 'c, 'pat>(
|
||||
|
|
@ -1933,15 +2052,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
(candidates, target_candidates)
|
||||
}
|
||||
|
||||
/// This is the most subtle part of the match lowering algorithm. At this point, the input
|
||||
/// candidates have been fully simplified, so all remaining match-pairs require some sort of
|
||||
/// test.
|
||||
/// This is the most subtle part of the match lowering algorithm. At this point, there are
|
||||
/// no fully-satisfied candidates, and no or-patterns to expand, so we actually need to
|
||||
/// perform some sort of test to make progress.
|
||||
///
|
||||
/// Once we pick what sort of test we are going to perform, this test will help us winnow down
|
||||
/// our candidates. So we walk over the candidates (from high to low priority) and check. We
|
||||
/// compute, for each outcome of the test, a transformed list of candidates. If a candidate
|
||||
/// matches in a single branch of our test, we add it to the corresponding outcome. We also
|
||||
/// transform it to record the fact that we know which outcome occurred.
|
||||
/// compute, for each outcome of the test, a list of (modified) candidates. If a candidate
|
||||
/// matches in exactly one branch of our test, we add it to the corresponding outcome. We also
|
||||
/// **mutate its list of match pairs** if appropriate, to reflect the fact that we know which
|
||||
/// outcome occurred.
|
||||
///
|
||||
/// For example, if we are testing `x.0`'s variant, and we have a candidate `(x.0 @ Some(v), x.1
|
||||
/// @ 22)`, then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)` in the
|
||||
|
|
@ -2036,32 +2156,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
|
||||
start_block: BasicBlock,
|
||||
) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> {
|
||||
// Extract the match-pair from the highest priority candidate and build a test from it.
|
||||
// Choose a match pair from the first candidate, and use it to determine a
|
||||
// test to perform that will confirm or refute that match pair.
|
||||
let (match_place, test) = self.pick_test(candidates);
|
||||
|
||||
// For each of the N possible test outcomes, build the vector of candidates that applies if
|
||||
// the test has that particular outcome.
|
||||
// the test has that particular outcome. This also mutates the candidates to remove match
|
||||
// pairs that are fully satisfied by the relevant outcome.
|
||||
let (remaining_candidates, target_candidates) =
|
||||
self.sort_candidates(match_place, &test, candidates);
|
||||
|
||||
// The block that we should branch to if none of the
|
||||
// `target_candidates` match.
|
||||
// The block that we should branch to if none of the `target_candidates` match.
|
||||
let remainder_start = self.cfg.start_new_block();
|
||||
|
||||
// For each outcome of test, process the candidates that still apply.
|
||||
// For each outcome of the test, recursively lower the rest of the match tree
|
||||
// from that point. (Note that we haven't lowered the actual test yet!)
|
||||
let target_blocks: FxIndexMap<_, _> = target_candidates
|
||||
.into_iter()
|
||||
.map(|(branch, mut candidates)| {
|
||||
let branch_start = self.cfg.start_new_block();
|
||||
// Recursively lower the rest of the match tree after the relevant outcome.
|
||||
let branch_otherwise =
|
||||
self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates);
|
||||
|
||||
// Link up the `otherwise` block of the subtree to `remainder_start`.
|
||||
let source_info = self.source_info(span);
|
||||
self.cfg.goto(branch_otherwise, source_info, remainder_start);
|
||||
(branch, branch_start)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Perform the test, branching to one of N blocks.
|
||||
// Perform the chosen test, branching to one of the N subtrees prepared above
|
||||
// (or to `remainder_start` if no outcome was satisfied).
|
||||
self.perform_test(
|
||||
span,
|
||||
scrutinee_span,
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
TestCase::Never => TestKind::Never,
|
||||
|
||||
// Or-patterns are not tested directly; instead they are expanded into subcandidates,
|
||||
// which are then distinguished by testing whatever non-or patterns they contain.
|
||||
TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
|
||||
|
||||
TestCase::Irrefutable { .. } => span_bug!(
|
||||
|
|
@ -544,6 +546,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
.enumerate()
|
||||
.find(|&(_, mp)| mp.place == Some(test_place))?;
|
||||
|
||||
// If true, the match pair is completely entailed by its corresponding test
|
||||
// branch, so it can be removed. If false, the match pair is _compatible_
|
||||
// with its test branch, but still needs a more specific test.
|
||||
let fully_matched;
|
||||
let ret = match (&test.kind, &match_pair.test_case) {
|
||||
// If we are performing a variant switch, then this
|
||||
|
|
@ -565,8 +570,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
(TestKind::SwitchInt, &TestCase::Constant { value })
|
||||
if is_switch_ty(match_pair.pattern.ty) =>
|
||||
{
|
||||
// Beware: there might be some ranges sorted into the failure case; we must not add
|
||||
// a success case that could be matched by one of these ranges.
|
||||
// An important invariant of candidate sorting is that a candidate
|
||||
// must not match in multiple branches. For `SwitchInt` tests, adding
|
||||
// a new value might invalidate that property for range patterns that
|
||||
// have already been sorted into the failure arm, so we must take care
|
||||
// not to add such values here.
|
||||
let is_covering_range = |test_case: &TestCase<'_, 'tcx>| {
|
||||
test_case.as_range().is_some_and(|range| {
|
||||
matches!(range.contains(value, self.tcx, self.param_env), None | Some(true))
|
||||
|
|
@ -591,6 +599,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
(TestKind::SwitchInt, TestCase::Range(range)) => {
|
||||
// When performing a `SwitchInt` test, a range pattern can be
|
||||
// sorted into the failure arm if it doesn't contain _any_ of
|
||||
// the values being tested. (This restricts what values can be
|
||||
// added to the test by subsequent candidates.)
|
||||
fully_matched = false;
|
||||
let not_contained =
|
||||
sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use super::{
|
|||
|
||||
use crate::errors;
|
||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||
use ast::mut_visit::{noop_visit_expr, MutVisitor};
|
||||
use ast::mut_visit::{self, MutVisitor};
|
||||
use ast::token::IdentIsRaw;
|
||||
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
|
||||
use core::mem;
|
||||
|
|
@ -3939,14 +3939,14 @@ impl MutVisitor for CondChecker<'_> {
|
|||
}
|
||||
}
|
||||
ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
|
||||
noop_visit_expr(e, self);
|
||||
mut_visit::walk_expr(self, e);
|
||||
}
|
||||
ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
|
||||
if let None | Some(NotSupportedOr(_)) = self.forbid_let_reason =>
|
||||
{
|
||||
let forbid_let_reason = self.forbid_let_reason;
|
||||
self.forbid_let_reason = Some(NotSupportedOr(or_span));
|
||||
noop_visit_expr(e, self);
|
||||
mut_visit::walk_expr(self, e);
|
||||
self.forbid_let_reason = forbid_let_reason;
|
||||
}
|
||||
ExprKind::Paren(ref inner)
|
||||
|
|
@ -3954,7 +3954,7 @@ impl MutVisitor for CondChecker<'_> {
|
|||
{
|
||||
let forbid_let_reason = self.forbid_let_reason;
|
||||
self.forbid_let_reason = Some(NotSupportedParentheses(inner.span));
|
||||
noop_visit_expr(e, self);
|
||||
mut_visit::walk_expr(self, e);
|
||||
self.forbid_let_reason = forbid_let_reason;
|
||||
}
|
||||
ExprKind::Assign(ref lhs, _, span) => {
|
||||
|
|
@ -3972,7 +3972,7 @@ impl MutVisitor for CondChecker<'_> {
|
|||
}
|
||||
let comparison = self.comparison;
|
||||
self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() });
|
||||
noop_visit_expr(e, self);
|
||||
mut_visit::walk_expr(self, e);
|
||||
self.forbid_let_reason = forbid_let_reason;
|
||||
self.missing_let = missing_let;
|
||||
self.comparison = comparison;
|
||||
|
|
@ -3992,7 +3992,7 @@ impl MutVisitor for CondChecker<'_> {
|
|||
| ExprKind::Paren(_) => {
|
||||
let forbid_let_reason = self.forbid_let_reason;
|
||||
self.forbid_let_reason = Some(OtherForbidden);
|
||||
noop_visit_expr(e, self);
|
||||
mut_visit::walk_expr(self, e);
|
||||
self.forbid_let_reason = forbid_let_reason;
|
||||
}
|
||||
ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::errors::{
|
|||
};
|
||||
use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr};
|
||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
||||
use rustc_ast::mut_visit::{walk_pat, MutVisitor};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
|
||||
use rustc_ast::{
|
||||
|
|
@ -810,7 +810,7 @@ impl<'a> Parser<'a> {
|
|||
self.0 = true;
|
||||
*m = Mutability::Mut;
|
||||
}
|
||||
noop_visit_pat(pat, self);
|
||||
walk_pat(self, pat);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -772,7 +772,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
ty::Alias(ty::Opaque, _) => {
|
||||
ty::Alias(ty::Opaque, alias) => {
|
||||
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) {
|
||||
// We do not generate an auto impl candidate for `impl Trait`s which already
|
||||
// reference our auto trait.
|
||||
|
|
@ -787,6 +787,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// We do not emit auto trait candidates for opaque types in coherence.
|
||||
// Doing so can result in weird dependency cycles.
|
||||
candidates.ambiguous = true;
|
||||
} else if self.infcx.can_define_opaque_ty(alias.def_id) {
|
||||
// We do not emit auto trait candidates for opaque types in their defining scope, as
|
||||
// we need to know the hidden type first, which we can't reliably know within the defining
|
||||
// scope.
|
||||
candidates.ambiguous = true;
|
||||
} else {
|
||||
candidates.vec.push(AutoImplCandidate)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1498,7 +1498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Avoid using the master cache during coherence and just rely
|
||||
// Avoid using the global cache during coherence and just rely
|
||||
// on the local cache. This effectively disables caching
|
||||
// during coherence. It is really just a simplification to
|
||||
// avoid us having to fear that coherence results "pollute"
|
||||
|
|
@ -1509,6 +1509,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Avoid using the global cache when we're defining opaque types
|
||||
// as their hidden type may impact the result of candidate selection.
|
||||
if !self.infcx.defining_opaque_types().is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, we can use the global cache.
|
||||
true
|
||||
}
|
||||
|
|
@ -2380,13 +2386,17 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
}
|
||||
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
|
||||
// We can resolve the `impl Trait` to its concrete type,
|
||||
// which enforces a DAG between the functions requiring
|
||||
// the auto trait bounds in question.
|
||||
match self.tcx().type_of_opaque(def_id) {
|
||||
Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
|
||||
Err(_) => {
|
||||
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
|
||||
if self.infcx.can_define_opaque_ty(def_id) {
|
||||
unreachable!()
|
||||
} else {
|
||||
// We can resolve the `impl Trait` to its concrete type,
|
||||
// which enforces a DAG between the functions requiring
|
||||
// the auto trait bounds in question.
|
||||
match self.tcx().type_of_opaque(def_id) {
|
||||
Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
|
||||
Err(_) => {
|
||||
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -484,7 +484,7 @@ impl<T: Ord, A: Allocator> BinaryHeap<T, A> {
|
|||
/// heap.push(4);
|
||||
/// ```
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "112353")]
|
||||
#[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "125961")]
|
||||
#[must_use]
|
||||
pub const fn new_in(alloc: A) -> BinaryHeap<T, A> {
|
||||
BinaryHeap { data: Vec::new_in(alloc) }
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@
|
|||
#![feature(array_windows)]
|
||||
#![feature(ascii_char)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(async_closure)]
|
||||
#![feature(async_fn_traits)]
|
||||
#![feature(async_iterator)]
|
||||
#![feature(clone_to_uninit)]
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ use core::intrinsics::abort;
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::iter;
|
||||
use core::marker::{PhantomData, Unsize};
|
||||
use core::mem::{self, align_of_val_raw, forget, ManuallyDrop};
|
||||
use core::mem::{self, align_of_val_raw, ManuallyDrop};
|
||||
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver};
|
||||
use core::panic::{RefUnwindSafe, UnwindSafe};
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
|
|
@ -908,19 +908,18 @@ impl<T, A: Allocator> Rc<T, A> {
|
|||
#[stable(feature = "rc_unique", since = "1.4.0")]
|
||||
pub fn try_unwrap(this: Self) -> Result<T, Self> {
|
||||
if Rc::strong_count(&this) == 1 {
|
||||
unsafe {
|
||||
let val = ptr::read(&*this); // copy the contained object
|
||||
let alloc = ptr::read(&this.alloc); // copy the allocator
|
||||
let this = ManuallyDrop::new(this);
|
||||
|
||||
// Indicate to Weaks that they can't be promoted by decrementing
|
||||
// the strong count, and then remove the implicit "strong weak"
|
||||
// pointer while also handling drop logic by just crafting a
|
||||
// fake Weak.
|
||||
this.inner().dec_strong();
|
||||
let _weak = Weak { ptr: this.ptr, alloc };
|
||||
forget(this);
|
||||
Ok(val)
|
||||
}
|
||||
let val: T = unsafe { ptr::read(&**this) }; // copy the contained object
|
||||
let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator
|
||||
|
||||
// Indicate to Weaks that they can't be promoted by decrementing
|
||||
// the strong count, and then remove the implicit "strong weak"
|
||||
// pointer while also handling drop logic by just crafting a
|
||||
// fake Weak.
|
||||
this.inner().dec_strong();
|
||||
let _weak = Weak { ptr: this.ptr, alloc };
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(this)
|
||||
}
|
||||
|
|
@ -1354,9 +1353,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
|
|||
#[stable(feature = "rc_raw", since = "1.17.0")]
|
||||
#[rustc_never_returns_null_ptr]
|
||||
pub fn into_raw(this: Self) -> *const T {
|
||||
let ptr = Self::as_ptr(&this);
|
||||
mem::forget(this);
|
||||
ptr
|
||||
let this = ManuallyDrop::new(this);
|
||||
Self::as_ptr(&*this)
|
||||
}
|
||||
|
||||
/// Consumes the `Rc`, returning the wrapped pointer and allocator.
|
||||
|
|
@ -2127,7 +2125,7 @@ impl<T> Rc<[T]> {
|
|||
}
|
||||
|
||||
// All clear. Forget the guard so it doesn't free the new RcBox.
|
||||
forget(guard);
|
||||
mem::forget(guard);
|
||||
|
||||
Self::from_ptr(ptr)
|
||||
}
|
||||
|
|
@ -3080,9 +3078,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
|
|||
#[must_use = "losing the pointer will leak memory"]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn into_raw(self) -> *const T {
|
||||
let result = self.as_ptr();
|
||||
mem::forget(self);
|
||||
result
|
||||
mem::ManuallyDrop::new(self).as_ptr()
|
||||
}
|
||||
|
||||
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
|
||||
|
|
@ -3762,10 +3758,11 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
|
|||
/// # Safety
|
||||
///
|
||||
/// The data must have been initialized (by writing to [`Self::data_ptr()`]).
|
||||
unsafe fn into_rc(mut self) -> Rc<T, A> {
|
||||
let ptr = self.ptr;
|
||||
let alloc = self.alloc.take().unwrap();
|
||||
mem::forget(self);
|
||||
unsafe fn into_rc(self) -> Rc<T, A> {
|
||||
let mut this = ManuallyDrop::new(self);
|
||||
let ptr = this.ptr;
|
||||
let alloc = this.alloc.take().unwrap();
|
||||
|
||||
// SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible
|
||||
// for having initialized the data.
|
||||
unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) }
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ impl str {
|
|||
without modifying the original"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
|
||||
pub fn replace<P: Pattern>(&self, from: P, to: &str) -> String {
|
||||
let mut result = String::new();
|
||||
let mut last_end = 0;
|
||||
for (start, part) in self.match_indices(from) {
|
||||
|
|
@ -309,7 +309,7 @@ impl str {
|
|||
#[must_use = "this returns the replaced string as a new allocation, \
|
||||
without modifying the original"]
|
||||
#[stable(feature = "str_replacen", since = "1.16.0")]
|
||||
pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String {
|
||||
pub fn replacen<P: Pattern>(&self, pat: P, to: &str, count: usize) -> String {
|
||||
// Hope to reduce the times of re-allocation
|
||||
let mut result = String::with_capacity(32);
|
||||
let mut last_end = 0;
|
||||
|
|
|
|||
|
|
@ -1497,10 +1497,7 @@ impl String {
|
|||
/// ```
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")]
|
||||
pub fn remove_matches<'a, P>(&'a mut self, pat: P)
|
||||
where
|
||||
P: for<'x> Pattern<'x>,
|
||||
{
|
||||
pub fn remove_matches<P: Pattern>(&mut self, pat: P) {
|
||||
use core::str::pattern::Searcher;
|
||||
|
||||
let rejections = {
|
||||
|
|
@ -2288,35 +2285,41 @@ impl<'a> Extend<Cow<'a, str>> for String {
|
|||
reason = "API not fully fleshed out and ready to be stabilized",
|
||||
issue = "27721"
|
||||
)]
|
||||
impl<'a, 'b> Pattern<'a> for &'b String {
|
||||
type Searcher = <&'b str as Pattern<'a>>::Searcher;
|
||||
impl<'b> Pattern for &'b String {
|
||||
type Searcher<'a> = <&'b str as Pattern>::Searcher<'a>;
|
||||
|
||||
fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher {
|
||||
fn into_searcher(self, haystack: &str) -> <&'b str as Pattern>::Searcher<'_> {
|
||||
self[..].into_searcher(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_contained_in(self, haystack: &'a str) -> bool {
|
||||
fn is_contained_in(self, haystack: &str) -> bool {
|
||||
self[..].is_contained_in(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_prefix_of(self, haystack: &'a str) -> bool {
|
||||
fn is_prefix_of(self, haystack: &str) -> bool {
|
||||
self[..].is_prefix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
|
||||
fn strip_prefix_of(self, haystack: &str) -> Option<&str> {
|
||||
self[..].strip_prefix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_suffix_of(self, haystack: &'a str) -> bool {
|
||||
fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
|
||||
where
|
||||
Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
|
||||
{
|
||||
self[..].is_suffix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> {
|
||||
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&str>
|
||||
where
|
||||
Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
|
||||
{
|
||||
self[..].strip_suffix_of(haystack)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use core::intrinsics::abort;
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::iter;
|
||||
use core::marker::{PhantomData, Unsize};
|
||||
use core::mem::{self, align_of_val_raw};
|
||||
use core::mem::{self, align_of_val_raw, ManuallyDrop};
|
||||
use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver};
|
||||
use core::panic::{RefUnwindSafe, UnwindSafe};
|
||||
use core::pin::Pin;
|
||||
|
|
@ -960,16 +960,14 @@ impl<T, A: Allocator> Arc<T, A> {
|
|||
|
||||
acquire!(this.inner().strong);
|
||||
|
||||
unsafe {
|
||||
let elem = ptr::read(&this.ptr.as_ref().data);
|
||||
let alloc = ptr::read(&this.alloc); // copy the allocator
|
||||
let this = ManuallyDrop::new(this);
|
||||
let elem: T = unsafe { ptr::read(&this.ptr.as_ref().data) };
|
||||
let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator
|
||||
|
||||
// Make a weak pointer to clean up the implicit strong-weak reference
|
||||
let _weak = Weak { ptr: this.ptr, alloc };
|
||||
mem::forget(this);
|
||||
// Make a weak pointer to clean up the implicit strong-weak reference
|
||||
let _weak = Weak { ptr: this.ptr, alloc };
|
||||
|
||||
Ok(elem)
|
||||
}
|
||||
Ok(elem)
|
||||
}
|
||||
|
||||
/// Returns the inner value, if the `Arc` has exactly one strong reference.
|
||||
|
|
@ -1493,9 +1491,8 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
|
|||
#[stable(feature = "rc_raw", since = "1.17.0")]
|
||||
#[rustc_never_returns_null_ptr]
|
||||
pub fn into_raw(this: Self) -> *const T {
|
||||
let ptr = Self::as_ptr(&this);
|
||||
mem::forget(this);
|
||||
ptr
|
||||
let this = ManuallyDrop::new(this);
|
||||
Self::as_ptr(&*this)
|
||||
}
|
||||
|
||||
/// Consumes the `Arc`, returning the wrapped pointer and allocator.
|
||||
|
|
@ -2801,9 +2798,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
|
|||
#[must_use = "losing the pointer will leak memory"]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn into_raw(self) -> *const T {
|
||||
let result = self.as_ptr();
|
||||
mem::forget(self);
|
||||
result
|
||||
ManuallyDrop::new(self).as_ptr()
|
||||
}
|
||||
|
||||
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
|
||||
|
|
@ -3875,13 +3870,14 @@ impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
|
|||
/// # Safety
|
||||
///
|
||||
/// The data must have been initialized (by writing to [`Self::data_ptr()`]).
|
||||
unsafe fn into_arc(mut self) -> Arc<T, A> {
|
||||
let ptr = self.ptr;
|
||||
let alloc = self.alloc.take().unwrap();
|
||||
mem::forget(self);
|
||||
unsafe fn into_arc(self) -> Arc<T, A> {
|
||||
let mut this = ManuallyDrop::new(self);
|
||||
let ptr = this.ptr.as_ptr();
|
||||
let alloc = this.alloc.take().unwrap();
|
||||
|
||||
// SAFETY: The pointer is valid as per `UniqueArcUninit::new`, and the caller is responsible
|
||||
// for having initialized the data.
|
||||
unsafe { Arc::from_ptr_in(ptr.as_ptr(), alloc) }
|
||||
unsafe { Arc::from_ptr_in(ptr, alloc) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1927,12 +1927,10 @@ mod pattern {
|
|||
}
|
||||
}
|
||||
|
||||
fn cmp_search_to_vec<'a>(
|
||||
rev: bool,
|
||||
pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
haystack: &'a str,
|
||||
right: Vec<SearchStep>,
|
||||
) {
|
||||
fn cmp_search_to_vec<P>(rev: bool, pat: P, haystack: &str, right: Vec<SearchStep>)
|
||||
where
|
||||
P: for<'a> Pattern<Searcher<'a>: ReverseSearcher<'a>>,
|
||||
{
|
||||
let mut searcher = pat.into_searcher(haystack);
|
||||
let mut v = vec![];
|
||||
loop {
|
||||
|
|
@ -2191,9 +2189,9 @@ generate_iterator_test! {
|
|||
fn different_str_pattern_forwarding_lifetimes() {
|
||||
use std::str::pattern::Pattern;
|
||||
|
||||
fn foo<'a, P>(p: P)
|
||||
fn foo<P>(p: P)
|
||||
where
|
||||
for<'b> &'b P: Pattern<'a>,
|
||||
for<'b> &'b P: Pattern,
|
||||
{
|
||||
for _ in 0..3 {
|
||||
"asdf".find(&p);
|
||||
|
|
|
|||
|
|
@ -183,6 +183,8 @@ impl Layout {
|
|||
/// - a [slice], then the length of the slice tail must be an initialized
|
||||
/// integer, and the size of the *entire value*
|
||||
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
|
||||
/// For the special case where the dynamic tail length is 0, this function
|
||||
/// is safe to call.
|
||||
/// - a [trait object], then the vtable part of the pointer must point
|
||||
/// to a valid vtable for the type `T` acquired by an unsizing coercion,
|
||||
/// and the size of the *entire value*
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ where
|
|||
/// ```
|
||||
///
|
||||
#[unstable(feature = "error_generic_member_access", issue = "99301")]
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
#[repr(transparent)]
|
||||
pub struct Request<'a>(Tagged<dyn Erased<'a> + 'a>);
|
||||
|
||||
impl<'a> Request<'a> {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ use crate::str;
|
|||
// However, `CStr` layout is considered an implementation detail and must not be relied upon. We
|
||||
// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
|
||||
// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
|
||||
#[cfg_attr(not(doc), repr(transparent))]
|
||||
#[repr(transparent)]
|
||||
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||
pub struct CStr {
|
||||
// FIXME: this should not be represented with a DST slice but rather with
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ mod c_long_definition {
|
|||
// be UB.
|
||||
#[doc = include_str!("c_void.md")]
|
||||
#[lang = "c_void"]
|
||||
#[cfg_attr(not(doc), repr(u8))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc
|
||||
#[stable(feature = "core_c_void", since = "1.30.0")]
|
||||
pub enum c_void {
|
||||
#[unstable(
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use crate::ops::{Deref, DerefMut};
|
|||
target_os = "uefi",
|
||||
windows,
|
||||
))]
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
#[repr(transparent)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f> {
|
||||
ptr: *mut c_void,
|
||||
|
|
@ -115,7 +115,7 @@ pub struct VaListImpl<'f> {
|
|||
}
|
||||
|
||||
/// A wrapper for a `va_list`
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct VaList<'a, 'f: 'a> {
|
||||
#[cfg(any(
|
||||
|
|
|
|||
|
|
@ -359,6 +359,12 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
/// - a [slice], then the length of the slice tail must be an initialized
|
||||
/// integer, and the size of the *entire value*
|
||||
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
|
||||
/// For the special case where the dynamic tail length is 0, this function
|
||||
/// is safe to call.
|
||||
// NOTE: the reason this is safe is that if an overflow were to occur already with size 0,
|
||||
// then we would stop compilation as even the "statically known" part of the type would
|
||||
// already be too big (or the call may be in dead code and optimized away, but then it
|
||||
// doesn't matter).
|
||||
/// - a [trait object], then the vtable part of the pointer must point
|
||||
/// to a valid vtable acquired by an unsizing coercion, and the size
|
||||
/// of the *entire value* (dynamic tail length + statically sized prefix)
|
||||
|
|
@ -506,6 +512,8 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
/// - a [slice], then the length of the slice tail must be an initialized
|
||||
/// integer, and the size of the *entire value*
|
||||
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
|
||||
/// For the special case where the dynamic tail length is 0, this function
|
||||
/// is safe to call.
|
||||
/// - a [trait object], then the vtable part of the pointer must point
|
||||
/// to a valid vtable acquired by an unsizing coercion, and the size
|
||||
/// of the *entire value* (dynamic tail length + statically sized prefix)
|
||||
|
|
|
|||
|
|
@ -65,8 +65,13 @@ macro_rules! uint_impl {
|
|||
///
|
||||
/// ```
|
||||
#[doc = concat!("let n = 0b01001100", stringify!($SelfT), ";")]
|
||||
///
|
||||
/// assert_eq!(n.count_ones(), 3);
|
||||
///
|
||||
#[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
|
||||
#[doc = concat!("assert_eq!(max.count_ones(), ", stringify!($BITS), ");")]
|
||||
///
|
||||
#[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
|
||||
/// assert_eq!(zero.count_ones(), 0);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_math", since = "1.32.0")]
|
||||
|
|
@ -86,7 +91,11 @@ macro_rules! uint_impl {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);")]
|
||||
#[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
|
||||
#[doc = concat!("assert_eq!(zero.count_zeros(), ", stringify!($BITS), ");")]
|
||||
///
|
||||
#[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
|
||||
/// assert_eq!(max.count_zeros(), 0);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_math", since = "1.32.0")]
|
||||
|
|
@ -108,8 +117,13 @@ macro_rules! uint_impl {
|
|||
///
|
||||
/// ```
|
||||
#[doc = concat!("let n = ", stringify!($SelfT), "::MAX >> 2;")]
|
||||
///
|
||||
/// assert_eq!(n.leading_zeros(), 2);
|
||||
///
|
||||
#[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
|
||||
#[doc = concat!("assert_eq!(zero.leading_zeros(), ", stringify!($BITS), ");")]
|
||||
///
|
||||
#[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
|
||||
/// assert_eq!(max.leading_zeros(), 0);
|
||||
/// ```
|
||||
#[doc = concat!("[`ilog2`]: ", stringify!($SelfT), "::ilog2")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -130,8 +144,13 @@ macro_rules! uint_impl {
|
|||
///
|
||||
/// ```
|
||||
#[doc = concat!("let n = 0b0101000", stringify!($SelfT), ";")]
|
||||
///
|
||||
/// assert_eq!(n.trailing_zeros(), 3);
|
||||
///
|
||||
#[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
|
||||
#[doc = concat!("assert_eq!(zero.trailing_zeros(), ", stringify!($BITS), ");")]
|
||||
///
|
||||
#[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
|
||||
#[doc = concat!("assert_eq!(max.trailing_zeros(), 0);")]
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_math", since = "1.32.0")]
|
||||
|
|
@ -150,8 +169,13 @@ macro_rules! uint_impl {
|
|||
///
|
||||
/// ```
|
||||
#[doc = concat!("let n = !(", stringify!($SelfT), "::MAX >> 2);")]
|
||||
///
|
||||
/// assert_eq!(n.leading_ones(), 2);
|
||||
///
|
||||
#[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
|
||||
/// assert_eq!(zero.leading_ones(), 0);
|
||||
///
|
||||
#[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
|
||||
#[doc = concat!("assert_eq!(max.leading_ones(), ", stringify!($BITS), ");")]
|
||||
/// ```
|
||||
#[stable(feature = "leading_trailing_ones", since = "1.46.0")]
|
||||
#[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
|
||||
|
|
@ -171,8 +195,13 @@ macro_rules! uint_impl {
|
|||
///
|
||||
/// ```
|
||||
#[doc = concat!("let n = 0b1010111", stringify!($SelfT), ";")]
|
||||
///
|
||||
/// assert_eq!(n.trailing_ones(), 3);
|
||||
///
|
||||
#[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
|
||||
/// assert_eq!(zero.trailing_ones(), 0);
|
||||
///
|
||||
#[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
|
||||
#[doc = concat!("assert_eq!(max.trailing_ones(), ", stringify!($BITS), ");")]
|
||||
/// ```
|
||||
#[stable(feature = "leading_trailing_ones", since = "1.46.0")]
|
||||
#[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
|
||||
|
|
@ -736,6 +765,67 @@ macro_rules! uint_impl {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = concat!(
|
||||
"Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`",
|
||||
stringify!($SignedT), "`], returning `None` if overflow occurred."
|
||||
)]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(unsigned_signed_diff)]
|
||||
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_signed_diff(2), Some(8));")]
|
||||
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_signed_diff(10), Some(-8));")]
|
||||
#[doc = concat!(
|
||||
"assert_eq!(",
|
||||
stringify!($SelfT),
|
||||
"::MAX.checked_signed_diff(",
|
||||
stringify!($SignedT),
|
||||
"::MAX as ",
|
||||
stringify!($SelfT),
|
||||
"), None);"
|
||||
)]
|
||||
#[doc = concat!(
|
||||
"assert_eq!((",
|
||||
stringify!($SignedT),
|
||||
"::MAX as ",
|
||||
stringify!($SelfT),
|
||||
").checked_signed_diff(",
|
||||
stringify!($SelfT),
|
||||
"::MAX), Some(",
|
||||
stringify!($SignedT),
|
||||
"::MIN));"
|
||||
)]
|
||||
#[doc = concat!(
|
||||
"assert_eq!((",
|
||||
stringify!($SignedT),
|
||||
"::MAX as ",
|
||||
stringify!($SelfT),
|
||||
" + 1).checked_signed_diff(0), None);"
|
||||
)]
|
||||
#[doc = concat!(
|
||||
"assert_eq!(",
|
||||
stringify!($SelfT),
|
||||
"::MAX.checked_signed_diff(",
|
||||
stringify!($SelfT),
|
||||
"::MAX), Some(0));"
|
||||
)]
|
||||
/// ```
|
||||
#[unstable(feature = "unsigned_signed_diff", issue = "126041")]
|
||||
#[inline]
|
||||
pub const fn checked_signed_diff(self, rhs: Self) -> Option<$SignedT> {
|
||||
let res = self.wrapping_sub(rhs) as $SignedT;
|
||||
let overflow = (self >= rhs) == (res < 0);
|
||||
|
||||
if !overflow {
|
||||
Some(res)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked integer multiplication. Computes `self * rhs`, returning
|
||||
/// `None` if overflow occurred.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::marker::Tuple;
|
|||
/// An async-aware version of the [`Fn`](crate::ops::Fn) trait.
|
||||
///
|
||||
/// All `async fn` and functions returning futures implement this trait.
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[unstable(feature = "async_closure", issue = "62290")]
|
||||
#[rustc_paren_sugar]
|
||||
#[fundamental]
|
||||
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||
|
|
@ -18,7 +18,7 @@ pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> {
|
|||
/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait.
|
||||
///
|
||||
/// All `async fn` and functions returning futures implement this trait.
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[unstable(feature = "async_closure", issue = "62290")]
|
||||
#[rustc_paren_sugar]
|
||||
#[fundamental]
|
||||
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||
|
|
@ -39,7 +39,7 @@ pub trait AsyncFnMut<Args: Tuple>: AsyncFnOnce<Args> {
|
|||
/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait.
|
||||
///
|
||||
/// All `async fn` and functions returning futures implement this trait.
|
||||
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||
#[unstable(feature = "async_closure", issue = "62290")]
|
||||
#[rustc_paren_sugar]
|
||||
#[fundamental]
|
||||
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
//! const SOME_PROPERTY: bool = true;
|
||||
//! }
|
||||
//!
|
||||
//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; }
|
||||
//! # trait QueryId { const SOME_PROPERTY: ::core::primitive::bool; }
|
||||
//! ```
|
||||
//!
|
||||
//! Note that the `SOME_PROPERTY` associated constant would not compile, as its
|
||||
|
|
@ -25,11 +25,17 @@
|
|||
//! pub struct bool;
|
||||
//!
|
||||
//! impl QueryId for bool {
|
||||
//! const SOME_PROPERTY: core::primitive::bool = true;
|
||||
//! const SOME_PROPERTY: ::core::primitive::bool = true;
|
||||
//! }
|
||||
//!
|
||||
//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; }
|
||||
//! # trait QueryId { const SOME_PROPERTY: ::core::primitive::bool; }
|
||||
//! ```
|
||||
//!
|
||||
//! We also used `::core` instead of `core`, because `core` can be
|
||||
//! shadowed, too. Paths, starting with `::`, are searched in
|
||||
//! the [extern prelude] since Edition 2018.
|
||||
//!
|
||||
//! [extern prelude]: https://doc.rust-lang.org/nightly/reference/names/preludes.html#extern-prelude
|
||||
|
||||
#[stable(feature = "core_primitive", since = "1.43.0")]
|
||||
pub use bool;
|
||||
|
|
|
|||
|
|
@ -4522,6 +4522,121 @@ impl<T> [T] {
|
|||
// are disjunct and in bounds.
|
||||
unsafe { Ok(self.get_many_unchecked_mut(indices)) }
|
||||
}
|
||||
|
||||
/// Returns the index that an element reference points to.
|
||||
///
|
||||
/// Returns `None` if `element` does not point within the slice or if it points between elements.
|
||||
///
|
||||
/// This method is useful for extending slice iterators like [`slice::split`].
|
||||
///
|
||||
/// Note that this uses pointer arithmetic and **does not compare elements**.
|
||||
/// To find the index of an element via comparison, use
|
||||
/// [`.iter().position()`](crate::iter::Iterator::position) instead.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if `T` is zero-sized.
|
||||
///
|
||||
/// # Examples
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// #![feature(substr_range)]
|
||||
///
|
||||
/// let nums: &[u32] = &[1, 7, 1, 1];
|
||||
/// let num = &nums[2];
|
||||
///
|
||||
/// assert_eq!(num, &1);
|
||||
/// assert_eq!(nums.elem_offset(num), Some(2));
|
||||
/// ```
|
||||
/// Returning `None` with an in-between element:
|
||||
/// ```
|
||||
/// #![feature(substr_range)]
|
||||
///
|
||||
/// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]];
|
||||
/// let flat_arr: &[u32] = arr.as_flattened();
|
||||
///
|
||||
/// let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap();
|
||||
/// let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap();
|
||||
///
|
||||
/// assert_eq!(ok_elm, &[0, 1]);
|
||||
/// assert_eq!(weird_elm, &[1, 2]);
|
||||
///
|
||||
/// assert_eq!(arr.elem_offset(ok_elm), Some(0)); // Points to element 0
|
||||
/// assert_eq!(arr.elem_offset(weird_elm), None); // Points between element 0 and 1
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "substr_range", issue = "126769")]
|
||||
pub fn elem_offset(&self, element: &T) -> Option<usize> {
|
||||
if T::IS_ZST {
|
||||
panic!("elements are zero-sized");
|
||||
}
|
||||
|
||||
let self_start = self.as_ptr() as usize;
|
||||
let elem_start = element as *const T as usize;
|
||||
|
||||
let byte_offset = elem_start.wrapping_sub(self_start);
|
||||
|
||||
if byte_offset % mem::size_of::<T>() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let offset = byte_offset / mem::size_of::<T>();
|
||||
|
||||
if offset < self.len() { Some(offset) } else { None }
|
||||
}
|
||||
|
||||
/// Returns the range of indices that a subslice points to.
|
||||
///
|
||||
/// Returns `None` if `subslice` does not point within the slice or if it points between elements.
|
||||
///
|
||||
/// This method **does not compare elements**. Instead, this method finds the location in the slice that
|
||||
/// `subslice` was obtained from. To find the index of a subslice via comparison, instead use
|
||||
/// [`.windows()`](slice::windows)[`.position()`](crate::iter::Iterator::position).
|
||||
///
|
||||
/// This method is useful for extending slice iterators like [`slice::split`].
|
||||
///
|
||||
/// Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`)
|
||||
/// if `subslice` has a length of zero and points to the beginning or end of another, separate, slice.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if `T` is zero-sized.
|
||||
///
|
||||
/// # Examples
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// #![feature(substr_range)]
|
||||
///
|
||||
/// let nums = &[0, 5, 10, 0, 0, 5];
|
||||
///
|
||||
/// let mut iter = nums
|
||||
/// .split(|t| *t == 0)
|
||||
/// .map(|n| nums.subslice_range(n).unwrap());
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(0..0));
|
||||
/// assert_eq!(iter.next(), Some(1..3));
|
||||
/// assert_eq!(iter.next(), Some(4..4));
|
||||
/// assert_eq!(iter.next(), Some(5..6));
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "substr_range", issue = "126769")]
|
||||
pub fn subslice_range(&self, subslice: &[T]) -> Option<Range<usize>> {
|
||||
if T::IS_ZST {
|
||||
panic!("elements are zero-sized");
|
||||
}
|
||||
|
||||
let self_start = self.as_ptr() as usize;
|
||||
let subslice_start = subslice.as_ptr() as usize;
|
||||
|
||||
let byte_start = subslice_start.wrapping_sub(self_start);
|
||||
|
||||
if byte_start % core::mem::size_of::<T>() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start = byte_start / core::mem::size_of::<T>();
|
||||
let end = start.wrapping_add(subslice.len());
|
||||
|
||||
if start <= self.len() && end <= self.len() { Some(start..end) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> [[T; N]] {
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ macro_rules! derive_pattern_clone {
|
|||
(clone $t:ident with |$s:ident| $e:expr) => {
|
||||
impl<'a, P> Clone for $t<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: Clone>,
|
||||
P: Pattern<Searcher<'a>: Clone>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
let $s = self;
|
||||
|
|
@ -424,7 +424,7 @@ macro_rules! derive_pattern_clone {
|
|||
/// This macro generates two public iterator structs
|
||||
/// wrapping a private internal one that makes use of the `Pattern` API.
|
||||
///
|
||||
/// For all patterns `P: Pattern<'a>` the following items will be
|
||||
/// For all patterns `P: Pattern` the following items will be
|
||||
/// generated (generics omitted):
|
||||
///
|
||||
/// struct $forward_iterator($internal_iterator);
|
||||
|
|
@ -484,12 +484,12 @@ macro_rules! generate_pattern_iterators {
|
|||
} => {
|
||||
$(#[$forward_iterator_attribute])*
|
||||
$(#[$common_stability_attribute])*
|
||||
pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>);
|
||||
pub struct $forward_iterator<'a, P: Pattern>(pub(super) $internal_iterator<'a, P>);
|
||||
|
||||
$(#[$common_stability_attribute])*
|
||||
impl<'a, P> fmt::Debug for $forward_iterator<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: fmt::Debug>,
|
||||
P: Pattern<Searcher<'a>: fmt::Debug>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple(stringify!($forward_iterator))
|
||||
|
|
@ -499,7 +499,7 @@ macro_rules! generate_pattern_iterators {
|
|||
}
|
||||
|
||||
$(#[$common_stability_attribute])*
|
||||
impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> {
|
||||
impl<'a, P: Pattern> Iterator for $forward_iterator<'a, P> {
|
||||
type Item = $iterty;
|
||||
|
||||
#[inline]
|
||||
|
|
@ -511,7 +511,7 @@ macro_rules! generate_pattern_iterators {
|
|||
$(#[$common_stability_attribute])*
|
||||
impl<'a, P> Clone for $forward_iterator<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: Clone>,
|
||||
P: Pattern<Searcher<'a>: Clone>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
$forward_iterator(self.0.clone())
|
||||
|
|
@ -520,12 +520,12 @@ macro_rules! generate_pattern_iterators {
|
|||
|
||||
$(#[$reverse_iterator_attribute])*
|
||||
$(#[$common_stability_attribute])*
|
||||
pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>);
|
||||
pub struct $reverse_iterator<'a, P: Pattern>(pub(super) $internal_iterator<'a, P>);
|
||||
|
||||
$(#[$common_stability_attribute])*
|
||||
impl<'a, P> fmt::Debug for $reverse_iterator<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: fmt::Debug>,
|
||||
P: Pattern<Searcher<'a>: fmt::Debug>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple(stringify!($reverse_iterator))
|
||||
|
|
@ -537,7 +537,7 @@ macro_rules! generate_pattern_iterators {
|
|||
$(#[$common_stability_attribute])*
|
||||
impl<'a, P> Iterator for $reverse_iterator<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
P: Pattern<Searcher<'a>: ReverseSearcher<'a>>,
|
||||
{
|
||||
type Item = $iterty;
|
||||
|
||||
|
|
@ -550,7 +550,7 @@ macro_rules! generate_pattern_iterators {
|
|||
$(#[$common_stability_attribute])*
|
||||
impl<'a, P> Clone for $reverse_iterator<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: Clone>,
|
||||
P: Pattern<Searcher<'a>: Clone>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
$reverse_iterator(self.0.clone())
|
||||
|
|
@ -558,12 +558,12 @@ macro_rules! generate_pattern_iterators {
|
|||
}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {}
|
||||
impl<'a, P: Pattern> FusedIterator for $forward_iterator<'a, P> {}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<'a, P> FusedIterator for $reverse_iterator<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
P: Pattern<Searcher<'a>: ReverseSearcher<'a>>,
|
||||
{}
|
||||
|
||||
generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*,
|
||||
|
|
@ -578,7 +578,7 @@ macro_rules! generate_pattern_iterators {
|
|||
$(#[$common_stability_attribute])*
|
||||
impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
|
||||
P: Pattern<Searcher<'a>: DoubleEndedSearcher<'a>>,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<$iterty> {
|
||||
|
|
@ -589,7 +589,7 @@ macro_rules! generate_pattern_iterators {
|
|||
$(#[$common_stability_attribute])*
|
||||
impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
|
||||
P: Pattern<Searcher<'a>: DoubleEndedSearcher<'a>>,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<$iterty> {
|
||||
|
|
@ -609,17 +609,17 @@ derive_pattern_clone! {
|
|||
with |s| SplitInternal { matcher: s.matcher.clone(), ..*s }
|
||||
}
|
||||
|
||||
pub(super) struct SplitInternal<'a, P: Pattern<'a>> {
|
||||
pub(super) struct SplitInternal<'a, P: Pattern> {
|
||||
pub(super) start: usize,
|
||||
pub(super) end: usize,
|
||||
pub(super) matcher: P::Searcher,
|
||||
pub(super) matcher: P::Searcher<'a>,
|
||||
pub(super) allow_trailing_empty: bool,
|
||||
pub(super) finished: bool,
|
||||
}
|
||||
|
||||
impl<'a, P> fmt::Debug for SplitInternal<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: fmt::Debug>,
|
||||
P: Pattern<Searcher<'a>: fmt::Debug>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SplitInternal")
|
||||
|
|
@ -632,7 +632,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
|
||||
impl<'a, P: Pattern> SplitInternal<'a, P> {
|
||||
#[inline]
|
||||
fn get_end(&mut self) -> Option<&'a str> {
|
||||
if !self.finished {
|
||||
|
|
@ -689,7 +689,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
|
|||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a str>
|
||||
where
|
||||
P::Searcher: ReverseSearcher<'a>,
|
||||
P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
if self.finished {
|
||||
return None;
|
||||
|
|
@ -726,7 +726,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
|
|||
#[inline]
|
||||
fn next_back_inclusive(&mut self) -> Option<&'a str>
|
||||
where
|
||||
P::Searcher: ReverseSearcher<'a>,
|
||||
P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
if self.finished {
|
||||
return None;
|
||||
|
|
@ -796,7 +796,7 @@ generate_pattern_iterators! {
|
|||
delegate double ended;
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> Split<'a, P> {
|
||||
impl<'a, P: Pattern> Split<'a, P> {
|
||||
/// Returns remainder of the split string.
|
||||
///
|
||||
/// If the iterator is empty, returns `None`.
|
||||
|
|
@ -819,7 +819,7 @@ impl<'a, P: Pattern<'a>> Split<'a, P> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> RSplit<'a, P> {
|
||||
impl<'a, P: Pattern> RSplit<'a, P> {
|
||||
/// Returns remainder of the split string.
|
||||
///
|
||||
/// If the iterator is empty, returns `None`.
|
||||
|
|
@ -860,7 +860,7 @@ generate_pattern_iterators! {
|
|||
delegate double ended;
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
|
||||
impl<'a, P: Pattern> SplitTerminator<'a, P> {
|
||||
/// Returns remainder of the split string.
|
||||
///
|
||||
/// If the iterator is empty, returns `None`.
|
||||
|
|
@ -883,7 +883,7 @@ impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
|
||||
impl<'a, P: Pattern> RSplitTerminator<'a, P> {
|
||||
/// Returns remainder of the split string.
|
||||
///
|
||||
/// If the iterator is empty, returns `None`.
|
||||
|
|
@ -911,7 +911,7 @@ derive_pattern_clone! {
|
|||
with |s| SplitNInternal { iter: s.iter.clone(), ..*s }
|
||||
}
|
||||
|
||||
pub(super) struct SplitNInternal<'a, P: Pattern<'a>> {
|
||||
pub(super) struct SplitNInternal<'a, P: Pattern> {
|
||||
pub(super) iter: SplitInternal<'a, P>,
|
||||
/// The number of splits remaining
|
||||
pub(super) count: usize,
|
||||
|
|
@ -919,7 +919,7 @@ pub(super) struct SplitNInternal<'a, P: Pattern<'a>> {
|
|||
|
||||
impl<'a, P> fmt::Debug for SplitNInternal<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: fmt::Debug>,
|
||||
P: Pattern<Searcher<'a>: fmt::Debug>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SplitNInternal")
|
||||
|
|
@ -929,7 +929,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
|
||||
impl<'a, P: Pattern> SplitNInternal<'a, P> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a str> {
|
||||
match self.count {
|
||||
|
|
@ -948,7 +948,7 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
|
|||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a str>
|
||||
where
|
||||
P::Searcher: ReverseSearcher<'a>,
|
||||
P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
match self.count {
|
||||
0 => None,
|
||||
|
|
@ -987,7 +987,7 @@ generate_pattern_iterators! {
|
|||
delegate single ended;
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> SplitN<'a, P> {
|
||||
impl<'a, P: Pattern> SplitN<'a, P> {
|
||||
/// Returns remainder of the split string.
|
||||
///
|
||||
/// If the iterator is empty, returns `None`.
|
||||
|
|
@ -1010,7 +1010,7 @@ impl<'a, P: Pattern<'a>> SplitN<'a, P> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
|
||||
impl<'a, P: Pattern> RSplitN<'a, P> {
|
||||
/// Returns remainder of the split string.
|
||||
///
|
||||
/// If the iterator is empty, returns `None`.
|
||||
|
|
@ -1038,18 +1038,18 @@ derive_pattern_clone! {
|
|||
with |s| MatchIndicesInternal(s.0.clone())
|
||||
}
|
||||
|
||||
pub(super) struct MatchIndicesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher);
|
||||
pub(super) struct MatchIndicesInternal<'a, P: Pattern>(pub(super) P::Searcher<'a>);
|
||||
|
||||
impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: fmt::Debug>,
|
||||
P: Pattern<Searcher<'a>: fmt::Debug>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("MatchIndicesInternal").field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
|
||||
impl<'a, P: Pattern> MatchIndicesInternal<'a, P> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(usize, &'a str)> {
|
||||
self.0
|
||||
|
|
@ -1061,7 +1061,7 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
|
|||
#[inline]
|
||||
fn next_back(&mut self) -> Option<(usize, &'a str)>
|
||||
where
|
||||
P::Searcher: ReverseSearcher<'a>,
|
||||
P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
self.0
|
||||
.next_match_back()
|
||||
|
|
@ -1093,18 +1093,18 @@ derive_pattern_clone! {
|
|||
with |s| MatchesInternal(s.0.clone())
|
||||
}
|
||||
|
||||
pub(super) struct MatchesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher);
|
||||
pub(super) struct MatchesInternal<'a, P: Pattern>(pub(super) P::Searcher<'a>);
|
||||
|
||||
impl<'a, P> fmt::Debug for MatchesInternal<'a, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: fmt::Debug>,
|
||||
P: Pattern<Searcher<'a>: fmt::Debug>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("MatchesInternal").field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> {
|
||||
impl<'a, P: Pattern> MatchesInternal<'a, P> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a str> {
|
||||
// SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
|
||||
|
|
@ -1117,7 +1117,7 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> {
|
|||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a str>
|
||||
where
|
||||
P::Searcher: ReverseSearcher<'a>,
|
||||
P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
// SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
|
||||
self.0.next_match_back().map(|(a, b)| unsafe {
|
||||
|
|
@ -1288,7 +1288,7 @@ pub struct SplitAsciiWhitespace<'a> {
|
|||
///
|
||||
/// [`split_inclusive`]: str::split_inclusive
|
||||
#[stable(feature = "split_inclusive", since = "1.51.0")]
|
||||
pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>);
|
||||
pub struct SplitInclusive<'a, P: Pattern>(pub(super) SplitInternal<'a, P>);
|
||||
|
||||
#[stable(feature = "split_whitespace", since = "1.1.0")]
|
||||
impl<'a> Iterator for SplitWhitespace<'a> {
|
||||
|
|
@ -1410,7 +1410,7 @@ impl<'a> SplitAsciiWhitespace<'a> {
|
|||
}
|
||||
|
||||
#[stable(feature = "split_inclusive", since = "1.51.0")]
|
||||
impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> {
|
||||
impl<'a, P: Pattern> Iterator for SplitInclusive<'a, P> {
|
||||
type Item = &'a str;
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1420,7 +1420,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> {
|
|||
}
|
||||
|
||||
#[stable(feature = "split_inclusive", since = "1.51.0")]
|
||||
impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> {
|
||||
impl<'a, P: Pattern<Searcher<'a>: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SplitInclusive").field("0", &self.0).finish()
|
||||
}
|
||||
|
|
@ -1428,14 +1428,14 @@ impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a,
|
|||
|
||||
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
|
||||
#[stable(feature = "split_inclusive", since = "1.51.0")]
|
||||
impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> {
|
||||
impl<'a, P: Pattern<Searcher<'a>: Clone>> Clone for SplitInclusive<'a, P> {
|
||||
fn clone(&self) -> Self {
|
||||
SplitInclusive(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "split_inclusive", since = "1.51.0")]
|
||||
impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator
|
||||
impl<'a, P: Pattern<Searcher<'a>: DoubleEndedSearcher<'a>>> DoubleEndedIterator
|
||||
for SplitInclusive<'a, P>
|
||||
{
|
||||
#[inline]
|
||||
|
|
@ -1445,9 +1445,9 @@ impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator
|
|||
}
|
||||
|
||||
#[stable(feature = "split_inclusive", since = "1.51.0")]
|
||||
impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
|
||||
impl<'a, P: Pattern> FusedIterator for SplitInclusive<'a, P> {}
|
||||
|
||||
impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
|
||||
impl<'a, P: Pattern> SplitInclusive<'a, P> {
|
||||
/// Returns remainder of the split string.
|
||||
///
|
||||
/// If the iterator is empty, returns `None`.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
|
|||
use crate::ascii;
|
||||
use crate::char::{self, EscapeDebugExtArgs};
|
||||
use crate::mem;
|
||||
use crate::ops::Range;
|
||||
use crate::slice::{self, SliceIndex};
|
||||
|
||||
pub mod pattern;
|
||||
|
|
@ -1137,7 +1138,7 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
|
||||
pub fn contains<P: Pattern>(&self, pat: P) -> bool {
|
||||
pat.is_contained_in(self)
|
||||
}
|
||||
|
||||
|
|
@ -1174,7 +1175,7 @@ impl str {
|
|||
/// assert!(bananas.starts_with(&['a', 'b', 'c', 'd']));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
|
||||
pub fn starts_with<P: Pattern>(&self, pat: P) -> bool {
|
||||
pat.is_prefix_of(self)
|
||||
}
|
||||
|
||||
|
|
@ -1198,9 +1199,9 @@ impl str {
|
|||
/// assert!(!bananas.ends_with("nana"));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn ends_with<'a, P>(&'a self, pat: P) -> bool
|
||||
pub fn ends_with<P: Pattern>(&self, pat: P) -> bool
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
pat.is_suffix_of(self)
|
||||
}
|
||||
|
|
@ -1249,7 +1250,7 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
|
||||
pub fn find<P: Pattern>(&self, pat: P) -> Option<usize> {
|
||||
pat.into_searcher(self).next_match().map(|(i, _)| i)
|
||||
}
|
||||
|
||||
|
|
@ -1295,9 +1296,9 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn rfind<'a, P>(&'a self, pat: P) -> Option<usize>
|
||||
pub fn rfind<P: Pattern>(&self, pat: P) -> Option<usize>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
pat.into_searcher(self).next_match_back().map(|(i, _)| i)
|
||||
}
|
||||
|
|
@ -1417,7 +1418,7 @@ impl str {
|
|||
/// [`split_whitespace`]: str::split_whitespace
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
|
||||
pub fn split<P: Pattern>(&self, pat: P) -> Split<'_, P> {
|
||||
Split(SplitInternal {
|
||||
start: 0,
|
||||
end: self.len(),
|
||||
|
|
@ -1457,7 +1458,7 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "split_inclusive", since = "1.51.0")]
|
||||
#[inline]
|
||||
pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> {
|
||||
pub fn split_inclusive<P: Pattern>(&self, pat: P) -> SplitInclusive<'_, P> {
|
||||
SplitInclusive(SplitInternal {
|
||||
start: 0,
|
||||
end: self.len(),
|
||||
|
|
@ -1512,9 +1513,9 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P>
|
||||
pub fn rsplit<P: Pattern>(&self, pat: P) -> RSplit<'_, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
RSplit(self.split(pat).0)
|
||||
}
|
||||
|
|
@ -1561,7 +1562,7 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
|
||||
pub fn split_terminator<P: Pattern>(&self, pat: P) -> SplitTerminator<'_, P> {
|
||||
SplitTerminator(SplitInternal { allow_trailing_empty: false, ..self.split(pat).0 })
|
||||
}
|
||||
|
||||
|
|
@ -1607,9 +1608,9 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P>
|
||||
pub fn rsplit_terminator<P: Pattern>(&self, pat: P) -> RSplitTerminator<'_, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
RSplitTerminator(self.split_terminator(pat).0)
|
||||
}
|
||||
|
|
@ -1662,7 +1663,7 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
|
||||
pub fn splitn<P: Pattern>(&self, n: usize, pat: P) -> SplitN<'_, P> {
|
||||
SplitN(SplitNInternal { iter: self.split(pat).0, count: n })
|
||||
}
|
||||
|
||||
|
|
@ -1711,9 +1712,9 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
|
||||
pub fn rsplitn<P: Pattern>(&self, n: usize, pat: P) -> RSplitN<'_, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
RSplitN(self.splitn(n, pat).0)
|
||||
}
|
||||
|
|
@ -1731,7 +1732,7 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "str_split_once", since = "1.52.0")]
|
||||
#[inline]
|
||||
pub fn split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> {
|
||||
pub fn split_once<P: Pattern>(&self, delimiter: P) -> Option<(&'_ str, &'_ str)> {
|
||||
let (start, end) = delimiter.into_searcher(self).next_match()?;
|
||||
// SAFETY: `Searcher` is known to return valid indices.
|
||||
unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) }
|
||||
|
|
@ -1749,9 +1750,9 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "str_split_once", since = "1.52.0")]
|
||||
#[inline]
|
||||
pub fn rsplit_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)>
|
||||
pub fn rsplit_once<P: Pattern>(&self, delimiter: P) -> Option<(&'_ str, &'_ str)>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
let (start, end) = delimiter.into_searcher(self).next_match_back()?;
|
||||
// SAFETY: `Searcher` is known to return valid indices.
|
||||
|
|
@ -1789,7 +1790,7 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "str_matches", since = "1.2.0")]
|
||||
#[inline]
|
||||
pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
|
||||
pub fn matches<P: Pattern>(&self, pat: P) -> Matches<'_, P> {
|
||||
Matches(MatchesInternal(pat.into_searcher(self)))
|
||||
}
|
||||
|
||||
|
|
@ -1823,9 +1824,9 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "str_matches", since = "1.2.0")]
|
||||
#[inline]
|
||||
pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P>
|
||||
pub fn rmatches<P: Pattern>(&self, pat: P) -> RMatches<'_, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
RMatches(self.matches(pat).0)
|
||||
}
|
||||
|
|
@ -1867,7 +1868,7 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "str_match_indices", since = "1.5.0")]
|
||||
#[inline]
|
||||
pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
|
||||
pub fn match_indices<P: Pattern>(&self, pat: P) -> MatchIndices<'_, P> {
|
||||
MatchIndices(MatchIndicesInternal(pat.into_searcher(self)))
|
||||
}
|
||||
|
||||
|
|
@ -1907,9 +1908,9 @@ impl str {
|
|||
/// ```
|
||||
#[stable(feature = "str_match_indices", since = "1.5.0")]
|
||||
#[inline]
|
||||
pub fn rmatch_indices<'a, P>(&'a self, pat: P) -> RMatchIndices<'a, P>
|
||||
pub fn rmatch_indices<P: Pattern>(&self, pat: P) -> RMatchIndices<'_, P>
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
RMatchIndices(self.match_indices(pat).0)
|
||||
}
|
||||
|
|
@ -2122,9 +2123,9 @@ impl str {
|
|||
#[must_use = "this returns the trimmed string as a new slice, \
|
||||
without modifying the original"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str
|
||||
pub fn trim_matches<P: Pattern>(&self, pat: P) -> &str
|
||||
where
|
||||
P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: DoubleEndedSearcher<'a>,
|
||||
{
|
||||
let mut i = 0;
|
||||
let mut j = 0;
|
||||
|
|
@ -2169,7 +2170,7 @@ impl str {
|
|||
#[must_use = "this returns the trimmed string as a new slice, \
|
||||
without modifying the original"]
|
||||
#[stable(feature = "trim_direction", since = "1.30.0")]
|
||||
pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
|
||||
pub fn trim_start_matches<P: Pattern>(&self, pat: P) -> &str {
|
||||
let mut i = self.len();
|
||||
let mut matcher = pat.into_searcher(self);
|
||||
if let Some((a, _)) = matcher.next_reject() {
|
||||
|
|
@ -2202,7 +2203,7 @@ impl str {
|
|||
#[must_use = "this returns the remaining substring as a new slice, \
|
||||
without modifying the original"]
|
||||
#[stable(feature = "str_strip", since = "1.45.0")]
|
||||
pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> {
|
||||
pub fn strip_prefix<P: Pattern>(&self, prefix: P) -> Option<&str> {
|
||||
prefix.strip_prefix_of(self)
|
||||
}
|
||||
|
||||
|
|
@ -2229,10 +2230,9 @@ impl str {
|
|||
#[must_use = "this returns the remaining substring as a new slice, \
|
||||
without modifying the original"]
|
||||
#[stable(feature = "str_strip", since = "1.45.0")]
|
||||
pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str>
|
||||
pub fn strip_suffix<P: Pattern>(&self, suffix: P) -> Option<&str>
|
||||
where
|
||||
P: Pattern<'a>,
|
||||
<P as Pattern<'a>>::Searcher: ReverseSearcher<'a>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
suffix.strip_suffix_of(self)
|
||||
}
|
||||
|
|
@ -2273,9 +2273,9 @@ impl str {
|
|||
#[must_use = "this returns the trimmed string as a new slice, \
|
||||
without modifying the original"]
|
||||
#[stable(feature = "trim_direction", since = "1.30.0")]
|
||||
pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str
|
||||
pub fn trim_end_matches<P: Pattern>(&self, pat: P) -> &str
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
let mut j = 0;
|
||||
let mut matcher = pat.into_searcher(self);
|
||||
|
|
@ -2317,7 +2317,7 @@ impl str {
|
|||
note = "superseded by `trim_start_matches`",
|
||||
suggestion = "trim_start_matches"
|
||||
)]
|
||||
pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
|
||||
pub fn trim_left_matches<P: Pattern>(&self, pat: P) -> &str {
|
||||
self.trim_start_matches(pat)
|
||||
}
|
||||
|
||||
|
|
@ -2360,9 +2360,9 @@ impl str {
|
|||
note = "superseded by `trim_end_matches`",
|
||||
suggestion = "trim_end_matches"
|
||||
)]
|
||||
pub fn trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str
|
||||
pub fn trim_right_matches<P: Pattern>(&self, pat: P) -> &str
|
||||
where
|
||||
P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
self.trim_end_matches(pat)
|
||||
}
|
||||
|
|
@ -2721,6 +2721,39 @@ impl str {
|
|||
pub fn escape_unicode(&self) -> EscapeUnicode<'_> {
|
||||
EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) }
|
||||
}
|
||||
|
||||
/// Returns the range that a substring points to.
|
||||
///
|
||||
/// Returns `None` if `substr` does not point within `self`.
|
||||
///
|
||||
/// Unlike [`str::find`], **this does not search through the string**.
|
||||
/// Instead, it uses pointer arithmetic to find where in the string
|
||||
/// `substr` is derived from.
|
||||
///
|
||||
/// This is useful for extending [`str::split`] and similar methods.
|
||||
///
|
||||
/// Note that this method may return false positives (typically either
|
||||
/// `Some(0..0)` or `Some(self.len()..self.len())`) if `substr` is a
|
||||
/// zero-length `str` that points at the beginning or end of another,
|
||||
/// independent, `str`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(substr_range)]
|
||||
///
|
||||
/// let data = "a, b, b, a";
|
||||
/// let mut iter = data.split(", ").map(|s| data.substr_range(s).unwrap());
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(0..1));
|
||||
/// assert_eq!(iter.next(), Some(3..4));
|
||||
/// assert_eq!(iter.next(), Some(6..7));
|
||||
/// assert_eq!(iter.next(), Some(9..10));
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "substr_range", issue = "126769")]
|
||||
pub fn substr_range(&self, substr: &str) -> Option<Range<usize>> {
|
||||
self.as_bytes().subslice_range(substr.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ use crate::slice::memchr;
|
|||
|
||||
/// A string pattern.
|
||||
///
|
||||
/// A `Pattern<'a>` expresses that the implementing type
|
||||
/// can be used as a string pattern for searching in a [`&'a str`][str].
|
||||
/// A `Pattern` expresses that the implementing type
|
||||
/// can be used as a string pattern for searching in a [`&str`][str].
|
||||
///
|
||||
/// For example, both `'a'` and `"aa"` are patterns that
|
||||
/// would match at index `1` in the string `"baaaab"`.
|
||||
|
|
@ -97,38 +97,38 @@ use crate::slice::memchr;
|
|||
/// assert_eq!("abcdef_z".find(|ch| ch > 'd' && ch < 'y'), Some(4));
|
||||
/// assert_eq!("abcddd_z".find(|ch| ch > 'd' && ch < 'y'), None);
|
||||
/// ```
|
||||
pub trait Pattern<'a>: Sized {
|
||||
pub trait Pattern: Sized {
|
||||
/// Associated searcher for this pattern
|
||||
type Searcher: Searcher<'a>;
|
||||
type Searcher<'a>: Searcher<'a>;
|
||||
|
||||
/// Constructs the associated searcher from
|
||||
/// `self` and the `haystack` to search in.
|
||||
fn into_searcher(self, haystack: &'a str) -> Self::Searcher;
|
||||
fn into_searcher(self, haystack: &str) -> Self::Searcher<'_>;
|
||||
|
||||
/// Checks whether the pattern matches anywhere in the haystack
|
||||
#[inline]
|
||||
fn is_contained_in(self, haystack: &'a str) -> bool {
|
||||
fn is_contained_in(self, haystack: &str) -> bool {
|
||||
self.into_searcher(haystack).next_match().is_some()
|
||||
}
|
||||
|
||||
/// Checks whether the pattern matches at the front of the haystack
|
||||
#[inline]
|
||||
fn is_prefix_of(self, haystack: &'a str) -> bool {
|
||||
fn is_prefix_of(self, haystack: &str) -> bool {
|
||||
matches!(self.into_searcher(haystack).next(), SearchStep::Match(0, _))
|
||||
}
|
||||
|
||||
/// Checks whether the pattern matches at the back of the haystack
|
||||
#[inline]
|
||||
fn is_suffix_of(self, haystack: &'a str) -> bool
|
||||
fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
|
||||
where
|
||||
Self::Searcher: ReverseSearcher<'a>,
|
||||
Self::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j)
|
||||
}
|
||||
|
||||
/// Removes the pattern from the front of haystack, if it matches.
|
||||
#[inline]
|
||||
fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
|
||||
fn strip_prefix_of(self, haystack: &str) -> Option<&str> {
|
||||
if let SearchStep::Match(start, len) = self.into_searcher(haystack).next() {
|
||||
debug_assert_eq!(
|
||||
start, 0,
|
||||
|
|
@ -144,9 +144,9 @@ pub trait Pattern<'a>: Sized {
|
|||
|
||||
/// Removes the pattern from the back of haystack, if it matches.
|
||||
#[inline]
|
||||
fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
|
||||
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
|
||||
where
|
||||
Self::Searcher: ReverseSearcher<'a>,
|
||||
Self::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
if let SearchStep::Match(start, end) = self.into_searcher(haystack).next_back() {
|
||||
debug_assert_eq!(
|
||||
|
|
@ -349,7 +349,7 @@ pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {}
|
|||
// Impl for char
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Associated type for `<char as Pattern<'a>>::Searcher`.
|
||||
/// Associated type for `<char as Pattern>::Searcher<'a>`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CharSearcher<'a> {
|
||||
haystack: &'a str,
|
||||
|
|
@ -543,11 +543,11 @@ impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {}
|
|||
/// ```
|
||||
/// assert_eq!("Hello world".find('o'), Some(4));
|
||||
/// ```
|
||||
impl<'a> Pattern<'a> for char {
|
||||
type Searcher = CharSearcher<'a>;
|
||||
impl Pattern for char {
|
||||
type Searcher<'a> = CharSearcher<'a>;
|
||||
|
||||
#[inline]
|
||||
fn into_searcher(self, haystack: &'a str) -> Self::Searcher {
|
||||
fn into_searcher(self, haystack: &str) -> Self::Searcher<'_> {
|
||||
let mut utf8_encoded = [0; 4];
|
||||
let utf8_size = self
|
||||
.encode_utf8(&mut utf8_encoded)
|
||||
|
|
@ -566,7 +566,7 @@ impl<'a> Pattern<'a> for char {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn is_contained_in(self, haystack: &'a str) -> bool {
|
||||
fn is_contained_in(self, haystack: &str) -> bool {
|
||||
if (self as u32) < 128 {
|
||||
haystack.as_bytes().contains(&(self as u8))
|
||||
} else {
|
||||
|
|
@ -576,27 +576,27 @@ impl<'a> Pattern<'a> for char {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn is_prefix_of(self, haystack: &'a str) -> bool {
|
||||
fn is_prefix_of(self, haystack: &str) -> bool {
|
||||
self.encode_utf8(&mut [0u8; 4]).is_prefix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
|
||||
fn strip_prefix_of(self, haystack: &str) -> Option<&str> {
|
||||
self.encode_utf8(&mut [0u8; 4]).strip_prefix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_suffix_of(self, haystack: &'a str) -> bool
|
||||
fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
|
||||
where
|
||||
Self::Searcher: ReverseSearcher<'a>,
|
||||
Self::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
|
||||
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
|
||||
where
|
||||
Self::Searcher: ReverseSearcher<'a>,
|
||||
Self::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
self.encode_utf8(&mut [0u8; 4]).strip_suffix_of(haystack)
|
||||
}
|
||||
|
|
@ -651,11 +651,11 @@ struct MultiCharEqSearcher<'a, C: MultiCharEq> {
|
|||
char_indices: super::CharIndices<'a>,
|
||||
}
|
||||
|
||||
impl<'a, C: MultiCharEq> Pattern<'a> for MultiCharEqPattern<C> {
|
||||
type Searcher = MultiCharEqSearcher<'a, C>;
|
||||
impl<C: MultiCharEq> Pattern for MultiCharEqPattern<C> {
|
||||
type Searcher<'a> = MultiCharEqSearcher<'a, C>;
|
||||
|
||||
#[inline]
|
||||
fn into_searcher(self, haystack: &'a str) -> MultiCharEqSearcher<'a, C> {
|
||||
fn into_searcher(self, haystack: &str) -> MultiCharEqSearcher<'_, C> {
|
||||
MultiCharEqSearcher { haystack, char_eq: self.0, char_indices: haystack.char_indices() }
|
||||
}
|
||||
}
|
||||
|
|
@ -710,41 +710,41 @@ impl<'a, C: MultiCharEq> DoubleEndedSearcher<'a> for MultiCharEqSearcher<'a, C>
|
|||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! pattern_methods {
|
||||
($t:ty, $pmap:expr, $smap:expr) => {
|
||||
type Searcher = $t;
|
||||
($a:lifetime, $t:ty, $pmap:expr, $smap:expr) => {
|
||||
type Searcher<$a> = $t;
|
||||
|
||||
#[inline]
|
||||
fn into_searcher(self, haystack: &'a str) -> $t {
|
||||
fn into_searcher<$a>(self, haystack: &$a str) -> $t {
|
||||
($smap)(($pmap)(self).into_searcher(haystack))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_contained_in(self, haystack: &'a str) -> bool {
|
||||
fn is_contained_in<$a>(self, haystack: &$a str) -> bool {
|
||||
($pmap)(self).is_contained_in(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_prefix_of(self, haystack: &'a str) -> bool {
|
||||
fn is_prefix_of<$a>(self, haystack: &$a str) -> bool {
|
||||
($pmap)(self).is_prefix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
|
||||
fn strip_prefix_of<$a>(self, haystack: &$a str) -> Option<&$a str> {
|
||||
($pmap)(self).strip_prefix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_suffix_of(self, haystack: &'a str) -> bool
|
||||
fn is_suffix_of<$a>(self, haystack: &$a str) -> bool
|
||||
where
|
||||
$t: ReverseSearcher<'a>,
|
||||
$t: ReverseSearcher<$a>,
|
||||
{
|
||||
($pmap)(self).is_suffix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
|
||||
fn strip_suffix_of<$a>(self, haystack: &$a str) -> Option<&$a str>
|
||||
where
|
||||
$t: ReverseSearcher<'a>,
|
||||
$t: ReverseSearcher<$a>,
|
||||
{
|
||||
($pmap)(self).strip_suffix_of(haystack)
|
||||
}
|
||||
|
|
@ -786,16 +786,16 @@ macro_rules! searcher_methods {
|
|||
};
|
||||
}
|
||||
|
||||
/// Associated type for `<[char; N] as Pattern<'a>>::Searcher`.
|
||||
/// Associated type for `<[char; N] as Pattern>::Searcher<'a>`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CharArraySearcher<'a, const N: usize>(
|
||||
<MultiCharEqPattern<[char; N]> as Pattern<'a>>::Searcher,
|
||||
<MultiCharEqPattern<[char; N]> as Pattern>::Searcher<'a>,
|
||||
);
|
||||
|
||||
/// Associated type for `<&[char; N] as Pattern<'a>>::Searcher`.
|
||||
/// Associated type for `<&[char; N] as Pattern>::Searcher<'a>`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CharArrayRefSearcher<'a, 'b, const N: usize>(
|
||||
<MultiCharEqPattern<&'b [char; N]> as Pattern<'a>>::Searcher,
|
||||
<MultiCharEqPattern<&'b [char; N]> as Pattern>::Searcher<'a>,
|
||||
);
|
||||
|
||||
/// Searches for chars that are equal to any of the [`char`]s in the array.
|
||||
|
|
@ -806,8 +806,8 @@ pub struct CharArrayRefSearcher<'a, 'b, const N: usize>(
|
|||
/// assert_eq!("Hello world".find(['o', 'l']), Some(2));
|
||||
/// assert_eq!("Hello world".find(['h', 'w']), Some(6));
|
||||
/// ```
|
||||
impl<'a, const N: usize> Pattern<'a> for [char; N] {
|
||||
pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher);
|
||||
impl<const N: usize> Pattern for [char; N] {
|
||||
pattern_methods!('a, CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher);
|
||||
}
|
||||
|
||||
unsafe impl<'a, const N: usize> Searcher<'a> for CharArraySearcher<'a, N> {
|
||||
|
|
@ -828,8 +828,8 @@ impl<'a, const N: usize> DoubleEndedSearcher<'a> for CharArraySearcher<'a, N> {}
|
|||
/// assert_eq!("Hello world".find(&['o', 'l']), Some(2));
|
||||
/// assert_eq!("Hello world".find(&['h', 'w']), Some(6));
|
||||
/// ```
|
||||
impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] {
|
||||
pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher);
|
||||
impl<'b, const N: usize> Pattern for &'b [char; N] {
|
||||
pattern_methods!('a, CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher);
|
||||
}
|
||||
|
||||
unsafe impl<'a, 'b, const N: usize> Searcher<'a> for CharArrayRefSearcher<'a, 'b, N> {
|
||||
|
|
@ -848,9 +848,9 @@ impl<'a, 'b, const N: usize> DoubleEndedSearcher<'a> for CharArrayRefSearcher<'a
|
|||
|
||||
// Todo: Change / Remove due to ambiguity in meaning.
|
||||
|
||||
/// Associated type for `<&[char] as Pattern<'a>>::Searcher`.
|
||||
/// Associated type for `<&[char] as Pattern>::Searcher<'a>`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CharSliceSearcher<'a, 'b>(<MultiCharEqPattern<&'b [char]> as Pattern<'a>>::Searcher);
|
||||
pub struct CharSliceSearcher<'a, 'b>(<MultiCharEqPattern<&'b [char]> as Pattern>::Searcher<'a>);
|
||||
|
||||
unsafe impl<'a, 'b> Searcher<'a> for CharSliceSearcher<'a, 'b> {
|
||||
searcher_methods!(forward);
|
||||
|
|
@ -870,17 +870,17 @@ impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {}
|
|||
/// assert_eq!("Hello world".find(&['l', 'l'] as &[_]), Some(2));
|
||||
/// assert_eq!("Hello world".find(&['l', 'l'][..]), Some(2));
|
||||
/// ```
|
||||
impl<'a, 'b> Pattern<'a> for &'b [char] {
|
||||
pattern_methods!(CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher);
|
||||
impl<'b> Pattern for &'b [char] {
|
||||
pattern_methods!('a, CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Impl for F: FnMut(char) -> bool
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Associated type for `<F as Pattern<'a>>::Searcher`.
|
||||
/// Associated type for `<F as Pattern>::Searcher<'a>`.
|
||||
#[derive(Clone)]
|
||||
pub struct CharPredicateSearcher<'a, F>(<MultiCharEqPattern<F> as Pattern<'a>>::Searcher)
|
||||
pub struct CharPredicateSearcher<'a, F>(<MultiCharEqPattern<F> as Pattern>::Searcher<'a>)
|
||||
where
|
||||
F: FnMut(char) -> bool;
|
||||
|
||||
|
|
@ -919,11 +919,11 @@ impl<'a, F> DoubleEndedSearcher<'a> for CharPredicateSearcher<'a, F> where F: Fn
|
|||
/// assert_eq!("Hello world".find(char::is_uppercase), Some(0));
|
||||
/// assert_eq!("Hello world".find(|c| "aeiou".contains(c)), Some(1));
|
||||
/// ```
|
||||
impl<'a, F> Pattern<'a> for F
|
||||
impl<F> Pattern for F
|
||||
where
|
||||
F: FnMut(char) -> bool,
|
||||
{
|
||||
pattern_methods!(CharPredicateSearcher<'a, F>, MultiCharEqPattern, CharPredicateSearcher);
|
||||
pattern_methods!('a, CharPredicateSearcher<'a, F>, MultiCharEqPattern, CharPredicateSearcher);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -931,8 +931,8 @@ where
|
|||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Delegates to the `&str` impl.
|
||||
impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str {
|
||||
pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s);
|
||||
impl<'b, 'c> Pattern for &'c &'b str {
|
||||
pattern_methods!('a, StrSearcher<'a, 'b>, |&s| s, |s| s);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -949,23 +949,23 @@ impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str {
|
|||
/// ```
|
||||
/// assert_eq!("Hello world".find("world"), Some(6));
|
||||
/// ```
|
||||
impl<'a, 'b> Pattern<'a> for &'b str {
|
||||
type Searcher = StrSearcher<'a, 'b>;
|
||||
impl<'b> Pattern for &'b str {
|
||||
type Searcher<'a> = StrSearcher<'a, 'b>;
|
||||
|
||||
#[inline]
|
||||
fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
|
||||
fn into_searcher(self, haystack: &str) -> StrSearcher<'_, 'b> {
|
||||
StrSearcher::new(haystack, self)
|
||||
}
|
||||
|
||||
/// Checks whether the pattern matches at the front of the haystack.
|
||||
#[inline]
|
||||
fn is_prefix_of(self, haystack: &'a str) -> bool {
|
||||
fn is_prefix_of(self, haystack: &str) -> bool {
|
||||
haystack.as_bytes().starts_with(self.as_bytes())
|
||||
}
|
||||
|
||||
/// Checks whether the pattern matches anywhere in the haystack
|
||||
#[inline]
|
||||
fn is_contained_in(self, haystack: &'a str) -> bool {
|
||||
fn is_contained_in(self, haystack: &str) -> bool {
|
||||
if self.len() == 0 {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -991,7 +991,7 @@ impl<'a, 'b> Pattern<'a> for &'b str {
|
|||
|
||||
/// Removes the pattern from the front of haystack, if it matches.
|
||||
#[inline]
|
||||
fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
|
||||
fn strip_prefix_of(self, haystack: &str) -> Option<&str> {
|
||||
if self.is_prefix_of(haystack) {
|
||||
// SAFETY: prefix was just verified to exist.
|
||||
unsafe { Some(haystack.get_unchecked(self.as_bytes().len()..)) }
|
||||
|
|
@ -1002,13 +1002,19 @@ impl<'a, 'b> Pattern<'a> for &'b str {
|
|||
|
||||
/// Checks whether the pattern matches at the back of the haystack.
|
||||
#[inline]
|
||||
fn is_suffix_of(self, haystack: &'a str) -> bool {
|
||||
fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
|
||||
where
|
||||
Self::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
haystack.as_bytes().ends_with(self.as_bytes())
|
||||
}
|
||||
|
||||
/// Removes the pattern from the back of haystack, if it matches.
|
||||
#[inline]
|
||||
fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> {
|
||||
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
|
||||
where
|
||||
Self::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
if self.is_suffix_of(haystack) {
|
||||
let i = haystack.len() - self.as_bytes().len();
|
||||
// SAFETY: suffix was just verified to exist.
|
||||
|
|
@ -1024,7 +1030,7 @@ impl<'a, 'b> Pattern<'a> for &'b str {
|
|||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Associated type for `<&str as Pattern<'a>>::Searcher`.
|
||||
/// Associated type for `<&str as Pattern>::Searcher<'a>`.
|
||||
pub struct StrSearcher<'a, 'b> {
|
||||
haystack: &'a str,
|
||||
needle: &'b str,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
#![stable(feature = "futures_api", since = "1.36.0")]
|
||||
|
||||
use crate::mem::transmute;
|
||||
|
||||
use crate::any::Any;
|
||||
use crate::fmt;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::{transmute, ManuallyDrop};
|
||||
use crate::panic::AssertUnwindSafe;
|
||||
use crate::ptr;
|
||||
|
||||
|
|
@ -429,7 +428,7 @@ impl<'a> ContextBuilder<'a> {
|
|||
/// [`Future::poll()`]: core::future::Future::poll
|
||||
/// [`Poll::Pending`]: core::task::Poll::Pending
|
||||
/// [`Wake`]: ../../alloc/task/trait.Wake.html
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
|
||||
#[repr(transparent)]
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
pub struct Waker {
|
||||
waker: RawWaker,
|
||||
|
|
@ -465,16 +464,14 @@ impl Waker {
|
|||
pub fn wake(self) {
|
||||
// The actual wakeup call is delegated through a virtual function call
|
||||
// to the implementation which is defined by the executor.
|
||||
let wake = self.waker.vtable.wake;
|
||||
let data = self.waker.data;
|
||||
|
||||
// Don't call `drop` -- the waker will be consumed by `wake`.
|
||||
crate::mem::forget(self);
|
||||
let this = ManuallyDrop::new(self);
|
||||
|
||||
// SAFETY: This is safe because `Waker::from_raw` is the only way
|
||||
// to initialize `wake` and `data` requiring the user to acknowledge
|
||||
// that the contract of `RawWaker` is upheld.
|
||||
unsafe { (wake)(data) };
|
||||
unsafe { (this.waker.vtable.wake)(this.waker.data) };
|
||||
}
|
||||
|
||||
/// Wake up the task associated with this `Waker` without consuming the `Waker`.
|
||||
|
|
@ -695,7 +692,7 @@ impl fmt::Debug for Waker {
|
|||
/// [`Poll::Pending`]: core::task::Poll::Pending
|
||||
/// [`local_waker`]: core::task::Context::local_waker
|
||||
#[unstable(feature = "local_waker", issue = "118959")]
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
|
||||
#[repr(transparent)]
|
||||
pub struct LocalWaker {
|
||||
waker: RawWaker,
|
||||
}
|
||||
|
|
@ -726,16 +723,14 @@ impl LocalWaker {
|
|||
pub fn wake(self) {
|
||||
// The actual wakeup call is delegated through a virtual function call
|
||||
// to the implementation which is defined by the executor.
|
||||
let wake = self.waker.vtable.wake;
|
||||
let data = self.waker.data;
|
||||
|
||||
// Don't call `drop` -- the waker will be consumed by `wake`.
|
||||
crate::mem::forget(self);
|
||||
let this = ManuallyDrop::new(self);
|
||||
|
||||
// SAFETY: This is safe because `Waker::from_raw` is the only way
|
||||
// to initialize `wake` and `data` requiring the user to acknowledge
|
||||
// that the contract of `RawWaker` is upheld.
|
||||
unsafe { (wake)(data) };
|
||||
unsafe { (this.waker.vtable.wake)(this.waker.data) };
|
||||
}
|
||||
|
||||
/// Wake up the task associated with this `LocalWaker` without consuming the `LocalWaker`.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Buffer management for same-process client<->server communication.
|
||||
|
||||
use std::io::{self, Write};
|
||||
use std::mem;
|
||||
use std::mem::{self, ManuallyDrop};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::slice;
|
||||
|
||||
|
|
@ -129,17 +129,16 @@ impl Drop for Buffer {
|
|||
}
|
||||
|
||||
impl From<Vec<u8>> for Buffer {
|
||||
fn from(mut v: Vec<u8>) -> Self {
|
||||
fn from(v: Vec<u8>) -> Self {
|
||||
let mut v = ManuallyDrop::new(v);
|
||||
let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity());
|
||||
mem::forget(v);
|
||||
|
||||
// This utility function is nested in here because it can *only*
|
||||
// be safely called on `Buffer`s created by *this* `proc_macro`.
|
||||
fn to_vec(b: Buffer) -> Vec<u8> {
|
||||
unsafe {
|
||||
let Buffer { data, len, capacity, .. } = b;
|
||||
mem::forget(b);
|
||||
Vec::from_raw_parts(data, len, capacity)
|
||||
let b = ManuallyDrop::new(b);
|
||||
Vec::from_raw_parts(b.data, b.len, b.capacity)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,9 +51,7 @@ macro_rules! define_client_handles {
|
|||
|
||||
impl<S> Encode<S> for $oty {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
let handle = self.handle;
|
||||
mem::forget(self);
|
||||
handle.encode(w, s);
|
||||
mem::ManuallyDrop::new(self).handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,10 +115,8 @@ impl crate::sealed::Sealed for OsString {}
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// `OsStr::from_inner` current implementation relies
|
||||
// on `OsStr` being layout-compatible with `Slice`.
|
||||
// However, `OsStr` layout is considered an implementation detail and must not be relied upon. We
|
||||
// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
|
||||
// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
|
||||
#[cfg_attr(not(doc), repr(transparent))]
|
||||
// However, `OsStr` layout is considered an implementation detail and must not be relied upon.
|
||||
#[repr(transparent)]
|
||||
pub struct OsStr {
|
||||
inner: Slice,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2400,13 +2400,8 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
|||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error in the following situations, but is not
|
||||
/// limited to just these cases:
|
||||
///
|
||||
/// * If any directory in the path specified by `path`
|
||||
/// does not already exist and it could not be created otherwise. The specific
|
||||
/// error conditions for when a directory is being created (after it is
|
||||
/// determined to not exist) are outlined by [`fs::create_dir`].
|
||||
/// The function will return an error if any directory specified in path does not exist and
|
||||
/// could not be created. There may be other error conditions; see [`fs::create_dir`] for specifics.
|
||||
///
|
||||
/// Notable exception is made for situations where any of the directories
|
||||
/// specified in the `path` could not be created as it was being created concurrently.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::fmt;
|
|||
use crate::fs;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::forget;
|
||||
use crate::mem::ManuallyDrop;
|
||||
#[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))]
|
||||
use crate::sys::cvt;
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
|
|
@ -148,9 +148,7 @@ impl AsRawFd for OwnedFd {
|
|||
impl IntoRawFd for OwnedFd {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
let fd = self.fd;
|
||||
forget(self);
|
||||
fd
|
||||
ManuallyDrop::new(self).fd
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
use crate::fmt;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::forget;
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::net;
|
||||
use crate::sys;
|
||||
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
|
||||
|
|
@ -148,9 +148,7 @@ impl AsRawFd for OwnedFd {
|
|||
impl IntoRawFd for OwnedFd {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
let fd = self.fd;
|
||||
forget(self);
|
||||
fd
|
||||
ManuallyDrop::new(self).fd
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1064,7 +1064,7 @@ pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io:
|
|||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "unix_chroot", since = "1.56.0")]
|
||||
#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
|
||||
#[cfg(not(target_os = "fuchsia"))]
|
||||
pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
|
||||
sys::fs::chroot(dir.as_ref())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::fmt;
|
|||
use crate::fs;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::{forget, ManuallyDrop};
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::ptr;
|
||||
use crate::sys;
|
||||
use crate::sys::cvt;
|
||||
|
|
@ -319,9 +319,7 @@ impl AsRawHandle for OwnedHandle {
|
|||
impl IntoRawHandle for OwnedHandle {
|
||||
#[inline]
|
||||
fn into_raw_handle(self) -> RawHandle {
|
||||
let handle = self.handle;
|
||||
forget(self);
|
||||
handle
|
||||
ManuallyDrop::new(self).handle
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
|
|||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem;
|
||||
use crate::mem::forget;
|
||||
use crate::mem::{self, ManuallyDrop};
|
||||
use crate::sys;
|
||||
#[cfg(not(target_vendor = "uwp"))]
|
||||
use crate::sys::cvt;
|
||||
|
|
@ -191,9 +190,7 @@ impl AsRawSocket for OwnedSocket {
|
|||
impl IntoRawSocket for OwnedSocket {
|
||||
#[inline]
|
||||
fn into_raw_socket(self) -> RawSocket {
|
||||
let socket = self.socket;
|
||||
forget(self);
|
||||
socket
|
||||
ManuallyDrop::new(self).socket
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2079,10 +2079,8 @@ impl AsRef<OsStr> for PathBuf {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// `Path::new` current implementation relies
|
||||
// on `Path` being layout-compatible with `OsStr`.
|
||||
// However, `Path` layout is considered an implementation detail and must not be relied upon. We
|
||||
// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
|
||||
// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
|
||||
#[cfg_attr(not(doc), repr(transparent))]
|
||||
// However, `Path` layout is considered an implementation detail and must not be relied upon.
|
||||
#[repr(transparent)]
|
||||
pub struct Path {
|
||||
inner: OsStr,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use super::hermit_abi;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::num::NonZero;
|
||||
use crate::ptr;
|
||||
use crate::time::Duration;
|
||||
|
|
@ -90,9 +90,7 @@ impl Thread {
|
|||
|
||||
#[inline]
|
||||
pub fn into_id(self) -> Tid {
|
||||
let id = self.tid;
|
||||
mem::forget(self);
|
||||
id
|
||||
ManuallyDrop::new(self).tid
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ impl Tls {
|
|||
#[allow(unused)]
|
||||
pub unsafe fn activate_persistent(self: Box<Self>) {
|
||||
// FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
|
||||
unsafe { set_tls_ptr(core::ptr::addr_of!(*self) as _) };
|
||||
mem::forget(self);
|
||||
let ptr = Box::into_raw(self).cast_const().cast::<u8>();
|
||||
unsafe { set_tls_ptr(ptr) };
|
||||
}
|
||||
|
||||
unsafe fn current<'a>() -> &'a Tls {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::cell::UnsafeCell;
|
|||
use crate::cmp;
|
||||
use crate::convert::TryInto;
|
||||
use crate::intrinsics;
|
||||
use crate::mem;
|
||||
use crate::mem::{self, ManuallyDrop};
|
||||
use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut};
|
||||
use crate::ptr::{self, NonNull};
|
||||
use crate::slice;
|
||||
|
|
@ -176,6 +176,7 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] {
|
|||
/// are used solely to indicate intent: a mutable reference is for writing to
|
||||
/// user memory, an immutable reference for reading from user memory.
|
||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||
#[repr(transparent)]
|
||||
pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
|
||||
/// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
|
||||
/// enclave memory. Access to the memory is only allowed by copying to avoid
|
||||
|
|
@ -266,9 +267,7 @@ where
|
|||
/// Converts this value into a raw pointer. The value will no longer be
|
||||
/// automatically freed.
|
||||
pub fn into_raw(self) -> *mut T {
|
||||
let ret = self.0;
|
||||
mem::forget(self);
|
||||
ret.as_ptr() as _
|
||||
ManuallyDrop::new(self).0.as_ptr() as _
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use fortanix_sgx_abi::Fd;
|
|||
|
||||
use super::abi::usercalls;
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
|
||||
use crate::mem;
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -21,9 +21,7 @@ impl FileDesc {
|
|||
|
||||
/// Extracts the actual file descriptor without closing it.
|
||||
pub fn into_raw(self) -> Fd {
|
||||
let fd = self.fd;
|
||||
mem::forget(self);
|
||||
fd
|
||||
ManuallyDrop::new(self).fd
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
|
|
@ -70,9 +68,7 @@ impl AsInner<Fd> for FileDesc {
|
|||
|
||||
impl IntoInner<Fd> for FileDesc {
|
||||
fn into_inner(self) -> Fd {
|
||||
let fd = self.fd;
|
||||
mem::forget(self);
|
||||
fd
|
||||
ManuallyDrop::new(self).fd
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use core::convert::TryInto;
|
||||
|
||||
use crate::cmp;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::mem::{self, ManuallyDrop};
|
||||
use crate::num::NonZero;
|
||||
use crate::ptr;
|
||||
use crate::sys::os;
|
||||
|
|
@ -115,11 +113,9 @@ impl Thread {
|
|||
|
||||
/// must join, because no pthread_detach supported
|
||||
pub fn join(self) {
|
||||
unsafe {
|
||||
let ret = libc::pthread_join(self.id, ptr::null_mut());
|
||||
mem::forget(self);
|
||||
assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
let id = self.into_id();
|
||||
let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
|
||||
pub fn id(&self) -> libc::pthread_t {
|
||||
|
|
@ -127,9 +123,7 @@ impl Thread {
|
|||
}
|
||||
|
||||
pub fn into_id(self) -> libc::pthread_t {
|
||||
let id = self.id;
|
||||
mem::forget(self);
|
||||
id
|
||||
ManuallyDrop::new(self).id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ impl FileDesc {
|
|||
(&mut me).read_to_end(buf)
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
|
||||
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", not(target_env = "musl")),
|
||||
|
|
@ -318,6 +319,7 @@ impl FileDesc {
|
|||
cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
|
||||
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", not(target_env = "musl")),
|
||||
|
|
|
|||
|
|
@ -463,15 +463,15 @@ impl FileAttr {
|
|||
#[cfg(target_os = "aix")]
|
||||
impl FileAttr {
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat.st_mtime.tv_sec as i64, self.stat.st_mtime.tv_nsec as i64))
|
||||
SystemTime::new(self.stat.st_mtime.tv_sec as i64, self.stat.st_mtime.tv_nsec as i64)
|
||||
}
|
||||
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat.st_atime.tv_sec as i64, self.stat.st_atime.tv_nsec as i64))
|
||||
SystemTime::new(self.stat.st_atime.tv_sec as i64, self.stat.st_atime.tv_nsec as i64)
|
||||
}
|
||||
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat.st_ctime.tv_sec as i64, self.stat.st_ctime.tv_nsec as i64))
|
||||
SystemTime::new(self.stat.st_ctime.tv_sec as i64, self.stat.st_ctime.tv_nsec as i64)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -857,6 +857,7 @@ impl Drop for Dir {
|
|||
target_os = "espidf",
|
||||
target_os = "fuchsia",
|
||||
target_os = "horizon",
|
||||
target_os = "vxworks",
|
||||
)))]
|
||||
{
|
||||
let fd = unsafe { libc::dirfd(self.0) };
|
||||
|
|
@ -1313,7 +1314,12 @@ impl File {
|
|||
}
|
||||
|
||||
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
|
||||
#[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon")))]
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vxworks"
|
||||
)))]
|
||||
let to_timespec = |time: Option<SystemTime>| match time {
|
||||
Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
|
||||
Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_io_error!(
|
||||
|
|
@ -1327,10 +1333,11 @@ impl File {
|
|||
None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
|
||||
};
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon"))] {
|
||||
if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks"))] {
|
||||
// Redox doesn't appear to support `UTIME_OMIT`.
|
||||
// ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore
|
||||
// the same as for Redox.
|
||||
// `futimens` and `UTIME_OMIT` are a work in progress for vxworks.
|
||||
let _ = times;
|
||||
Err(io::const_io_error!(
|
||||
io::ErrorKind::Unsupported,
|
||||
|
|
@ -1962,6 +1969,7 @@ pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "vxworks"))]
|
||||
pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
|
||||
run_path_with_cstr(path, &|path| {
|
||||
cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })
|
||||
|
|
@ -1969,11 +1977,23 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "vxworks")]
|
||||
pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
|
||||
let (_, _, _) = (path, uid, gid);
|
||||
Err(io::const_io_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks"))
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
|
||||
pub fn chroot(dir: &Path) -> io::Result<()> {
|
||||
run_path_with_cstr(dir, &|dir| cvt(unsafe { libc::chroot(dir.as_ptr()) }).map(|_| ()))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "vxworks")]
|
||||
pub fn chroot(dir: &Path) -> io::Result<()> {
|
||||
let _ = dir;
|
||||
Err(io::const_io_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks"))
|
||||
}
|
||||
|
||||
pub use remove_dir_impl::remove_dir_all;
|
||||
|
||||
// Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
|
|||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "horizon",
|
||||
target_os = "vxworks",
|
||||
// Unikraft's `signal` implementation is currently broken:
|
||||
// https://github.com/unikraft/lib-musl/issues/57
|
||||
target_vendor = "unikraft",
|
||||
|
|
@ -209,6 +210,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
|
|||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "horizon",
|
||||
target_os = "vxworks",
|
||||
)))]
|
||||
static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
|
||||
crate::sync::atomic::AtomicBool::new(false);
|
||||
|
|
@ -218,6 +220,7 @@ static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
|
|||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "horizon",
|
||||
target_os = "vxworks",
|
||||
)))]
|
||||
pub(crate) fn on_broken_pipe_flag_used() -> bool {
|
||||
ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ use crate::io::{self, ErrorKind};
|
|||
use crate::num::NonZero;
|
||||
use crate::sys;
|
||||
use crate::sys::cvt;
|
||||
use crate::sys::pal::unix::thread;
|
||||
use crate::sys::process::process_common::*;
|
||||
use crate::sys_common::thread;
|
||||
use libc::RTP_ID;
|
||||
use libc::{self, c_char, c_int};
|
||||
|
||||
|
|
@ -68,7 +68,12 @@ impl Command {
|
|||
.as_ref()
|
||||
.map(|c| c.as_ptr())
|
||||
.unwrap_or_else(|| *sys::os::environ() as *const _);
|
||||
let stack_size = thread::min_stack();
|
||||
let stack_size = crate::cmp::max(
|
||||
crate::env::var_os("RUST_MIN_STACK")
|
||||
.and_then(|s| s.to_str().and_then(|s| s.parse().ok()))
|
||||
.unwrap_or(thread::DEFAULT_MIN_STACK_SIZE),
|
||||
libc::PTHREAD_STACK_MIN,
|
||||
);
|
||||
|
||||
// ensure that access to the environment is synchronized
|
||||
let _lock = sys::os::env_read_lock();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::cmp;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::mem::{self, ManuallyDrop};
|
||||
use crate::num::NonZero;
|
||||
use crate::ptr;
|
||||
use crate::sys::{os, stack_overflow};
|
||||
|
|
@ -268,11 +268,9 @@ impl Thread {
|
|||
}
|
||||
|
||||
pub fn join(self) {
|
||||
unsafe {
|
||||
let ret = libc::pthread_join(self.id, ptr::null_mut());
|
||||
mem::forget(self);
|
||||
assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
let id = self.into_id();
|
||||
let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
|
||||
pub fn id(&self) -> libc::pthread_t {
|
||||
|
|
@ -280,9 +278,7 @@ impl Thread {
|
|||
}
|
||||
|
||||
pub fn into_id(self) -> libc::pthread_t {
|
||||
let id = self.id;
|
||||
mem::forget(self);
|
||||
id
|
||||
ManuallyDrop::new(self).id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,12 +172,10 @@ impl Thread {
|
|||
pub fn join(self) {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_feature = "atomics")] {
|
||||
unsafe {
|
||||
let ret = libc::pthread_join(self.id, ptr::null_mut());
|
||||
mem::forget(self);
|
||||
if ret != 0 {
|
||||
rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
let id = mem::ManuallyDrop::new(self).id;
|
||||
let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
if ret != 0 {
|
||||
rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
} else {
|
||||
self.0
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE)
|
|||
// Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
|
||||
//
|
||||
// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut core::ffi::c_void);
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut c_void);
|
||||
|
||||
// Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`,
|
||||
// to a block of at least `dwBytes` bytes, either shrinking the block in place,
|
||||
|
|
@ -61,9 +61,9 @@ windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dw
|
|||
windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
|
||||
hheap: c::HANDLE,
|
||||
dwflags : u32,
|
||||
lpmem: *const core::ffi::c_void,
|
||||
lpmem: *const c_void,
|
||||
dwbytes: usize
|
||||
) -> *mut core::ffi::c_void);
|
||||
) -> *mut c_void);
|
||||
|
||||
// Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`.
|
||||
// Returns a nonzero value if the operation is successful, and zero if the operation fails.
|
||||
|
|
@ -79,7 +79,7 @@ windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
|
|||
// Note that `lpMem` is allowed to be null, which will not cause the operation to fail.
|
||||
//
|
||||
// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const core::ffi::c_void) -> c::BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const c_void) -> c::BOOL);
|
||||
|
||||
// Cached handle to the default heap of the current process.
|
||||
// Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed.
|
||||
|
|
|
|||
|
|
@ -4,13 +4,10 @@
|
|||
#![cfg_attr(test, allow(dead_code))]
|
||||
#![unstable(issue = "none", feature = "windows_c")]
|
||||
#![allow(clippy::style)]
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use crate::ffi::CStr;
|
||||
use crate::mem;
|
||||
use crate::os::raw::{c_uint, c_ulong, c_ushort, c_void};
|
||||
use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
|
||||
use crate::ptr;
|
||||
use core::ffi::{c_uint, c_ulong, c_ushort, c_void, CStr};
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
|
||||
pub(super) mod windows_targets;
|
||||
|
||||
|
|
@ -114,89 +111,6 @@ if #[cfg(not(target_vendor = "uwp"))] {
|
|||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn WriteFileEx(
|
||||
hFile: BorrowedHandle<'_>,
|
||||
lpBuffer: *mut ::core::ffi::c_void,
|
||||
nNumberOfBytesToWrite: u32,
|
||||
lpOverlapped: *mut OVERLAPPED,
|
||||
lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> BOOL {
|
||||
windows_sys::WriteFileEx(
|
||||
hFile.as_raw_handle(),
|
||||
lpBuffer.cast::<u8>(),
|
||||
nNumberOfBytesToWrite,
|
||||
lpOverlapped,
|
||||
lpCompletionRoutine,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn ReadFileEx(
|
||||
hFile: BorrowedHandle<'_>,
|
||||
lpBuffer: *mut ::core::ffi::c_void,
|
||||
nNumberOfBytesToRead: u32,
|
||||
lpOverlapped: *mut OVERLAPPED,
|
||||
lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> BOOL {
|
||||
windows_sys::ReadFileEx(
|
||||
hFile.as_raw_handle(),
|
||||
lpBuffer.cast::<u8>(),
|
||||
nNumberOfBytesToRead,
|
||||
lpOverlapped,
|
||||
lpCompletionRoutine,
|
||||
)
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(target_vendor = "uwp"))] {
|
||||
pub unsafe fn NtReadFile(
|
||||
filehandle: BorrowedHandle<'_>,
|
||||
event: HANDLE,
|
||||
apcroutine: PIO_APC_ROUTINE,
|
||||
apccontext: *mut c_void,
|
||||
iostatusblock: &mut IO_STATUS_BLOCK,
|
||||
buffer: *mut crate::mem::MaybeUninit<u8>,
|
||||
length: u32,
|
||||
byteoffset: Option<&i64>,
|
||||
key: Option<&u32>,
|
||||
) -> NTSTATUS {
|
||||
windows_sys::NtReadFile(
|
||||
filehandle.as_raw_handle(),
|
||||
event,
|
||||
apcroutine,
|
||||
apccontext,
|
||||
iostatusblock,
|
||||
buffer.cast::<c_void>(),
|
||||
length,
|
||||
byteoffset.map(|o| o as *const i64).unwrap_or(ptr::null()),
|
||||
key.map(|k| k as *const u32).unwrap_or(ptr::null()),
|
||||
)
|
||||
}
|
||||
pub unsafe fn NtWriteFile(
|
||||
filehandle: BorrowedHandle<'_>,
|
||||
event: HANDLE,
|
||||
apcroutine: PIO_APC_ROUTINE,
|
||||
apccontext: *mut c_void,
|
||||
iostatusblock: &mut IO_STATUS_BLOCK,
|
||||
buffer: *const u8,
|
||||
length: u32,
|
||||
byteoffset: Option<&i64>,
|
||||
key: Option<&u32>,
|
||||
) -> NTSTATUS {
|
||||
windows_sys::NtWriteFile(
|
||||
filehandle.as_raw_handle(),
|
||||
event,
|
||||
apcroutine,
|
||||
apccontext,
|
||||
iostatusblock,
|
||||
buffer.cast::<c_void>(),
|
||||
length,
|
||||
byteoffset.map(|o| o as *const i64).unwrap_or(ptr::null()),
|
||||
key.map(|k| k as *const u32).unwrap_or(ptr::null()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(target_vendor = "win7"))] {
|
||||
|
|
@ -220,26 +134,26 @@ compat_fn_with_fallback! {
|
|||
// >= Win10 1607
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
|
||||
pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL
|
||||
unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL }
|
||||
}
|
||||
|
||||
// >= Win10 1607
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription
|
||||
pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL
|
||||
unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL }
|
||||
}
|
||||
|
||||
// >= Win8 / Server 2012
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
|
||||
#[cfg(target_vendor = "win7")]
|
||||
pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () {
|
||||
GetSystemTimeAsFileTime(lpsystemtimeasfiletime)
|
||||
unsafe { GetSystemTimeAsFileTime(lpsystemtimeasfiletime) }
|
||||
}
|
||||
|
||||
// >= Win11 / Server 2022
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
|
||||
pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
|
||||
GetTempPathW(bufferlength, buffer)
|
||||
unsafe { GetTempPathW(bufferlength, buffer) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -272,12 +186,12 @@ extern "system" {
|
|||
compat_fn_optional! {
|
||||
crate::sys::compat::load_synch_functions();
|
||||
pub fn WaitOnAddress(
|
||||
address: *const ::core::ffi::c_void,
|
||||
compareaddress: *const ::core::ffi::c_void,
|
||||
address: *const c_void,
|
||||
compareaddress: *const c_void,
|
||||
addresssize: usize,
|
||||
dwmilliseconds: u32
|
||||
) -> BOOL;
|
||||
pub fn WakeByAddressSingle(address: *const ::core::ffi::c_void);
|
||||
pub fn WakeByAddressSingle(address: *const c_void);
|
||||
}
|
||||
|
||||
#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))]
|
||||
|
|
@ -324,36 +238,36 @@ compat_fn_with_fallback! {
|
|||
shareaccess: FILE_SHARE_MODE,
|
||||
createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
|
||||
createoptions: NTCREATEFILE_CREATE_OPTIONS,
|
||||
eabuffer: *const ::core::ffi::c_void,
|
||||
eabuffer: *const c_void,
|
||||
ealength: u32
|
||||
) -> NTSTATUS {
|
||||
STATUS_NOT_IMPLEMENTED
|
||||
}
|
||||
#[cfg(target_vendor = "uwp")]
|
||||
pub fn NtReadFile(
|
||||
filehandle: BorrowedHandle<'_>,
|
||||
filehandle: HANDLE,
|
||||
event: HANDLE,
|
||||
apcroutine: PIO_APC_ROUTINE,
|
||||
apccontext: *mut c_void,
|
||||
iostatusblock: &mut IO_STATUS_BLOCK,
|
||||
buffer: *mut crate::mem::MaybeUninit<u8>,
|
||||
apccontext: *const c_void,
|
||||
iostatusblock: *mut IO_STATUS_BLOCK,
|
||||
buffer: *mut c_void,
|
||||
length: u32,
|
||||
byteoffset: Option<&i64>,
|
||||
key: Option<&u32>
|
||||
byteoffset: *const i64,
|
||||
key: *const u32
|
||||
) -> NTSTATUS {
|
||||
STATUS_NOT_IMPLEMENTED
|
||||
}
|
||||
#[cfg(target_vendor = "uwp")]
|
||||
pub fn NtWriteFile(
|
||||
filehandle: BorrowedHandle<'_>,
|
||||
filehandle: HANDLE,
|
||||
event: HANDLE,
|
||||
apcroutine: PIO_APC_ROUTINE,
|
||||
apccontext: *mut c_void,
|
||||
iostatusblock: &mut IO_STATUS_BLOCK,
|
||||
buffer: *const u8,
|
||||
apccontext: *const c_void,
|
||||
iostatusblock: *mut IO_STATUS_BLOCK,
|
||||
buffer: *const c_void,
|
||||
length: u32,
|
||||
byteoffset: Option<&i64>,
|
||||
key: Option<&u32>
|
||||
byteoffset: *const i64,
|
||||
key: *const u32
|
||||
) -> NTSTATUS {
|
||||
STATUS_NOT_IMPLEMENTED
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,8 +158,10 @@ macro_rules! compat_fn_with_fallback {
|
|||
static PTR: AtomicPtr<c_void> = AtomicPtr::new(load as *mut _);
|
||||
|
||||
unsafe extern "system" fn load($($argname: $argtype),*) -> $rettype {
|
||||
let func = load_from_module(Module::new($module));
|
||||
func($($argname),*)
|
||||
unsafe {
|
||||
let func = load_from_module(Module::new($module));
|
||||
func($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_from_module(module: Option<Module>) -> F {
|
||||
|
|
@ -182,8 +184,10 @@ macro_rules! compat_fn_with_fallback {
|
|||
|
||||
#[inline(always)]
|
||||
pub unsafe fn call($($argname: $argtype),*) -> $rettype {
|
||||
let func: F = mem::transmute(PTR.load(Ordering::Relaxed));
|
||||
func($($argname),*)
|
||||
unsafe {
|
||||
let func: F = mem::transmute(PTR.load(Ordering::Relaxed));
|
||||
func($($argname),*)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(unused)]
|
||||
|
|
@ -225,7 +229,7 @@ macro_rules! compat_fn_optional {
|
|||
}
|
||||
#[inline]
|
||||
pub unsafe extern "system" fn $symbol($($argname: $argtype),*) $(-> $rettype)? {
|
||||
$symbol::option().unwrap()($($argname),*)
|
||||
unsafe { $symbol::option().unwrap()($($argname),*) }
|
||||
}
|
||||
)+
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::cmp;
|
||||
use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, Read};
|
||||
use crate::mem;
|
||||
use crate::os::windows::io::{
|
||||
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
|
||||
};
|
||||
use crate::ptr;
|
||||
use crate::sys::c;
|
||||
use crate::sys::cvt;
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
use core::cmp;
|
||||
use core::ffi::c_void;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
|
||||
/// An owned container for `HANDLE` object, closing them on Drop.
|
||||
///
|
||||
|
|
@ -250,15 +251,15 @@ impl Handle {
|
|||
// the provided `len`.
|
||||
let status = unsafe {
|
||||
c::NtReadFile(
|
||||
self.as_handle(),
|
||||
self.as_raw_handle(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut(),
|
||||
&mut io_status,
|
||||
buf,
|
||||
buf.cast::<c_void>(),
|
||||
len,
|
||||
offset.map(|n| n as _).as_ref(),
|
||||
None,
|
||||
offset.as_ref().map(|n| ptr::from_ref(n).cast::<i64>()).unwrap_or(ptr::null()),
|
||||
ptr::null(),
|
||||
)
|
||||
};
|
||||
|
||||
|
|
@ -300,15 +301,15 @@ impl Handle {
|
|||
let len = cmp::min(buf.len(), u32::MAX as usize) as u32;
|
||||
let status = unsafe {
|
||||
c::NtWriteFile(
|
||||
self.as_handle(),
|
||||
self.as_raw_handle(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut(),
|
||||
&mut io_status,
|
||||
buf.as_ptr(),
|
||||
buf.as_ptr().cast::<c_void>(),
|
||||
len,
|
||||
offset.map(|n| n as _).as_ref(),
|
||||
None,
|
||||
offset.as_ref().map(|n| ptr::from_ref(n).cast::<i64>()).unwrap_or(ptr::null()),
|
||||
ptr::null(),
|
||||
)
|
||||
};
|
||||
let status = if status == c::STATUS_PENDING {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![allow(missing_docs, nonstandard_style)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::io::ErrorKind;
|
||||
|
|
|
|||
|
|
@ -238,15 +238,6 @@ fn random_number() -> usize {
|
|||
}
|
||||
}
|
||||
|
||||
// Abstracts over `ReadFileEx` and `WriteFileEx`
|
||||
type AlertableIoFn = unsafe extern "system" fn(
|
||||
BorrowedHandle<'_>,
|
||||
*mut core::ffi::c_void,
|
||||
u32,
|
||||
*mut c::OVERLAPPED,
|
||||
c::LPOVERLAPPED_COMPLETION_ROUTINE,
|
||||
) -> c::BOOL;
|
||||
|
||||
impl AnonPipe {
|
||||
pub fn handle(&self) -> &Handle {
|
||||
&self.inner
|
||||
|
|
@ -262,7 +253,10 @@ impl AnonPipe {
|
|||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let result = unsafe {
|
||||
let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32;
|
||||
self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len)
|
||||
let ptr = buf.as_mut_ptr();
|
||||
self.alertable_io_internal(|overlapped, callback| {
|
||||
c::ReadFileEx(self.inner.as_raw_handle(), ptr, len, overlapped, callback)
|
||||
})
|
||||
};
|
||||
|
||||
match result {
|
||||
|
|
@ -278,7 +272,10 @@ impl AnonPipe {
|
|||
pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
let result = unsafe {
|
||||
let len = crate::cmp::min(buf.capacity(), u32::MAX as usize) as u32;
|
||||
self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len)
|
||||
let ptr = buf.as_mut().as_mut_ptr().cast::<u8>();
|
||||
self.alertable_io_internal(|overlapped, callback| {
|
||||
c::ReadFileEx(self.inner.as_raw_handle(), ptr, len, overlapped, callback)
|
||||
})
|
||||
};
|
||||
|
||||
match result {
|
||||
|
|
@ -313,7 +310,9 @@ impl AnonPipe {
|
|||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32;
|
||||
self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len)
|
||||
self.alertable_io_internal(|overlapped, callback| {
|
||||
c::WriteFileEx(self.inner.as_raw_handle(), buf.as_ptr(), len, overlapped, callback)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -341,12 +340,9 @@ impl AnonPipe {
|
|||
/// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex
|
||||
/// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex
|
||||
/// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn alertable_io_internal(
|
||||
&self,
|
||||
io: AlertableIoFn,
|
||||
buf: *mut core::ffi::c_void,
|
||||
len: u32,
|
||||
io: impl FnOnce(&mut c::OVERLAPPED, c::LPOVERLAPPED_COMPLETION_ROUTINE) -> c::BOOL,
|
||||
) -> io::Result<usize> {
|
||||
// Use "alertable I/O" to synchronize the pipe I/O.
|
||||
// This has four steps.
|
||||
|
|
@ -384,20 +380,25 @@ impl AnonPipe {
|
|||
lpOverlapped: *mut c::OVERLAPPED,
|
||||
) {
|
||||
// Set `async_result` using a pointer smuggled through `hEvent`.
|
||||
let result =
|
||||
AsyncResult { error: dwErrorCode, transferred: dwNumberOfBytesTransferred };
|
||||
*(*lpOverlapped).hEvent.cast::<Option<AsyncResult>>() = Some(result);
|
||||
// SAFETY:
|
||||
// At this point, the OVERLAPPED struct will have been written to by the OS,
|
||||
// except for our `hEvent` field which we set to a valid AsyncResult pointer (see below)
|
||||
unsafe {
|
||||
let result =
|
||||
AsyncResult { error: dwErrorCode, transferred: dwNumberOfBytesTransferred };
|
||||
*(*lpOverlapped).hEvent.cast::<Option<AsyncResult>>() = Some(result);
|
||||
}
|
||||
}
|
||||
|
||||
// STEP 1: Start the I/O operation.
|
||||
let mut overlapped: c::OVERLAPPED = crate::mem::zeroed();
|
||||
let mut overlapped: c::OVERLAPPED = unsafe { crate::mem::zeroed() };
|
||||
// `hEvent` is unused by `ReadFileEx` and `WriteFileEx`.
|
||||
// Therefore the documentation suggests using it to smuggle a pointer to the callback.
|
||||
overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _;
|
||||
|
||||
// Asynchronous read of the pipe.
|
||||
// If successful, `callback` will be called once it completes.
|
||||
let result = io(self.inner.as_handle(), buf, len, &mut overlapped, Some(callback));
|
||||
let result = io(&mut overlapped, Some(callback));
|
||||
if result == c::FALSE {
|
||||
// We can return here because the call failed.
|
||||
// After this we must not return until the I/O completes.
|
||||
|
|
@ -408,7 +409,7 @@ impl AnonPipe {
|
|||
let result = loop {
|
||||
// STEP 2: Enter an alertable state.
|
||||
// The second parameter of `SleepEx` is used to make this sleep alertable.
|
||||
c::SleepEx(c::INFINITE, c::TRUE);
|
||||
unsafe { c::SleepEx(c::INFINITE, c::TRUE) };
|
||||
if let Some(result) = async_result {
|
||||
break result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ use crate::ffi::CStr;
|
|||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::{self, forget};
|
||||
use crate::mem::{self, forget, ManuallyDrop};
|
||||
use crate::num::NonZero;
|
||||
use crate::panic;
|
||||
use crate::panicking;
|
||||
|
|
@ -192,22 +192,14 @@ pub use scoped::{scope, Scope, ScopedJoinHandle};
|
|||
#[macro_use]
|
||||
mod local;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(test)] {
|
||||
// Avoid duplicating the global state associated with thread-locals between this crate and
|
||||
// realstd. Miri relies on this.
|
||||
pub use realstd::thread::{local_impl, AccessError, LocalKey};
|
||||
} else {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::local::{AccessError, LocalKey};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::local::{AccessError, LocalKey};
|
||||
|
||||
// Implementation details used by the thread_local!{} macro.
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "thread_local_internals", issue = "none")]
|
||||
pub mod local_impl {
|
||||
pub use crate::sys::thread_local::*;
|
||||
}
|
||||
}
|
||||
// Implementation details used by the thread_local!{} macro.
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "thread_local_internals", issue = "none")]
|
||||
pub mod local_impl {
|
||||
pub use crate::sys::thread_local::*;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -510,11 +502,10 @@ impl Builder {
|
|||
MaybeDangling(mem::MaybeUninit::new(x))
|
||||
}
|
||||
fn into_inner(self) -> T {
|
||||
// SAFETY: we are always initialized.
|
||||
let ret = unsafe { self.0.assume_init_read() };
|
||||
// Make sure we don't drop.
|
||||
mem::forget(self);
|
||||
ret
|
||||
let this = ManuallyDrop::new(self);
|
||||
// SAFETY: we are always initialized.
|
||||
unsafe { this.0.assume_init_read() }
|
||||
}
|
||||
}
|
||||
impl<T> Drop for MaybeDangling<T> {
|
||||
|
|
|
|||
|
|
@ -1700,6 +1700,7 @@ impl Step for Assemble {
|
|||
|
||||
// If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.
|
||||
if builder.download_rustc() {
|
||||
builder.ensure(Std::new(target_compiler, target_compiler.host));
|
||||
let sysroot =
|
||||
builder.ensure(Sysroot { compiler: target_compiler, force_recompile: false });
|
||||
// Ensure that `libLLVM.so` ends up in the newly created target directory,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ PICK_REFS=()
|
|||
# commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in
|
||||
# addition to versions of prebuilts. It should be bumped regularly by the
|
||||
# Fuchsia team – we aim for every 1-2 months.
|
||||
INTEGRATION_SHA=d1d2f20efe46e22be179953dd6726c96eced54ab
|
||||
INTEGRATION_SHA=1c5b42266fbfefb2337c6b2f0030a91bde15f9e9
|
||||
|
||||
checkout=fuchsia
|
||||
jiri=.jiri_root/bin/jiri
|
||||
|
|
|
|||
|
|
@ -316,7 +316,8 @@ trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + fmt::Display {
|
|||
fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) {
|
||||
write!(w, "{}", document(cx, item, None, HeadingOffset::H2));
|
||||
|
||||
let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>();
|
||||
let mut not_stripped_items =
|
||||
items.iter().filter(|i| !i.is_stripped()).enumerate().collect::<Vec<_>>();
|
||||
|
||||
// the order of item types in the listing
|
||||
fn reorder(ty: ItemType) -> u8 {
|
||||
|
|
@ -338,37 +339,29 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
|
|||
}
|
||||
}
|
||||
|
||||
fn cmp(
|
||||
i1: &clean::Item,
|
||||
i2: &clean::Item,
|
||||
idx1: usize,
|
||||
idx2: usize,
|
||||
tcx: TyCtxt<'_>,
|
||||
) -> Ordering {
|
||||
let ty1 = i1.type_();
|
||||
let ty2 = i2.type_();
|
||||
if item_ty_to_section(ty1) != item_ty_to_section(ty2)
|
||||
|| (ty1 != ty2 && (ty1 == ItemType::ExternCrate || ty2 == ItemType::ExternCrate))
|
||||
{
|
||||
return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2));
|
||||
fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
|
||||
let rty1 = reorder(i1.type_());
|
||||
let rty2 = reorder(i2.type_());
|
||||
if rty1 != rty2 {
|
||||
return rty1.cmp(&rty2);
|
||||
}
|
||||
let s1 = i1.stability(tcx).as_ref().map(|s| s.level);
|
||||
let s2 = i2.stability(tcx).as_ref().map(|s| s.level);
|
||||
if let (Some(a), Some(b)) = (s1, s2) {
|
||||
match (a.is_stable(), b.is_stable()) {
|
||||
(true, true) | (false, false) => {}
|
||||
(false, true) => return Ordering::Greater,
|
||||
(true, false) => return Ordering::Less,
|
||||
}
|
||||
let is_stable1 = i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
|
||||
let is_stable2 = i2.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
|
||||
if is_stable1 != is_stable2 {
|
||||
// true is bigger than false in the standard bool ordering,
|
||||
// but we actually want stable items to come first
|
||||
return is_stable2.cmp(&is_stable1);
|
||||
}
|
||||
let lhs = i1.name.unwrap_or(kw::Empty);
|
||||
let rhs = i2.name.unwrap_or(kw::Empty);
|
||||
compare_names(lhs.as_str(), rhs.as_str())
|
||||
}
|
||||
|
||||
let tcx = cx.tcx();
|
||||
|
||||
match cx.shared.module_sorting {
|
||||
ModuleSorting::Alphabetical => {
|
||||
indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2, cx.tcx()));
|
||||
not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx));
|
||||
}
|
||||
ModuleSorting::DeclarationOrder => {}
|
||||
}
|
||||
|
|
@ -391,24 +384,19 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
|
|||
// can be identical even if the elements are different (mostly in imports).
|
||||
// So in case this is an import, we keep everything by adding a "unique id"
|
||||
// (which is the position in the vector).
|
||||
indices.dedup_by_key(|i| {
|
||||
not_stripped_items.dedup_by_key(|(idx, i)| {
|
||||
(
|
||||
items[*i].item_id,
|
||||
if items[*i].name.is_some() { Some(full_path(cx, &items[*i])) } else { None },
|
||||
items[*i].type_(),
|
||||
if items[*i].is_import() { *i } else { 0 },
|
||||
i.item_id,
|
||||
if i.name.is_some() { Some(full_path(cx, i)) } else { None },
|
||||
i.type_(),
|
||||
if i.is_import() { *idx } else { 0 },
|
||||
)
|
||||
});
|
||||
|
||||
debug!("{indices:?}");
|
||||
debug!("{not_stripped_items:?}");
|
||||
let mut last_section = None;
|
||||
|
||||
for &idx in &indices {
|
||||
let myitem = &items[idx];
|
||||
if myitem.is_stripped() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (_, myitem) in ¬_stripped_items {
|
||||
let my_section = item_ty_to_section(myitem.type_());
|
||||
if Some(my_section) != last_section {
|
||||
if last_section.is_some() {
|
||||
|
|
@ -424,7 +412,6 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
|
|||
);
|
||||
}
|
||||
|
||||
let tcx = cx.tcx();
|
||||
match *myitem.kind {
|
||||
clean::ExternCrateItem { ref src } => {
|
||||
use crate::html::format::anchor;
|
||||
|
|
@ -453,7 +440,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
|
|||
let stab_tags = if let Some(import_def_id) = import.source.did {
|
||||
// Just need an item with the correct def_id and attrs
|
||||
let import_item =
|
||||
clean::Item { item_id: import_def_id.into(), ..myitem.clone() };
|
||||
clean::Item { item_id: import_def_id.into(), ..(*myitem).clone() };
|
||||
|
||||
let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string());
|
||||
stab_tags
|
||||
|
|
@ -2010,40 +1997,102 @@ fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
|
|||
}
|
||||
|
||||
/// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
|
||||
pub(crate) fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering {
|
||||
/// Takes a non-numeric and a numeric part from the given &str.
|
||||
fn take_parts<'a>(s: &mut &'a str) -> (&'a str, &'a str) {
|
||||
let i = s.find(|c: char| c.is_ascii_digit());
|
||||
let (a, b) = s.split_at(i.unwrap_or(s.len()));
|
||||
let i = b.find(|c: char| !c.is_ascii_digit());
|
||||
let (b, c) = b.split_at(i.unwrap_or(b.len()));
|
||||
*s = c;
|
||||
(a, b)
|
||||
}
|
||||
///
|
||||
/// This code is copied from [`rustfmt`], and should probably be released as a crate at some point.
|
||||
///
|
||||
/// [`rustfmt`]:https://github.com/rust-lang/rustfmt/blob/rustfmt-2.0.0-rc.2/src/formatting/reorder.rs#L32
|
||||
pub(crate) fn compare_names(left: &str, right: &str) -> Ordering {
|
||||
let mut left = left.chars().peekable();
|
||||
let mut right = right.chars().peekable();
|
||||
|
||||
while !lhs.is_empty() || !rhs.is_empty() {
|
||||
let (la, lb) = take_parts(&mut lhs);
|
||||
let (ra, rb) = take_parts(&mut rhs);
|
||||
// First process the non-numeric part.
|
||||
match la.cmp(ra) {
|
||||
Ordering::Equal => (),
|
||||
x => return x,
|
||||
}
|
||||
// Then process the numeric part, if both sides have one (and they fit in a u64).
|
||||
if let (Ok(ln), Ok(rn)) = (lb.parse::<u64>(), rb.parse::<u64>()) {
|
||||
match ln.cmp(&rn) {
|
||||
Ordering::Equal => (),
|
||||
x => return x,
|
||||
loop {
|
||||
// The strings are equal so far and not inside a number in both sides
|
||||
let (l, r) = match (left.next(), right.next()) {
|
||||
// Is this the end of both strings?
|
||||
(None, None) => return Ordering::Equal,
|
||||
// If for one, the shorter one is considered smaller
|
||||
(None, Some(_)) => return Ordering::Less,
|
||||
(Some(_), None) => return Ordering::Greater,
|
||||
(Some(l), Some(r)) => (l, r),
|
||||
};
|
||||
let next_ordering = match (l.to_digit(10), r.to_digit(10)) {
|
||||
// If neither is a digit, just compare them
|
||||
(None, None) => Ord::cmp(&l, &r),
|
||||
// The one with shorter non-digit run is smaller
|
||||
// For `strverscmp` it's smaller iff next char in longer is greater than digits
|
||||
(None, Some(_)) => Ordering::Greater,
|
||||
(Some(_), None) => Ordering::Less,
|
||||
// If both start numbers, we have to compare the numbers
|
||||
(Some(l), Some(r)) => {
|
||||
if l == 0 || r == 0 {
|
||||
// Fraction mode: compare as if there was leading `0.`
|
||||
let ordering = Ord::cmp(&l, &r);
|
||||
if ordering != Ordering::Equal {
|
||||
return ordering;
|
||||
}
|
||||
loop {
|
||||
// Get next pair
|
||||
let (l, r) = match (left.peek(), right.peek()) {
|
||||
// Is this the end of both strings?
|
||||
(None, None) => return Ordering::Equal,
|
||||
// If for one, the shorter one is considered smaller
|
||||
(None, Some(_)) => return Ordering::Less,
|
||||
(Some(_), None) => return Ordering::Greater,
|
||||
(Some(l), Some(r)) => (l, r),
|
||||
};
|
||||
// Are they digits?
|
||||
match (l.to_digit(10), r.to_digit(10)) {
|
||||
// If out of digits, use the stored ordering due to equal length
|
||||
(None, None) => break Ordering::Equal,
|
||||
// If one is shorter, it's smaller
|
||||
(None, Some(_)) => return Ordering::Less,
|
||||
(Some(_), None) => return Ordering::Greater,
|
||||
// If both are digits, consume them and take into account
|
||||
(Some(l), Some(r)) => {
|
||||
left.next();
|
||||
right.next();
|
||||
let ordering = Ord::cmp(&l, &r);
|
||||
if ordering != Ordering::Equal {
|
||||
return ordering;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Integer mode
|
||||
let mut same_length_ordering = Ord::cmp(&l, &r);
|
||||
loop {
|
||||
// Get next pair
|
||||
let (l, r) = match (left.peek(), right.peek()) {
|
||||
// Is this the end of both strings?
|
||||
(None, None) => return same_length_ordering,
|
||||
// If for one, the shorter one is considered smaller
|
||||
(None, Some(_)) => return Ordering::Less,
|
||||
(Some(_), None) => return Ordering::Greater,
|
||||
(Some(l), Some(r)) => (l, r),
|
||||
};
|
||||
// Are they digits?
|
||||
match (l.to_digit(10), r.to_digit(10)) {
|
||||
// If out of digits, use the stored ordering due to equal length
|
||||
(None, None) => break same_length_ordering,
|
||||
// If one is shorter, it's smaller
|
||||
(None, Some(_)) => return Ordering::Less,
|
||||
(Some(_), None) => return Ordering::Greater,
|
||||
// If both are digits, consume them and take into account
|
||||
(Some(l), Some(r)) => {
|
||||
left.next();
|
||||
right.next();
|
||||
same_length_ordering = same_length_ordering.then(Ord::cmp(&l, &r));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then process the numeric part again, but this time as strings.
|
||||
match lb.cmp(rb) {
|
||||
Ordering::Equal => (),
|
||||
x => return x,
|
||||
};
|
||||
if next_ordering != Ordering::Equal {
|
||||
return next_ordering;
|
||||
}
|
||||
}
|
||||
|
||||
Ordering::Equal
|
||||
}
|
||||
|
||||
pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ fn test_compare_names() {
|
|||
#[test]
|
||||
fn test_name_sorting() {
|
||||
let names = [
|
||||
"Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit1", "Fruit02", "Fruit2",
|
||||
"Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit02", "Fruit1", "Fruit2",
|
||||
"Fruit20", "Fruit30x", "Fruit100", "Pear",
|
||||
];
|
||||
let mut sorted = names.to_owned();
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ fn remove_all_parens(pat: &mut P<Pat>) {
|
|||
struct Visitor;
|
||||
impl MutVisitor for Visitor {
|
||||
fn visit_pat(&mut self, pat: &mut P<Pat>) {
|
||||
noop_visit_pat(pat, self);
|
||||
walk_pat(self, pat);
|
||||
let inner = match &mut pat.kind {
|
||||
Paren(i) => mem::replace(&mut i.kind, Wild),
|
||||
_ => return,
|
||||
|
|
@ -138,7 +138,7 @@ fn insert_necessary_parens(pat: &mut P<Pat>) {
|
|||
impl MutVisitor for Visitor {
|
||||
fn visit_pat(&mut self, pat: &mut P<Pat>) {
|
||||
use ast::BindingMode;
|
||||
noop_visit_pat(pat, self);
|
||||
walk_pat(self, pat);
|
||||
let target = match &mut pat.kind {
|
||||
// `i @ a | b`, `box a | b`, and `& mut? a | b`.
|
||||
Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
|
||||
|
|
@ -160,7 +160,7 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
|
|||
impl MutVisitor for Visitor {
|
||||
fn visit_pat(&mut self, p: &mut P<Pat>) {
|
||||
// This is a bottom up transformation, so recurse first.
|
||||
noop_visit_pat(p, self);
|
||||
walk_pat(self, p);
|
||||
|
||||
// Don't have an or-pattern? Just quit early on.
|
||||
let Or(alternatives) = &mut p.kind else { return };
|
||||
|
|
@ -189,7 +189,7 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
|
|||
|
||||
// Deal with `Some(Some(0)) | Some(Some(1))`.
|
||||
if this_level_changed {
|
||||
noop_visit_pat(p, self);
|
||||
walk_pat(self, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use build_helper::git::{get_git_modified_files, get_git_untracked_files};
|
|||
use core::panic;
|
||||
use getopts::Options;
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::OsString;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs;
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -225,6 +225,29 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
// Avoid spawning an external command when we know tidy won't be used.
|
||||
false
|
||||
};
|
||||
let filters = if mode == Mode::RunMake {
|
||||
matches
|
||||
.free
|
||||
.iter()
|
||||
.map(|f| {
|
||||
let path = Path::new(f);
|
||||
let mut iter = path.iter().skip(1);
|
||||
|
||||
// We skip the test folder and check if the user passed `rmake.rs` or `Makefile`.
|
||||
if iter
|
||||
.next()
|
||||
.is_some_and(|s| s == OsStr::new("rmake.rs") || s == OsStr::new("Makefile"))
|
||||
&& iter.next().is_none()
|
||||
{
|
||||
path.parent().unwrap().to_str().unwrap().to_string()
|
||||
} else {
|
||||
f.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
matches.free.clone()
|
||||
};
|
||||
Config {
|
||||
bless: matches.opt_present("bless"),
|
||||
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
|
||||
|
|
@ -249,7 +272,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
debugger: None,
|
||||
run_ignored,
|
||||
with_debug_assertions,
|
||||
filters: matches.free.clone(),
|
||||
filters,
|
||||
skip: matches.opt_strs("skip"),
|
||||
filter_exact: matches.opt_present("exact"),
|
||||
force_pass_mode: matches.opt_str("pass").map(|mode| {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _
|
|||
error: deadlock: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
|
|
||||
LL | let ret = libc::pthread_join(self.id, ptr::null_mut());
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
|
|||
error: deadlock: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
|
|
||||
LL | let ret = libc::pthread_join(self.id, ptr::null_mut());
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
|
|||
error: deadlock: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
|
|
||||
LL | let ret = libc::pthread_join(self.id, ptr::null_mut());
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@
|
|||
// ignore-tidy-dbg
|
||||
|
||||
use crate::walk::{filter_dirs, walk};
|
||||
use regex::RegexSet;
|
||||
use regex::RegexSetBuilder;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::{ffi::OsStr, path::Path};
|
||||
use std::{ffi::OsStr, path::Path, sync::LazyLock};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
@ -110,16 +110,26 @@ const ROOT_PROBLEMATIC_CONSTS: &[u32] = &[
|
|||
173390526, 721077,
|
||||
];
|
||||
|
||||
const LETTER_DIGIT: &[(char, char)] = &[('A', '4'), ('B', '8'), ('E', '3')];
|
||||
|
||||
// Returns all permutations of problematic consts, over 2000 elements.
|
||||
fn generate_problematic_strings(
|
||||
consts: &[u32],
|
||||
letter_digit: &FxHashMap<char, char>,
|
||||
) -> Vec<String> {
|
||||
generate_problems(consts, letter_digit)
|
||||
.flat_map(|v| vec![v.to_string(), format!("{:x}", v), format!("{:X}", v)])
|
||||
.flat_map(|v| vec![v.to_string(), format!("{:X}", v)])
|
||||
.collect()
|
||||
}
|
||||
|
||||
static PROBLEMATIC_CONSTS_STRINGS: LazyLock<Vec<String>> = LazyLock::new(|| {
|
||||
generate_problematic_strings(ROOT_PROBLEMATIC_CONSTS, &LETTER_DIGIT.iter().cloned().collect())
|
||||
});
|
||||
|
||||
fn contains_problematic_const(trimmed: &str) -> bool {
|
||||
PROBLEMATIC_CONSTS_STRINGS.iter().any(|s| trimmed.to_uppercase().contains(s))
|
||||
}
|
||||
|
||||
const INTERNAL_COMPILER_DOCS_LINE: &str = "#### This error code is internal to the compiler and will not be emitted with normal Rust code.";
|
||||
|
||||
/// Parser states for `line_is_url`.
|
||||
|
|
@ -316,14 +326,14 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
// We only check CSS files in rustdoc.
|
||||
path.extension().map_or(false, |e| e == "css") && !is_in(path, "src", "librustdoc")
|
||||
}
|
||||
let problematic_consts_strings = generate_problematic_strings(
|
||||
ROOT_PROBLEMATIC_CONSTS,
|
||||
&[('A', '4'), ('B', '8'), ('E', '3')].iter().cloned().collect(),
|
||||
);
|
||||
|
||||
// This creates a RegexSet as regex contains performance optimizations to be able to deal with these over
|
||||
// 2000 needles efficiently. This runs over the entire source code, so performance matters.
|
||||
let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
|
||||
|
||||
let problematic_regex = RegexSetBuilder::new(PROBLEMATIC_CONSTS_STRINGS.as_slice())
|
||||
.case_insensitive(true)
|
||||
.build()
|
||||
.unwrap();
|
||||
let style_file = Path::new(file!());
|
||||
walk(path, skip, &mut |entry, contents| {
|
||||
let file = entry.path();
|
||||
let filename = file.file_name().unwrap().to_string_lossy();
|
||||
|
|
@ -389,10 +399,15 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
let mut lines = 0;
|
||||
let mut last_safety_comment = false;
|
||||
let mut comment_block: Option<(usize, usize)> = None;
|
||||
let is_test = file.components().any(|c| c.as_os_str() == "tests");
|
||||
let is_test = file.components().any(|c| c.as_os_str() == "tests")
|
||||
|| file.file_stem().unwrap() == "tests";
|
||||
let is_style = file.ends_with(style_file) || style_file.ends_with(file);
|
||||
let is_style_test =
|
||||
is_test && file.parent().unwrap().ends_with(style_file.with_extension(""));
|
||||
// scanning the whole file for multiple needles at once is more efficient than
|
||||
// executing lines times needles separate searches.
|
||||
let any_problematic_line = problematic_regex.is_match(contents);
|
||||
let any_problematic_line =
|
||||
!is_style && !is_style_test && problematic_regex.is_match(contents);
|
||||
for (i, line) in contents.split('\n').enumerate() {
|
||||
if line.is_empty() {
|
||||
if i == 0 {
|
||||
|
|
@ -451,7 +466,7 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
if line.contains('\r') {
|
||||
suppressible_tidy_err!(err, skip_cr, "CR character");
|
||||
}
|
||||
if filename != "style.rs" {
|
||||
if !is_style {
|
||||
// Allow using TODO in diagnostic suggestions by marking the
|
||||
// relevant line with `// ignore-tidy-todo`.
|
||||
if trimmed.contains("TODO") && !trimmed.contains("ignore-tidy-todo") {
|
||||
|
|
@ -462,12 +477,8 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
if trimmed.contains("//") && trimmed.contains(" XXX") {
|
||||
err("Instead of XXX use FIXME")
|
||||
}
|
||||
if any_problematic_line {
|
||||
for s in problematic_consts_strings.iter() {
|
||||
if trimmed.contains(s) {
|
||||
err("Don't use magic numbers that spell things (consider 0x12345678)");
|
||||
}
|
||||
}
|
||||
if any_problematic_line && contains_problematic_const(trimmed) {
|
||||
err("Don't use magic numbers that spell things (consider 0x12345678)");
|
||||
}
|
||||
}
|
||||
// for now we just check libcore
|
||||
|
|
|
|||
|
|
@ -1,17 +1,10 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_generate_problematic_strings() {
|
||||
let problematic_regex = RegexSet::new(
|
||||
generate_problematic_strings(
|
||||
ROOT_PROBLEMATIC_CONSTS,
|
||||
&[('A', '4'), ('B', '8'), ('E', '3'), ('0', 'F')].iter().cloned().collect(), // use "futile" F intentionally
|
||||
)
|
||||
.as_slice(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(problematic_regex.is_match("786357")); // check with no "decimal" hex digits - converted to integer
|
||||
assert!(problematic_regex.is_match("589701")); // check with "decimal" replacements - converted to integer
|
||||
assert!(problematic_regex.is_match("8FF85")); // check for hex display
|
||||
assert!(!problematic_regex.is_match("1193046")); // check for non-matching value
|
||||
fn test_contains_problematic_const() {
|
||||
assert!(contains_problematic_const("721077")); // check with no "decimal" hex digits - converted to integer
|
||||
assert!(contains_problematic_const("524421")); // check with "decimal" replacements - converted to integer
|
||||
assert!(contains_problematic_const(&(285 * 281).to_string())); // check for hex display
|
||||
assert!(contains_problematic_const(&format!("{:x}B5", 2816))); // check for case-alternating hex display
|
||||
assert!(!contains_problematic_const("1193046")); // check for non-matching value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
|
|||
--> $DIR/invalid_const_in_lifetime_position.rs:4:26
|
||||
|
|
||||
LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
|
||||
| ^--- help: remove these generics
|
||||
| ^--- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
|
||||
|
|
@ -49,7 +49,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
|
|||
--> $DIR/invalid_const_in_lifetime_position.rs:4:26
|
||||
|
|
||||
LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
|
||||
| ^--- help: remove these generics
|
||||
| ^--- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
|
||||
|
|
@ -81,7 +81,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
|
|||
--> $DIR/invalid_const_in_lifetime_position.rs:4:26
|
||||
|
|
||||
LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
|
||||
| ^--- help: remove these generics
|
||||
| ^--- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0107]: type alias takes 1 lifetime argument but 2 lifetime arguments were
|
|||
--> $DIR/mismatched_arg_count.rs:7:29
|
||||
|
|
||||
LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
|
||||
| ^^^^^ -- help: remove this lifetime argument
|
||||
| ^^^^^ ---- help: remove the lifetime argument
|
||||
| |
|
||||
| expected 1 lifetime argument
|
||||
|
|
||||
|
|
|
|||
|
|
@ -46,9 +46,11 @@ use thin_vec::{thin_vec, ThinVec};
|
|||
fn parse_expr(psess: &ParseSess, src: &str) -> Option<P<Expr>> {
|
||||
let src_as_string = src.to_string();
|
||||
|
||||
let mut p = unwrap_or_emit_fatal(
|
||||
new_parser_from_source_str(psess, FileName::Custom(src_as_string.clone()), src_as_string)
|
||||
);
|
||||
let mut p = unwrap_or_emit_fatal(new_parser_from_source_str(
|
||||
psess,
|
||||
FileName::Custom(src_as_string.clone()),
|
||||
src_as_string,
|
||||
));
|
||||
p.parse_expr().map_err(|e| e.cancel()).ok()
|
||||
}
|
||||
|
||||
|
|
@ -181,10 +183,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
|
|||
18 => {
|
||||
let pat =
|
||||
P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None });
|
||||
iter_exprs(
|
||||
depth - 1,
|
||||
&mut |e| g(ExprKind::Let(pat.clone(), e, DUMMY_SP, Recovered::No))
|
||||
)
|
||||
iter_exprs(depth - 1, &mut |e| {
|
||||
g(ExprKind::Let(pat.clone(), e, DUMMY_SP, Recovered::No))
|
||||
})
|
||||
}
|
||||
_ => panic!("bad counter value in iter_exprs"),
|
||||
}
|
||||
|
|
@ -202,7 +203,7 @@ impl MutVisitor for RemoveParens {
|
|||
ExprKind::Paren(inner) => *e = inner,
|
||||
_ => {}
|
||||
};
|
||||
mut_visit::noop_visit_expr(e, self);
|
||||
mut_visit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +212,7 @@ struct AddParens;
|
|||
|
||||
impl MutVisitor for AddParens {
|
||||
fn visit_expr(&mut self, e: &mut P<Expr>) {
|
||||
mut_visit::noop_visit_expr(e, self);
|
||||
mut_visit::walk_expr(self, e);
|
||||
visit_clobber(e, |e| {
|
||||
P(Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp
|
|||
--> $DIR/issue-100154.rs:4:5
|
||||
|
|
||||
LL | foo::<()>(());
|
||||
| ^^^------ help: remove these generics
|
||||
| ^^^------ help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
|
||||
|
|
|
|||
|
|
@ -3,5 +3,7 @@ fn foo(x: impl async Fn()) -> impl async Fn() { x }
|
|||
//~| ERROR `async` trait bounds are only allowed in Rust 2018 or later
|
||||
//~| ERROR async closures are unstable
|
||||
//~| ERROR async closures are unstable
|
||||
//~| ERROR use of unstable library feature 'async_closure'
|
||||
//~| ERROR use of unstable library feature 'async_closure'
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,26 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= help: to use an async block, remove the `||`: `async {`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error[E0658]: use of unstable library feature 'async_closure'
|
||||
--> $DIR/edition-2015.rs:1:22
|
||||
|
|
||||
LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
|
||||
| ^^^^
|
||||
|
|
||||
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
|
||||
= help: add `#![feature(async_closure)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: use of unstable library feature 'async_closure'
|
||||
--> $DIR/edition-2015.rs:1:42
|
||||
|
|
||||
LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
|
||||
| ^^^^
|
||||
|
|
||||
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
|
||||
= help: add `#![feature(async_closure)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
//@ edition: 2021
|
||||
//@ build-pass
|
||||
|
||||
#![feature(async_fn_traits)]
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
//@ known-bug: #119272
|
||||
//! used to ICE: #119272
|
||||
|
||||
//@ check-pass
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
mod defining_scope {
|
||||
use super::*;
|
||||
|
|
@ -2,7 +2,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
|
|||
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
|
||||
|
|
||||
LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
|
||||
| ^^^^^^^^^^^^---- help: remove these generics
|
||||
| ^^^^^^^^^^^^---- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 lifetime arguments
|
||||
|
|
||||
|
|
@ -32,7 +32,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
|
|||
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
|
||||
|
|
||||
LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
|
||||
| ^^^^^^^^^^^^---- help: remove these generics
|
||||
| ^^^^^^^^^^^^---- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 lifetime arguments
|
||||
|
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0107]: trait takes at most 2 generic arguments but 3 generic arguments we
|
|||
--> $DIR/transmutable-ice-110969.rs:11:14
|
||||
|
|
||||
LL | Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ ------ help: remove this generic argument
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ -------- help: remove the unnecessary generic argument
|
||||
| |
|
||||
| expected at most 2 generic arguments
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ error[E0107]: struct takes 2 generic arguments but 3 generic arguments were supp
|
|||
--> $DIR/infer-arg-test.rs:18:10
|
||||
|
|
||||
LL | let a: All<_, _, _>;
|
||||
| ^^^ - help: remove this generic argument
|
||||
| ^^^ --- help: remove the unnecessary generic argument
|
||||
| |
|
||||
| expected 2 generic arguments
|
||||
|
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0107]: function takes 1 generic argument but 2 generic arguments were sup
|
|||
--> $DIR/issue_114151.rs:17:5
|
||||
|
|
||||
LL | foo::<_, L>([(); L + 1 + L]);
|
||||
| ^^^ - help: remove this generic argument
|
||||
| ^^^ --- help: remove the unnecessary generic argument
|
||||
| |
|
||||
| expected 1 generic argument
|
||||
|
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
|
|||
--> $DIR/issue-102768.rs:9:30
|
||||
|
|
||||
LL | fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
|
||||
| ^--- help: remove these generics
|
||||
| ^--- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
|
||||
|
|
@ -49,7 +49,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
|
|||
--> $DIR/issue-102768.rs:9:30
|
||||
|
|
||||
LL | fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
|
||||
| ^--- help: remove these generics
|
||||
| ^--- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
|
||||
|
|
@ -81,7 +81,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
|
|||
--> $DIR/issue-102768.rs:9:30
|
||||
|
|
||||
LL | fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
|
||||
| ^--- help: remove these generics
|
||||
| ^--- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ error[E0107]: function takes 2 generic arguments but 3 generic arguments were su
|
|||
--> $DIR/incorrect-number-of-const-args.rs:9:5
|
||||
|
|
||||
LL | foo::<0, 0, 0>();
|
||||
| ^^^ - help: remove this generic argument
|
||||
| ^^^ --- help: remove the unnecessary generic argument
|
||||
| |
|
||||
| expected 2 generic arguments
|
||||
|
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ help: consider moving this generic argument to the `TryInto` trait, which takes
|
|||
|
|
||||
LL | let _: u32 = TryInto::<32>::try_into(5i32).unwrap();
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
help: remove these generics
|
||||
help: remove the unnecessary generics
|
||||
|
|
||||
LL - let _: u32 = 5i32.try_into::<32>().unwrap();
|
||||
LL + let _: u32 = 5i32.try_into().unwrap();
|
||||
|
|
@ -27,7 +27,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli
|
|||
--> $DIR/invalid-const-arg-for-type-param.rs:12:5
|
||||
|
|
||||
LL | S::<0>;
|
||||
| ^----- help: remove these generics
|
||||
| ^----- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl
|
|||
--> $DIR/invalid-constant-in-args.rs:4:12
|
||||
|
|
||||
LL | let _: Cell<&str, "a"> = Cell::new("");
|
||||
| ^^^^ --- help: remove this generic argument
|
||||
| ^^^^ ----- help: remove the unnecessary generic argument
|
||||
| |
|
||||
| expected 1 generic argument
|
||||
|
||||
|
|
|
|||
|
|
@ -122,8 +122,6 @@ note: ...which requires const checking `main::{constant#0}`...
|
|||
|
|
||||
LL | foo::<42>();
|
||||
| ^^
|
||||
= note: ...which requires computing whether `Foo` is freeze...
|
||||
= note: ...which requires evaluating trait selection obligation `Foo: core::marker::Freeze`...
|
||||
= note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle
|
||||
note: cycle used when computing type of `Foo::{opaque#0}`
|
||||
--> $DIR/opaque_types.rs:3:12
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue