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_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::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!(

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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 {
err.span_suggestion(
callee.span.shrink_to_hi(),
"try adding a semicolon",
"consider using a semicolon here",
";".to_owned(),
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() {
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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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.
//
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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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
[`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/

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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
...
LL | generic::<()>()
| ^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
| ^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
| |
| 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`
...
LL | vindictive()
| -^^^^^^^^^^^- help: try adding a semicolon: `;`
| -^^^^^^^^^^^- help: consider using a semicolon here: `;`
| _____|
| |
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
// 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
}

View file

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

View file

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