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_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::hash::{Hash, Hasher};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::panic;
|
||||
use std::path::Path;
|
||||
use std::{error, fmt};
|
||||
|
@ -359,7 +360,7 @@ pub struct HandlerFlags {
|
|||
pub can_emit_warnings: bool,
|
||||
/// If true, error-level diagnostics are upgraded to bug-level.
|
||||
/// (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.
|
||||
/// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
|
||||
pub dont_buffer_diagnostics: bool,
|
||||
|
@ -396,7 +397,7 @@ impl Handler {
|
|||
pub fn with_tty_emitter(
|
||||
color_config: ColorConfig,
|
||||
can_emit_warnings: bool,
|
||||
treat_err_as_bug: Option<usize>,
|
||||
treat_err_as_bug: Option<NonZeroUsize>,
|
||||
sm: Option<Lrc<SourceMap>>,
|
||||
) -> Self {
|
||||
Self::with_tty_emitter_and_flags(
|
||||
|
@ -424,7 +425,7 @@ impl Handler {
|
|||
|
||||
pub fn with_emitter(
|
||||
can_emit_warnings: bool,
|
||||
treat_err_as_bug: Option<usize>,
|
||||
treat_err_as_bug: Option<NonZeroUsize>,
|
||||
emitter: Box<dyn Emitter + sync::Send>,
|
||||
) -> Self {
|
||||
Handler::with_emitter_and_flags(
|
||||
|
@ -841,7 +842,7 @@ impl HandlerInner {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -950,7 +951,7 @@ impl HandlerInner {
|
|||
// 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.
|
||||
// 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
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
|
@ -1023,7 +1024,7 @@ impl HandlerInner {
|
|||
|
||||
fn panic_if_treat_err_as_bug(&self) {
|
||||
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`"),
|
||||
(0, _) | (1, _) => {}
|
||||
(count, as_bug) => panic!(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// ignore-tidy-filelength
|
||||
use crate::def::{DefKind, Namespace, Res};
|
||||
use crate::def::{CtorKind, DefKind, Namespace, Res};
|
||||
use crate::def_id::DefId;
|
||||
crate use crate::hir_id::HirId;
|
||||
use crate::{itemlikevisit, LangItem};
|
||||
|
@ -1576,6 +1576,63 @@ impl 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.
|
||||
|
|
|
@ -20,6 +20,7 @@ use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}
|
|||
use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::iter::FromIterator;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
type CfgSpecs = FxHashSet<(String, Option<String>)>;
|
||||
|
@ -595,7 +596,7 @@ fn test_debugging_options_tracking_hash() {
|
|||
tracked!(tune_cpu, Some(String::from("abc")));
|
||||
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
|
||||
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!(use_ctors_section, Some(true));
|
||||
tracked!(verify_llvm_ir, true);
|
||||
|
|
|
@ -998,12 +998,11 @@ macro_rules! visit_place_fns {
|
|||
() => {
|
||||
fn visit_projection(
|
||||
&mut self,
|
||||
local: Local,
|
||||
projection: &[PlaceElem<'tcx>],
|
||||
place_ref: PlaceRef<'tcx>,
|
||||
context: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
self.super_projection(local, projection, context, location);
|
||||
self.super_projection(place_ref, context, location);
|
||||
}
|
||||
|
||||
fn visit_projection_elem(
|
||||
|
@ -1033,20 +1032,20 @@ macro_rules! visit_place_fns {
|
|||
|
||||
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(
|
||||
&mut self,
|
||||
local: Local,
|
||||
projection: &[PlaceElem<'tcx>],
|
||||
place_ref: PlaceRef<'tcx>,
|
||||
context: PlaceContext,
|
||||
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 {
|
||||
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
|
||||
// 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) {
|
||||
// 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.
|
||||
match *rvalue {
|
||||
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 {
|
||||
BorrowKind::Shared => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||
|
@ -530,21 +530,21 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
|||
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
}
|
||||
};
|
||||
self.visit_local(&place.local, ctx, location);
|
||||
self.visit_projection(place.local, reborrowed_proj, ctx, location);
|
||||
self.visit_local(&reborrowed_place_ref.local, ctx, location);
|
||||
self.visit_projection(reborrowed_place_ref, ctx, location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
Mutability::Not => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
|
||||
}
|
||||
Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
|
||||
};
|
||||
self.visit_local(&place.local, ctx, location);
|
||||
self.visit_projection(place.local, reborrowed_proj, ctx, location);
|
||||
self.visit_local(&reborrowed_place_ref.local, ctx, location);
|
||||
self.visit_projection(reborrowed_place_ref, ctx, location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1039,7 +1039,7 @@ fn place_as_reborrow(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
) -> Option<&'a [PlaceElem<'tcx>]> {
|
||||
) -> Option<PlaceRef<'tcx>> {
|
||||
match place.as_ref().last_projection() {
|
||||
Some((place_base, ProjectionElem::Deref)) => {
|
||||
// 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
|
||||
} else {
|
||||
// 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
|
||||
// reborrow, even if the check above were to disappear.
|
||||
let inner_ty = place_base.ty(body, tcx).ty;
|
||||
match inner_ty.kind() {
|
||||
ty::Ref(..) => Some(place_base.projection),
|
||||
_ => None,
|
||||
|
||||
if let ty::Ref(..) = inner_ty.kind() {
|
||||
return Some(place_base);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -413,8 +413,7 @@ impl UsedLocals {
|
|||
} else {
|
||||
// A definition. Although, it still might use other locals for indexing.
|
||||
self.super_projection(
|
||||
place.local,
|
||||
&place.projection,
|
||||
place.as_ref(),
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection),
|
||||
location,
|
||||
);
|
||||
|
|
|
@ -950,7 +950,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
Ok(Ident::new(symbol, self.prev_token.span))
|
||||
} 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 is_ref = self.eat_keyword(kw::Ref);
|
||||
let is_mut = self.eat_keyword(kw::Mut);
|
||||
let fieldname = self.parse_ident()?;
|
||||
let fieldname = self.parse_field_name()?;
|
||||
hi = self.prev_token.span;
|
||||
|
||||
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::BTreeMap;
|
||||
use std::hash::Hash;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::PathBuf;
|
||||
|
||||
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!(Option<bool>);
|
||||
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, u64)>);
|
||||
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::hash::Hasher;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::PathBuf;
|
||||
use std::str;
|
||||
|
||||
|
@ -591,10 +592,10 @@ macro_rules! options {
|
|||
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 {
|
||||
Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
|
||||
None => { *slot = Some(1); true }
|
||||
Some(s) => { *slot = s.parse().ok(); slot.is_some() }
|
||||
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)"),
|
||||
trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"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"),
|
||||
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
|
||||
"in diagnostics, use heuristics to shorten paths referring to items"),
|
||||
|
|
|
@ -169,10 +169,14 @@ symbols! {
|
|||
Option,
|
||||
Ord,
|
||||
Ordering,
|
||||
OsStr,
|
||||
OsString,
|
||||
Output,
|
||||
Param,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Path,
|
||||
PathBuf,
|
||||
Pending,
|
||||
Pin,
|
||||
Poll,
|
||||
|
@ -198,6 +202,8 @@ symbols! {
|
|||
StructuralPartialEq,
|
||||
Sync,
|
||||
Target,
|
||||
ToOwned,
|
||||
ToString,
|
||||
Try,
|
||||
Ty,
|
||||
TyCtxt,
|
||||
|
|
|
@ -641,6 +641,7 @@ supported_targets! {
|
|||
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
|
||||
("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl),
|
||||
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
|
||||
("s390x-unknown-linux-musl", s390x_unknown_linux_musl),
|
||||
("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
|
||||
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
|
||||
("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 {
|
||||
err.span_suggestion(
|
||||
callee.span.shrink_to_hi(),
|
||||
"try adding a semicolon",
|
||||
"consider using a semicolon here",
|
||||
";".to_owned(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
|
@ -1450,7 +1450,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
) {
|
||||
if cond_expr.span.desugaring_kind().is_none() {
|
||||
err.span_label(cond_expr.span, "expected this to be `()`");
|
||||
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
|
||||
if expr.can_have_side_effects() {
|
||||
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))
|
||||
|
@ -1458,7 +1460,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
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() {
|
||||
pointing_at_return_type |= fcx.suggest_missing_return_type(
|
||||
&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
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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) => {
|
||||
// Check with expected type of `()`.
|
||||
self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
|
||||
self.suggest_semicolon_at_end(expr.span, err);
|
||||
if expr.can_have_side_effects() {
|
||||
self.suggest_semicolon_at_end(expr.span, err);
|
||||
}
|
||||
});
|
||||
}
|
||||
hir::StmtKind::Semi(ref expr) => {
|
||||
|
|
|
@ -44,11 +44,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
blk_id: hir::HirId,
|
||||
) -> bool {
|
||||
let expr = expr.peel_drop_temps();
|
||||
self.suggest_missing_semicolon(err, expr, expected, cause_span);
|
||||
if expr.can_have_side_effects() {
|
||||
self.suggest_missing_semicolon(err, expr, expected, cause_span);
|
||||
}
|
||||
let mut pointing_at_return_type = false;
|
||||
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
||||
pointing_at_return_type =
|
||||
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
|
||||
}
|
||||
|
@ -392,10 +395,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| ExprKind::Loop(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::Block(..) => {
|
||||
| ExprKind::Block(..)
|
||||
if expression.can_have_side_effects() =>
|
||||
{
|
||||
err.span_suggestion(
|
||||
cause_span.shrink_to_hi(),
|
||||
"try adding a semicolon",
|
||||
"consider using a semicolon here",
|
||||
";".to_string(),
|
||||
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(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
|
|
|
@ -17,6 +17,7 @@ use rustc_span::source_map::{Span, Spanned};
|
|||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{BytePos, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::{ObligationCause, Pattern};
|
||||
use ty::VariantDef;
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
|
@ -1264,14 +1265,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
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();
|
||||
}
|
||||
(None, None) => {}
|
||||
(None, None) => {
|
||||
if let Some(mut err) =
|
||||
self.error_tuple_variant_index_shorthand(variant, pat, fields)
|
||||
{
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
let sess = self.tcx.sess;
|
||||
let sm = sess.source_map();
|
||||
|
@ -1411,16 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
let (sugg, appl) = if fields.len() == variant.fields.len() {
|
||||
(
|
||||
fields
|
||||
.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(", "),
|
||||
self.get_suggested_tuple_struct_pattern(fields, variant),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
} else {
|
||||
|
@ -1429,10 +1471,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
};
|
||||
err.span_suggestion(
|
||||
pat.span,
|
||||
err.span_suggestion_verbose(
|
||||
qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
|
||||
"use the tuple variant pattern syntax instead",
|
||||
format!("{}({})", path, sugg),
|
||||
format!("({})", sugg),
|
||||
appl,
|
||||
);
|
||||
return Some(err);
|
||||
|
@ -1440,6 +1482,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
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
|
||||
/// inaccessible fields.
|
||||
///
|
||||
|
|
|
@ -31,6 +31,7 @@ where
|
|||
/// implementing the `Clone` trait. But `Clone` works only for going from `&T`
|
||||
/// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data
|
||||
/// from any borrow of a given type.
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait ToOwned {
|
||||
/// The resulting type after obtaining ownership.
|
||||
|
|
|
@ -1063,7 +1063,7 @@ impl<T> VecDeque<T> {
|
|||
where
|
||||
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 head = self.wrap_add(self.tail, end);
|
||||
(tail, head)
|
||||
|
|
|
@ -115,7 +115,6 @@
|
|||
#![feature(or_patterns)]
|
||||
#![feature(pattern)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(range_bounds_assert_len)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(receiver_trait)]
|
||||
#![cfg_attr(bootstrap, feature(min_const_generics))]
|
||||
|
@ -123,6 +122,7 @@
|
|||
#![feature(set_ptr_value)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(slice_ptr_len)]
|
||||
#![feature(slice_range)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(trusted_len)]
|
||||
|
|
|
@ -92,6 +92,8 @@ use crate::borrow::ToOwned;
|
|||
use crate::boxed::Box;
|
||||
use crate::vec::Vec;
|
||||
|
||||
#[unstable(feature = "slice_range", issue = "76393")]
|
||||
pub use core::slice::range;
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
pub use core::slice::ArrayChunks;
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
|
@ -220,6 +222,7 @@ mod hack {
|
|||
}
|
||||
|
||||
#[lang = "slice_alloc"]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "slice")]
|
||||
#[cfg(not(test))]
|
||||
impl<T> [T] {
|
||||
/// Sorts the slice.
|
||||
|
|
|
@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator};
|
|||
use core::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
use core::str::{lossy, pattern::Pattern};
|
||||
|
||||
use crate::borrow::{Cow, ToOwned};
|
||||
|
@ -1510,14 +1511,14 @@ impl String {
|
|||
// of the vector version. The data is just plain bytes.
|
||||
// Because the range removal happens in Drop, if the Drain iterator is leaked,
|
||||
// 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(end));
|
||||
|
||||
// Take out two simultaneous borrows. The &mut String won't be accessed
|
||||
// until iteration is over, in Drop.
|
||||
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();
|
||||
|
||||
Drain { start, end, iter: chars_iter, string: self_ptr }
|
||||
|
@ -2174,6 +2175,7 @@ impl FromStr for String {
|
|||
/// implementation for free.
|
||||
///
|
||||
/// [`Display`]: fmt::Display
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait ToString {
|
||||
/// 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.
|
||||
//
|
||||
let len = self.len();
|
||||
let Range { start, end } = range.assert_len(len);
|
||||
let Range { start, end } = slice::range(range, ..len);
|
||||
|
||||
unsafe {
|
||||
// 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
|
||||
R: RangeBounds<usize>,
|
||||
{
|
||||
let range = src.assert_len(self.len());
|
||||
let range = slice::range(src, ..self.len());
|
||||
self.reserve(range.len());
|
||||
|
||||
// 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 {
|
||||
self.spec_extend_from_within(range);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ macro_rules! benches {
|
|||
use test::black_box;
|
||||
use test::Bencher;
|
||||
|
||||
const ASCII_CASE_MASK: u8 = 0b0010_0000;
|
||||
|
||||
benches! {
|
||||
fn case00_alloc_only(_bytes: &mut [u8]) {}
|
||||
|
||||
|
@ -204,7 +206,7 @@ benches! {
|
|||
}
|
||||
}
|
||||
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 {
|
||||
*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()
|
||||
})
|
||||
}
|
||||
|
||||
#[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")]
|
||||
#[inline]
|
||||
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.
|
||||
|
@ -1116,7 +1120,11 @@ impl char {
|
|||
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
|
||||
#[inline]
|
||||
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.
|
||||
|
|
|
@ -152,6 +152,9 @@ impl isize {
|
|||
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"]
|
||||
impl u8 {
|
||||
uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
|
||||
|
@ -195,7 +198,7 @@ impl u8 {
|
|||
#[inline]
|
||||
pub fn to_ascii_uppercase(&self) -> u8 {
|
||||
// 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.
|
||||
|
@ -218,7 +221,13 @@ impl u8 {
|
|||
#[inline]
|
||||
pub fn to_ascii_lowercase(&self) -> u8 {
|
||||
// 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.
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
use crate::fmt;
|
||||
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 (`..`).
|
||||
///
|
||||
|
@ -764,92 +760,6 @@ pub trait RangeBounds<T: ?Sized> {
|
|||
#[stable(feature = "collections_range", since = "1.28.0")]
|
||||
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.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
@ -37,28 +37,28 @@ fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
|
|||
#[inline(never)]
|
||||
#[cold]
|
||||
#[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);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
#[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);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
#[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");
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
#[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");
|
||||
}
|
||||
|
||||
|
@ -449,3 +449,100 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
|
|||
(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::result::Result;
|
||||
use crate::result::Result::{Err, Ok};
|
||||
use crate::slice;
|
||||
|
||||
#[unstable(
|
||||
feature = "slice_internals",
|
||||
|
@ -29,7 +30,7 @@ pub mod memchr;
|
|||
|
||||
mod ascii;
|
||||
mod cmp;
|
||||
pub(crate) mod index;
|
||||
mod index;
|
||||
mod iter;
|
||||
mod raw;
|
||||
mod rotate;
|
||||
|
@ -76,6 +77,9 @@ pub use sort::heapsort;
|
|||
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
||||
pub use index::SliceIndex;
|
||||
|
||||
#[unstable(feature = "slice_range", issue = "76393")]
|
||||
pub use index::range;
|
||||
|
||||
#[lang = "slice"]
|
||||
#[cfg(not(test))]
|
||||
impl<T> [T] {
|
||||
|
@ -3075,7 +3079,7 @@ impl<T> [T] {
|
|||
where
|
||||
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;
|
||||
assert!(dest <= self.len() - count, "dest is out of bounds");
|
||||
// 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
|
||||
/// [conversions]: super#conversions
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "OsString")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct OsString {
|
||||
inner: Buf,
|
||||
|
@ -93,6 +94,7 @@ impl crate::sealed::Sealed for OsString {}
|
|||
///
|
||||
/// [`&str`]: str
|
||||
/// [conversions]: super#conversions
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// FIXME:
|
||||
// `OsStr::from_inner` current implementation relies
|
||||
|
|
|
@ -3,40 +3,40 @@
|
|||
#![stable(feature = "os", since = "1.0.0")]
|
||||
#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(doc)] {
|
||||
// When documenting libstd we want to show unix/windows/linux modules as these are the "main
|
||||
// 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
|
||||
// documentation.
|
||||
// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make
|
||||
// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038
|
||||
|
||||
// When documenting libstd we want to show unix/windows/linux modules as
|
||||
// these are the "main modules" that are used across platforms. This
|
||||
// should help show platform-specific functionality in a hopefully
|
||||
// cross-platform way in the documentation
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::unix_ext as unix;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::unix_ext as unix;
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::windows_ext as windows;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::windows_ext as windows;
|
||||
#[cfg(doc)]
|
||||
#[doc(cfg(target_os = "linux"))]
|
||||
pub mod linux;
|
||||
|
||||
#[doc(cfg(target_os = "linux"))]
|
||||
pub mod linux;
|
||||
} else {
|
||||
// If we're not documenting libstd then we just expose the main modules as we otherwise would.
|
||||
|
||||
// If we're not documenting libstd then we just expose the main modules
|
||||
// as we otherwise would.
|
||||
#[cfg(not(doc))]
|
||||
#[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::ext as unix;
|
||||
|
||||
#[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::ext as unix;
|
||||
#[cfg(not(doc))]
|
||||
#[cfg(windows)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::ext as windows;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::ext as windows;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "l4re"))]
|
||||
pub mod linux;
|
||||
|
||||
}
|
||||
}
|
||||
#[cfg(not(doc))]
|
||||
#[cfg(any(target_os = "linux", target_os = "l4re"))]
|
||||
pub mod linux;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub mod android;
|
||||
|
|
|
@ -1066,6 +1066,7 @@ impl FusedIterator for Ancestors<'_> {}
|
|||
///
|
||||
/// Which method works best depends on what kind of situation you're in.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// FIXME:
|
||||
// `PathBuf::as_mut_vec` current implementation relies
|
||||
|
@ -1719,6 +1720,7 @@ impl AsRef<OsStr> for PathBuf {
|
|||
/// let extension = path.extension();
|
||||
/// assert_eq!(extension, Some(OsStr::new("txt")));
|
||||
/// ```
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Path")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// FIXME:
|
||||
// `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<()> {
|
||||
let (original, original_file) = open_parent(original)?;
|
||||
let (link, link_file) = open_parent(link)?;
|
||||
original.link(
|
||||
wasi::LOOKUPFLAGS_SYMLINK_FOLLOW,
|
||||
osstr2str(original_file.as_ref())?,
|
||||
&link,
|
||||
osstr2str(link_file.as_ref())?,
|
||||
)
|
||||
// Pass 0 as the flags argument, meaning don't follow symlinks.
|
||||
original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?)
|
||||
}
|
||||
|
||||
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)
|
||||
`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)
|
||||
`s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL)
|
||||
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
|
||||
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
|
||||
`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
|
||||
[`std::env::args()`][env::args] function:
|
||||
|
||||
``````text
|
||||
``````markdown
|
||||
Returns the arguments which this program was started with (normally passed
|
||||
via the command line).
|
||||
|
||||
|
@ -135,7 +135,7 @@ for argument in env::args() {
|
|||
|
||||
Everything before the first empty line will be reused to describe the component
|
||||
in searches and module overviews. For example, the function `std::env::args()`
|
||||
above will be shown on the [`std::env`] module documentation. It is good
|
||||
above will be shown on the [`std::env`] module documentation. It is good
|
||||
practice to keep the summary to one line: concise writing is a goal of good
|
||||
documentation.
|
||||
|
||||
|
@ -153,9 +153,10 @@ and finally provides a code example.
|
|||
|
||||
## Markdown
|
||||
|
||||
`rustdoc` uses the [CommonMark markdown specification]. You might be
|
||||
interested into taking a look at their website to see what's possible to do.
|
||||
- [commonmark quick reference]
|
||||
`rustdoc` uses the [CommonMark Markdown specification]. You might be
|
||||
interested in taking a look at their website to see what's possible:
|
||||
|
||||
- [CommonMark quick reference]
|
||||
- [current spec]
|
||||
|
||||
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.
|
||||
|
||||
### 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/
|
||||
[commonmark markdown specification]: https://commonmark.org/
|
||||
[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_STRIKETHROUGH
|
||||
| Options::ENABLE_TASKLISTS
|
||||
| Options::ENABLE_SMART_PUNCTUATION
|
||||
}
|
||||
|
||||
/// A subset of [`opts()`] used for rendering summaries.
|
||||
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
|
||||
|
|
|
@ -201,8 +201,8 @@ fn test_short_markdown_summary() {
|
|||
t("Hard-break \nsummary", "Hard-break summary");
|
||||
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("code `let x = i32;` ...", "code <code>let x = i32;</code> ...");
|
||||
t("type `Type<'static>` ...", "type <code>Type<'static></code> ...");
|
||||
t("code `let x = i32;` ...", "code <code>let x = i32;</code> …");
|
||||
t("type `Type<'static>` ...", "type <code>Type<'static></code> …");
|
||||
t("# top header", "top header");
|
||||
t("## header", "header");
|
||||
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("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
|
||||
t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
|
||||
t("code `let x = i32;` ...", "code `let x = i32;` ...");
|
||||
t("type `Type<'static>` ...", "type `Type<'static>` ...");
|
||||
t("code `let x = i32;` ...", "code `let x = i32;` …");
|
||||
t("type `Type<'static>` ...", "type `Type<'static>` …");
|
||||
t("# top header", "top header");
|
||||
t("# top header\n\nfollowed by some text", "top 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>Struct<'a, T></p>\n");
|
||||
t("Struct<'a, T>", "<p>Struct<’a, T></p>\n");
|
||||
t("Struct<br>", "<p>Struct<br></p>\n");
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ function focusSearchBar() {
|
|||
getSearchInput().focus();
|
||||
}
|
||||
|
||||
// Removes the focus from the search bar
|
||||
// Removes the focus from the search bar.
|
||||
function defocusSearchBar() {
|
||||
getSearchInput().blur();
|
||||
}
|
||||
|
@ -220,6 +220,11 @@ function defocusSearchBar() {
|
|||
addClass(search, "hidden");
|
||||
removeClass(main, "hidden");
|
||||
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
|
||||
|
|
|
@ -4,6 +4,6 @@ extern crate inner;
|
|||
|
||||
|
||||
// @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',
|
||||
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() {
|
||||
dummy()
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP try adding a semicolon
|
||||
//~| HELP consider using a semicolon here
|
||||
//~| HELP consider `await`ing on the `Future`
|
||||
//~| SUGGESTION .await
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ help: consider `await`ing on the `Future`
|
|||
|
|
||||
LL | dummy().await
|
||||
| ^^^^^^
|
||||
help: try adding a semicolon
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | dummy();
|
||||
| ^
|
||||
|
|
|
@ -14,9 +14,7 @@ LL | | true
|
|||
| | ^^^^ expected `()`, found `bool`
|
||||
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
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ error[E0308]: mismatched types
|
|||
LL | foo()
|
||||
| ^^^^^ expected `()`, found `usize`
|
||||
|
|
||||
help: try adding a semicolon
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | foo();
|
||||
| ^
|
||||
|
|
|
@ -2,7 +2,12 @@ error[E0769]: tuple variant `MyOption::MySome` written as struct variant
|
|||
--> $DIR/issue-17800.rs:8:9
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -3,6 +3,11 @@ error[E0308]: mismatched types
|
|||
|
|
||||
LL | { true }
|
||||
| ^^^^ expected `()`, found `bool`
|
||||
|
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | { return true; }
|
||||
| ^^^^^^ ^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -2,19 +2,29 @@ error[E0308]: mismatched types
|
|||
--> $DIR/expr-as-stmt-2.rs:3:26
|
||||
|
|
||||
LL | if let Some(x) = a { true } else { false }
|
||||
| ---------------------^^^^------------------ help: consider using a semicolon here
|
||||
| ---------------------^^^^-----------------
|
||||
| | |
|
||||
| | expected `()`, found `bool`
|
||||
| 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
|
||||
--> $DIR/expr-as-stmt-2.rs:3:40
|
||||
|
|
||||
LL | if let Some(x) = a { true } else { false }
|
||||
| -----------------------------------^^^^^--- help: consider using a semicolon here
|
||||
| -----------------------------------^^^^^--
|
||||
| | |
|
||||
| | expected `()`, found `bool`
|
||||
| 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
|
||||
--> $DIR/expr-as-stmt-2.rs:6:5
|
||||
|
|
|
@ -40,24 +40,44 @@ error[E0308]: mismatched types
|
|||
|
|
||||
LL | {2} + {2}
|
||||
| ^ expected `()`, found integer
|
||||
|
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | {return 2;} + {2}
|
||||
| ^^^^^^ ^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/expr-as-stmt.rs:12:6
|
||||
|
|
||||
LL | {2} + 2
|
||||
| ^ expected `()`, found integer
|
||||
|
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | {return 2;} + 2
|
||||
| ^^^^^^ ^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/expr-as-stmt.rs:18:7
|
||||
|
|
||||
LL | { 42 } + foo;
|
||||
| ^^ expected `()`, found integer
|
||||
|
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | { return 42; } + foo;
|
||||
| ^^^^^^ ^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/expr-as-stmt.rs:24:7
|
||||
|
|
||||
LL | { 3 } * 3
|
||||
| ^ expected `()`, found integer
|
||||
|
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | { return 3; } * 3
|
||||
| ^^^^^^ ^
|
||||
|
||||
error[E0614]: type `{integer}` cannot be dereferenced
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/struct-literal-variant-in-if.rs:10:20
|
||||
|
|
||||
LL | if x == E::V { field } {}
|
||||
| ---------------^^^^^--- help: consider using a semicolon here
|
||||
| ---------------^^^^^--
|
||||
| | |
|
||||
| | expected `()`, found `bool`
|
||||
| expected this to be `()`
|
||||
|
|
|
@ -5,7 +5,7 @@ LL | fn main() {
|
|||
| - expected `()` because of default return type
|
||||
LL | // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE.
|
||||
LL | std::cell::Cell::new(0)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
|
||||
| |
|
||||
| expected `()`, found struct `Cell`
|
||||
|
|
||||
|
|
|
@ -6,7 +6,7 @@ LL | foo(4 as usize)
|
|||
|
|
||||
= note: expected unit type `()`
|
||||
found struct `S<usize>`
|
||||
help: try adding a semicolon
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
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
|
||||
...
|
||||
LL | generic::<()>()
|
||||
| ^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
|
||||
| ^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
|
||||
| |
|
||||
| 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`
|
||||
...
|
||||
LL | vindictive()
|
||||
| -^^^^^^^^^^^- help: try adding a semicolon: `;`
|
||||
| -^^^^^^^^^^^- help: consider using a semicolon here: `;`
|
||||
| _____|
|
||||
| |
|
||||
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
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
match 3 {
|
||||
4 => 1,
|
||||
3 => {
|
||||
2 //~ ERROR mismatched types
|
||||
foo() //~ ERROR mismatched types
|
||||
}
|
||||
_ => 2
|
||||
}
|
||||
|
@ -16,3 +15,7 @@ fn main() {
|
|||
}
|
||||
let _ = ();
|
||||
}
|
||||
|
||||
fn foo() -> i32 {
|
||||
42
|
||||
}
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/match-needing-semi.rs:8:13
|
||||
--> $DIR/match-needing-semi.rs:7:13
|
||||
|
|
||||
LL | / match 3 {
|
||||
LL | | 4 => 1,
|
||||
LL | | 3 => {
|
||||
LL | | 2
|
||||
| | ^ expected `()`, found integer
|
||||
LL | | foo()
|
||||
| | ^^^^^ expected `()`, found `i32`
|
||||
LL | | }
|
||||
LL | | _ => 2
|
||||
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
|
||||
--> $DIR/match-needing-semi.rs:12:5
|
||||
--> $DIR/match-needing-semi.rs:11:5
|
||||
|
|
||||
LL | / match 3 {
|
||||
LL | | 4 => 1,
|
||||
|
|
|
@ -2,7 +2,12 @@ error[E0769]: tuple variant `X::Y` written as struct variant
|
|||
--> $DIR/issue-41314.rs:7:9
|
||||
|
|
||||
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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue