Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2024-07-25 05:17:55 +00:00
commit 4a26aa4439
196 changed files with 2507 additions and 1673 deletions

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,7 +2,7 @@
//@ edition: 2021
//@ build-pass
#![feature(async_fn_traits)]
#![feature(async_closure)]
extern crate block_on;

View file

@ -1,4 +1,7 @@
//@ known-bug: #119272
//! used to ICE: #119272
//@ check-pass
#![feature(type_alias_impl_trait)]
mod defining_scope {
use super::*;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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