Auto merge of #101115 - matthiaskrgr:rollup-iy14ztr, r=matthiaskrgr

Rollup of 13 pull requests

Successful merges:

 - #97015 (std::io: migrate ReadBuf to BorrowBuf/BorrowCursor)
 - #98301 (Add GDB/LLDB pretty-printers for NonZero types)
 - #99570 (Box::from(slice): Clarify that contents are copied)
 - #100296 (Add standard C error function aliases to last_os_error)
 - #100520 (Add mention of `BufReader` in `Read::bytes` docs)
 - #100885 (Export Cancel from std::os::fortanix_sgx::usercalls::raw)
 - #100955 (Some papercuts on error::Error)
 - #101002 (Provide structured suggestion for `hashmap[idx] = val`)
 - #101038 (no alignment check during interning)
 - #101055 (Use smaller span for suggestions)
 - #101091 (Extend attrs if local_def_id exists)
 - #101098 (rustc_middle: Remove `Visibility::Invisible`)
 - #101102 (unstable-book-gen: use std::fs::write)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-08-28 09:45:27 +00:00
commit 3fdd578d72
66 changed files with 972 additions and 646 deletions

View file

@ -223,14 +223,12 @@ impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
error_code!(E0565),
);
if self.is_bytestr {
if let Ok(lint_str) = sess.source_map().span_to_snippet(self.span) {
diag.span_suggestion(
self.span,
fluent::attr::unsupported_literal_suggestion,
&lint_str[1..],
Applicability::MaybeIncorrect,
);
}
diag.span_suggestion(
sess.source_map().start_point(self.span),
fluent::attr::unsupported_literal_suggestion,
"",
Applicability::MaybeIncorrect,
);
}
diag
}

View file

@ -1,5 +1,8 @@
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{
Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed,
};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
use rustc_middle::hir::map::Map;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
@ -614,7 +617,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
"trait `IndexMut` is required to modify indexed content, \
but it is not implemented for `{ty}`",
));
self.suggest_map_index_mut_alternatives(ty, &mut err);
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
}
_ => (),
}
@ -632,13 +635,120 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&self,
ty: Ty<'_>,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
span: Span,
) {
let Some(adt) = ty.ty_adt_def() else { return };
let did = adt.did();
if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
|| self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
{
err.help(format!("to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API"));
struct V<'a, 'b, 'tcx, G: EmissionGuarantee> {
assign_span: Span,
err: &'a mut DiagnosticBuilder<'b, G>,
ty: Ty<'tcx>,
suggested: bool,
}
impl<'a, 'b: 'a, 'hir, 'tcx, G: EmissionGuarantee> Visitor<'hir> for V<'a, 'b, 'tcx, G> {
fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) {
hir::intravisit::walk_stmt(self, stmt);
let expr = match stmt.kind {
hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr,
_ => {
return;
}
};
if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
&& let hir::ExprKind::Index(val, index) = place.kind
&& (expr.span == self.assign_span || place.span == self.assign_span)
{
// val[index] = rv;
// ---------- place
self.err.multipart_suggestions(
&format!(
"to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
self.ty,
),
vec![
vec![ // val.insert(index, rv);
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
".insert(".to_string(),
),
(
index.span.shrink_to_hi().with_hi(rv.span.lo()),
", ".to_string(),
),
(rv.span.shrink_to_hi(), ")".to_string()),
],
vec![ // val.get_mut(index).map(|v| { *v = rv; });
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
".get_mut(".to_string(),
),
(
index.span.shrink_to_hi().with_hi(place.span.hi()),
").map(|val| { *val".to_string(),
),
(
rv.span.shrink_to_hi(),
"; })".to_string(),
),
],
vec![ // let x = val.entry(index).or_insert(rv);
(val.span.shrink_to_lo(), "let val = ".to_string()),
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
".entry(".to_string(),
),
(
index.span.shrink_to_hi().with_hi(rv.span.lo()),
").or_insert(".to_string(),
),
(rv.span.shrink_to_hi(), ")".to_string()),
],
].into_iter(),
Applicability::MachineApplicable,
);
self.suggested = true;
} else if let hir::ExprKind::MethodCall(_path, args @ [_, ..], sp) = expr.kind
&& let hir::ExprKind::Index(val, index) = args[0].kind
&& expr.span == self.assign_span
{
// val[index].path(args..);
self.err.multipart_suggestion(
&format!("to modify a `{}` use `.get_mut()`", self.ty),
vec![
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
".get_mut(".to_string(),
),
(
index.span.shrink_to_hi().with_hi(args[0].span.hi()),
").map(|val| val".to_string(),
),
(sp.shrink_to_hi(), ")".to_string()),
],
Applicability::MachineApplicable,
);
self.suggested = true;
}
}
}
let hir_map = self.infcx.tcx.hir();
let def_id = self.body.source.def_id();
let hir_id = hir_map.local_def_id_to_hir_id(def_id.as_local().unwrap());
let node = hir_map.find(hir_id);
let Some(hir::Node::Item(item)) = node else { return; };
let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
let body = self.infcx.tcx.hir().body(body_id);
let mut v = V { assign_span: span, err, ty, suggested: false };
v.visit_body(body);
if !v.suggested {
err.help(&format!(
"to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
));
}
}
}

View file

@ -1500,24 +1500,18 @@ fn vcall_visibility_metadata<'ll, 'tcx>(
// If there is not LTO and the visibility in public, we have to assume that the vtable can
// be seen from anywhere. With multiple CGUs, the vtable is quasi-public.
(Lto::No | Lto::ThinLocal, Visibility::Public, _)
| (Lto::No, Visibility::Restricted(_) | Visibility::Invisible, false) => {
VCallVisibility::Public
}
| (Lto::No, Visibility::Restricted(_), false) => VCallVisibility::Public,
// With LTO and a quasi-public visibility, the usages of the functions of the vtable are
// all known by the `LinkageUnit`.
// FIXME: LLVM only supports this optimization for `Lto::Fat` currently. Once it also
// supports `Lto::Thin` the `VCallVisibility` may have to be adjusted for those.
(Lto::Fat | Lto::Thin, Visibility::Public, _)
| (
Lto::ThinLocal | Lto::Thin | Lto::Fat,
Visibility::Restricted(_) | Visibility::Invisible,
false,
) => VCallVisibility::LinkageUnit,
| (Lto::ThinLocal | Lto::Thin | Lto::Fat, Visibility::Restricted(_), false) => {
VCallVisibility::LinkageUnit
}
// If there is only one CGU, private vtables can only be seen by that CGU/translation unit
// and therefore we know of all usages of functions in the vtable.
(_, Visibility::Restricted(_) | Visibility::Invisible, true) => {
VCallVisibility::TranslationUnit
}
(_, Visibility::Restricted(_), true) => VCallVisibility::TranslationUnit,
};
let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);

View file

@ -74,7 +74,9 @@ fn eval_body_using_ecx<'mir, 'tcx>(
None => InternKind::Constant,
}
};
ecx.machine.check_alignment = false; // interning doesn't need to respect alignment
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
// we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
debug!("eval_body_using_ecx done: {:?}", *ret);
Ok(ret)

View file

@ -89,10 +89,10 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
/// exhaustion error.
///
/// Setting this to `0` disables the limit and allows the interpreter to run forever.
pub steps_remaining: usize,
pub(super) steps_remaining: usize,
/// The virtual call stack.
pub(crate) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
pub(super) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
/// We need to make sure consts never point to anything mutable, even recursively. That is
/// relied on for pattern matching on consts with references.
@ -103,7 +103,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
pub(super) can_access_statics: bool,
/// Whether to check alignment during evaluation.
check_alignment: bool,
pub(super) check_alignment: bool,
}
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {

View file

@ -293,7 +293,7 @@ fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// These are not visible outside crate; therefore
// stability markers are irrelevant, if even present.
ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true,
ty::Visibility::Restricted(..) => true,
}
}

View file

@ -169,14 +169,10 @@ impl<'tcx> FieldDef {
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest<'tcx> {
let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
// FIXME(canndrew): Currently enum fields are (incorrectly) stored with
// `Visibility::Invisible` so we need to override `self.vis` if we're
// dealing with an enum.
if is_enum {
data_uninhabitedness()
} else {
match self.vis {
Visibility::Invisible => DefIdForest::empty(),
Visibility::Restricted(from) => {
let forest = DefIdForest::from_id(from);
let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));

View file

@ -268,8 +268,6 @@ pub enum Visibility {
Public,
/// Visible only in the given crate-local module.
Restricted(DefId),
/// Not visible anywhere in the local crate. This is the visibility of private external items.
Invisible,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
@ -366,8 +364,6 @@ impl Visibility {
let restriction = match self {
// Public items are visible everywhere.
Visibility::Public => return true,
// Private items from other crates are visible nowhere.
Visibility::Invisible => return false,
// Restricted items are visible in an arbitrary local module.
Visibility::Restricted(other) if other.krate != module.krate => return false,
Visibility::Restricted(module) => module,
@ -380,7 +376,6 @@ impl Visibility {
pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool {
let vis_restriction = match vis {
Visibility::Public => return self == Visibility::Public,
Visibility::Invisible => return true,
Visibility::Restricted(module) => module,
};
@ -392,7 +387,6 @@ impl Visibility {
match self {
Visibility::Public => true,
Visibility::Restricted(def_id) => def_id.is_local(),
Visibility::Invisible => false,
}
}

View file

@ -1731,7 +1731,6 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
if !vis.is_at_least(self.required_visibility, self.tcx) {
let vis_descr = match vis {
ty::Visibility::Public => "public",
ty::Visibility::Invisible => "private",
ty::Visibility::Restricted(vis_def_id) => {
if vis_def_id == self.tcx.parent_module(hir_id).to_def_id() {
"private"

View file

@ -380,7 +380,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
has_attributes: !item.attrs.is_empty(),
root_span,
root_id,
vis: Cell::new(vis),
vis: Cell::new(Some(vis)),
used: Cell::new(false),
});
@ -588,7 +588,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
ast::UseTreeKind::Glob => {
let kind = ImportKind::Glob {
is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import),
max_vis: Cell::new(ty::Visibility::Invisible),
max_vis: Cell::new(None),
};
self.r.visibilities.insert(self.r.local_def_id(id), vis);
self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis);
@ -650,7 +650,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
true,
// The whole `use` item
item,
ty::Visibility::Invisible,
ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()),
root_span,
);
}
@ -885,7 +885,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
root_span: item.span,
span: item.span,
module_path: Vec::new(),
vis: Cell::new(vis),
vis: Cell::new(Some(vis)),
used: Cell::new(used),
});
self.r.potentially_unused_imports.push(import);
@ -1118,7 +1118,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
root_span: span,
span,
module_path: Vec::new(),
vis: Cell::new(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())),
vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))),
used: Cell::new(false),
})
};

View file

@ -227,7 +227,7 @@ impl Resolver<'_> {
for import in self.potentially_unused_imports.iter() {
match import.kind {
_ if import.used.get()
|| import.vis.get().is_public()
|| import.expect_vis().is_public()
|| import.span.is_dummy() =>
{
if let ImportKind::MacroUse = import.kind {

View file

@ -953,7 +953,10 @@ impl<'a> Resolver<'a> {
// Check if one of single imports can still define the name,
// if it can then our result is not determined and can be invalidated.
for single_import in &resolution.single_imports {
if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) {
let Some(import_vis) = single_import.vis.get() else {
continue;
};
if !self.is_accessible_from(import_vis, parent_scope.module) {
continue;
}
let Some(module) = single_import.imported_module.get() else {
@ -1018,7 +1021,10 @@ impl<'a> Resolver<'a> {
// Check if one of glob imports can still define the name,
// if it can then our "no resolution" result is not determined and can be invalidated.
for glob_import in module.globs.borrow().iter() {
if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) {
let Some(import_vis) = glob_import.vis.get() else {
continue;
};
if !self.is_accessible_from(import_vis, parent_scope.module) {
continue;
}
let module = match glob_import.imported_module.get() {

View file

@ -52,8 +52,8 @@ pub enum ImportKind<'a> {
},
Glob {
is_prelude: bool,
max_vis: Cell<ty::Visibility>, // The visibility of the greatest re-export.
// n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
max_vis: Cell<Option<ty::Visibility>>, // The visibility of the greatest re-export.
// n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
},
ExternCrate {
source: Option<Symbol>,
@ -144,7 +144,7 @@ pub(crate) struct Import<'a> {
pub module_path: Vec<Segment>,
/// The resolution of `module_path`.
pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
pub vis: Cell<ty::Visibility>,
pub vis: Cell<Option<ty::Visibility>>,
pub used: Cell<bool>,
}
@ -159,6 +159,10 @@ impl<'a> Import<'a> {
_ => false,
}
}
pub(crate) fn expect_vis(&self) -> ty::Visibility {
self.vis.get().expect("encountered cleared import visibility")
}
}
/// Records information about the resolution of a name in a namespace of a module.
@ -199,7 +203,7 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi
import: Import { kind: ImportKind::ExternCrate { .. }, .. },
..
},
) => import.vis.get().is_public(),
) => import.expect_vis().is_public(),
_ => false,
}
}
@ -212,17 +216,20 @@ impl<'a> Resolver<'a> {
binding: &'a NameBinding<'a>,
import: &'a Import<'a>,
) -> &'a NameBinding<'a> {
let vis = if binding.vis.is_at_least(import.vis.get(), self)
let import_vis = import.expect_vis();
let vis = if binding.vis.is_at_least(import_vis, self)
|| pub_use_of_private_extern_crate_hack(import, binding)
{
import.vis.get()
import_vis
} else {
binding.vis
};
if let ImportKind::Glob { ref max_vis, .. } = import.kind {
if vis == import.vis.get() || vis.is_at_least(max_vis.get(), self) {
max_vis.set(vis)
if vis == import_vis
|| max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self))
{
max_vis.set(Some(vis))
}
}
@ -536,7 +543,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
} else {
// For better failure detection, pretend that the import will
// not define any names while resolving its module path.
let orig_vis = import.vis.replace(ty::Visibility::Invisible);
let orig_vis = import.vis.take();
let path_res =
self.r.maybe_resolve_path(&import.module_path, None, &import.parent_scope);
import.vis.set(orig_vis);
@ -571,7 +578,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
if let Err(Undetermined) = source_bindings[ns].get() {
// For better failure detection, pretend that the import will
// not define any names while resolving its module path.
let orig_vis = import.vis.replace(ty::Visibility::Invisible);
let orig_vis = import.vis.take();
let binding = this.resolve_ident_in_module(
module,
source,
@ -620,7 +627,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
/// Optionally returns an unresolved import error. This error is buffered and used to
/// consolidate multiple unresolved import errors into a single diagnostic.
fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
let orig_vis = import.vis.replace(ty::Visibility::Invisible);
let orig_vis = import.vis.take();
let ignore_binding = match &import.kind {
ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
_ => None,
@ -727,9 +734,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
});
}
}
if !is_prelude &&
max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
!max_vis.get().is_at_least(import.vis.get(), &*self.r)
if !is_prelude
&& let Some(max_vis) = max_vis.get()
&& !max_vis.is_at_least(import.expect_vis(), &*self.r)
{
let msg = "glob import doesn't reexport anything because no candidate is public enough";
self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
@ -742,7 +749,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let mut all_ns_err = true;
self.r.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
let orig_vis = import.vis.replace(ty::Visibility::Invisible);
let orig_vis = import.vis.take();
let binding = this.resolve_ident_in_module(
module,
ident,
@ -906,8 +913,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let mut crate_private_reexport = false;
self.r.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
let vis = import.vis.get();
if !binding.vis.is_at_least(vis, &*this) {
if !binding.vis.is_at_least(import.expect_vis(), &*this) {
reexport_error = Some((ns, binding));
if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
if binding_def_id.is_top_level_module() {

View file

@ -1299,7 +1299,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// local binding
if let hir::def::Res::Local(hir_id) = path.res {
let span = tcx.hir().span(hir_id);
let snippet = tcx.sess.source_map().span_to_snippet(span);
let filename = tcx.sess.source_map().span_to_filename(span);
let parent_node =
@ -1309,7 +1308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
concrete_type,
);
match (filename, parent_node, snippet) {
match (filename, parent_node) {
(
FileName::Real(_),
Node::Local(hir::Local {
@ -1317,14 +1316,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty,
..
}),
Ok(ref snippet),
) => {
let type_span = ty.map(|ty| ty.span.with_lo(span.hi())).unwrap_or(span.shrink_to_hi());
err.span_suggestion(
// account for `let x: _ = 42;`
// ^^^^
span.to(ty.as_ref().map(|ty| ty.span).unwrap_or(span)),
// ^^^
type_span,
&msg,
format!("{}: {}", snippet, concrete_type),
format!(": {concrete_type}"),
Applicability::MaybeIncorrect,
);
}

View file

@ -762,16 +762,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
// If there is a single unbound associated type and a single excess generic param
// suggest replacing the generic param with the associated type bound
if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
let mut suggestions = vec![];
let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
for (potential, name) in iter::zip(unused_generics, &unbound_types) {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(potential.span()) {
suggestions.push((potential.span(), format!("{} = {}", name, snippet)));
}
}
let suggestions = iter::zip(unused_generics, &unbound_types)
.map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = ")))
.collect::<Vec<_>>();
if !suggestions.is_empty() {
err.multipart_suggestion(
err.multipart_suggestion_verbose(
&format!(
"replace the generic bound{s} with the associated type{s}",
s = pluralize!(unbound_types.len())

View file

@ -1485,7 +1485,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
/// Converts a `&[T]` into a `Box<[T]>`
///
/// This conversion allocates on the heap
/// and performs a copy of `slice`.
/// and performs a copy of `slice` and its contents.
///
/// # Examples
/// ```rust

View file

@ -1,17 +1,6 @@
#![doc = include_str!("error.md")]
#![unstable(feature = "error_in_core", issue = "none")]
// A note about crates and the facade:
//
// Originally, the `Error` trait was defined in libcore, and the impls
// were scattered about. However, coherence objected to this
// arrangement, because to create the blanket impls for `Box` required
// knowing that `&str: !Error`, and we have no means to deal with that
// sort of conflict just now. Therefore, for the time being, we have
// moved the `Error` trait into libstd. As we evolve a sol'n to the
// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.
#[cfg(test)]
mod tests;
@ -30,12 +19,12 @@ use crate::fmt::{Debug, Display};
/// assert_eq!(err.to_string(), "invalid digit found in string");
/// ```
///
/// Errors may provide cause chain information. [`Error::source()`] is generally
/// Errors may provide cause information. [`Error::source()`] is generally
/// used when errors cross "abstraction boundaries". If one module must report
/// an error that is caused by an error from a lower-level module, it can allow
/// accessing that error via [`Error::source()`]. This makes it possible for the
/// high-level module to provide its own errors while also revealing some of the
/// implementation for debugging via `source` chains.
/// implementation for debugging.
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
#[rustc_has_incoherent_inherent_impls]
@ -182,8 +171,8 @@ pub trait Error: Debug + Display {
/// }
///
/// impl std::error::Error for Error {
/// fn provide<'a>(&'a self, req: &mut Demand<'a>) {
/// req
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
/// demand
/// .provide_ref::<MyBacktrace>(&self.backtrace)
/// .provide_ref::<dyn std::error::Error + 'static>(&self.source);
/// }
@ -201,7 +190,7 @@ pub trait Error: Debug + Display {
/// ```
#[unstable(feature = "error_generic_member_access", issue = "99301")]
#[allow(unused_variables)]
fn provide<'a>(&'a self, req: &mut Demand<'a>) {}
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {}
}
#[unstable(feature = "error_generic_member_access", issue = "99301")]
@ -209,8 +198,8 @@ impl<E> Provider for E
where
E: Error + ?Sized,
{
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
self.provide(req)
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
self.provide(demand)
}
}
@ -397,7 +386,7 @@ impl dyn Error {
/// // let err : Box<Error> = b.into(); // or
/// let err = &b as &(dyn Error);
///
/// let mut iter = err.chain();
/// let mut iter = err.sources();
///
/// assert_eq!("B".to_string(), iter.next().unwrap().to_string());
/// assert_eq!("A".to_string(), iter.next().unwrap().to_string());
@ -406,8 +395,19 @@ impl dyn Error {
/// ```
#[unstable(feature = "error_iter", issue = "58520")]
#[inline]
pub fn chain(&self) -> Chain<'_> {
Chain { current: Some(self) }
pub fn sources(&self) -> Source<'_> {
// You may think this method would be better in the Error trait, and you'd be right.
// Unfortunately that doesn't work, not because of the object safety rules but because we
// save a reference to self in Sources below as a trait object. If this method was
// declared in Error, then self would have the type &T where T is some concrete type which
// implements Error. We would need to coerce self to have type &dyn Error, but that requires
// that Self has a known size (i.e., Self: Sized). We can't put that bound on Error
// since that would forbid Error trait objects, and we can't put that bound on the method
// because that means the method can't be called on trait objects (we'd also need the
// 'static bound, but that isn't allowed because methods with bounds on Self other than
// Sized are not object-safe). Requiring an Unsize bound is not backwards compatible.
Source { current: Some(self) }
}
}
@ -417,12 +417,12 @@ impl dyn Error {
/// its sources, use `skip(1)`.
#[unstable(feature = "error_iter", issue = "58520")]
#[derive(Clone, Debug)]
pub struct Chain<'a> {
pub struct Source<'a> {
current: Option<&'a (dyn Error + 'static)>,
}
#[unstable(feature = "error_iter", issue = "58520")]
impl<'a> Iterator for Chain<'a> {
impl<'a> Iterator for Source<'a> {
type Item = &'a (dyn Error + 'static);
fn next(&mut self) -> Option<Self::Item> {
@ -448,8 +448,8 @@ impl<'a, T: Error + ?Sized> Error for &'a T {
Error::source(&**self)
}
fn provide<'b>(&'b self, req: &mut Demand<'b>) {
Error::provide(&**self, req);
fn provide<'b>(&'b self, demand: &mut Demand<'b>) {
Error::provide(&**self, demand);
}
}

View file

@ -1,17 +1,6 @@
#![doc = include_str!("../../core/src/error.md")]
#![stable(feature = "rust1", since = "1.0.0")]
// A note about crates and the facade:
//
// Originally, the `Error` trait was defined in libcore, and the impls
// were scattered about. However, coherence objected to this
// arrangement, because to create the blanket impls for `Box` required
// knowing that `&str: !Error`, and we have no means to deal with that
// sort of conflict just now. Therefore, for the time being, we have
// moved the `Error` trait into libstd. As we evolve a sol'n to the
// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.
#[cfg(test)]
mod tests;
@ -69,12 +58,12 @@ pub use core::error::Error;
/// assert_eq!(err.to_string(), "invalid digit found in string");
/// ```
///
/// Errors may provide cause chain information. [`Error::source()`] is generally
/// Errors may provide cause information. [`Error::source()`] is generally
/// used when errors cross "abstraction boundaries". If one module must report
/// an error that is caused by an error from a lower-level module, it can allow
/// accessing that error via [`Error::source()`]. This makes it possible for the
/// high-level module to provide its own errors while also revealing some of the
/// implementation for debugging via `source` chains.
/// implementation for debugging.
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
#[cfg(bootstrap)]
@ -221,8 +210,8 @@ pub trait Error: Debug + Display {
/// }
///
/// impl std::error::Error for Error {
/// fn provide<'a>(&'a self, req: &mut Demand<'a>) {
/// req
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
/// demand
/// .provide_ref::<MyBacktrace>(&self.backtrace)
/// .provide_ref::<dyn std::error::Error + 'static>(&self.source);
/// }
@ -240,14 +229,14 @@ pub trait Error: Debug + Display {
/// ```
#[unstable(feature = "error_generic_member_access", issue = "99301")]
#[allow(unused_variables)]
fn provide<'a>(&'a self, req: &mut Demand<'a>) {}
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {}
}
#[cfg(bootstrap)]
#[unstable(feature = "error_generic_member_access", issue = "99301")]
impl<'b> Provider for dyn Error + 'b {
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
self.provide(req)
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
self.provide(demand)
}
}
@ -659,8 +648,8 @@ impl<'a, T: Error + ?Sized> Error for &'a T {
Error::source(&**self)
}
fn provide<'b>(&'b self, req: &mut Demand<'b>) {
Error::provide(&**self, req);
fn provide<'b>(&'b self, demand: &mut Demand<'b>) {
Error::provide(&**self, demand);
}
}
@ -681,8 +670,8 @@ impl<T: Error + ?Sized> Error for Arc<T> {
Error::source(&**self)
}
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
Error::provide(&**self, req);
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
Error::provide(&**self, demand);
}
}
@ -976,7 +965,7 @@ impl dyn Error {
/// // let err : Box<Error> = b.into(); // or
/// let err = &b as &(dyn Error);
///
/// let mut iter = err.chain();
/// let mut iter = err.sources();
///
/// assert_eq!("B".to_string(), iter.next().unwrap().to_string());
/// assert_eq!("A".to_string(), iter.next().unwrap().to_string());
@ -985,8 +974,19 @@ impl dyn Error {
/// ```
#[unstable(feature = "error_iter", issue = "58520")]
#[inline]
pub fn chain(&self) -> Chain<'_> {
Chain { current: Some(self) }
pub fn sources(&self) -> Sources<'_> {
// You may think this method would be better in the Error trait, and you'd be right.
// Unfortunately that doesn't work, not because of the object safety rules but because we
// save a reference to self in Sources below as a trait object. If this method was
// declared in Error, then self would have the type &T where T is some concrete type which
// implements Error. We would need to coerce self to have type &dyn Error, but that requires
// that Self has a known size (i.e., Self: Sized). We can't put that bound on Error
// since that would forbid Error trait objects, and we can't put that bound on the method
// because that means the method can't be called on trait objects (we'd also need the
// 'static bound, but that isn't allowed because methods with bounds on Self other than
// Sized are not object-safe). Requiring an Unsize bound is not backwards compatible.
Sources { current: Some(self) }
}
}
@ -997,13 +997,13 @@ impl dyn Error {
#[unstable(feature = "error_iter", issue = "58520")]
#[derive(Clone, Debug)]
#[cfg(bootstrap)]
pub struct Chain<'a> {
pub struct Sources<'a> {
current: Option<&'a (dyn Error + 'static)>,
}
#[cfg(bootstrap)]
#[unstable(feature = "error_iter", issue = "58520")]
impl<'a> Iterator for Chain<'a> {
impl<'a> Iterator for Sources<'a> {
type Item = &'a (dyn Error + 'static);
fn next(&mut self) -> Option<Self::Item> {
@ -1043,8 +1043,8 @@ impl dyn Error + Send + Sync {
/// An error reporter that prints an error and its sources.
///
/// Report also exposes configuration options for formatting the error chain, either entirely on a
/// single line, or in multi-line format with each cause in the error chain on a new line.
/// Report also exposes configuration options for formatting the error sources, either entirely on a
/// single line, or in multi-line format with each source on a new line.
///
/// `Report` only requires that the wrapped error implement `Error`. It doesn't require that the
/// wrapped error be `Send`, `Sync`, or `'static`.
@ -1389,7 +1389,7 @@ impl<E> Report<E> {
///
/// **Note**: Report will search for the first `Backtrace` it can find starting from the
/// outermost error. In this example it will display the backtrace from the second error in the
/// chain, `SuperErrorSideKick`.
/// sources, `SuperErrorSideKick`.
///
/// ```rust
/// #![feature(error_reporter)]
@ -1427,9 +1427,8 @@ impl<E> Report<E> {
/// }
///
/// impl Error for SuperErrorSideKick {
/// fn provide<'a>(&'a self, req: &mut Demand<'a>) {
/// req
/// .provide_ref::<Backtrace>(&self.backtrace);
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
/// demand.provide_ref::<Backtrace>(&self.backtrace);
/// }
/// }
///
@ -1486,7 +1485,7 @@ where
let backtrace = backtrace.or_else(|| {
self.error
.source()
.map(|source| source.chain().find_map(|source| source.request_ref()))
.map(|source| source.sources().find_map(|source| source.request_ref()))
.flatten()
});
backtrace
@ -1497,7 +1496,7 @@ where
fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.error)?;
let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
let sources = self.error.source().into_iter().flat_map(<dyn Error>::sources);
for cause in sources {
write!(f, ": {cause}")?;
@ -1518,7 +1517,7 @@ where
let multiple = cause.source().is_some();
for (ind, error) in cause.chain().enumerate() {
for (ind, error) in cause.sources().enumerate() {
writeln!(f)?;
let mut indented = Indented { inner: f };
if multiple {

View file

@ -13,7 +13,7 @@ mod tests;
use crate::ffi::OsString;
use crate::fmt;
use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
use crate::path::{Path, PathBuf};
use crate::sys::fs as fs_imp;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@ -703,8 +703,8 @@ impl Read for File {
self.inner.read_vectored(bufs)
}
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
self.inner.read_buf(buf)
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.inner.read_buf(cursor)
}
#[inline]
@ -755,8 +755,8 @@ impl Read for &File {
self.inner.read(buf)
}
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
self.inner.read_buf(buf)
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.inner.read_buf(cursor)
}
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {

View file

@ -2,7 +2,7 @@ mod buffer;
use crate::fmt;
use crate::io::{
self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
self, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
};
use buffer::Buffer;
@ -266,21 +266,21 @@ impl<R: Read> Read for BufReader<R> {
Ok(nread)
}
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
if self.buf.pos() == self.buf.filled() && buf.remaining() >= self.capacity() {
if self.buf.pos() == self.buf.filled() && cursor.capacity() >= self.capacity() {
self.discard_buffer();
return self.inner.read_buf(buf);
return self.inner.read_buf(cursor);
}
let prev = buf.filled_len();
let prev = cursor.written();
let mut rem = self.fill_buf()?;
rem.read_buf(buf)?;
rem.read_buf(cursor.reborrow())?;
self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf
self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf
Ok(())
}

View file

@ -9,7 +9,7 @@
/// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so
/// without encountering any runtime bounds checks.
use crate::cmp;
use crate::io::{self, Read, ReadBuf};
use crate::io::{self, BorrowedBuf, Read};
use crate::mem::MaybeUninit;
pub struct Buffer {
@ -93,11 +93,15 @@ impl Buffer {
if self.pos >= self.filled {
debug_assert!(self.pos == self.filled);
let mut readbuf = ReadBuf::uninit(&mut self.buf);
let mut buf = BorrowedBuf::from(&mut *self.buf);
// SAFETY: `self.filled` bytes will always have been initialized.
unsafe {
buf.set_init(self.filled);
}
reader.read_buf(&mut readbuf)?;
reader.read_buf(buf.unfilled())?;
self.filled = readbuf.filled_len();
self.filled = buf.len();
self.pos = 0;
}
Ok(self.buffer())

View file

@ -1,5 +1,7 @@
use crate::io::prelude::*;
use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom};
use crate::io::{
self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom,
};
use crate::mem::MaybeUninit;
use crate::panic;
use crate::sync::atomic::{AtomicUsize, Ordering};
@ -61,48 +63,48 @@ fn test_buffered_reader_read_buf() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, inner);
let mut buf = [MaybeUninit::uninit(); 3];
let mut buf = ReadBuf::uninit(&mut buf);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3];
let mut buf: BorrowedBuf<'_> = buf.into();
reader.read_buf(&mut buf).unwrap();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [5, 6, 7]);
assert_eq!(reader.buffer(), []);
let mut buf = [MaybeUninit::uninit(); 2];
let mut buf = ReadBuf::uninit(&mut buf);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 2];
let mut buf: BorrowedBuf<'_> = buf.into();
reader.read_buf(&mut buf).unwrap();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [0, 1]);
assert_eq!(reader.buffer(), []);
let mut buf = [MaybeUninit::uninit(); 1];
let mut buf = ReadBuf::uninit(&mut buf);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1];
let mut buf: BorrowedBuf<'_> = buf.into();
reader.read_buf(&mut buf).unwrap();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [2]);
assert_eq!(reader.buffer(), [3]);
let mut buf = [MaybeUninit::uninit(); 3];
let mut buf = ReadBuf::uninit(&mut buf);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3];
let mut buf: BorrowedBuf<'_> = buf.into();
reader.read_buf(&mut buf).unwrap();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [3]);
assert_eq!(reader.buffer(), []);
reader.read_buf(&mut buf).unwrap();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [3, 4]);
assert_eq!(reader.buffer(), []);
buf.clear();
reader.read_buf(&mut buf).unwrap();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled_len(), 0);
assert!(buf.filled().is_empty());
}
#[test]

View file

@ -1,4 +1,4 @@
use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE};
use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
use crate::mem::MaybeUninit;
/// Copies the entire contents of a reader into a writer.
@ -97,37 +97,39 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
loop {
let buf = writer.buffer_mut();
let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
// SAFETY: init is either 0 or the initialized_len of the previous iteration
unsafe {
read_buf.assume_init(init);
// SAFETY: init is either 0 or the init_len from the previous iteration.
read_buf.set_init(init);
}
if read_buf.capacity() >= DEFAULT_BUF_SIZE {
match reader.read_buf(&mut read_buf) {
let mut cursor = read_buf.unfilled();
match reader.read_buf(cursor.reborrow()) {
Ok(()) => {
let bytes_read = read_buf.filled_len();
let bytes_read = cursor.written();
if bytes_read == 0 {
return Ok(len);
}
init = read_buf.initialized_len() - bytes_read;
// SAFETY: ReadBuf guarantees all of its filled bytes are init
unsafe { buf.set_len(buf.len() + bytes_read) };
init = read_buf.init_len() - bytes_read;
len += bytes_read as u64;
// SAFETY: BorrowedBuf guarantees all of its filled bytes are init
unsafe { buf.set_len(buf.len() + bytes_read) };
// Read again if the buffer still has enough capacity, as BufWriter itself would do
// This will occur if the reader returns short reads
continue;
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
} else {
writer.flush_buf()?;
init = 0;
}
writer.flush_buf()?;
}
}
}
@ -136,13 +138,13 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R,
writer: &mut W,
) -> Result<u64> {
let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
let mut buf = ReadBuf::uninit(&mut buf);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
let mut buf: BorrowedBuf<'_> = buf.into();
let mut len = 0;
loop {
match reader.read_buf(&mut buf) {
match reader.read_buf(buf.unfilled()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),

View file

@ -5,7 +5,7 @@ use crate::io::prelude::*;
use crate::alloc::Allocator;
use crate::cmp;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
@ -323,12 +323,12 @@ where
Ok(n)
}
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
let prev_filled = buf.filled_len();
fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
let prev_written = cursor.written();
Read::read_buf(&mut self.fill_buf()?, buf)?;
Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?;
self.pos += (buf.filled_len() - prev_filled) as u64;
self.pos += (cursor.written() - prev_written) as u64;
Ok(())
}

View file

@ -573,6 +573,8 @@ impl Error {
/// println!("last OS error: {os_error:?}");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(alias = "GetLastError")]
#[doc(alias = "errno")]
#[must_use]
#[inline]
pub fn last_os_error() -> Error {

View file

@ -6,7 +6,7 @@ use crate::cmp;
use crate::collections::VecDeque;
use crate::fmt;
use crate::io::{
self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
self, BorrowedCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
};
use crate::mem;
@ -21,8 +21,8 @@ impl<R: Read + ?Sized> Read for &mut R {
}
#[inline]
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
(**self).read_buf(buf)
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
(**self).read_buf(cursor)
}
#[inline]
@ -125,8 +125,8 @@ impl<R: Read + ?Sized> Read for Box<R> {
}
#[inline]
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
(**self).read_buf(buf)
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
(**self).read_buf(cursor)
}
#[inline]
@ -249,11 +249,11 @@ impl Read for &[u8] {
}
#[inline]
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
let amt = cmp::min(buf.remaining(), self.len());
fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
let amt = cmp::min(cursor.capacity(), self.len());
let (a, b) = self.split_at(amt);
buf.append(a);
cursor.append(a);
*self = b;
Ok(())
@ -427,10 +427,10 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
}
#[inline]
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
let (ref mut front, _) = self.as_slices();
let n = cmp::min(buf.remaining(), front.len());
Read::read_buf(front, buf)?;
let n = cmp::min(cursor.capacity(), front.len());
Read::read_buf(front, cursor)?;
self.drain(..n);
Ok(())
}

View file

@ -278,7 +278,7 @@ pub use self::{
};
#[unstable(feature = "read_buf", issue = "78485")]
pub use self::readbuf::ReadBuf;
pub use self::readbuf::{BorrowedBuf, BorrowedCursor};
pub(crate) use error::const_io_error;
mod buffered;
@ -362,29 +362,30 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>
buf.reserve(32); // buf is full, need more space
}
let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
// SAFETY: These bytes were initialized but not filled in the previous loop
unsafe {
read_buf.assume_init(initialized);
read_buf.set_init(initialized);
}
match r.read_buf(&mut read_buf) {
let mut cursor = read_buf.unfilled();
match r.read_buf(cursor.reborrow()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
if read_buf.filled_len() == 0 {
if cursor.written() == 0 {
return Ok(buf.len() - start_len);
}
// store how much was initialized but not filled
initialized = read_buf.initialized_len() - read_buf.filled_len();
let new_len = read_buf.filled_len() + buf.len();
initialized = cursor.init_ref().len();
// SAFETY: ReadBuf's invariants mean this much memory is init
// SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
unsafe {
let new_len = read_buf.filled().len() + buf.len();
buf.set_len(new_len);
}
@ -461,12 +462,15 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
}
}
pub(crate) fn default_read_buf<F>(read: F, buf: &mut ReadBuf<'_>) -> Result<()>
pub(crate) fn default_read_buf<F>(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()>
where
F: FnOnce(&mut [u8]) -> Result<usize>,
{
let n = read(buf.initialize_unfilled())?;
buf.add_filled(n);
let n = read(cursor.ensure_init().init_mut())?;
unsafe {
// SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to.
cursor.advance(n);
}
Ok(())
}
@ -803,30 +807,30 @@ pub trait Read {
/// Pull some bytes from this source into the specified buffer.
///
/// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to allow use
/// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use
/// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.
///
/// The default implementation delegates to `read`.
#[unstable(feature = "read_buf", issue = "78485")]
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
default_read_buf(|b| self.read(b), buf)
}
/// Read the exact number of bytes required to fill `buf`.
/// Read the exact number of bytes required to fill `cursor`.
///
/// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to
/// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to
/// allow use with uninitialized buffers.
#[unstable(feature = "read_buf", issue = "78485")]
fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
while buf.remaining() > 0 {
let prev_filled = buf.filled().len();
match self.read_buf(buf) {
fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> {
while cursor.capacity() > 0 {
let prev_written = cursor.written();
match self.read_buf(cursor.reborrow()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
if buf.filled().len() == prev_filled {
if cursor.written() == prev_written {
return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer"));
}
}
@ -883,6 +887,10 @@ pub trait Read {
/// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
/// otherwise. EOF is mapped to returning [`None`] from this iterator.
///
/// The default implementation calls `read` for each byte,
/// which can be very inefficient for data that's not in memory,
/// such as [`File`]. Consider using a [`BufReader`] in such cases.
///
/// # Examples
///
/// [`File`]s implement `Read`:
@ -895,10 +903,11 @@ pub trait Read {
/// ```no_run
/// use std::io;
/// use std::io::prelude::*;
/// use std::io::BufReader;
/// use std::fs::File;
///
/// fn main() -> io::Result<()> {
/// let f = File::open("foo.txt")?;
/// let f = BufReader::new(File::open("foo.txt")?);
///
/// for byte in f.bytes() {
/// println!("{}", byte.unwrap());
@ -2582,50 +2591,48 @@ impl<T: Read> Read for Take<T> {
Ok(n)
}
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> {
// Don't call into inner reader at all at EOF because it may still block
if self.limit == 0 {
return Ok(());
}
let prev_filled = buf.filled_len();
if self.limit <= buf.remaining() as u64 {
if self.limit <= buf.capacity() as u64 {
// if we just use an as cast to convert, limit may wrap around on a 32 bit target
let limit = cmp::min(self.limit, usize::MAX as u64) as usize;
let extra_init = cmp::min(limit as usize, buf.initialized_len() - buf.filled_len());
let extra_init = cmp::min(limit as usize, buf.init_ref().len());
// SAFETY: no uninit data is written to ibuf
let ibuf = unsafe { &mut buf.unfilled_mut()[..limit] };
let ibuf = unsafe { &mut buf.as_mut()[..limit] };
let mut sliced_buf = ReadBuf::uninit(ibuf);
let mut sliced_buf: BorrowedBuf<'_> = ibuf.into();
// SAFETY: extra_init bytes of ibuf are known to be initialized
unsafe {
sliced_buf.assume_init(extra_init);
sliced_buf.set_init(extra_init);
}
self.inner.read_buf(&mut sliced_buf)?;
let mut cursor = sliced_buf.unfilled();
self.inner.read_buf(cursor.reborrow())?;
let new_init = sliced_buf.initialized_len();
let filled = sliced_buf.filled_len();
let new_init = cursor.init_ref().len();
let filled = sliced_buf.len();
// sliced_buf / ibuf must drop here
// cursor / sliced_buf / ibuf must drop here
// SAFETY: new_init bytes of buf's unfilled buffer have been initialized
unsafe {
buf.assume_init(new_init);
// SAFETY: filled bytes have been filled and therefore initialized
buf.advance(filled);
// SAFETY: new_init bytes of buf's unfilled buffer have been initialized
buf.set_init(new_init);
}
buf.add_filled(filled);
self.limit -= filled as u64;
} else {
self.inner.read_buf(buf)?;
//inner may unfill
self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64;
let written = buf.written();
self.inner.read_buf(buf.reborrow())?;
self.limit -= (buf.written() - written) as u64;
}
Ok(())

View file

@ -5,9 +5,10 @@ mod tests;
use crate::cmp;
use crate::fmt::{self, Debug, Formatter};
use crate::mem::MaybeUninit;
use crate::io::{Result, Write};
use crate::mem::{self, MaybeUninit};
/// A wrapper around a byte buffer that is incrementally filled and initialized.
/// A borrowed byte buffer which is incrementally filled and initialized.
///
/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the
/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet
@ -20,146 +21,95 @@ use crate::mem::MaybeUninit;
/// [ filled | unfilled ]
/// [ initialized | uninitialized ]
/// ```
pub struct ReadBuf<'a> {
buf: &'a mut [MaybeUninit<u8>],
///
/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference
/// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be
/// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor
/// has write-only access to the unfilled portion of the buffer (you can think of it as a
/// write-only iterator).
///
/// The lifetime `'data` is a bound on the lifetime of the underlying data.
pub struct BorrowedBuf<'data> {
/// The buffer's underlying data.
buf: &'data mut [MaybeUninit<u8>],
/// The length of `self.buf` which is known to be filled.
filled: usize,
initialized: usize,
/// The length of `self.buf` which is known to be initialized.
init: usize,
}
impl Debug for ReadBuf<'_> {
impl Debug for BorrowedBuf<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("ReadBuf")
.field("init", &self.initialized())
f.debug_struct("BorrowedBuf")
.field("init", &self.init)
.field("filled", &self.filled)
.field("capacity", &self.capacity())
.finish()
}
}
impl<'a> ReadBuf<'a> {
/// Creates a new `ReadBuf` from a fully initialized buffer.
/// Create a new `BorrowedBuf` from a fully initialized slice.
impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
let len = buf.len();
fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> {
let len = slice.len();
ReadBuf {
//SAFETY: initialized data never becoming uninitialized is an invariant of ReadBuf
buf: unsafe { (buf as *mut [u8]).as_uninit_slice_mut().unwrap() },
BorrowedBuf {
// SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf
buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() },
filled: 0,
initialized: len,
init: len,
}
}
}
/// Creates a new `ReadBuf` from a fully uninitialized buffer.
///
/// Use `assume_init` if part of the buffer is known to be already initialized.
/// Create a new `BorrowedBuf` from an uninitialized buffer.
///
/// Use `set_init` if part of the buffer is known to be already initialized.
impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuf<'data> {
#[inline]
pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
ReadBuf { buf, filled: 0, initialized: 0 }
fn from(buf: &'data mut [MaybeUninit<u8>]) -> BorrowedBuf<'data> {
BorrowedBuf { buf, filled: 0, init: 0 }
}
}
impl<'data> BorrowedBuf<'data> {
/// Returns the total capacity of the buffer.
#[inline]
pub fn capacity(&self) -> usize {
self.buf.len()
}
/// Returns the length of the filled part of the buffer.
#[inline]
pub fn len(&self) -> usize {
self.filled
}
/// Returns the length of the initialized part of the buffer.
#[inline]
pub fn init_len(&self) -> usize {
self.init
}
/// Returns a shared reference to the filled portion of the buffer.
#[inline]
pub fn filled(&self) -> &[u8] {
//SAFETY: We only slice the filled part of the buffer, which is always valid
// SAFETY: We only slice the filled part of the buffer, which is always valid
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
}
/// Returns a mutable reference to the filled portion of the buffer.
/// Returns a cursor over the unfilled part of the buffer.
#[inline]
pub fn filled_mut(&mut self) -> &mut [u8] {
//SAFETY: We only slice the filled part of the buffer, which is always valid
unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
}
/// Returns a shared reference to the initialized portion of the buffer.
///
/// This includes the filled portion.
#[inline]
pub fn initialized(&self) -> &[u8] {
//SAFETY: We only slice the initialized part of the buffer, which is always valid
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.initialized]) }
}
/// Returns a mutable reference to the initialized portion of the buffer.
///
/// This includes the filled portion.
#[inline]
pub fn initialized_mut(&mut self) -> &mut [u8] {
//SAFETY: We only slice the initialized part of the buffer, which is always valid
unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.initialized]) }
}
/// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
/// initialized.
///
/// # Safety
///
/// The caller must not de-initialize portions of the buffer that have already been initialized.
#[inline]
pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.buf[self.filled..]
}
/// Returns a mutable reference to the uninitialized part of the buffer.
///
/// It is safe to uninitialize any of these bytes.
#[inline]
pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.buf[self.initialized..]
}
/// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
///
/// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
/// the first use.
#[inline]
pub fn initialize_unfilled(&mut self) -> &mut [u8] {
// should optimize out the assertion
self.initialize_unfilled_to(self.remaining())
}
/// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
/// fully initialized.
///
/// # Panics
///
/// Panics if `self.remaining()` is less than `n`.
#[inline]
pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
assert!(self.remaining() >= n);
let extra_init = self.initialized - self.filled;
// If we don't have enough initialized, do zeroing
if n > extra_init {
let uninit = n - extra_init;
let unfilled = &mut self.uninitialized_mut()[0..uninit];
for byte in unfilled.iter_mut() {
byte.write(0);
}
// SAFETY: we just initialized uninit bytes, and the previous bytes were already init
unsafe {
self.assume_init(n);
}
pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
BorrowedCursor {
start: self.filled,
// SAFETY: we never assign into `BorrowedCursor::buf`, so treating its
// lifetime covariantly is safe.
buf: unsafe {
mem::transmute::<&'this mut BorrowedBuf<'data>, &'this mut BorrowedBuf<'this>>(self)
},
}
let filled = self.filled;
&mut self.initialized_mut()[filled..filled + n]
}
/// Returns the number of bytes at the end of the slice that have not yet been filled.
#[inline]
pub fn remaining(&self) -> usize {
self.capacity() - self.filled
}
/// Clears the buffer, resetting the filled region to empty.
@ -167,83 +117,190 @@ impl<'a> ReadBuf<'a> {
/// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
#[inline]
pub fn clear(&mut self) -> &mut Self {
self.set_filled(0) // The assertion in `set_filled` is optimized out
}
/// Increases the size of the filled region of the buffer.
///
/// The number of initialized bytes is not changed.
///
/// # Panics
///
/// Panics if the filled region of the buffer would become larger than the initialized region.
#[inline]
pub fn add_filled(&mut self, n: usize) -> &mut Self {
self.set_filled(self.filled + n)
}
/// Sets the size of the filled region of the buffer.
///
/// The number of initialized bytes is not changed.
///
/// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
/// example, by a `Read` implementation that compresses data in-place).
///
/// # Panics
///
/// Panics if the filled region of the buffer would become larger than the initialized region.
#[inline]
pub fn set_filled(&mut self, n: usize) -> &mut Self {
assert!(n <= self.initialized);
self.filled = n;
self.filled = 0;
self
}
/// Asserts that the first `n` unfilled bytes of the buffer are initialized.
/// Asserts that the first `n` bytes of the buffer are initialized.
///
/// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
/// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
/// bytes than are already known to be initialized.
///
/// # Safety
///
/// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
#[inline]
pub unsafe fn assume_init(&mut self, n: usize) -> &mut Self {
self.initialized = cmp::max(self.initialized, self.filled + n);
pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
self.init = cmp::max(self.init, n);
self
}
}
/// A writeable view of the unfilled portion of a [`BorrowedBuf`](BorrowedBuf).
///
/// Provides access to the initialized and uninitialized parts of the underlying `BorrowedBuf`.
/// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or
/// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the
/// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform
/// the cursor how many bytes have been written.
///
/// Once data is written to the cursor, it becomes part of the filled portion of the underlying
/// `BorrowedBuf` and can no longer be accessed or re-written by the cursor. I.e., the cursor tracks
/// the unfilled part of the underlying `BorrowedBuf`.
///
/// The lifetime `'a` is a bound on the lifetime of the underlying buffer (which means it is a bound
/// on the data in that buffer by transitivity).
#[derive(Debug)]
pub struct BorrowedCursor<'a> {
/// The underlying buffer.
// Safety invariant: we treat the type of buf as covariant in the lifetime of `BorrowedBuf` when
// we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into
// it, so don't do that!
buf: &'a mut BorrowedBuf<'a>,
/// The length of the filled portion of the underlying buffer at the time of the cursor's
/// creation.
start: usize,
}
impl<'a> BorrowedCursor<'a> {
/// Reborrow this cursor by cloning it with a smaller lifetime.
///
/// Since a cursor maintains unique access to its underlying buffer, the borrowed cursor is
/// not accessible while the new cursor exists.
#[inline]
pub fn reborrow<'this>(&'this mut self) -> BorrowedCursor<'this> {
BorrowedCursor {
// SAFETY: we never assign into `BorrowedCursor::buf`, so treating its
// lifetime covariantly is safe.
buf: unsafe {
mem::transmute::<&'this mut BorrowedBuf<'a>, &'this mut BorrowedBuf<'this>>(
self.buf,
)
},
start: self.start,
}
}
/// Returns the available space in the cursor.
#[inline]
pub fn capacity(&self) -> usize {
self.buf.capacity() - self.buf.filled
}
/// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`.
///
/// Note that if this cursor is a reborrowed clone of another, then the count returned is the
/// count written via either cursor, not the count since the cursor was reborrowed.
#[inline]
pub fn written(&self) -> usize {
self.buf.filled - self.start
}
/// Returns a shared reference to the initialized portion of the cursor.
#[inline]
pub fn init_ref(&self) -> &[u8] {
// SAFETY: We only slice the initialized part of the buffer, which is always valid
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.buf[self.buf.filled..self.buf.init]) }
}
/// Returns a mutable reference to the initialized portion of the cursor.
#[inline]
pub fn init_mut(&mut self) -> &mut [u8] {
// SAFETY: We only slice the initialized part of the buffer, which is always valid
unsafe {
MaybeUninit::slice_assume_init_mut(&mut self.buf.buf[self.buf.filled..self.buf.init])
}
}
/// Returns a mutable reference to the uninitialized part of the cursor.
///
/// It is safe to uninitialize any of these bytes.
#[inline]
pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.buf.buf[self.buf.init..]
}
/// Returns a mutable reference to the whole cursor.
///
/// # Safety
///
/// The caller must not uninitialize any bytes in the initialized portion of the cursor.
#[inline]
pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.buf.buf[self.buf.filled..]
}
/// Advance the cursor by asserting that `n` bytes have been filled.
///
/// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
/// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements
/// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements.
///
/// # Safety
///
/// The caller must ensure that the first `n` bytes of the cursor have been properly
/// initialised.
#[inline]
pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
self.buf.filled += n;
self.buf.init = cmp::max(self.buf.init, self.buf.filled);
self
}
/// Appends data to the buffer, advancing the written position and possibly also the initialized position.
/// Initializes all bytes in the cursor.
#[inline]
pub fn ensure_init(&mut self) -> &mut Self {
for byte in self.uninit_mut() {
byte.write(0);
}
self.buf.init = self.buf.capacity();
self
}
/// Asserts that the first `n` unfilled bytes of the cursor are initialized.
///
/// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when
/// called with fewer bytes than are already known to be initialized.
///
/// # Safety
///
/// The caller must ensure that the first `n` bytes of the buffer have already been initialized.
#[inline]
pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
self.buf.init = cmp::max(self.buf.init, self.buf.filled + n);
self
}
/// Appends data to the cursor, advancing position within its buffer.
///
/// # Panics
///
/// Panics if `self.remaining()` is less than `buf.len()`.
/// Panics if `self.capacity()` is less than `buf.len()`.
#[inline]
pub fn append(&mut self, buf: &[u8]) {
assert!(self.remaining() >= buf.len());
assert!(self.capacity() >= buf.len());
// SAFETY: we do not de-initialize any of the elements of the slice
unsafe {
MaybeUninit::write_slice(&mut self.unfilled_mut()[..buf.len()], buf);
MaybeUninit::write_slice(&mut self.as_mut()[..buf.len()], buf);
}
// SAFETY: We just added the entire contents of buf to the filled section.
unsafe {
self.assume_init(buf.len());
self.set_init(buf.len());
}
self.add_filled(buf.len());
}
/// Returns the amount of bytes that have been filled.
#[inline]
pub fn filled_len(&self) -> usize {
self.filled
}
/// Returns the amount of bytes that have been initialized.
#[inline]
pub fn initialized_len(&self) -> usize {
self.initialized
self.buf.filled += buf.len();
}
}
impl<'a> Write for BorrowedCursor<'a> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.append(buf);
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}

