Auto merge of #82430 - Dylan-DPC:rollup-nu4kfyc, r=Dylan-DPC
Rollup of 12 pull requests Successful merges: - #79423 (Enable smart punctuation) - #81154 (Improve design of `assert_len`) - #81235 (Improve suggestion for tuple struct pattern matching errors.) - #81769 (Suggest `return`ing tail expressions that match return type) - #81837 (Slight perf improvement on char::to_ascii_lowercase) - #81969 (Avoid `cfg_if` in `std::os`) - #81984 (Make WASI's `hard_link` behavior match other platforms.) - #82091 (use PlaceRef abstractions more consistently) - #82128 (add diagnostic items for OsString/PathBuf/Owned as well as to_vec on slice) - #82166 (add s390x-unknown-linux-musl target) - #82234 (Remove query parameters when skipping search results) - #82255 (Make `treat_err_as_bug` Option<NonZeroUsize>) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a4e595db8f
68 changed files with 680 additions and 268 deletions
|
@ -199,7 +199,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_local(&place_ref.local, context, location);
|
self.visit_local(&place_ref.local, context, location);
|
||||||
self.visit_projection(place_ref.local, place_ref.projection, context, location);
|
self.visit_projection(*place_ref, context, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ use rustc_span::{Loc, MultiSpan, Span};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::num::NonZeroUsize;
|
||||||
use std::panic;
|
use std::panic;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::{error, fmt};
|
use std::{error, fmt};
|
||||||
|
@ -359,7 +360,7 @@ pub struct HandlerFlags {
|
||||||
pub can_emit_warnings: bool,
|
pub can_emit_warnings: bool,
|
||||||
/// If true, error-level diagnostics are upgraded to bug-level.
|
/// If true, error-level diagnostics are upgraded to bug-level.
|
||||||
/// (rustc: see `-Z treat-err-as-bug`)
|
/// (rustc: see `-Z treat-err-as-bug`)
|
||||||
pub treat_err_as_bug: Option<usize>,
|
pub treat_err_as_bug: Option<NonZeroUsize>,
|
||||||
/// If true, immediately emit diagnostics that would otherwise be buffered.
|
/// If true, immediately emit diagnostics that would otherwise be buffered.
|
||||||
/// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
|
/// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
|
||||||
pub dont_buffer_diagnostics: bool,
|
pub dont_buffer_diagnostics: bool,
|
||||||
|
@ -396,7 +397,7 @@ impl Handler {
|
||||||
pub fn with_tty_emitter(
|
pub fn with_tty_emitter(
|
||||||
color_config: ColorConfig,
|
color_config: ColorConfig,
|
||||||
can_emit_warnings: bool,
|
can_emit_warnings: bool,
|
||||||
treat_err_as_bug: Option<usize>,
|
treat_err_as_bug: Option<NonZeroUsize>,
|
||||||
sm: Option<Lrc<SourceMap>>,
|
sm: Option<Lrc<SourceMap>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::with_tty_emitter_and_flags(
|
Self::with_tty_emitter_and_flags(
|
||||||
|
@ -424,7 +425,7 @@ impl Handler {
|
||||||
|
|
||||||
pub fn with_emitter(
|
pub fn with_emitter(
|
||||||
can_emit_warnings: bool,
|
can_emit_warnings: bool,
|
||||||
treat_err_as_bug: Option<usize>,
|
treat_err_as_bug: Option<NonZeroUsize>,
|
||||||
emitter: Box<dyn Emitter + sync::Send>,
|
emitter: Box<dyn Emitter + sync::Send>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Handler::with_emitter_and_flags(
|
Handler::with_emitter_and_flags(
|
||||||
|
@ -841,7 +842,7 @@ impl HandlerInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn treat_err_as_bug(&self) -> bool {
|
fn treat_err_as_bug(&self) -> bool {
|
||||||
self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c)
|
self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_error_count(&mut self, registry: &Registry) {
|
fn print_error_count(&mut self, registry: &Registry) {
|
||||||
|
@ -950,7 +951,7 @@ impl HandlerInner {
|
||||||
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
|
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
|
||||||
// incrementing `err_count` by one, so we need to +1 the comparing.
|
// incrementing `err_count` by one, so we need to +1 the comparing.
|
||||||
// FIXME: Would be nice to increment err_count in a more coherent way.
|
// FIXME: Would be nice to increment err_count in a more coherent way.
|
||||||
if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c) {
|
if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c.get()) {
|
||||||
// FIXME: don't abort here if report_delayed_bugs is off
|
// FIXME: don't abort here if report_delayed_bugs is off
|
||||||
self.span_bug(sp, msg);
|
self.span_bug(sp, msg);
|
||||||
}
|
}
|
||||||
|
@ -1023,7 +1024,7 @@ impl HandlerInner {
|
||||||
|
|
||||||
fn panic_if_treat_err_as_bug(&self) {
|
fn panic_if_treat_err_as_bug(&self) {
|
||||||
if self.treat_err_as_bug() {
|
if self.treat_err_as_bug() {
|
||||||
match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
|
match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) {
|
||||||
(1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
|
(1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
|
||||||
(0, _) | (1, _) => {}
|
(0, _) | (1, _) => {}
|
||||||
(count, as_bug) => panic!(
|
(count, as_bug) => panic!(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// ignore-tidy-filelength
|
// ignore-tidy-filelength
|
||||||
use crate::def::{DefKind, Namespace, Res};
|
use crate::def::{CtorKind, DefKind, Namespace, Res};
|
||||||
use crate::def_id::DefId;
|
use crate::def_id::DefId;
|
||||||
crate use crate::hir_id::HirId;
|
crate use crate::hir_id::HirId;
|
||||||
use crate::{itemlikevisit, LangItem};
|
use crate::{itemlikevisit, LangItem};
|
||||||
|
@ -1576,6 +1576,63 @@ impl Expr<'_> {
|
||||||
}
|
}
|
||||||
expr
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_have_side_effects(&self) -> bool {
|
||||||
|
match self.peel_drop_temps().kind {
|
||||||
|
ExprKind::Path(_) | ExprKind::Lit(_) => false,
|
||||||
|
ExprKind::Type(base, _)
|
||||||
|
| ExprKind::Unary(_, base)
|
||||||
|
| ExprKind::Field(base, _)
|
||||||
|
| ExprKind::Index(base, _)
|
||||||
|
| ExprKind::AddrOf(.., base)
|
||||||
|
| ExprKind::Cast(base, _) => {
|
||||||
|
// This isn't exactly true for `Index` and all `Unnary`, but we are using this
|
||||||
|
// method exclusively for diagnostics and there's a *cultural* pressure against
|
||||||
|
// them being used only for its side-effects.
|
||||||
|
base.can_have_side_effects()
|
||||||
|
}
|
||||||
|
ExprKind::Struct(_, fields, init) => fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| field.expr)
|
||||||
|
.chain(init.into_iter())
|
||||||
|
.all(|e| e.can_have_side_effects()),
|
||||||
|
|
||||||
|
ExprKind::Array(args)
|
||||||
|
| ExprKind::Tup(args)
|
||||||
|
| ExprKind::Call(
|
||||||
|
Expr {
|
||||||
|
kind:
|
||||||
|
ExprKind::Path(QPath::Resolved(
|
||||||
|
None,
|
||||||
|
Path { res: Res::Def(DefKind::Ctor(_, CtorKind::Fn), _), .. },
|
||||||
|
)),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
args,
|
||||||
|
) => args.iter().all(|arg| arg.can_have_side_effects()),
|
||||||
|
ExprKind::If(..)
|
||||||
|
| ExprKind::Match(..)
|
||||||
|
| ExprKind::MethodCall(..)
|
||||||
|
| ExprKind::Call(..)
|
||||||
|
| ExprKind::Closure(..)
|
||||||
|
| ExprKind::Block(..)
|
||||||
|
| ExprKind::Repeat(..)
|
||||||
|
| ExprKind::Break(..)
|
||||||
|
| ExprKind::Continue(..)
|
||||||
|
| ExprKind::Ret(..)
|
||||||
|
| ExprKind::Loop(..)
|
||||||
|
| ExprKind::Assign(..)
|
||||||
|
| ExprKind::InlineAsm(..)
|
||||||
|
| ExprKind::LlvmInlineAsm(..)
|
||||||
|
| ExprKind::AssignOp(..)
|
||||||
|
| ExprKind::ConstBlock(..)
|
||||||
|
| ExprKind::Box(..)
|
||||||
|
| ExprKind::Binary(..)
|
||||||
|
| ExprKind::Yield(..)
|
||||||
|
| ExprKind::DropTemps(..)
|
||||||
|
| ExprKind::Err => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the specified expression is a built-in range literal.
|
/// Checks if the specified expression is a built-in range literal.
|
||||||
|
|
|
@ -20,6 +20,7 @@ use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}
|
||||||
use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel};
|
use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel};
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
use std::num::NonZeroUsize;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
type CfgSpecs = FxHashSet<(String, Option<String>)>;
|
type CfgSpecs = FxHashSet<(String, Option<String>)>;
|
||||||
|
@ -595,7 +596,7 @@ fn test_debugging_options_tracking_hash() {
|
||||||
tracked!(tune_cpu, Some(String::from("abc")));
|
tracked!(tune_cpu, Some(String::from("abc")));
|
||||||
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
|
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
|
||||||
tracked!(trap_unreachable, Some(false));
|
tracked!(trap_unreachable, Some(false));
|
||||||
tracked!(treat_err_as_bug, Some(1));
|
tracked!(treat_err_as_bug, NonZeroUsize::new(1));
|
||||||
tracked!(unleash_the_miri_inside_of_you, true);
|
tracked!(unleash_the_miri_inside_of_you, true);
|
||||||
tracked!(use_ctors_section, Some(true));
|
tracked!(use_ctors_section, Some(true));
|
||||||
tracked!(verify_llvm_ir, true);
|
tracked!(verify_llvm_ir, true);
|
||||||
|
|
|
@ -998,12 +998,11 @@ macro_rules! visit_place_fns {
|
||||||
() => {
|
() => {
|
||||||
fn visit_projection(
|
fn visit_projection(
|
||||||
&mut self,
|
&mut self,
|
||||||
local: Local,
|
place_ref: PlaceRef<'tcx>,
|
||||||
projection: &[PlaceElem<'tcx>],
|
|
||||||
context: PlaceContext,
|
context: PlaceContext,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
self.super_projection(local, projection, context, location);
|
self.super_projection(place_ref, context, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_projection_elem(
|
fn visit_projection_elem(
|
||||||
|
@ -1033,20 +1032,20 @@ macro_rules! visit_place_fns {
|
||||||
|
|
||||||
self.visit_local(&place.local, context, location);
|
self.visit_local(&place.local, context, location);
|
||||||
|
|
||||||
self.visit_projection(place.local, &place.projection, context, location);
|
self.visit_projection(place.as_ref(), context, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_projection(
|
fn super_projection(
|
||||||
&mut self,
|
&mut self,
|
||||||
local: Local,
|
place_ref: PlaceRef<'tcx>,
|
||||||
projection: &[PlaceElem<'tcx>],
|
|
||||||
context: PlaceContext,
|
context: PlaceContext,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
let mut cursor = projection;
|
// FIXME: Use PlaceRef::iter_projections, once that exists.
|
||||||
|
let mut cursor = place_ref.projection;
|
||||||
while let &[ref proj_base @ .., elem] = cursor {
|
while let &[ref proj_base @ .., elem] = cursor {
|
||||||
cursor = proj_base;
|
cursor = proj_base;
|
||||||
self.visit_projection_elem(local, cursor, elem, context, location);
|
self.visit_projection_elem(place_ref.local, cursor, elem, context, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ where
|
||||||
|
|
||||||
// We purposefully do not call `super_place` here to avoid calling `visit_local` for this
|
// We purposefully do not call `super_place` here to avoid calling `visit_local` for this
|
||||||
// place with one of the `Projection` variants of `PlaceContext`.
|
// place with one of the `Projection` variants of `PlaceContext`.
|
||||||
self.visit_projection(local, projection, context, location);
|
self.visit_projection(place.as_ref(), context, location);
|
||||||
|
|
||||||
match DefUse::for_place(context) {
|
match DefUse::for_place(context) {
|
||||||
// Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
|
// Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
|
||||||
|
|
|
@ -515,7 +515,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
// Special-case reborrows to be more like a copy of a reference.
|
// Special-case reborrows to be more like a copy of a reference.
|
||||||
match *rvalue {
|
match *rvalue {
|
||||||
Rvalue::Ref(_, kind, place) => {
|
Rvalue::Ref(_, kind, place) => {
|
||||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, self.body, place) {
|
if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
|
||||||
let ctx = match kind {
|
let ctx = match kind {
|
||||||
BorrowKind::Shared => {
|
BorrowKind::Shared => {
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||||
|
@ -530,21 +530,21 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.visit_local(&place.local, ctx, location);
|
self.visit_local(&reborrowed_place_ref.local, ctx, location);
|
||||||
self.visit_projection(place.local, reborrowed_proj, ctx, location);
|
self.visit_projection(reborrowed_place_ref, ctx, location);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rvalue::AddressOf(mutbl, place) => {
|
Rvalue::AddressOf(mutbl, place) => {
|
||||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, self.body, place) {
|
if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
|
||||||
let ctx = match mutbl {
|
let ctx = match mutbl {
|
||||||
Mutability::Not => {
|
Mutability::Not => {
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
|
||||||
}
|
}
|
||||||
Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
|
Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
|
||||||
};
|
};
|
||||||
self.visit_local(&place.local, ctx, location);
|
self.visit_local(&reborrowed_place_ref.local, ctx, location);
|
||||||
self.visit_projection(place.local, reborrowed_proj, ctx, location);
|
self.visit_projection(reborrowed_place_ref, ctx, location);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1039,7 +1039,7 @@ fn place_as_reborrow(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
place: Place<'tcx>,
|
place: Place<'tcx>,
|
||||||
) -> Option<&'a [PlaceElem<'tcx>]> {
|
) -> Option<PlaceRef<'tcx>> {
|
||||||
match place.as_ref().last_projection() {
|
match place.as_ref().last_projection() {
|
||||||
Some((place_base, ProjectionElem::Deref)) => {
|
Some((place_base, ProjectionElem::Deref)) => {
|
||||||
// A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
|
// A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
|
||||||
|
@ -1048,13 +1048,14 @@ fn place_as_reborrow(
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// Ensure the type being derefed is a reference and not a raw pointer.
|
// Ensure the type being derefed is a reference and not a raw pointer.
|
||||||
//
|
|
||||||
// This is sufficient to prevent an access to a `static mut` from being marked as a
|
// This is sufficient to prevent an access to a `static mut` from being marked as a
|
||||||
// reborrow, even if the check above were to disappear.
|
// reborrow, even if the check above were to disappear.
|
||||||
let inner_ty = place_base.ty(body, tcx).ty;
|
let inner_ty = place_base.ty(body, tcx).ty;
|
||||||
match inner_ty.kind() {
|
|
||||||
ty::Ref(..) => Some(place_base.projection),
|
if let ty::Ref(..) = inner_ty.kind() {
|
||||||
_ => None,
|
return Some(place_base);
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,8 +413,7 @@ impl UsedLocals {
|
||||||
} else {
|
} else {
|
||||||
// A definition. Although, it still might use other locals for indexing.
|
// A definition. Although, it still might use other locals for indexing.
|
||||||
self.super_projection(
|
self.super_projection(
|
||||||
place.local,
|
place.as_ref(),
|
||||||
&place.projection,
|
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Projection),
|
PlaceContext::MutatingUse(MutatingUseContext::Projection),
|
||||||
location,
|
location,
|
||||||
);
|
);
|
||||||
|
|
|
@ -950,7 +950,7 @@ impl<'a> Parser<'a> {
|
||||||
self.bump();
|
self.bump();
|
||||||
Ok(Ident::new(symbol, self.prev_token.span))
|
Ok(Ident::new(symbol, self.prev_token.span))
|
||||||
} else {
|
} else {
|
||||||
self.parse_ident_common(false)
|
self.parse_ident_common(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1028,7 +1028,7 @@ impl<'a> Parser<'a> {
|
||||||
let boxed_span = self.token.span;
|
let boxed_span = self.token.span;
|
||||||
let is_ref = self.eat_keyword(kw::Ref);
|
let is_ref = self.eat_keyword(kw::Ref);
|
||||||
let is_mut = self.eat_keyword(kw::Mut);
|
let is_mut = self.eat_keyword(kw::Mut);
|
||||||
let fieldname = self.parse_ident()?;
|
let fieldname = self.parse_field_name()?;
|
||||||
hi = self.prev_token.span;
|
hi = self.prev_token.span;
|
||||||
|
|
||||||
let bind_type = match (is_ref, is_mut) {
|
let bind_type = match (is_ref, is_mut) {
|
||||||
|
|
|
@ -2313,6 +2313,7 @@ crate mod dep_tracking {
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
use std::num::NonZeroUsize;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub trait DepTrackingHash {
|
pub trait DepTrackingHash {
|
||||||
|
@ -2353,6 +2354,7 @@ crate mod dep_tracking {
|
||||||
impl_dep_tracking_hash_via_hash!(lint::Level);
|
impl_dep_tracking_hash_via_hash!(lint::Level);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<bool>);
|
impl_dep_tracking_hash_via_hash!(Option<bool>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<usize>);
|
impl_dep_tracking_hash_via_hash!(Option<usize>);
|
||||||
|
impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<String>);
|
impl_dep_tracking_hash_via_hash!(Option<String>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
|
impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
|
impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
|
||||||
|
|
|
@ -16,6 +16,7 @@ use std::collections::BTreeMap;
|
||||||
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
|
use std::num::NonZeroUsize;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
@ -591,10 +592,10 @@ macro_rules! options {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
|
fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
|
||||||
match v {
|
match v {
|
||||||
Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
|
Some(s) => { *slot = s.parse().ok(); slot.is_some() }
|
||||||
None => { *slot = Some(1); true }
|
None => { *slot = NonZeroUsize::new(1); true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1141,7 +1142,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||||
"for every macro invocation, print its name and arguments (default: no)"),
|
"for every macro invocation, print its name and arguments (default: no)"),
|
||||||
trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
"generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
|
"generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
|
||||||
treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
|
treat_err_as_bug: Option<NonZeroUsize> = (None, parse_treat_err_as_bug, [TRACKED],
|
||||||
"treat error number `val` that occurs as bug"),
|
"treat error number `val` that occurs as bug"),
|
||||||
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
|
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
|
||||||
"in diagnostics, use heuristics to shorten paths referring to items"),
|
"in diagnostics, use heuristics to shorten paths referring to items"),
|
||||||
|
|
|
@ -169,10 +169,14 @@ symbols! {
|
||||||
Option,
|
Option,
|
||||||
Ord,
|
Ord,
|
||||||
Ordering,
|
Ordering,
|
||||||
|
OsStr,
|
||||||
|
OsString,
|
||||||
Output,
|
Output,
|
||||||
Param,
|
Param,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
PartialOrd,
|
PartialOrd,
|
||||||
|
Path,
|
||||||
|
PathBuf,
|
||||||
Pending,
|
Pending,
|
||||||
Pin,
|
Pin,
|
||||||
Poll,
|
Poll,
|
||||||
|
@ -198,6 +202,8 @@ symbols! {
|
||||||
StructuralPartialEq,
|
StructuralPartialEq,
|
||||||
Sync,
|
Sync,
|
||||||
Target,
|
Target,
|
||||||
|
ToOwned,
|
||||||
|
ToString,
|
||||||
Try,
|
Try,
|
||||||
Ty,
|
Ty,
|
||||||
TyCtxt,
|
TyCtxt,
|
||||||
|
|
|
@ -641,6 +641,7 @@ supported_targets! {
|
||||||
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
|
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
|
||||||
("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl),
|
("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl),
|
||||||
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
|
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
|
||||||
|
("s390x-unknown-linux-musl", s390x_unknown_linux_musl),
|
||||||
("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
|
("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
|
||||||
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
|
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
|
||||||
("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
|
("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
|
||||||
|
|
24
compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
Normal file
24
compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use crate::abi::Endian;
|
||||||
|
use crate::spec::Target;
|
||||||
|
|
||||||
|
pub fn target() -> Target {
|
||||||
|
let mut base = super::linux_musl_base::opts();
|
||||||
|
base.endian = Endian::Big;
|
||||||
|
// z10 is the oldest CPU supported by LLVM
|
||||||
|
base.cpu = "z10".to_string();
|
||||||
|
// FIXME: The data_layout string below and the ABI implementation in
|
||||||
|
// cabi_s390x.rs are for now hard-coded to assume the no-vector ABI.
|
||||||
|
// Pass the -vector feature string to LLVM to respect this assumption.
|
||||||
|
base.features = "-vector".to_string();
|
||||||
|
base.max_atomic_width = Some(64);
|
||||||
|
base.min_global_align = Some(16);
|
||||||
|
base.static_position_independent_executables = true;
|
||||||
|
|
||||||
|
Target {
|
||||||
|
llvm_target: "s390x-unknown-linux-musl".to_string(),
|
||||||
|
pointer_width: 64,
|
||||||
|
data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(),
|
||||||
|
arch: "s390x".to_string(),
|
||||||
|
options: base,
|
||||||
|
}
|
||||||
|
}
|
|
@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if call_is_multiline {
|
if call_is_multiline {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
callee.span.shrink_to_hi(),
|
callee.span.shrink_to_hi(),
|
||||||
"try adding a semicolon",
|
"consider using a semicolon here",
|
||||||
";".to_owned(),
|
";".to_owned(),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1450,15 +1450,17 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||||
) {
|
) {
|
||||||
if cond_expr.span.desugaring_kind().is_none() {
|
if cond_expr.span.desugaring_kind().is_none() {
|
||||||
err.span_label(cond_expr.span, "expected this to be `()`");
|
err.span_label(cond_expr.span, "expected this to be `()`");
|
||||||
|
if expr.can_have_side_effects() {
|
||||||
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
|
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
|
fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
|
||||||
} else {
|
} else {
|
||||||
fcx.get_fn_decl(parent_id)
|
fcx.get_fn_decl(parent_id)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let (Some((fn_decl, can_suggest)), _) = (fn_decl, pointing_at_return_type) {
|
if let Some((fn_decl, can_suggest)) = fn_decl {
|
||||||
if expression.is_none() {
|
if expression.is_none() {
|
||||||
pointing_at_return_type |= fcx.suggest_missing_return_type(
|
pointing_at_return_type |= fcx.suggest_missing_return_type(
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -1472,6 +1474,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||||
fn_output = Some(&fn_decl.output); // `impl Trait` return type
|
fn_output = Some(&fn_decl.output); // `impl Trait` return type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let parent_id = fcx.tcx.hir().get_parent_item(id);
|
||||||
|
let parent_item = fcx.tcx.hir().get(parent_id);
|
||||||
|
|
||||||
|
if let (Some((expr, _)), Some((fn_decl, _, _))) =
|
||||||
|
(expression, fcx.get_node_fn_decl(parent_item))
|
||||||
|
{
|
||||||
|
fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found);
|
||||||
|
}
|
||||||
|
|
||||||
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
|
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
|
||||||
self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
|
self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
|
||||||
}
|
}
|
||||||
|
|
|
@ -561,7 +561,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
hir::StmtKind::Expr(ref expr) => {
|
hir::StmtKind::Expr(ref expr) => {
|
||||||
// Check with expected type of `()`.
|
// Check with expected type of `()`.
|
||||||
self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
|
self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
|
||||||
|
if expr.can_have_side_effects() {
|
||||||
self.suggest_semicolon_at_end(expr.span, err);
|
self.suggest_semicolon_at_end(expr.span, err);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
hir::StmtKind::Semi(ref expr) => {
|
hir::StmtKind::Semi(ref expr) => {
|
||||||
|
|
|
@ -44,11 +44,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
blk_id: hir::HirId,
|
blk_id: hir::HirId,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let expr = expr.peel_drop_temps();
|
let expr = expr.peel_drop_temps();
|
||||||
|
if expr.can_have_side_effects() {
|
||||||
self.suggest_missing_semicolon(err, expr, expected, cause_span);
|
self.suggest_missing_semicolon(err, expr, expected, cause_span);
|
||||||
|
}
|
||||||
let mut pointing_at_return_type = false;
|
let mut pointing_at_return_type = false;
|
||||||
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
||||||
pointing_at_return_type =
|
pointing_at_return_type =
|
||||||
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
|
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
|
||||||
|
self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found);
|
||||||
}
|
}
|
||||||
pointing_at_return_type
|
pointing_at_return_type
|
||||||
}
|
}
|
||||||
|
@ -392,10 +395,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
| ExprKind::Loop(..)
|
| ExprKind::Loop(..)
|
||||||
| ExprKind::If(..)
|
| ExprKind::If(..)
|
||||||
| ExprKind::Match(..)
|
| ExprKind::Match(..)
|
||||||
| ExprKind::Block(..) => {
|
| ExprKind::Block(..)
|
||||||
|
if expression.can_have_side_effects() =>
|
||||||
|
{
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
cause_span.shrink_to_hi(),
|
cause_span.shrink_to_hi(),
|
||||||
"try adding a semicolon",
|
"consider using a semicolon here",
|
||||||
";".to_string(),
|
";".to_string(),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
@ -464,6 +469,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn suggest_missing_return_expr(
|
||||||
|
&self,
|
||||||
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
fn_decl: &hir::FnDecl<'_>,
|
||||||
|
expected: Ty<'tcx>,
|
||||||
|
found: Ty<'tcx>,
|
||||||
|
) {
|
||||||
|
if !expected.is_unit() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let found = self.resolve_vars_with_obligations(found);
|
||||||
|
if let hir::FnRetTy::Return(ty) = fn_decl.output {
|
||||||
|
let ty = AstConv::ast_ty_to_ty(self, ty);
|
||||||
|
let ty = self.normalize_associated_types_in(expr.span, ty);
|
||||||
|
if self.can_coerce(found, ty) {
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"you might have meant to return this value",
|
||||||
|
vec![
|
||||||
|
(expr.span.shrink_to_lo(), "return ".to_string()),
|
||||||
|
(expr.span.shrink_to_hi(), ";".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(in super::super) fn suggest_missing_parentheses(
|
pub(in super::super) fn suggest_missing_parentheses(
|
||||||
&self,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
|
|
|
@ -17,6 +17,7 @@ use rustc_span::source_map::{Span, Spanned};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::{BytePos, DUMMY_SP};
|
use rustc_span::{BytePos, DUMMY_SP};
|
||||||
use rustc_trait_selection::traits::{ObligationCause, Pattern};
|
use rustc_trait_selection::traits::{ObligationCause, Pattern};
|
||||||
|
use ty::VariantDef;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
|
@ -1264,14 +1265,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
u.emit();
|
u.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, Some(mut err)) | (Some(mut err), None) => {
|
(None, Some(mut u)) => {
|
||||||
|
if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
|
||||||
|
u.delay_as_bug();
|
||||||
|
e.emit();
|
||||||
|
} else {
|
||||||
|
u.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(mut err), None) => {
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
(None, None) => {}
|
(None, None) => {
|
||||||
|
if let Some(mut err) =
|
||||||
|
self.error_tuple_variant_index_shorthand(variant, pat, fields)
|
||||||
|
{
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
no_field_errors
|
no_field_errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn error_tuple_variant_index_shorthand(
|
||||||
|
&self,
|
||||||
|
variant: &VariantDef,
|
||||||
|
pat: &'_ Pat<'_>,
|
||||||
|
fields: &[hir::FieldPat<'_>],
|
||||||
|
) -> Option<DiagnosticBuilder<'_>> {
|
||||||
|
// if this is a tuple struct, then all field names will be numbers
|
||||||
|
// so if any fields in a struct pattern use shorthand syntax, they will
|
||||||
|
// be invalid identifiers (for example, Foo { 0, 1 }).
|
||||||
|
if let (CtorKind::Fn, PatKind::Struct(qpath, field_patterns, ..)) =
|
||||||
|
(variant.ctor_kind, &pat.kind)
|
||||||
|
{
|
||||||
|
let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
|
||||||
|
if has_shorthand_field_name {
|
||||||
|
let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
|
||||||
|
s.print_qpath(qpath, false)
|
||||||
|
});
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
self.tcx.sess,
|
||||||
|
pat.span,
|
||||||
|
E0769,
|
||||||
|
"tuple variant `{}` written as struct variant",
|
||||||
|
path
|
||||||
|
);
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
|
||||||
|
"use the tuple variant pattern syntax instead",
|
||||||
|
format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
return Some(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
|
fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
|
||||||
let sess = self.tcx.sess;
|
let sess = self.tcx.sess;
|
||||||
let sm = sess.source_map();
|
let sm = sess.source_map();
|
||||||
|
@ -1411,16 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
let (sugg, appl) = if fields.len() == variant.fields.len() {
|
let (sugg, appl) = if fields.len() == variant.fields.len() {
|
||||||
(
|
(
|
||||||
fields
|
self.get_suggested_tuple_struct_pattern(fields, variant),
|
||||||
.iter()
|
|
||||||
.map(|f| match self.tcx.sess.source_map().span_to_snippet(f.pat.span) {
|
|
||||||
Ok(f) => f,
|
|
||||||
Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
|
|
||||||
s.print_pat(f.pat)
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(", "),
|
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1429,10 +1471,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
err.span_suggestion(
|
err.span_suggestion_verbose(
|
||||||
pat.span,
|
qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
|
||||||
"use the tuple variant pattern syntax instead",
|
"use the tuple variant pattern syntax instead",
|
||||||
format!("{}({})", path, sugg),
|
format!("({})", sugg),
|
||||||
appl,
|
appl,
|
||||||
);
|
);
|
||||||
return Some(err);
|
return Some(err);
|
||||||
|
@ -1440,6 +1482,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_suggested_tuple_struct_pattern(
|
||||||
|
&self,
|
||||||
|
fields: &[hir::FieldPat<'_>],
|
||||||
|
variant: &VariantDef,
|
||||||
|
) -> String {
|
||||||
|
let variant_field_idents = variant.fields.iter().map(|f| f.ident).collect::<Vec<Ident>>();
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
|
||||||
|
Ok(f) => {
|
||||||
|
// Field names are numbers, but numbers
|
||||||
|
// are not valid identifiers
|
||||||
|
if variant_field_idents.contains(&field.ident) {
|
||||||
|
String::from("_")
|
||||||
|
} else {
|
||||||
|
f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
|
||||||
|
s.print_pat(field.pat)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
|
/// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
|
||||||
/// inaccessible fields.
|
/// inaccessible fields.
|
||||||
///
|
///
|
||||||
|
|
|
@ -31,6 +31,7 @@ where
|
||||||
/// implementing the `Clone` trait. But `Clone` works only for going from `&T`
|
/// implementing the `Clone` trait. But `Clone` works only for going from `&T`
|
||||||
/// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data
|
/// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data
|
||||||
/// from any borrow of a given type.
|
/// from any borrow of a given type.
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub trait ToOwned {
|
pub trait ToOwned {
|
||||||
/// The resulting type after obtaining ownership.
|
/// The resulting type after obtaining ownership.
|
||||||
|
|
|
@ -1063,7 +1063,7 @@ impl<T> VecDeque<T> {
|
||||||
where
|
where
|
||||||
R: RangeBounds<usize>,
|
R: RangeBounds<usize>,
|
||||||
{
|
{
|
||||||
let Range { start, end } = range.assert_len(self.len());
|
let Range { start, end } = slice::range(range, ..self.len());
|
||||||
let tail = self.wrap_add(self.tail, start);
|
let tail = self.wrap_add(self.tail, start);
|
||||||
let head = self.wrap_add(self.tail, end);
|
let head = self.wrap_add(self.tail, end);
|
||||||
(tail, head)
|
(tail, head)
|
||||||
|
|
|
@ -115,7 +115,6 @@
|
||||||
#![feature(or_patterns)]
|
#![feature(or_patterns)]
|
||||||
#![feature(pattern)]
|
#![feature(pattern)]
|
||||||
#![feature(ptr_internals)]
|
#![feature(ptr_internals)]
|
||||||
#![feature(range_bounds_assert_len)]
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(receiver_trait)]
|
#![feature(receiver_trait)]
|
||||||
#![cfg_attr(bootstrap, feature(min_const_generics))]
|
#![cfg_attr(bootstrap, feature(min_const_generics))]
|
||||||
|
@ -123,6 +122,7 @@
|
||||||
#![feature(set_ptr_value)]
|
#![feature(set_ptr_value)]
|
||||||
#![feature(slice_ptr_get)]
|
#![feature(slice_ptr_get)]
|
||||||
#![feature(slice_ptr_len)]
|
#![feature(slice_ptr_len)]
|
||||||
|
#![feature(slice_range)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(str_internals)]
|
#![feature(str_internals)]
|
||||||
#![feature(trusted_len)]
|
#![feature(trusted_len)]
|
||||||
|
|
|
@ -92,6 +92,8 @@ use crate::borrow::ToOwned;
|
||||||
use crate::boxed::Box;
|
use crate::boxed::Box;
|
||||||
use crate::vec::Vec;
|
use crate::vec::Vec;
|
||||||
|
|
||||||
|
#[unstable(feature = "slice_range", issue = "76393")]
|
||||||
|
pub use core::slice::range;
|
||||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||||
pub use core::slice::ArrayChunks;
|
pub use core::slice::ArrayChunks;
|
||||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||||
|
@ -220,6 +222,7 @@ mod hack {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "slice_alloc"]
|
#[lang = "slice_alloc"]
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "slice")]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
impl<T> [T] {
|
impl<T> [T] {
|
||||||
/// Sorts the slice.
|
/// Sorts the slice.
|
||||||
|
|
|
@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator};
|
||||||
use core::ops::Bound::{Excluded, Included, Unbounded};
|
use core::ops::Bound::{Excluded, Included, Unbounded};
|
||||||
use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
|
use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
use core::slice;
|
||||||
use core::str::{lossy, pattern::Pattern};
|
use core::str::{lossy, pattern::Pattern};
|
||||||
|
|
||||||
use crate::borrow::{Cow, ToOwned};
|
use crate::borrow::{Cow, ToOwned};
|
||||||
|
@ -1510,14 +1511,14 @@ impl String {
|
||||||
// of the vector version. The data is just plain bytes.
|
// of the vector version. The data is just plain bytes.
|
||||||
// Because the range removal happens in Drop, if the Drain iterator is leaked,
|
// Because the range removal happens in Drop, if the Drain iterator is leaked,
|
||||||
// the removal will not happen.
|
// the removal will not happen.
|
||||||
let Range { start, end } = range.assert_len(self.len());
|
let Range { start, end } = slice::range(range, ..self.len());
|
||||||
assert!(self.is_char_boundary(start));
|
assert!(self.is_char_boundary(start));
|
||||||
assert!(self.is_char_boundary(end));
|
assert!(self.is_char_boundary(end));
|
||||||
|
|
||||||
// Take out two simultaneous borrows. The &mut String won't be accessed
|
// Take out two simultaneous borrows. The &mut String won't be accessed
|
||||||
// until iteration is over, in Drop.
|
// until iteration is over, in Drop.
|
||||||
let self_ptr = self as *mut _;
|
let self_ptr = self as *mut _;
|
||||||
// SAFETY: `assert_len` and `is_char_boundary` do the appropriate bounds checks.
|
// SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks.
|
||||||
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
|
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
|
||||||
|
|
||||||
Drain { start, end, iter: chars_iter, string: self_ptr }
|
Drain { start, end, iter: chars_iter, string: self_ptr }
|
||||||
|
@ -2174,6 +2175,7 @@ impl FromStr for String {
|
||||||
/// implementation for free.
|
/// implementation for free.
|
||||||
///
|
///
|
||||||
/// [`Display`]: fmt::Display
|
/// [`Display`]: fmt::Display
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub trait ToString {
|
pub trait ToString {
|
||||||
/// Converts the given value to a `String`.
|
/// Converts the given value to a `String`.
|
||||||
|
|
|
@ -1651,7 +1651,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
// the hole, and the vector length is restored to the new length.
|
// the hole, and the vector length is restored to the new length.
|
||||||
//
|
//
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
let Range { start, end } = range.assert_len(len);
|
let Range { start, end } = slice::range(range, ..len);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// set self.vec length's to start, to be safe in case Drain is leaked
|
// set self.vec length's to start, to be safe in case Drain is leaked
|
||||||
|
@ -2037,11 +2037,11 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
|
||||||
where
|
where
|
||||||
R: RangeBounds<usize>,
|
R: RangeBounds<usize>,
|
||||||
{
|
{
|
||||||
let range = src.assert_len(self.len());
|
let range = slice::range(src, ..self.len());
|
||||||
self.reserve(range.len());
|
self.reserve(range.len());
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - `assert_len` guarantees that the given range is valid for indexing self
|
// - `slice::range` guarantees that the given range is valid for indexing self
|
||||||
unsafe {
|
unsafe {
|
||||||
self.spec_extend_from_within(range);
|
self.spec_extend_from_within(range);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,8 @@ macro_rules! benches {
|
||||||
use test::black_box;
|
use test::black_box;
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
|
const ASCII_CASE_MASK: u8 = 0b0010_0000;
|
||||||
|
|
||||||
benches! {
|
benches! {
|
||||||
fn case00_alloc_only(_bytes: &mut [u8]) {}
|
fn case00_alloc_only(_bytes: &mut [u8]) {}
|
||||||
|
|
||||||
|
@ -204,7 +206,7 @@ benches! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for byte in bytes {
|
for byte in bytes {
|
||||||
*byte &= !((is_ascii_lowercase(*byte) as u8) << 5)
|
*byte &= !((is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +218,7 @@ benches! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for byte in bytes {
|
for byte in bytes {
|
||||||
*byte -= (is_ascii_lowercase(*byte) as u8) << 5
|
*byte -= (is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,3 +35,13 @@ fn bench_to_digit_radix_var(b: &mut Bencher) {
|
||||||
.min()
|
.min()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_to_ascii_uppercase(b: &mut Bencher) {
|
||||||
|
b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_uppercase()).min())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_to_ascii_lowercase(b: &mut Bencher) {
|
||||||
|
b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_lowercase()).min())
|
||||||
|
}
|
||||||
|
|
|
@ -1088,7 +1088,11 @@ impl char {
|
||||||
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
|
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_ascii_uppercase(&self) -> char {
|
pub fn to_ascii_uppercase(&self) -> char {
|
||||||
if self.is_ascii() { (*self as u8).to_ascii_uppercase() as char } else { *self }
|
if self.is_ascii_lowercase() {
|
||||||
|
(*self as u8).ascii_change_case_unchecked() as char
|
||||||
|
} else {
|
||||||
|
*self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a copy of the value in its ASCII lower case equivalent.
|
/// Makes a copy of the value in its ASCII lower case equivalent.
|
||||||
|
@ -1116,7 +1120,11 @@ impl char {
|
||||||
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
|
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_ascii_lowercase(&self) -> char {
|
pub fn to_ascii_lowercase(&self) -> char {
|
||||||
if self.is_ascii() { (*self as u8).to_ascii_lowercase() as char } else { *self }
|
if self.is_ascii_uppercase() {
|
||||||
|
(*self as u8).ascii_change_case_unchecked() as char
|
||||||
|
} else {
|
||||||
|
*self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that two values are an ASCII case-insensitive match.
|
/// Checks that two values are an ASCII case-insensitive match.
|
||||||
|
|
|
@ -152,6 +152,9 @@ impl isize {
|
||||||
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
|
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If 6th bit set ascii is upper case.
|
||||||
|
const ASCII_CASE_MASK: u8 = 0b0010_0000;
|
||||||
|
|
||||||
#[lang = "u8"]
|
#[lang = "u8"]
|
||||||
impl u8 {
|
impl u8 {
|
||||||
uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
|
uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
|
||||||
|
@ -195,7 +198,7 @@ impl u8 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_ascii_uppercase(&self) -> u8 {
|
pub fn to_ascii_uppercase(&self) -> u8 {
|
||||||
// Unset the fifth bit if this is a lowercase letter
|
// Unset the fifth bit if this is a lowercase letter
|
||||||
*self & !((self.is_ascii_lowercase() as u8) << 5)
|
*self & !((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a copy of the value in its ASCII lower case equivalent.
|
/// Makes a copy of the value in its ASCII lower case equivalent.
|
||||||
|
@ -218,7 +221,13 @@ impl u8 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_ascii_lowercase(&self) -> u8 {
|
pub fn to_ascii_lowercase(&self) -> u8 {
|
||||||
// Set the fifth bit if this is an uppercase letter
|
// Set the fifth bit if this is an uppercase letter
|
||||||
*self | ((self.is_ascii_uppercase() as u8) << 5)
|
*self | (self.is_ascii_uppercase() as u8 * ASCII_CASE_MASK)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assumes self is ascii
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn ascii_change_case_unchecked(&self) -> u8 {
|
||||||
|
*self ^ ASCII_CASE_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that two values are an ASCII case-insensitive match.
|
/// Checks that two values are an ASCII case-insensitive match.
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::hash::Hash;
|
use crate::hash::Hash;
|
||||||
use crate::slice::index::{
|
|
||||||
slice_end_index_len_fail, slice_end_index_overflow_fail, slice_index_order_fail,
|
|
||||||
slice_start_index_overflow_fail,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An unbounded range (`..`).
|
/// An unbounded range (`..`).
|
||||||
///
|
///
|
||||||
|
@ -764,92 +760,6 @@ pub trait RangeBounds<T: ?Sized> {
|
||||||
#[stable(feature = "collections_range", since = "1.28.0")]
|
#[stable(feature = "collections_range", since = "1.28.0")]
|
||||||
fn end_bound(&self) -> Bound<&T>;
|
fn end_bound(&self) -> Bound<&T>;
|
||||||
|
|
||||||
/// Performs bounds-checking of this range.
|
|
||||||
///
|
|
||||||
/// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and
|
|
||||||
/// [`slice::get_unchecked_mut`] for slices of the given length.
|
|
||||||
///
|
|
||||||
/// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
|
|
||||||
/// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the range would be out of bounds.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(range_bounds_assert_len)]
|
|
||||||
///
|
|
||||||
/// use std::ops::RangeBounds;
|
|
||||||
///
|
|
||||||
/// let v = [10, 40, 30];
|
|
||||||
/// assert_eq!(1..2, (1..2).assert_len(v.len()));
|
|
||||||
/// assert_eq!(0..2, (..2).assert_len(v.len()));
|
|
||||||
/// assert_eq!(1..3, (1..).assert_len(v.len()));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Panics when [`Index::index`] would panic:
|
|
||||||
///
|
|
||||||
/// ```should_panic
|
|
||||||
/// #![feature(range_bounds_assert_len)]
|
|
||||||
///
|
|
||||||
/// use std::ops::RangeBounds;
|
|
||||||
///
|
|
||||||
/// (2..1).assert_len(3);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```should_panic
|
|
||||||
/// #![feature(range_bounds_assert_len)]
|
|
||||||
///
|
|
||||||
/// use std::ops::RangeBounds;
|
|
||||||
///
|
|
||||||
/// (1..4).assert_len(3);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```should_panic
|
|
||||||
/// #![feature(range_bounds_assert_len)]
|
|
||||||
///
|
|
||||||
/// use std::ops::RangeBounds;
|
|
||||||
///
|
|
||||||
/// (1..=usize::MAX).assert_len(3);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Index::index`]: crate::ops::Index::index
|
|
||||||
#[track_caller]
|
|
||||||
#[unstable(feature = "range_bounds_assert_len", issue = "76393")]
|
|
||||||
fn assert_len(self, len: usize) -> Range<usize>
|
|
||||||
where
|
|
||||||
Self: RangeBounds<usize>,
|
|
||||||
{
|
|
||||||
let start: Bound<&usize> = self.start_bound();
|
|
||||||
let start = match start {
|
|
||||||
Bound::Included(&start) => start,
|
|
||||||
Bound::Excluded(start) => {
|
|
||||||
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
|
|
||||||
}
|
|
||||||
Bound::Unbounded => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let end: Bound<&usize> = self.end_bound();
|
|
||||||
let end = match end {
|
|
||||||
Bound::Included(end) => {
|
|
||||||
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
|
|
||||||
}
|
|
||||||
Bound::Excluded(&end) => end,
|
|
||||||
Bound::Unbounded => len,
|
|
||||||
};
|
|
||||||
|
|
||||||
if start > end {
|
|
||||||
slice_index_order_fail(start, end);
|
|
||||||
}
|
|
||||||
if end > len {
|
|
||||||
slice_end_index_len_fail(end, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
Range { start, end }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if `item` is contained in the range.
|
/// Returns `true` if `item` is contained in the range.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
@ -37,28 +37,28 @@ fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
|
fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
|
||||||
panic!("range end index {} out of range for slice of length {}", index, len);
|
panic!("range end index {} out of range for slice of length {}", index, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! {
|
fn slice_index_order_fail(index: usize, end: usize) -> ! {
|
||||||
panic!("slice index starts at {} but ends at {}", index, end);
|
panic!("slice index starts at {} but ends at {}", index, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub(crate) fn slice_start_index_overflow_fail() -> ! {
|
fn slice_start_index_overflow_fail() -> ! {
|
||||||
panic!("attempted to index slice from after maximum usize");
|
panic!("attempted to index slice from after maximum usize");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub(crate) fn slice_end_index_overflow_fail() -> ! {
|
fn slice_end_index_overflow_fail() -> ! {
|
||||||
panic!("attempted to index slice up to maximum usize");
|
panic!("attempted to index slice up to maximum usize");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,3 +449,100 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
|
||||||
(0..=self.end).index_mut(slice)
|
(0..=self.end).index_mut(slice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs bounds-checking of a range.
|
||||||
|
///
|
||||||
|
/// This method is similar to [`Index::index`] for slices, but it returns a
|
||||||
|
/// [`Range`] equivalent to `range`. You can use this method to turn any range
|
||||||
|
/// into `start` and `end` values.
|
||||||
|
///
|
||||||
|
/// `bounds` is the range of the slice to use for bounds-checking. It should
|
||||||
|
/// be a [`RangeTo`] range that ends at the length of the slice.
|
||||||
|
///
|
||||||
|
/// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and
|
||||||
|
/// [`slice::get_unchecked_mut`] for slices with the given range.
|
||||||
|
///
|
||||||
|
/// [`Range`]: ops::Range
|
||||||
|
/// [`RangeTo`]: ops::RangeTo
|
||||||
|
/// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
|
||||||
|
/// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `range` would be out of bounds.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_range)]
|
||||||
|
///
|
||||||
|
/// use std::slice;
|
||||||
|
///
|
||||||
|
/// let v = [10, 40, 30];
|
||||||
|
/// assert_eq!(1..2, slice::range(1..2, ..v.len()));
|
||||||
|
/// assert_eq!(0..2, slice::range(..2, ..v.len()));
|
||||||
|
/// assert_eq!(1..3, slice::range(1.., ..v.len()));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Panics when [`Index::index`] would panic:
|
||||||
|
///
|
||||||
|
/// ```should_panic
|
||||||
|
/// #![feature(slice_range)]
|
||||||
|
///
|
||||||
|
/// use std::slice;
|
||||||
|
///
|
||||||
|
/// slice::range(2..1, ..3);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```should_panic
|
||||||
|
/// #![feature(slice_range)]
|
||||||
|
///
|
||||||
|
/// use std::slice;
|
||||||
|
///
|
||||||
|
/// slice::range(1..4, ..3);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```should_panic
|
||||||
|
/// #![feature(slice_range)]
|
||||||
|
///
|
||||||
|
/// use std::slice;
|
||||||
|
///
|
||||||
|
/// slice::range(1..=usize::MAX, ..3);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`Index::index`]: ops::Index::index
|
||||||
|
#[track_caller]
|
||||||
|
#[unstable(feature = "slice_range", issue = "76393")]
|
||||||
|
pub fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
|
||||||
|
where
|
||||||
|
R: ops::RangeBounds<usize>,
|
||||||
|
{
|
||||||
|
let len = bounds.end;
|
||||||
|
|
||||||
|
let start: ops::Bound<&usize> = range.start_bound();
|
||||||
|
let start = match start {
|
||||||
|
ops::Bound::Included(&start) => start,
|
||||||
|
ops::Bound::Excluded(start) => {
|
||||||
|
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
|
||||||
|
}
|
||||||
|
ops::Bound::Unbounded => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let end: ops::Bound<&usize> = range.end_bound();
|
||||||
|
let end = match end {
|
||||||
|
ops::Bound::Included(end) => {
|
||||||
|
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
|
||||||
|
}
|
||||||
|
ops::Bound::Excluded(&end) => end,
|
||||||
|
ops::Bound::Unbounded => len,
|
||||||
|
};
|
||||||
|
|
||||||
|
if start > end {
|
||||||
|
slice_index_order_fail(start, end);
|
||||||
|
}
|
||||||
|
if end > len {
|
||||||
|
slice_end_index_len_fail(end, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
ops::Range { start, end }
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ use crate::option::Option::{None, Some};
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
use crate::result::Result;
|
use crate::result::Result;
|
||||||
use crate::result::Result::{Err, Ok};
|
use crate::result::Result::{Err, Ok};
|
||||||
|
use crate::slice;
|
||||||
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
feature = "slice_internals",
|
feature = "slice_internals",
|
||||||
|
@ -29,7 +30,7 @@ pub mod memchr;
|
||||||
|
|
||||||
mod ascii;
|
mod ascii;
|
||||||
mod cmp;
|
mod cmp;
|
||||||
pub(crate) mod index;
|
mod index;
|
||||||
mod iter;
|
mod iter;
|
||||||
mod raw;
|
mod raw;
|
||||||
mod rotate;
|
mod rotate;
|
||||||
|
@ -76,6 +77,9 @@ pub use sort::heapsort;
|
||||||
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
||||||
pub use index::SliceIndex;
|
pub use index::SliceIndex;
|
||||||
|
|
||||||
|
#[unstable(feature = "slice_range", issue = "76393")]
|
||||||
|
pub use index::range;
|
||||||
|
|
||||||
#[lang = "slice"]
|
#[lang = "slice"]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
impl<T> [T] {
|
impl<T> [T] {
|
||||||
|
@ -3075,7 +3079,7 @@ impl<T> [T] {
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
{
|
{
|
||||||
let Range { start: src_start, end: src_end } = src.assert_len(self.len());
|
let Range { start: src_start, end: src_end } = slice::range(src, ..self.len());
|
||||||
let count = src_end - src_start;
|
let count = src_end - src_start;
|
||||||
assert!(dest <= self.len() - count, "dest is out of bounds");
|
assert!(dest <= self.len() - count, "dest is out of bounds");
|
||||||
// SAFETY: the conditions for `ptr::copy` have all been checked above,
|
// SAFETY: the conditions for `ptr::copy` have all been checked above,
|
||||||
|
|
|
@ -71,6 +71,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||||
/// [`CStr`]: crate::ffi::CStr
|
/// [`CStr`]: crate::ffi::CStr
|
||||||
/// [conversions]: super#conversions
|
/// [conversions]: super#conversions
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "OsString")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct OsString {
|
pub struct OsString {
|
||||||
inner: Buf,
|
inner: Buf,
|
||||||
|
@ -93,6 +94,7 @@ impl crate::sealed::Sealed for OsString {}
|
||||||
///
|
///
|
||||||
/// [`&str`]: str
|
/// [`&str`]: str
|
||||||
/// [conversions]: super#conversions
|
/// [conversions]: super#conversions
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
// FIXME:
|
// FIXME:
|
||||||
// `OsStr::from_inner` current implementation relies
|
// `OsStr::from_inner` current implementation relies
|
||||||
|
|
|
@ -3,41 +3,41 @@
|
||||||
#![stable(feature = "os", since = "1.0.0")]
|
#![stable(feature = "os", since = "1.0.0")]
|
||||||
#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
|
#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
// When documenting libstd we want to show unix/windows/linux modules as these are the "main
|
||||||
if #[cfg(doc)] {
|
// modules" that are used across platforms, so all modules are enabled when `cfg(doc)` is set.
|
||||||
|
// This should help show platform-specific functionality in a hopefully cross-platform way in the
|
||||||
// When documenting libstd we want to show unix/windows/linux modules as
|
// documentation.
|
||||||
// these are the "main modules" that are used across platforms. This
|
// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make
|
||||||
// should help show platform-specific functionality in a hopefully
|
// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038
|
||||||
// cross-platform way in the documentation
|
|
||||||
|
|
||||||
|
#[cfg(doc)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use crate::sys::unix_ext as unix;
|
pub use crate::sys::unix_ext as unix;
|
||||||
|
|
||||||
|
#[cfg(doc)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use crate::sys::windows_ext as windows;
|
pub use crate::sys::windows_ext as windows;
|
||||||
|
|
||||||
|
#[cfg(doc)]
|
||||||
#[doc(cfg(target_os = "linux"))]
|
#[doc(cfg(target_os = "linux"))]
|
||||||
pub mod linux;
|
pub mod linux;
|
||||||
} else {
|
|
||||||
|
|
||||||
// If we're not documenting libstd then we just expose the main modules
|
// If we're not documenting libstd then we just expose the main modules as we otherwise would.
|
||||||
// as we otherwise would.
|
|
||||||
|
|
||||||
|
#[cfg(not(doc))]
|
||||||
#[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))]
|
#[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use crate::sys::ext as unix;
|
pub use crate::sys::ext as unix;
|
||||||
|
|
||||||
|
#[cfg(not(doc))]
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use crate::sys::ext as windows;
|
pub use crate::sys::ext as windows;
|
||||||
|
|
||||||
|
#[cfg(not(doc))]
|
||||||
#[cfg(any(target_os = "linux", target_os = "l4re"))]
|
#[cfg(any(target_os = "linux", target_os = "l4re"))]
|
||||||
pub mod linux;
|
pub mod linux;
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
pub mod android;
|
pub mod android;
|
||||||
#[cfg(target_os = "dragonfly")]
|
#[cfg(target_os = "dragonfly")]
|
||||||
|
|
|
@ -1066,6 +1066,7 @@ impl FusedIterator for Ancestors<'_> {}
|
||||||
///
|
///
|
||||||
/// Which method works best depends on what kind of situation you're in.
|
/// Which method works best depends on what kind of situation you're in.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
// FIXME:
|
// FIXME:
|
||||||
// `PathBuf::as_mut_vec` current implementation relies
|
// `PathBuf::as_mut_vec` current implementation relies
|
||||||
|
@ -1719,6 +1720,7 @@ impl AsRef<OsStr> for PathBuf {
|
||||||
/// let extension = path.extension();
|
/// let extension = path.extension();
|
||||||
/// assert_eq!(extension, Some(OsStr::new("txt")));
|
/// assert_eq!(extension, Some(OsStr::new("txt")));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "Path")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
// FIXME:
|
// FIXME:
|
||||||
// `Path::new` current implementation relies
|
// `Path::new` current implementation relies
|
||||||
|
|
|
@ -557,12 +557,8 @@ pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
|
||||||
pub fn link(original: &Path, link: &Path) -> io::Result<()> {
|
pub fn link(original: &Path, link: &Path) -> io::Result<()> {
|
||||||
let (original, original_file) = open_parent(original)?;
|
let (original, original_file) = open_parent(original)?;
|
||||||
let (link, link_file) = open_parent(link)?;
|
let (link, link_file) = open_parent(link)?;
|
||||||
original.link(
|
// Pass 0 as the flags argument, meaning don't follow symlinks.
|
||||||
wasi::LOOKUPFLAGS_SYMLINK_FOLLOW,
|
original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?)
|
||||||
osstr2str(original_file.as_ref())?,
|
|
||||||
&link,
|
|
||||||
osstr2str(link_file.as_ref())?,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stat(p: &Path) -> io::Result<FileAttr> {
|
pub fn stat(p: &Path) -> io::Result<FileAttr> {
|
||||||
|
|
|
@ -208,6 +208,7 @@ target | std | host | notes
|
||||||
`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
|
`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
|
||||||
`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
|
`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
|
||||||
`riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
|
`riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
|
||||||
|
`s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL)
|
||||||
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
|
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
|
||||||
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
|
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
|
||||||
`sparc64-unknown-openbsd` | ? | |
|
`sparc64-unknown-openbsd` | ? | |
|
||||||
|
|
|
@ -101,7 +101,7 @@ what an item is, how it is used, and for what purpose it exists.
|
||||||
Let's see an example coming from the [standard library] by taking a look at the
|
Let's see an example coming from the [standard library] by taking a look at the
|
||||||
[`std::env::args()`][env::args] function:
|
[`std::env::args()`][env::args] function:
|
||||||
|
|
||||||
``````text
|
``````markdown
|
||||||
Returns the arguments which this program was started with (normally passed
|
Returns the arguments which this program was started with (normally passed
|
||||||
via the command line).
|
via the command line).
|
||||||
|
|
||||||
|
@ -153,9 +153,10 @@ and finally provides a code example.
|
||||||
|
|
||||||
## Markdown
|
## Markdown
|
||||||
|
|
||||||
`rustdoc` uses the [CommonMark markdown specification]. You might be
|
`rustdoc` uses the [CommonMark Markdown specification]. You might be
|
||||||
interested into taking a look at their website to see what's possible to do.
|
interested in taking a look at their website to see what's possible:
|
||||||
- [commonmark quick reference]
|
|
||||||
|
- [CommonMark quick reference]
|
||||||
- [current spec]
|
- [current spec]
|
||||||
|
|
||||||
In addition to the standard CommonMark syntax, `rustdoc` supports several
|
In addition to the standard CommonMark syntax, `rustdoc` supports several
|
||||||
|
@ -240,6 +241,21 @@ This will render as
|
||||||
|
|
||||||
See the specification for the [task list extension] for more details.
|
See the specification for the [task list extension] for more details.
|
||||||
|
|
||||||
|
### Smart punctuation
|
||||||
|
|
||||||
|
Some ASCII punctuation sequences will be automatically turned into fancy Unicode
|
||||||
|
characters:
|
||||||
|
|
||||||
|
| ASCII sequence | Unicode |
|
||||||
|
|----------------|---------|
|
||||||
|
| `--` | – |
|
||||||
|
| `---` | — |
|
||||||
|
| `...` | … |
|
||||||
|
| `"` | “ or ”, depending on context |
|
||||||
|
| `'` | ‘ or ’, depending on context |
|
||||||
|
|
||||||
|
So, no need to manually enter those Unicode characters!
|
||||||
|
|
||||||
[`backtrace`]: https://docs.rs/backtrace/0.3.50/backtrace/
|
[`backtrace`]: https://docs.rs/backtrace/0.3.50/backtrace/
|
||||||
[commonmark markdown specification]: https://commonmark.org/
|
[commonmark markdown specification]: https://commonmark.org/
|
||||||
[commonmark quick reference]: https://commonmark.org/help/
|
[commonmark quick reference]: https://commonmark.org/help/
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
# `range_bounds_assert_len`
|
|
||||||
|
|
||||||
The tracking issue for this feature is: [#76393]
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
This adds [`RangeBounds::assert_len`].
|
|
||||||
|
|
||||||
[#76393]: https://github.com/rust-lang/rust/issues/76393
|
|
||||||
[`RangeBounds::assert_len`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.assert_len
|
|
|
@ -52,11 +52,12 @@ pub(crate) fn opts() -> Options {
|
||||||
| Options::ENABLE_FOOTNOTES
|
| Options::ENABLE_FOOTNOTES
|
||||||
| Options::ENABLE_STRIKETHROUGH
|
| Options::ENABLE_STRIKETHROUGH
|
||||||
| Options::ENABLE_TASKLISTS
|
| Options::ENABLE_TASKLISTS
|
||||||
|
| Options::ENABLE_SMART_PUNCTUATION
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A subset of [`opts()`] used for rendering summaries.
|
/// A subset of [`opts()`] used for rendering summaries.
|
||||||
pub(crate) fn summary_opts() -> Options {
|
pub(crate) fn summary_opts() -> Options {
|
||||||
Options::ENABLE_STRIKETHROUGH
|
Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When `to_string` is called, this struct will emit the HTML corresponding to
|
/// When `to_string` is called, this struct will emit the HTML corresponding to
|
||||||
|
|
|
@ -201,8 +201,8 @@ fn test_short_markdown_summary() {
|
||||||
t("Hard-break \nsummary", "Hard-break summary");
|
t("Hard-break \nsummary", "Hard-break summary");
|
||||||
t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
|
t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
|
||||||
t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
|
t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
|
||||||
t("code `let x = i32;` ...", "code <code>let x = i32;</code> ...");
|
t("code `let x = i32;` ...", "code <code>let x = i32;</code> …");
|
||||||
t("type `Type<'static>` ...", "type <code>Type<'static></code> ...");
|
t("type `Type<'static>` ...", "type <code>Type<'static></code> …");
|
||||||
t("# top header", "top header");
|
t("# top header", "top header");
|
||||||
t("## header", "header");
|
t("## header", "header");
|
||||||
t("first paragraph\n\nsecond paragraph", "first paragraph");
|
t("first paragraph\n\nsecond paragraph", "first paragraph");
|
||||||
|
@ -227,8 +227,8 @@ fn test_plain_text_summary() {
|
||||||
t("Hard-break \nsummary", "Hard-break summary");
|
t("Hard-break \nsummary", "Hard-break summary");
|
||||||
t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
|
t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
|
||||||
t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
|
t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
|
||||||
t("code `let x = i32;` ...", "code `let x = i32;` ...");
|
t("code `let x = i32;` ...", "code `let x = i32;` …");
|
||||||
t("type `Type<'static>` ...", "type `Type<'static>` ...");
|
t("type `Type<'static>` ...", "type `Type<'static>` …");
|
||||||
t("# top header", "top header");
|
t("# top header", "top header");
|
||||||
t("# top header\n\nfollowed by some text", "top header");
|
t("# top header\n\nfollowed by some text", "top header");
|
||||||
t("## header", "header");
|
t("## header", "header");
|
||||||
|
@ -251,6 +251,6 @@ fn test_markdown_html_escape() {
|
||||||
}
|
}
|
||||||
|
|
||||||
t("`Struct<'a, T>`", "<p><code>Struct<'a, T></code></p>\n");
|
t("`Struct<'a, T>`", "<p><code>Struct<'a, T></code></p>\n");
|
||||||
t("Struct<'a, T>", "<p>Struct<'a, T></p>\n");
|
t("Struct<'a, T>", "<p>Struct<’a, T></p>\n");
|
||||||
t("Struct<br>", "<p>Struct<br></p>\n");
|
t("Struct<br>", "<p>Struct<br></p>\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ function focusSearchBar() {
|
||||||
getSearchInput().focus();
|
getSearchInput().focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the focus from the search bar
|
// Removes the focus from the search bar.
|
||||||
function defocusSearchBar() {
|
function defocusSearchBar() {
|
||||||
getSearchInput().blur();
|
getSearchInput().blur();
|
||||||
}
|
}
|
||||||
|
@ -220,6 +220,11 @@ function defocusSearchBar() {
|
||||||
addClass(search, "hidden");
|
addClass(search, "hidden");
|
||||||
removeClass(main, "hidden");
|
removeClass(main, "hidden");
|
||||||
document.title = titleBeforeSearch;
|
document.title = titleBeforeSearch;
|
||||||
|
// We also remove the query parameter from the URL.
|
||||||
|
if (browserSupportsHistoryApi()) {
|
||||||
|
history.replaceState("", window.currentCrate + " - Rust",
|
||||||
|
getNakedUrl() + window.location.hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// used for special search precedence
|
// used for special search precedence
|
||||||
|
|
|
@ -4,6 +4,6 @@ extern crate inner;
|
||||||
|
|
||||||
|
|
||||||
// @has add_docs/struct.MyStruct.html
|
// @has add_docs/struct.MyStruct.html
|
||||||
// @has add_docs/struct.MyStruct.html "Doc comment from 'pub use', Doc comment from definition"
|
// @has add_docs/struct.MyStruct.html "Doc comment from ‘pub use’, Doc comment from definition"
|
||||||
/// Doc comment from 'pub use',
|
/// Doc comment from 'pub use',
|
||||||
pub use inner::MyStruct;
|
pub use inner::MyStruct;
|
||||||
|
|
30
src/test/rustdoc/smart-punct.rs
Normal file
30
src/test/rustdoc/smart-punct.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
#![crate_name = "foo"]
|
||||||
|
|
||||||
|
//! This is the "start" of the 'document'! How'd you know that "it's" the start?
|
||||||
|
//!
|
||||||
|
//! # Header with "smart punct'"
|
||||||
|
//!
|
||||||
|
//! [link with "smart punct'" -- yessiree!][]
|
||||||
|
//!
|
||||||
|
//! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org
|
||||||
|
//!
|
||||||
|
//! # Code should not be smart-punct'd
|
||||||
|
//!
|
||||||
|
//! `this inline code -- it shouldn't have "smart punct"`
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! let x = "don't smart-punct me -- please!";
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! I say "don't smart-punct me -- please!"
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
// @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?"
|
||||||
|
// @has "foo/index.html" "//h1" "Header with “smart punct’”"
|
||||||
|
// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!"
|
||||||
|
// @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\""
|
||||||
|
// @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";"
|
||||||
|
// @has "foo/index.html" '//pre' "I say \"don't smart-punct me -- please!\""
|
|
@ -21,7 +21,7 @@ async fn dummy() {}
|
||||||
async fn suggest_await_in_async_fn_return() {
|
async fn suggest_await_in_async_fn_return() {
|
||||||
dummy()
|
dummy()
|
||||||
//~^ ERROR mismatched types [E0308]
|
//~^ ERROR mismatched types [E0308]
|
||||||
//~| HELP try adding a semicolon
|
//~| HELP consider using a semicolon here
|
||||||
//~| HELP consider `await`ing on the `Future`
|
//~| HELP consider `await`ing on the `Future`
|
||||||
//~| SUGGESTION .await
|
//~| SUGGESTION .await
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ help: consider `await`ing on the `Future`
|
||||||
|
|
|
|
||||||
LL | dummy().await
|
LL | dummy().await
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
help: try adding a semicolon
|
help: consider using a semicolon here
|
||||||
|
|
|
|
||||||
LL | dummy();
|
LL | dummy();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
@ -14,9 +14,7 @@ LL | | true
|
||||||
| | ^^^^ expected `()`, found `bool`
|
| | ^^^^ expected `()`, found `bool`
|
||||||
LL | |
|
LL | |
|
||||||
LL | | }
|
LL | | }
|
||||||
| | -- help: consider using a semicolon here
|
| |_____- expected this to be `()`
|
||||||
| |_____|
|
|
||||||
| expected this to be `()`
|
|
||||||
|
|
||||||
error: aborting due to previous error; 1 warning emitted
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ error[E0308]: mismatched types
|
||||||
LL | foo()
|
LL | foo()
|
||||||
| ^^^^^ expected `()`, found `usize`
|
| ^^^^^ expected `()`, found `usize`
|
||||||
|
|
|
|
||||||
help: try adding a semicolon
|
help: consider using a semicolon here
|
||||||
|
|
|
|
||||||
LL | foo();
|
LL | foo();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
@ -2,7 +2,12 @@ error[E0769]: tuple variant `MyOption::MySome` written as struct variant
|
||||||
--> $DIR/issue-17800.rs:8:9
|
--> $DIR/issue-17800.rs:8:9
|
||||||
|
|
|
|
||||||
LL | MyOption::MySome { x: 42 } => (),
|
LL | MyOption::MySome { x: 42 } => (),
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `MyOption::MySome(42)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use the tuple variant pattern syntax instead
|
||||||
|
|
|
||||||
|
LL | MyOption::MySome(42) => (),
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,11 @@ error[E0308]: mismatched types
|
||||||
|
|
|
|
||||||
LL | { true }
|
LL | { true }
|
||||||
| ^^^^ expected `()`, found `bool`
|
| ^^^^ expected `()`, found `bool`
|
||||||
|
|
|
||||||
|
help: you might have meant to return this value
|
||||||
|
|
|
||||||
|
LL | { return true; }
|
||||||
|
| ^^^^^^ ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/empty-trailing-stmt.rs:5:13
|
--> $DIR/empty-trailing-stmt.rs:5:13
|
||||||
|
|
|
@ -2,7 +2,12 @@ error[E0769]: tuple variant `S` written as struct variant
|
||||||
--> $DIR/missing-fields-in-struct-pattern.rs:4:12
|
--> $DIR/missing-fields-in-struct-pattern.rs:4:12
|
||||||
|
|
|
|
||||||
LL | if let S { a, b, c, d } = S(1, 2, 3, 4) {
|
LL | if let S { a, b, c, d } = S(1, 2, 3, 4) {
|
||||||
| ^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `S(a, b, c, d)`
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use the tuple variant pattern syntax instead
|
||||||
|
|
|
||||||
|
LL | if let S(a, b, c, d) = S(1, 2, 3, 4) {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,29 @@ error[E0308]: mismatched types
|
||||||
--> $DIR/expr-as-stmt-2.rs:3:26
|
--> $DIR/expr-as-stmt-2.rs:3:26
|
||||||
|
|
|
|
||||||
LL | if let Some(x) = a { true } else { false }
|
LL | if let Some(x) = a { true } else { false }
|
||||||
| ---------------------^^^^------------------ help: consider using a semicolon here
|
| ---------------------^^^^-----------------
|
||||||
| | |
|
| | |
|
||||||
| | expected `()`, found `bool`
|
| | expected `()`, found `bool`
|
||||||
| expected this to be `()`
|
| expected this to be `()`
|
||||||
|
|
|
||||||
|
help: you might have meant to return this value
|
||||||
|
|
|
||||||
|
LL | if let Some(x) = a { return true; } else { false }
|
||||||
|
| ^^^^^^ ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/expr-as-stmt-2.rs:3:40
|
--> $DIR/expr-as-stmt-2.rs:3:40
|
||||||
|
|
|
|
||||||
LL | if let Some(x) = a { true } else { false }
|
LL | if let Some(x) = a { true } else { false }
|
||||||
| -----------------------------------^^^^^--- help: consider using a semicolon here
|
| -----------------------------------^^^^^--
|
||||||
| | |
|
| | |
|
||||||
| | expected `()`, found `bool`
|
| | expected `()`, found `bool`
|
||||||
| expected this to be `()`
|
| expected this to be `()`
|
||||||
|
|
|
||||||
|
help: you might have meant to return this value
|
||||||
|
|
|
||||||
|
LL | if let Some(x) = a { true } else { return false; }
|
||||||
|
| ^^^^^^ ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/expr-as-stmt-2.rs:6:5
|
--> $DIR/expr-as-stmt-2.rs:6:5
|
||||||
|
|
|
@ -40,24 +40,44 @@ error[E0308]: mismatched types
|
||||||
|
|
|
|
||||||
LL | {2} + {2}
|
LL | {2} + {2}
|
||||||
| ^ expected `()`, found integer
|
| ^ expected `()`, found integer
|
||||||
|
|
|
||||||
|
help: you might have meant to return this value
|
||||||
|
|
|
||||||
|
LL | {return 2;} + {2}
|
||||||
|
| ^^^^^^ ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/expr-as-stmt.rs:12:6
|
--> $DIR/expr-as-stmt.rs:12:6
|
||||||
|
|
|
|
||||||
LL | {2} + 2
|
LL | {2} + 2
|
||||||
| ^ expected `()`, found integer
|
| ^ expected `()`, found integer
|
||||||
|
|
|
||||||
|
help: you might have meant to return this value
|
||||||
|
|
|
||||||
|
LL | {return 2;} + 2
|
||||||
|
| ^^^^^^ ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/expr-as-stmt.rs:18:7
|
--> $DIR/expr-as-stmt.rs:18:7
|
||||||
|
|
|
|
||||||
LL | { 42 } + foo;
|
LL | { 42 } + foo;
|
||||||
| ^^ expected `()`, found integer
|
| ^^ expected `()`, found integer
|
||||||
|
|
|
||||||
|
help: you might have meant to return this value
|
||||||
|
|
|
||||||
|
LL | { return 42; } + foo;
|
||||||
|
| ^^^^^^ ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/expr-as-stmt.rs:24:7
|
--> $DIR/expr-as-stmt.rs:24:7
|
||||||
|
|
|
|
||||||
LL | { 3 } * 3
|
LL | { 3 } * 3
|
||||||
| ^ expected `()`, found integer
|
| ^ expected `()`, found integer
|
||||||
|
|
|
||||||
|
help: you might have meant to return this value
|
||||||
|
|
|
||||||
|
LL | { return 3; } * 3
|
||||||
|
| ^^^^^^ ^
|
||||||
|
|
||||||
error[E0614]: type `{integer}` cannot be dereferenced
|
error[E0614]: type `{integer}` cannot be dereferenced
|
||||||
--> $DIR/expr-as-stmt.rs:24:11
|
--> $DIR/expr-as-stmt.rs:24:11
|
||||||
|
|
|
@ -22,7 +22,12 @@ error[E0769]: tuple variant `Enum::Bar` written as struct variant
|
||||||
--> $DIR/recover-from-bad-variant.rs:12:9
|
--> $DIR/recover-from-bad-variant.rs:12:9
|
||||||
|
|
|
|
||||||
LL | Enum::Bar { a, b } => {}
|
LL | Enum::Bar { a, b } => {}
|
||||||
| ^^^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Enum::Bar(a, b)`
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use the tuple variant pattern syntax instead
|
||||||
|
|
|
||||||
|
LL | Enum::Bar(a, b) => {}
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ error[E0308]: mismatched types
|
||||||
--> $DIR/struct-literal-variant-in-if.rs:10:20
|
--> $DIR/struct-literal-variant-in-if.rs:10:20
|
||||||
|
|
|
|
||||||
LL | if x == E::V { field } {}
|
LL | if x == E::V { field } {}
|
||||||
| ---------------^^^^^--- help: consider using a semicolon here
|
| ---------------^^^^^--
|
||||||
| | |
|
| | |
|
||||||
| | expected `()`, found `bool`
|
| | expected `()`, found `bool`
|
||||||
| expected this to be `()`
|
| expected this to be `()`
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | fn main() {
|
||||||
| - expected `()` because of default return type
|
| - expected `()` because of default return type
|
||||||
LL | // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE.
|
LL | // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE.
|
||||||
LL | std::cell::Cell::new(0)
|
LL | std::cell::Cell::new(0)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
|
| ^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
|
||||||
| |
|
| |
|
||||||
| expected `()`, found struct `Cell`
|
| expected `()`, found struct `Cell`
|
||||||
|
|
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ LL | foo(4 as usize)
|
||||||
|
|
|
|
||||||
= note: expected unit type `()`
|
= note: expected unit type `()`
|
||||||
found struct `S<usize>`
|
found struct `S<usize>`
|
||||||
help: try adding a semicolon
|
help: consider using a semicolon here
|
||||||
|
|
|
|
||||||
LL | foo(4 as usize);
|
LL | foo(4 as usize);
|
||||||
| ^
|
| ^
|
||||||
|
|
10
src/test/ui/return/tail-expr-as-potential-return.rs
Normal file
10
src/test/ui/return/tail-expr-as-potential-return.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fn main() {
|
||||||
|
let _ = foo(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(x: bool) -> Result<f64, i32> {
|
||||||
|
if x {
|
||||||
|
Err(42) //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
Ok(42.0)
|
||||||
|
}
|
19
src/test/ui/return/tail-expr-as-potential-return.stderr
Normal file
19
src/test/ui/return/tail-expr-as-potential-return.stderr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/tail-expr-as-potential-return.rs:7:9
|
||||||
|
|
|
||||||
|
LL | / if x {
|
||||||
|
LL | | Err(42)
|
||||||
|
| | ^^^^^^^ expected `()`, found enum `Result`
|
||||||
|
LL | | }
|
||||||
|
| |_____- expected this to be `()`
|
||||||
|
|
|
||||||
|
= note: expected unit type `()`
|
||||||
|
found enum `Result<_, {integer}>`
|
||||||
|
help: you might have meant to return this value
|
||||||
|
|
|
||||||
|
LL | return Err(42);
|
||||||
|
| ^^^^^^ ^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -29,7 +29,7 @@ LL | fn monomorphic() -> () {
|
||||||
| -- expected `()` because of return type
|
| -- expected `()` because of return type
|
||||||
...
|
...
|
||||||
LL | generic::<()>()
|
LL | generic::<()>()
|
||||||
| ^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
|
| ^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
|
||||||
| |
|
| |
|
||||||
| expected `()`, found associated type
|
| expected `()`, found associated type
|
||||||
|
|
|
|
||||||
|
|
15
src/test/ui/structs/struct-tuple-field-names.rs
Normal file
15
src/test/ui/structs/struct-tuple-field-names.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
struct S(i32, f32);
|
||||||
|
enum E {
|
||||||
|
S(i32, f32),
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let x = E::S(1, 2.2);
|
||||||
|
match x {
|
||||||
|
E::S { 0, 1 } => {}
|
||||||
|
//~^ ERROR tuple variant `E::S` written as struct variant [E0769]
|
||||||
|
}
|
||||||
|
let y = S(1, 2.2);
|
||||||
|
match y {
|
||||||
|
S { } => {} //~ ERROR: tuple variant `S` written as struct variant [E0769]
|
||||||
|
}
|
||||||
|
}
|
25
src/test/ui/structs/struct-tuple-field-names.stderr
Normal file
25
src/test/ui/structs/struct-tuple-field-names.stderr
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
error[E0769]: tuple variant `E::S` written as struct variant
|
||||||
|
--> $DIR/struct-tuple-field-names.rs:8:9
|
||||||
|
|
|
||||||
|
LL | E::S { 0, 1 } => {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use the tuple variant pattern syntax instead
|
||||||
|
|
|
||||||
|
LL | E::S(_, _) => {}
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error[E0769]: tuple variant `S` written as struct variant
|
||||||
|
--> $DIR/struct-tuple-field-names.rs:13:9
|
||||||
|
|
|
||||||
|
LL | S { } => {}
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: use the tuple variant pattern syntax instead
|
||||||
|
|
|
||||||
|
LL | S(_, _) => {}
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0769`.
|
|
@ -5,7 +5,7 @@ LL | fn vindictive() -> bool { true }
|
||||||
| ----------------------- `vindictive` defined here returns `bool`
|
| ----------------------- `vindictive` defined here returns `bool`
|
||||||
...
|
...
|
||||||
LL | vindictive()
|
LL | vindictive()
|
||||||
| -^^^^^^^^^^^- help: try adding a semicolon: `;`
|
| -^^^^^^^^^^^- help: consider using a semicolon here: `;`
|
||||||
| _____|
|
| _____|
|
||||||
| |
|
| |
|
||||||
LL | | (1, 2)
|
LL | | (1, 2)
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
// check-only
|
|
||||||
// run-rustfix
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
match 3 {
|
|
||||||
4 => 1,
|
|
||||||
3 => {
|
|
||||||
2 //~ ERROR mismatched types
|
|
||||||
}
|
|
||||||
_ => 2
|
|
||||||
};
|
|
||||||
match 3 { //~ ERROR mismatched types
|
|
||||||
4 => 1,
|
|
||||||
3 => 2,
|
|
||||||
_ => 2
|
|
||||||
};
|
|
||||||
let _ = ();
|
|
||||||
}
|
|
|
@ -1,11 +1,10 @@
|
||||||
// check-only
|
// check-only
|
||||||
// run-rustfix
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match 3 {
|
match 3 {
|
||||||
4 => 1,
|
4 => 1,
|
||||||
3 => {
|
3 => {
|
||||||
2 //~ ERROR mismatched types
|
foo() //~ ERROR mismatched types
|
||||||
}
|
}
|
||||||
_ => 2
|
_ => 2
|
||||||
}
|
}
|
||||||
|
@ -16,3 +15,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
let _ = ();
|
let _ = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn foo() -> i32 {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/match-needing-semi.rs:8:13
|
--> $DIR/match-needing-semi.rs:7:13
|
||||||
|
|
|
|
||||||
LL | / match 3 {
|
LL | / match 3 {
|
||||||
LL | | 4 => 1,
|
LL | | 4 => 1,
|
||||||
LL | | 3 => {
|
LL | | 3 => {
|
||||||
LL | | 2
|
LL | | foo()
|
||||||
| | ^ expected `()`, found integer
|
| | ^^^^^ expected `()`, found `i32`
|
||||||
LL | | }
|
LL | | }
|
||||||
LL | | _ => 2
|
LL | | _ => 2
|
||||||
LL | | }
|
LL | | }
|
||||||
| | -- help: consider using a semicolon here
|
| |_____- expected this to be `()`
|
||||||
| |_____|
|
|
|
||||||
| expected this to be `()`
|
help: consider using a semicolon here
|
||||||
|
|
|
||||||
|
LL | foo();
|
||||||
|
| ^
|
||||||
|
help: consider using a semicolon here
|
||||||
|
|
|
||||||
|
LL | };
|
||||||
|
| ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/match-needing-semi.rs:12:5
|
--> $DIR/match-needing-semi.rs:11:5
|
||||||
|
|
|
|
||||||
LL | / match 3 {
|
LL | / match 3 {
|
||||||
LL | | 4 => 1,
|
LL | | 4 => 1,
|
||||||
|
|
|
@ -2,7 +2,12 @@ error[E0769]: tuple variant `X::Y` written as struct variant
|
||||||
--> $DIR/issue-41314.rs:7:9
|
--> $DIR/issue-41314.rs:7:9
|
||||||
|
|
|
|
||||||
LL | X::Y { number } => {}
|
LL | X::Y { number } => {}
|
||||||
| ^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `X::Y(number)`
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use the tuple variant pattern syntax instead
|
||||||
|
|
|
||||||
|
LL | X::Y(number) => {}
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue