1
Fork 0

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:
bors 2021-02-23 04:31:32 +00:00
commit a4e595db8f
68 changed files with 680 additions and 268 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

@ -1450,7 +1450,9 @@ 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 `()`");
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)) 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) 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);
} }

View file

@ -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| {
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) => { hir::StmtKind::Semi(ref expr) => {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,40 +3,40 @@
#![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
// 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 #[cfg(doc)]
// these are the "main modules" that are used across platforms. This #[stable(feature = "rust1", since = "1.0.0")]
// should help show platform-specific functionality in a hopefully pub use crate::sys::unix_ext as unix;
// cross-platform way in the documentation
#[stable(feature = "rust1", since = "1.0.0")] #[cfg(doc)]
pub use crate::sys::unix_ext as unix; #[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::windows_ext as windows;
#[stable(feature = "rust1", since = "1.0.0")] #[cfg(doc)]
pub use crate::sys::windows_ext as windows; #[doc(cfg(target_os = "linux"))]
pub mod linux;
#[doc(cfg(target_os = "linux"))] // If we're not documenting libstd then we just expose the main modules as we otherwise would.
pub mod linux;
} else {
// If we're not documenting libstd then we just expose the main modules #[cfg(not(doc))]
// as we otherwise would. #[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"))] #[cfg(not(doc))]
#[stable(feature = "rust1", since = "1.0.0")] #[cfg(windows)]
pub use crate::sys::ext as unix; #[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::ext as windows;
#[cfg(windows)] #[cfg(not(doc))]
#[stable(feature = "rust1", since = "1.0.0")] #[cfg(any(target_os = "linux", target_os = "l4re"))]
pub use crate::sys::ext as windows; pub mod linux;
#[cfg(any(target_os = "linux", target_os = "l4re"))]
pub mod linux;
}
}
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
pub mod android; pub mod android;

View file

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

View file

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

View file

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

View file

@ -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).
@ -135,7 +135,7 @@ for argument in env::args() {
Everything before the first empty line will be reused to describe the component 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()` 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 practice to keep the summary to one line: concise writing is a goal of good
documentation. documentation.
@ -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/

View file

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

View file

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

View file

@ -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&lt;'a, T&gt;</code></p>\n"); t("`Struct<'a, T>`", "<p><code>Struct&lt;'a, T&gt;</code></p>\n");
t("Struct<'a, T>", "<p>Struct&lt;'a, T&gt;</p>\n"); t("Struct<'a, T>", "<p>Struct&lt;a, T&gt;</p>\n");
t("Struct<br>", "<p>Struct&lt;br&gt;</p>\n"); t("Struct<br>", "<p>Struct&lt;br&gt;</p>\n");
} }

View file

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

View file

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

View 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! Howd you know that “its” 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!\""

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View 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]
}
}

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

View file

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

View file

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

View file

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

View file

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

View file

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