View file

@ -1,181 +1,175 @@
use super::ReadBuf;
use super::BorrowedBuf;
use crate::mem::MaybeUninit;
/// Test that ReadBuf has the correct numbers when created with new
/// Test that BorrowedBuf has the correct numbers when created with new
#[test]
fn new() {
let mut buf = [0; 16];
let rbuf = ReadBuf::new(&mut buf);
let buf: &mut [_] = &mut [0; 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
assert_eq!(rbuf.filled_len(), 0);
assert_eq!(rbuf.initialized_len(), 16);
assert_eq!(rbuf.filled().len(), 0);
assert_eq!(rbuf.init_len(), 16);
assert_eq!(rbuf.capacity(), 16);
assert_eq!(rbuf.remaining(), 16);
assert_eq!(rbuf.unfilled().capacity(), 16);
}
/// Test that ReadBuf has the correct numbers when created with uninit
/// Test that BorrowedBuf has the correct numbers when created with uninit
#[test]
fn uninit() {
let mut buf = [MaybeUninit::uninit(); 16];
let rbuf = ReadBuf::uninit(&mut buf);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
assert_eq!(rbuf.filled_len(), 0);
assert_eq!(rbuf.initialized_len(), 0);
assert_eq!(rbuf.filled().len(), 0);
assert_eq!(rbuf.init_len(), 0);
assert_eq!(rbuf.capacity(), 16);
assert_eq!(rbuf.remaining(), 16);
assert_eq!(rbuf.unfilled().capacity(), 16);
}
#[test]
fn initialize_unfilled() {
let mut buf = [MaybeUninit::uninit(); 16];
let mut rbuf = ReadBuf::uninit(&mut buf);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
rbuf.initialize_unfilled();
rbuf.unfilled().ensure_init();
assert_eq!(rbuf.initialized_len(), 16);
assert_eq!(rbuf.init_len(), 16);
}
#[test]
fn initialize_unfilled_to() {
let mut buf = [MaybeUninit::uninit(); 16];
let mut rbuf = ReadBuf::uninit(&mut buf);
fn addvance_filled() {
let buf: &mut [_] = &mut [0; 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
rbuf.initialize_unfilled_to(8);
unsafe {
rbuf.unfilled().advance(1);
}
assert_eq!(rbuf.initialized_len(), 8);
rbuf.initialize_unfilled_to(4);
assert_eq!(rbuf.initialized_len(), 8);
rbuf.set_filled(8);
rbuf.initialize_unfilled_to(6);
assert_eq!(rbuf.initialized_len(), 14);
rbuf.initialize_unfilled_to(8);
assert_eq!(rbuf.initialized_len(), 16);
}
#[test]
fn add_filled() {
let mut buf = [0; 16];
let mut rbuf = ReadBuf::new(&mut buf);
rbuf.add_filled(1);
assert_eq!(rbuf.filled_len(), 1);
assert_eq!(rbuf.remaining(), 15);
}
#[test]
#[should_panic]
fn add_filled_panic() {
let mut buf = [MaybeUninit::uninit(); 16];
let mut rbuf = ReadBuf::uninit(&mut buf);
rbuf.add_filled(1);
}
#[test]
fn set_filled() {
let mut buf = [0; 16];
let mut rbuf = ReadBuf::new(&mut buf);
rbuf.set_filled(16);
assert_eq!(rbuf.filled_len(), 16);
assert_eq!(rbuf.remaining(), 0);
rbuf.set_filled(6);
assert_eq!(rbuf.filled_len(), 6);
assert_eq!(rbuf.remaining(), 10);
}
#[test]
#[should_panic]
fn set_filled_panic() {
let mut buf = [MaybeUninit::uninit(); 16];
let mut rbuf = ReadBuf::uninit(&mut buf);
rbuf.set_filled(16);
assert_eq!(rbuf.filled().len(), 1);
assert_eq!(rbuf.unfilled().capacity(), 15);
}
#[test]
fn clear() {
let mut buf = [255; 16];
let mut rbuf = ReadBuf::new(&mut buf);
let buf: &mut [_] = &mut [255; 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
rbuf.set_filled(16);
unsafe {
rbuf.unfilled().advance(16);
}
assert_eq!(rbuf.filled_len(), 16);
assert_eq!(rbuf.remaining(), 0);
assert_eq!(rbuf.filled().len(), 16);
assert_eq!(rbuf.unfilled().capacity(), 0);
rbuf.clear();
assert_eq!(rbuf.filled_len(), 0);
assert_eq!(rbuf.remaining(), 16);
assert_eq!(rbuf.filled().len(), 0);
assert_eq!(rbuf.unfilled().capacity(), 16);
assert_eq!(rbuf.initialized(), [255; 16]);
assert_eq!(rbuf.unfilled().init_ref(), [255; 16]);
}
#[test]
fn assume_init() {
let mut buf = [MaybeUninit::uninit(); 16];
let mut rbuf = ReadBuf::uninit(&mut buf);
fn set_init() {
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
unsafe {
rbuf.assume_init(8);
rbuf.set_init(8);
}
assert_eq!(rbuf.initialized_len(), 8);
rbuf.add_filled(4);
assert_eq!(rbuf.init_len(), 8);
unsafe {
rbuf.assume_init(2);
rbuf.unfilled().advance(4);
}
assert_eq!(rbuf.initialized_len(), 8);
unsafe {
rbuf.assume_init(8);
rbuf.set_init(2);
}
assert_eq!(rbuf.initialized_len(), 12);
assert_eq!(rbuf.init_len(), 8);
unsafe {
rbuf.set_init(8);
}
assert_eq!(rbuf.init_len(), 8);
}
#[test]
fn append() {
let mut buf = [MaybeUninit::new(255); 16];
let mut rbuf = ReadBuf::uninit(&mut buf);
let buf: &mut [_] = &mut [MaybeUninit::new(255); 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
rbuf.append(&[0; 8]);
rbuf.unfilled().append(&[0; 8]);
assert_eq!(rbuf.initialized_len(), 8);
assert_eq!(rbuf.filled_len(), 8);
assert_eq!(rbuf.init_len(), 8);
assert_eq!(rbuf.filled().len(), 8);
assert_eq!(rbuf.filled(), [0; 8]);
rbuf.clear();
rbuf.append(&[1; 16]);
rbuf.unfilled().append(&[1; 16]);
assert_eq!(rbuf.initialized_len(), 16);
assert_eq!(rbuf.filled_len(), 16);
assert_eq!(rbuf.init_len(), 16);
assert_eq!(rbuf.filled().len(), 16);
assert_eq!(rbuf.filled(), [1; 16]);
}
#[test]
fn filled_mut() {
let mut buf = [0; 16];
let mut rbuf = ReadBuf::new(&mut buf);
fn reborrow_written() {
let buf: &mut [_] = &mut [MaybeUninit::new(0); 32];
let mut buf: BorrowedBuf<'_> = buf.into();
rbuf.add_filled(8);
let mut cursor = buf.unfilled();
cursor.append(&[1; 16]);
let filled = rbuf.filled().to_vec();
let mut cursor2 = cursor.reborrow();
cursor2.append(&[2; 16]);
assert_eq!(&*filled, &*rbuf.filled_mut());
assert_eq!(cursor2.written(), 32);
assert_eq!(cursor.written(), 32);
assert_eq!(buf.unfilled().written(), 0);
assert_eq!(buf.init_len(), 32);
assert_eq!(buf.filled().len(), 32);
let filled = buf.filled();
assert_eq!(&filled[..16], [1; 16]);
assert_eq!(&filled[16..], [2; 16]);
}
#[test]
fn cursor_set_init() {
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
unsafe {
rbuf.unfilled().set_init(8);
}
assert_eq!(rbuf.init_len(), 8);
assert_eq!(rbuf.unfilled().init_ref().len(), 8);
assert_eq!(rbuf.unfilled().init_mut().len(), 8);
assert_eq!(rbuf.unfilled().uninit_mut().len(), 8);
assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 16);
unsafe {
rbuf.unfilled().advance(4);
}
unsafe {
rbuf.unfilled().set_init(2);
}
assert_eq!(rbuf.init_len(), 8);
unsafe {
rbuf.unfilled().set_init(8);
}
assert_eq!(rbuf.init_len(), 12);
assert_eq!(rbuf.unfilled().init_ref().len(), 8);
assert_eq!(rbuf.unfilled().init_mut().len(), 8);
assert_eq!(rbuf.unfilled().uninit_mut().len(), 4);
assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 12);
}

View file

@ -1,4 +1,4 @@
use super::{repeat, Cursor, ReadBuf, SeekFrom};
use super::{repeat, BorrowedBuf, Cursor, SeekFrom};
use crate::cmp::{self, min};
use crate::io::{self, IoSlice, IoSliceMut};
use crate::io::{BufRead, BufReader, Read, Seek, Write};
@ -159,24 +159,24 @@ fn read_exact_slice() {
#[test]
fn read_buf_exact() {
let mut buf = [0; 4];
let mut buf = ReadBuf::new(&mut buf);
let buf: &mut [_] = &mut [0; 4];
let mut buf: BorrowedBuf<'_> = buf.into();
let mut c = Cursor::new(&b""[..]);
assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
let mut c = Cursor::new(&b"123456789"[..]);
c.read_buf_exact(&mut buf).unwrap();
c.read_buf_exact(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), b"1234");
buf.clear();
c.read_buf_exact(&mut buf).unwrap();
c.read_buf_exact(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), b"5678");
buf.clear();
assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
}
#[test]
@ -615,10 +615,10 @@ fn bench_take_read(b: &mut test::Bencher) {
#[bench]
fn bench_take_read_buf(b: &mut test::Bencher) {
b.iter(|| {
let mut buf = [MaybeUninit::uninit(); 64];
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 64];
let mut rbuf = ReadBuf::uninit(&mut buf);
let mut buf: BorrowedBuf<'_> = buf.into();
[255; 128].take(64).read_buf(&mut rbuf).unwrap();
[255; 128].take(64).read_buf(buf.unfilled()).unwrap();
});
}

View file

@ -5,7 +5,7 @@ mod tests;
use crate::fmt;
use crate::io::{
self, BufRead, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, Write,
self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
};
/// A reader which is always at EOF.
@ -47,7 +47,7 @@ impl Read for Empty {
}
#[inline]
fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> {
Ok(())
}
}
@ -130,21 +130,19 @@ impl Read for Repeat {
Ok(buf.len())
}
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
// SAFETY: No uninit bytes are being written
for slot in unsafe { buf.unfilled_mut() } {
for slot in unsafe { buf.as_mut() } {
slot.write(self.byte);
}
let remaining = buf.remaining();
let remaining = buf.capacity();
// SAFETY: the entire unfilled portion of buf has been initialized
unsafe {
buf.assume_init(remaining);
buf.advance(remaining);
}
buf.add_filled(remaining);
Ok(())
}

View file

@ -1,7 +1,7 @@
use crate::cmp::{max, min};
use crate::io::prelude::*;
use crate::io::{
copy, empty, repeat, sink, BufWriter, Empty, ReadBuf, Repeat, Result, SeekFrom, Sink,
copy, empty, repeat, sink, BorrowedBuf, BufWriter, Empty, Repeat, Result, SeekFrom, Sink,
DEFAULT_BUF_SIZE,
};
@ -79,29 +79,29 @@ fn empty_reads() {
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
let mut buf = [];
let mut buf = ReadBuf::uninit(&mut buf);
e.read_buf(&mut buf).unwrap();
assert_eq!(buf.filled_len(), 0);
assert_eq!(buf.initialized_len(), 0);
let buf: &mut [MaybeUninit<_>] = &mut [];
let mut buf: BorrowedBuf<'_> = buf.into();
e.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let mut buf = [MaybeUninit::uninit()];
let mut buf = ReadBuf::uninit(&mut buf);
e.read_buf(&mut buf).unwrap();
assert_eq!(buf.filled_len(), 0);
assert_eq!(buf.initialized_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit()];
let mut buf: BorrowedBuf<'_> = buf.into();
e.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let mut buf = [MaybeUninit::uninit(); 1024];
let mut buf = ReadBuf::uninit(&mut buf);
e.read_buf(&mut buf).unwrap();
assert_eq!(buf.filled_len(), 0);
assert_eq!(buf.initialized_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
let mut buf: BorrowedBuf<'_> = buf.into();
e.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let mut buf = [MaybeUninit::uninit(); 1024];
let mut buf = ReadBuf::uninit(&mut buf);
e.by_ref().read_buf(&mut buf).unwrap();
assert_eq!(buf.filled_len(), 0);
assert_eq!(buf.initialized_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
let mut buf: BorrowedBuf<'_> = buf.into();
e.by_ref().read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
}
#[test]

View file

@ -30,7 +30,9 @@ pub mod usercalls {
// fortanix-sgx-abi re-exports
pub use crate::sys::abi::usercalls::raw::Error;
pub use crate::sys::abi::usercalls::raw::{ByteBuffer, FifoDescriptor, Return, Usercall};
pub use crate::sys::abi::usercalls::raw::{
ByteBuffer, Cancel, FifoDescriptor, Return, Usercall,
};
pub use crate::sys::abi::usercalls::raw::{Fd, Result, Tcs};
pub use crate::sys::abi::usercalls::raw::{
EV_RETURNQ_NOT_EMPTY, EV_UNPARK, EV_USERCALLQ_NOT_FULL, FD_STDERR, FD_STDIN, FD_STDOUT,

View file

@ -2,7 +2,7 @@ use crate::ffi::{CStr, CString, OsString};
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, Error, ErrorKind};
use crate::io::{IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::os::unix::ffi::OsStrExt;
use crate::path::{Path, PathBuf};
use crate::sys::cvt;
@ -312,8 +312,8 @@ impl File {
false
}
pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
crate::io::default_read_buf(|buf| self.read(buf), buf)
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
crate::io::default_read_buf(|buf| self.read(buf), cursor)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {

View file

@ -2,7 +2,7 @@ use super::{abi, error};
use crate::{
ffi::{CStr, CString, OsStr, OsString},
fmt,
io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom},
io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom},
mem::MaybeUninit,
os::raw::{c_int, c_short},
os::solid::ffi::OsStrExt,
@ -366,13 +366,13 @@ impl File {
}
}
pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
unsafe {
let len = buf.remaining();
let len = cursor.capacity();
let mut out_num_bytes = MaybeUninit::uninit();
error::SolidError::err_if_negative(abi::SOLID_FS_Read(
self.fd.raw(),
buf.unfilled_mut().as_mut_ptr() as *mut u8,
cursor.as_mut().as_mut_ptr() as *mut u8,
len,
out_num_bytes.as_mut_ptr(),
))
@ -384,9 +384,7 @@ impl File {
// Safety: `num_bytes_read` bytes were written to the unfilled
// portion of the buffer
buf.assume_init(num_bytes_read);
buf.add_filled(num_bytes_read);
cursor.advance(num_bytes_read);
Ok(())
}

View file

@ -4,7 +4,7 @@
mod tests;
use crate::cmp;
use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner};
@ -131,20 +131,19 @@ impl FileDesc {
}
}
pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
let ret = cvt(unsafe {
libc::read(
self.as_raw_fd(),
buf.unfilled_mut().as_mut_ptr() as *mut libc::c_void,
cmp::min(buf.remaining(), READ_LIMIT),
cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
cmp::min(cursor.capacity(), READ_LIMIT),
)
})?;
// Safety: `ret` bytes were written to the initialized portion of the buffer
unsafe {
buf.assume_init(ret as usize);
cursor.advance(ret as usize);
}
buf.add_filled(ret as usize);
Ok(())
}

View file

@ -2,7 +2,7 @@ use crate::os::unix::prelude::*;
use crate::ffi::{CStr, CString, OsStr, OsString};
use crate::fmt;
use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
use crate::mem;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
use crate::path::{Path, PathBuf};
@ -1037,8 +1037,8 @@ impl File {
self.0.read_at(buf, offset)
}
pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
self.0.read_buf(buf)
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(cursor)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {

View file

@ -1,7 +1,7 @@
use crate::ffi::OsString;
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::path::{Path, PathBuf};
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
@ -214,7 +214,7 @@ impl File {
self.0
}
pub fn read_buf(&self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.0
}

View file

@ -3,7 +3,7 @@
use super::fd::WasiFd;
use crate::ffi::{CStr, CString, OsStr, OsString};
use crate::fmt;
use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::iter;
use crate::mem::{self, ManuallyDrop};
use crate::os::raw::c_int;
@ -439,8 +439,8 @@ impl File {
true
}
pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
crate::io::default_read_buf(|buf| self.read(buf), buf)
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
crate::io::default_read_buf(|buf| self.read(buf), cursor)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {

View file

@ -2,7 +2,7 @@ use crate::os::windows::prelude::*;
use crate::ffi::OsString;
use crate::fmt;
use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
use crate::mem;
use crate::os::windows::io::{AsHandle, BorrowedHandle};
use crate::path::{Path, PathBuf};
@ -415,8 +415,8 @@ impl File {
self.handle.read_at(buf, offset)
}
pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
self.handle.read_buf(buf)
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.handle.read_buf(cursor)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {

View file

@ -4,7 +4,7 @@
mod tests;
use crate::cmp;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf};
use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, Read};
use crate::mem;
use crate::os::windows::io::{
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
@ -112,18 +112,16 @@ impl Handle {
}
}
pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
let res = unsafe {
self.synchronous_read(buf.unfilled_mut().as_mut_ptr(), buf.remaining(), None)
};
pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
let res =
unsafe { self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), None) };
match res {
Ok(read) => {
// Safety: `read` bytes were written to the initialized portion of the buffer
unsafe {
buf.assume_init(read as usize);
cursor.advance(read as usize);
}
buf.add_filled(read as usize);
Ok(())
}

View file

@ -89,4 +89,7 @@ def lookup(valobj):
if rust_type == RustType.STD_REF_CELL:
return StdRefCellProvider(valobj)
if rust_type == RustType.STD_NONZERO_NUMBER:
return StdNonZeroNumberProvider(valobj)
return None

View file

@ -231,6 +231,17 @@ class StdRefCellProvider:
yield "borrow", self.borrow
class StdNonZeroNumberProvider:
def __init__(self, valobj):
fields = valobj.type.fields()
assert len(fields) == 1
field = list(fields)[0]
self.value = str(valobj[field.name])
def to_string(self):
return self.value
# Yields children (in a provider's sense of the word) for a BTreeMap.
def children_of_btree_map(map):
# Yields each key/value pair in the node and in any child nodes.

View file

@ -15,4 +15,5 @@ type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)C
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
type category enable Rust

View file

@ -55,6 +55,9 @@ def summary_lookup(valobj, dict):
if rust_type == RustType.STD_REF_CELL:
return StdRefSummaryProvider(valobj, dict)
if rust_type == RustType.STD_NONZERO_NUMBER:
return StdNonZeroNumberSummaryProvider(valobj, dict)
return ""

View file

@ -739,3 +739,11 @@ class StdRefSyntheticProvider:
def has_children(self):
# type: () -> bool
return True
def StdNonZeroNumberSummaryProvider(valobj, _dict):
# type: (SBValue, dict) -> str
objtype = valobj.GetType()
field = objtype.GetFieldAtIndex(0)
element = valobj.GetChildMemberWithName(field.name)
return element.GetValue()

View file

@ -31,6 +31,7 @@ class RustType(object):
STD_REF = "StdRef"
STD_REF_MUT = "StdRefMut"
STD_REF_CELL = "StdRefCell"
STD_NONZERO_NUMBER = "StdNonZeroNumber"
STD_STRING_REGEX = re.compile(r"^(alloc::(\w+::)+)String$")
@ -49,6 +50,7 @@ STD_CELL_REGEX = re.compile(r"^(core::(\w+::)+)Cell<.+>$")
STD_REF_REGEX = re.compile(r"^(core::(\w+::)+)Ref<.+>$")
STD_REF_MUT_REGEX = re.compile(r"^(core::(\w+::)+)RefMut<.+>$")
STD_REF_CELL_REGEX = re.compile(r"^(core::(\w+::)+)RefCell<.+>$")
STD_NONZERO_NUMBER_REGEX = re.compile(r"^core::num::([a-z_]+::)*NonZero.+$")
TUPLE_ITEM_REGEX = re.compile(r"__\d+$")
@ -72,6 +74,7 @@ STD_TYPE_TO_REGEX = {
RustType.STD_REF_MUT: STD_REF_MUT_REGEX,
RustType.STD_REF_CELL: STD_REF_CELL_REGEX,
RustType.STD_CELL: STD_CELL_REGEX,
RustType.STD_NONZERO_NUMBER: STD_NONZERO_NUMBER_REGEX,
}
def is_tuple_fields(fields):

View file

@ -1776,11 +1776,6 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {
match vis {
ty::Visibility::Public => Visibility::Public,
// NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
// while rustdoc really does mean inherited. That means that for enum variants, such as
// `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc.
// Various parts of clean override `tcx.visibility` explicitly to make sure this distinction is captured.
ty::Visibility::Invisible => Visibility::Inherited,
ty::Visibility::Restricted(module) => Visibility::Restricted(module),
}
}

View file

@ -41,8 +41,9 @@ impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
if self.parent != Some(expected_parent) {
let mut attrs = Vec::new();
for (parent_hir_id, _) in hir.parent_iter(hir_id) {
let def_id = hir.local_def_id(parent_hir_id).to_def_id();
attrs.extend_from_slice(load_attrs(self.cx, def_id));
if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
}
}
let (_, cfg) =
merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));

View file

@ -1,6 +1,7 @@
// only-cdb
// compile-flags:-g
// min-gdb-version: 8.1
// Tests the visualizations for `NonZero{I,U}{8,16,32,64,128,size}`, `Wrapping<T>` and
// `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`.
@ -153,6 +154,90 @@
// cdb-check:a_usize : 0x400 [Type: core::sync::atomic::AtomicUsize]
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicUsize]
// === GDB TESTS ===================================================================================
// gdb-command:run
// gdb-command:print/d nz_i8
// gdb-check:[...]$1 = 11
// gdb-command:print nz_i16
// gdb-check:[...]$2 = 22
// gdb-command:print nz_i32
// gdb-check:[...]$3 = 33
// gdb-command:print nz_i64
// gdb-check:[...]$4 = 44
// gdb-command:print nz_i128
// gdb-check:[...]$5 = 55
// gdb-command:print nz_isize
// gdb-check:[...]$6 = 66
// gdb-command:print/d nz_u8
// gdb-check:[...]$7 = 77
// gdb-command:print nz_u16
// gdb-check:[...]$8 = 88
// gdb-command:print nz_u32
// gdb-check:[...]$9 = 99
// gdb-command:print nz_u64
// gdb-check:[...]$10 = 100
// gdb-command:print nz_u128
// gdb-check:[...]$11 = 111
// gdb-command:print nz_usize
// gdb-check:[...]$12 = 122
// === LLDB TESTS ==================================================================================
// lldb-command:run
// lldb-command:print/d nz_i8
// lldb-check:[...]$0 = 11 { __0 = 11 }
// lldb-command:print nz_i16
// lldb-check:[...]$1 = 22 { __0 = 22 }
// lldb-command:print nz_i32
// lldb-check:[...]$2 = 33 { __0 = 33 }
// lldb-command:print nz_i64
// lldb-check:[...]$3 = 44 { __0 = 44 }
// lldb-command:print nz_i128
// lldb-check:[...]$4 = 55 { __0 = 55 }
// lldb-command:print nz_isize
// lldb-check:[...]$5 = 66 { __0 = 66 }
// lldb-command:print/d nz_u8
// lldb-check:[...]$6 = 77 { __0 = 77 }
// lldb-command:print nz_u16
// lldb-check:[...]$7 = 88 { __0 = 88 }
// lldb-command:print nz_u32
// lldb-check:[...]$8 = 99 { __0 = 99 }
// lldb-command:print nz_u64
// lldb-check:[...]$9 = 100 { __0 = 100 }
// lldb-command:print nz_u128
// lldb-check:[...]$10 = 111 { __0 = 111 }
// lldb-command:print nz_usize
// lldb-check:[...]$11 = 122 { __0 = 122 }
use std::num::*;
use std::sync::atomic::*;

View file

@ -0,0 +1,14 @@
// check-pass
const _: () = {
#[macro_export]
macro_rules! first_macro {
() => {}
}
mod foo {
#[macro_export]
macro_rules! second_macro {
() => {}
}
}
};

View file

@ -1,10 +1,9 @@
// When mutably indexing a type that implements `Index` but not `IndexMut`, a
// special 'help' message is added to the output.
use std::collections::HashMap;
fn main() {
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("peter", "23".to_string());

View file

@ -1,23 +1,33 @@
error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable
--> $DIR/index-mut-help.rs:11:5
--> $DIR/index-mut-help.rs:10:5
|
LL | map["peter"].clear();
| ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
= help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
help: to modify a `HashMap<&str, String>` use `.get_mut()`
|
LL | map.get_mut("peter").map(|val| val.clear());
| ~~~~~~~~~ ~~~~~~~~~~~~~~~ +
error[E0594]: cannot assign to data in an index of `HashMap<&str, String>`
--> $DIR/index-mut-help.rs:12:5
--> $DIR/index-mut-help.rs:11:5
|
LL | map["peter"] = "0".to_string();
| ^^^^^^^^^^^^ cannot assign
|
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
= help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
|
LL | map.insert("peter", "0".to_string());
| ~~~~~~~~ ~ +
LL | map.get_mut("peter").map(|val| { *val = "0".to_string(); });
| ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ++++
LL | let val = map.entry("peter").or_insert("0".to_string());
| +++++++++ ~~~~~~~ ~~~~~~~~~~~~ +
error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable
--> $DIR/index-mut-help.rs:13:13
--> $DIR/index-mut-help.rs:12:13
|
LL | let _ = &mut map["peter"];
| ^^^^^^^^^^^^^^^^^ cannot borrow as mutable

View file

@ -5,7 +5,14 @@ LL | map[&0] = 1;
| ^^^^^^^^^^^ cannot assign
|
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap<u32, u32>`
= help: to modify a `BTreeMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
help: to modify a `BTreeMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
|
LL | map.insert(&0, 1);
| ~~~~~~~~ ~ +
LL | map.get_mut(&0).map(|val| { *val = 1; });
| ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ++++
LL | let val = map.entry(&0).or_insert(1);
| +++++++++ ~~~~~~~ ~~~~~~~~~~~~ +
error: aborting due to previous error

View file

@ -50,7 +50,9 @@ error[E0565]: literal in `cfg` predicate value must be a string
--> $DIR/cfg-attr-syntax-validation.rs:25:11
|
LL | #[cfg(a = b"hi")]
| ^^^^^ help: consider removing the prefix: `"hi"`
| -^^^^
| |
| help: consider removing the prefix
error: expected unsuffixed literal or identifier, found `concat!("nonexistent")`
--> $DIR/cfg-attr-syntax-validation.rs:30:25

View file

@ -13,15 +13,17 @@ error[E0107]: this trait takes 0 generic arguments but 1 generic argument was su
--> $DIR/issue-87493.rs:8:8
|
LL | T: MyTrait<Assoc == S::Assoc>,
| ^^^^^^^ ----------------- help: replace the generic bound with the associated type: `Assoc = Assoc == S::Assoc`
| |
| expected 0 generic arguments
| ^^^^^^^ expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
--> $DIR/issue-87493.rs:1:11
|
LL | pub trait MyTrait {
| ^^^^^^^
help: replace the generic bound with the associated type
|
LL | T: MyTrait<Assoc = Assoc == S::Assoc>,
| +++++++
error: aborting due to 2 previous errors

View file

@ -0,0 +1,17 @@
// check-pass
// compile-flags: -Zextra-const-ub-checks
#[repr(packed)]
pub struct Foo {
bar: u8,
baa: [u32; 1],
}
const FOOMP: Foo = Foo {
bar: 0,
baa: [69; 1],
};
fn main() {
let _val = FOOMP;
}

View file

@ -44,7 +44,9 @@ error[E0565]: literal in `deprecated` value must be a string
--> $DIR/deprecation-sanity.rs:19:25
|
LL | #[deprecated(note = b"test")]
| ^^^^^^^ help: consider removing the prefix: `"test"`
| -^^^^^^
| |
| help: consider removing the prefix
error[E0565]: item in `deprecated` must be a key/value pair
--> $DIR/deprecation-sanity.rs:22:18

View file

@ -142,7 +142,7 @@ LL | pub trait T {
help: replace the generic bounds with the associated types
|
LL | fn trait_bound_generic<I: T<A = u8, B = u16>>(_i: I) {
| ~~~~~~ ~~~~~~~
| +++ +++
error: aborting due to 10 previous errors

View file

@ -2,7 +2,9 @@ error[E0565]: literal in `deprecated` value must be a string
--> $DIR/E0565-2.rs:2:22
|
LL | #[deprecated(since = b"1.29", note = "hi")]
| ^^^^^^^ help: consider removing the prefix: `"1.29"`
| -^^^^^^
| |
| help: consider removing the prefix
error: aborting due to previous error

View file

@ -5,7 +5,14 @@ LL | map[&0] = 1;
| ^^^^^^^^^^^ cannot assign
|
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<u32, u32>`
= help: to modify a `HashMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
help: to modify a `HashMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
|
LL | map.insert(&0, 1);
| ~~~~~~~~ ~ +
LL | map.get_mut(&0).map(|val| { *val = 1; });
| ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ++++
LL | let val = map.entry(&0).or_insert(1);
| +++++++++ ~~~~~~~ ~~~~~~~~~~~~ +
error: aborting due to previous error

View file

@ -5,7 +5,10 @@ LL | things[src.as_str()].sort();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<String, Vec<String>>`
= help: to modify a `HashMap<String, Vec<String>>`, use `.get_mut()`, `.insert()` or the entry API
help: to modify a `HashMap<String, Vec<String>>` use `.get_mut()`
|
LL | things.get_mut(src.as_str()).map(|val| val.sort());
| ~~~~~~~~~ ~~~~~~~~~~~~~~~ +
error: aborting due to previous error

View file

@ -18,7 +18,7 @@ LL | let x = y.neg();
help: you must specify a type for this binding, like `f32`
|
LL | let y: f32 = 2.0;
| ~~~~~~
| +++++
error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
--> $DIR/method-on-ambiguous-numeric-type.rs:19:26
@ -37,7 +37,7 @@ LL | local_bar.pow(2);
help: you must specify a type for this binding, like `i32`
|
LL | ($ident:ident) => { let $ident: i32 = 42; }
| ~~~~~~~~~~~
| +++++
error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
--> $DIR/method-on-ambiguous-numeric-type.rs:30:9
@ -46,10 +46,10 @@ LL | bar.pow(2);
| ^^^
|
help: you must specify a type for this binding, like `i32`
--> $DIR/auxiliary/macro-in-other-crate.rs:3:29
--> $DIR/auxiliary/macro-in-other-crate.rs:3:35
|
LL | ($ident:ident) => { let $ident: i32 = 42; }
| ~~~~~~~~~~~
| +++++
error: aborting due to 5 previous errors

View file

@ -12,7 +12,7 @@ LL | pub trait T<X, Y> {
help: replace the generic bounds with the associated types
|
LL | i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
| ~~~~~~~~~ ~~~~~~~~~
| +++ +++
error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified
--> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16

View file

@ -1103,6 +1103,7 @@ impl<'test> TestCx<'test> {
"^(core::([a-z_]+::)+)Ref<.+>$",
"^(core::([a-z_]+::)+)RefMut<.+>$",
"^(core::([a-z_]+::)+)RefCell<.+>$",
"^core::num::([a-z_]+::)*NonZero.+$",
];
script_str

View file

@ -2,37 +2,23 @@
use std::collections::BTreeSet;
use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::fs::{self, write};
use std::path::Path;
use tidy::features::{collect_lang_features, collect_lib_features, Features};
use tidy::t;
use tidy::unstable_book::{
collect_unstable_book_section_file_names, collect_unstable_feature_names, LANG_FEATURES_DIR,
LIB_FEATURES_DIR, PATH_STR,
};
/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
macro_rules! t {
($e:expr) => {
match $e {
Ok(e) => e,
Err(e) => panic!("{} failed with {}", stringify!($e), e),
}
};
}
fn generate_stub_issue(path: &Path, name: &str, issue: u32) {
let mut file = t!(File::create(path));
t!(write!(file, include_str!("stub-issue.md"), name = name, issue = issue));
let content = format!(include_str!("stub-issue.md"), name = name, issue = issue);
t!(write(path, content), path);
}
fn generate_stub_no_issue(path: &Path, name: &str) {
let mut file = t!(File::create(path));
t!(write!(file, include_str!("stub-no-issue.md"), name = name));
let content = format!(include_str!("stub-no-issue.md"), name = name);
t!(write(path, content), path);
}
fn set_to_summary_str(set: &BTreeSet<String>, dir: &str) -> String {
@ -52,13 +38,14 @@ fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Featur
let lang_features_str = set_to_summary_str(&unstable_lang_features, "language-features");
let lib_features_str = set_to_summary_str(&unstable_lib_features, "library-features");
let mut file = t!(File::create(&path.join("src/SUMMARY.md")));
t!(file.write_fmt(format_args!(
let summary_path = path.join("src/SUMMARY.md");
let content = format!(
include_str!("SUMMARY.md"),
compiler_flags = compiler_flags_str,
language_features = lang_features_str,
library_features = lib_features_str
)));
);
t!(write(&summary_path, content), summary_path);
}
fn generate_unstable_book_files(src: &Path, out: &Path, features: &Features) {