diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index fd0ff5b66e607..289629d921545 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -199,7 +199,7 @@ impl> 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); } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 61586dd1a1c45..2fef7c2cc087d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 023555d91cc92..9530efaedbce4 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -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); } } diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs index 85aaff5ab7293..2d20f0d9547c1 100644 --- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs @@ -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. diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 4973450ca8374..a82636837122f 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -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> { 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; } } } diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index 11539d3ef30f4..ae4f15b3bbc4d 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -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, ); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 1292286bc18b0..8a097bf481dc2 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -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) } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8874548da784d..9e2e7359ca96e 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -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) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 653d70b6cf244..4ed0262bf2cfe 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -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, diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 4836418b3c210..f2fbb95fc021c 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -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, ); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index b2395b7bb2502..792836f666555 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -42,6 +42,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, }; @@ -1448,9 +1449,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expected.is_unit(), pointing_at_return_type, ) { - if cond_expr.span.desugaring_kind().is_none() { + // If the block is from an external macro, then do not suggest + // adding a semicolon, because there's nowhere to put it. + // See issue #81943. + if cond_expr.span.desugaring_kind().is_none() + && !in_external_macro(fcx.tcx.sess, cond_expr.span) + { 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 +1466,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 +1480,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); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 3326be796cee3..155c10e891652 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -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) => { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index a0465ca6aef07..416b75d9e2e0c 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -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<'_>, diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 5df00ea1d75af..897b1f01569f4 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -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> { + // 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::>() - .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::>(); + 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::>() + .join(", ") + } + /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to /// inaccessible fields. /// diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index adf996fc78275..bdb2d67347e43 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -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. diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index eb8994681937a..f7cefdce27856 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - 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) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 99c42a4ba4423..c020a969f1fb9 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -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)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index cb015b949305c..9924f60ff77e9 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -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] { /// Sorts the slice. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3218b3535c970..6fb3fcbb63be2 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -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`. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b6166617789a0..dbb7708b60057 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1651,7 +1651,7 @@ impl Vec { // 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 Vec { where R: RangeBounds, { - 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); } diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs index bc59c378609f0..64938745a4a16 100644 --- a/library/core/benches/ascii.rs +++ b/library/core/benches/ascii.rs @@ -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 } } diff --git a/library/core/benches/char/methods.rs b/library/core/benches/char/methods.rs index a9a08a4d76200..de4b63030fa7c 100644 --- a/library/core/benches/char/methods.rs +++ b/library/core/benches/char/methods.rs @@ -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()) +} diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 64ae7db0d9b53..4390342134d1d 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -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. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 6bdfa18fa434c..c13f000a73615 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -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. diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 0571dc74b9af9..dbeb391213006 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -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 { #[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 - where - Self: RangeBounds, - { - 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 diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 660c8a2da5da0..d20986bb724fc 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -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 SliceIndex<[T]> for ops::RangeToInclusive { (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(range: R, bounds: ops::RangeTo) -> ops::Range +where + R: ops::RangeBounds, +{ + 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 } +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1c1b9e0b27e25..80c2631c24566 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -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] { @@ -3075,7 +3079,7 @@ impl [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, diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 5bb3f6bdcfd7b..272eccda89471 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -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 diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index fd6ee088e961c..f61e402e37027 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -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; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 581c09e23dfa6..de3b57df44e1e 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -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 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 diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 4134ef676719c..83debdfc86043 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -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 { diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md index 9938cddc94106..688be7aedea38 100644 --- a/src/doc/rustdoc/src/how-to-write-documentation.md +++ b/src/doc/rustdoc/src/how-to-write-documentation.md @@ -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/ diff --git a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md deleted file mode 100644 index 0e95d5ded9296..0000000000000 --- a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md +++ /dev/null @@ -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 diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b7854bbf82b17..cb11f22d0d859 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -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 diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 994fe8206e8d4..6b2cfe685752d 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -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 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("## 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>`", "

Struct<'a, T>

\n"); - t("Struct<'a, T>", "

Struct<'a, T>

\n"); + t("Struct<'a, T>", "

Struct<’a, T>

\n"); t("Struct
", "

Struct<br>

\n"); } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index d6d3171afbffe..6da3b54289b2a 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -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 diff --git a/src/test/rustdoc/inline_cross/add-docs.rs b/src/test/rustdoc/inline_cross/add-docs.rs index 1af5e8f03b44e..8f0c4e5e64184 100644 --- a/src/test/rustdoc/inline_cross/add-docs.rs +++ b/src/test/rustdoc/inline_cross/add-docs.rs @@ -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; diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs new file mode 100644 index 0000000000000..a1ca2699554e5 --- /dev/null +++ b/src/test/rustdoc/smart-punct.rs @@ -0,0 +1,30 @@ +// ignore-tidy-linelength + +#![crate_name = "foo"] + +//! This is the "start" of the 'document'! How'd you know that "it's" the start? +//! +//! # Header with "smart punct'" +//! +//! [link with "smart punct'" -- yessiree!][] +//! +//! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org +//! +//! # Code should not be smart-punct'd +//! +//! `this inline code -- it shouldn't have "smart punct"` +//! +//! ``` +//! let x = "don't smart-punct me -- please!"; +//! ``` +//! +//! ```text +//! I say "don't smart-punct me -- please!" +//! ``` + +// @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" +// @has "foo/index.html" "//h1" "Header with “smart punct’”" +// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" +// @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\"" +// @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";" +// @has "foo/index.html" '//pre' "I say \"don't smart-punct me -- please!\"" diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs index d629054911dac..352a88ac10cd5 100644 --- a/src/test/ui/async-await/suggest-missing-await.rs +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -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 } diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 46615dae7e2ba..26e81a52c2141 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -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(); | ^ diff --git a/src/test/ui/block-result/block-must-not-have-result-while.stderr b/src/test/ui/block-result/block-must-not-have-result-while.stderr index d4845290d8a90..7f96aa289d0ab 100644 --- a/src/test/ui/block-result/block-must-not-have-result-while.stderr +++ b/src/test/ui/block-result/block-must-not-have-result-while.stderr @@ -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 diff --git a/src/test/ui/block-result/unexpected-return-on-unit.stderr b/src/test/ui/block-result/unexpected-return-on-unit.stderr index 3dce459ddbdae..4fcd0ee2c48e2 100644 --- a/src/test/ui/block-result/unexpected-return-on-unit.stderr +++ b/src/test/ui/block-result/unexpected-return-on-unit.stderr @@ -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(); | ^ diff --git a/src/test/ui/issues/issue-17800.stderr b/src/test/ui/issues/issue-17800.stderr index fc034a0cbf3b8..7df86d7326bc6 100644 --- a/src/test/ui/issues/issue-17800.stderr +++ b/src/test/ui/issues/issue-17800.stderr @@ -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 diff --git a/src/test/ui/macros/empty-trailing-stmt.stderr b/src/test/ui/macros/empty-trailing-stmt.stderr index e88b12712fb8c..1db759a2181d5 100644 --- a/src/test/ui/macros/empty-trailing-stmt.stderr +++ b/src/test/ui/macros/empty-trailing-stmt.stderr @@ -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 diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr index 6583524aad18f..a95b5bb94d24a 100644 --- a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr +++ b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr @@ -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 diff --git a/src/test/ui/parser/expr-as-stmt-2.stderr b/src/test/ui/parser/expr-as-stmt-2.stderr index ee07c36763356..2a70127485785 100644 --- a/src/test/ui/parser/expr-as-stmt-2.stderr +++ b/src/test/ui/parser/expr-as-stmt-2.stderr @@ -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 diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr index 324aed0ad7cf6..09a6d7cbeb176 100644 --- a/src/test/ui/parser/expr-as-stmt.stderr +++ b/src/test/ui/parser/expr-as-stmt.stderr @@ -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 diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr index 89232a519d7b2..9b9d2bc4972b4 100644 --- a/src/test/ui/parser/recover-from-bad-variant.stderr +++ b/src/test/ui/parser/recover-from-bad-variant.stderr @@ -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 diff --git a/src/test/ui/parser/struct-literal-variant-in-if.stderr b/src/test/ui/parser/struct-literal-variant-in-if.stderr index a2252d4e4d282..3ea5ca565c5e5 100644 --- a/src/test/ui/parser/struct-literal-variant-in-if.stderr +++ b/src/test/ui/parser/struct-literal-variant-in-if.stderr @@ -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 `()` diff --git a/src/test/ui/proc-macro/issue-37788.stderr b/src/test/ui/proc-macro/issue-37788.stderr index 0538701290297..345520d4852ae 100644 --- a/src/test/ui/proc-macro/issue-37788.stderr +++ b/src/test/ui/proc-macro/issue-37788.stderr @@ -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` | diff --git a/src/test/ui/return/return-type.stderr b/src/test/ui/return/return-type.stderr index 535428f1c91f7..6ef921bef3d7a 100644 --- a/src/test/ui/return/return-type.stderr +++ b/src/test/ui/return/return-type.stderr @@ -6,7 +6,7 @@ LL | foo(4 as usize) | = note: expected unit type `()` found struct `S` -help: try adding a semicolon +help: consider using a semicolon here | LL | foo(4 as usize); | ^ diff --git a/src/test/ui/return/tail-expr-as-potential-return.rs b/src/test/ui/return/tail-expr-as-potential-return.rs new file mode 100644 index 0000000000000..83266abfa06e6 --- /dev/null +++ b/src/test/ui/return/tail-expr-as-potential-return.rs @@ -0,0 +1,10 @@ +fn main() { + let _ = foo(true); +} + +fn foo(x: bool) -> Result { + if x { + Err(42) //~ ERROR mismatched types + } + Ok(42.0) +} diff --git a/src/test/ui/return/tail-expr-as-potential-return.stderr b/src/test/ui/return/tail-expr-as-potential-return.stderr new file mode 100644 index 0000000000000..f8527961374dd --- /dev/null +++ b/src/test/ui/return/tail-expr-as-potential-return.stderr @@ -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`. diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr index 445bc1646f04e..7a2b75a1c1f0a 100644 --- a/src/test/ui/specialization/specialization-default-projection.stderr +++ b/src/test/ui/specialization/specialization-default-projection.stderr @@ -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 | diff --git a/src/test/ui/structs/struct-tuple-field-names.rs b/src/test/ui/structs/struct-tuple-field-names.rs new file mode 100644 index 0000000000000..7bd54af1dbee5 --- /dev/null +++ b/src/test/ui/structs/struct-tuple-field-names.rs @@ -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] + } +} diff --git a/src/test/ui/structs/struct-tuple-field-names.stderr b/src/test/ui/structs/struct-tuple-field-names.stderr new file mode 100644 index 0000000000000..29e721465215d --- /dev/null +++ b/src/test/ui/structs/struct-tuple-field-names.stderr @@ -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`. diff --git a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr index 6e4cee18c1603..438075083d370 100644 --- a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr +++ b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr @@ -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) diff --git a/src/test/ui/suggestions/match-needing-semi.fixed b/src/test/ui/suggestions/match-needing-semi.fixed deleted file mode 100644 index 03cbed1376ea3..0000000000000 --- a/src/test/ui/suggestions/match-needing-semi.fixed +++ /dev/null @@ -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 _ = (); -} diff --git a/src/test/ui/suggestions/match-needing-semi.rs b/src/test/ui/suggestions/match-needing-semi.rs index f34071ac75886..833555d0e406e 100644 --- a/src/test/ui/suggestions/match-needing-semi.rs +++ b/src/test/ui/suggestions/match-needing-semi.rs @@ -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 +} diff --git a/src/test/ui/suggestions/match-needing-semi.stderr b/src/test/ui/suggestions/match-needing-semi.stderr index 28abd089525df..3739c9940f0cc 100644 --- a/src/test/ui/suggestions/match-needing-semi.stderr +++ b/src/test/ui/suggestions/match-needing-semi.stderr @@ -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, diff --git a/src/test/ui/type/type-check/issue-41314.stderr b/src/test/ui/type/type-check/issue-41314.stderr index bd4d2071c2059..c3d41ae68cd6a 100644 --- a/src/test/ui/type/type-check/issue-41314.stderr +++ b/src/test/ui/type/type-check/issue-41314.stderr @@ -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 diff --git a/src/test/ui/typeck/issue-81943.rs b/src/test/ui/typeck/issue-81943.rs new file mode 100644 index 0000000000000..61eb46d232ae8 --- /dev/null +++ b/src/test/ui/typeck/issue-81943.rs @@ -0,0 +1,9 @@ +fn f(f: F) { f(0); } +fn main() { + f(|x| dbg!(x)); //~ERROR + f(|x| match x { tmp => { tmp } }); //~ERROR + macro_rules! d { + ($e:expr) => { match $e { x => { x } } } //~ERROR + } + f(|x| d!(x)); +} diff --git a/src/test/ui/typeck/issue-81943.stderr b/src/test/ui/typeck/issue-81943.stderr new file mode 100644 index 0000000000000..ab2f4da4ec8eb --- /dev/null +++ b/src/test/ui/typeck/issue-81943.stderr @@ -0,0 +1,34 @@ +error[E0308]: mismatched types + --> $DIR/issue-81943.rs:3:9 + | +LL | f(|x| dbg!(x)); + | ^^^^^^^ expected `()`, found `i32` + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/issue-81943.rs:4:28 + | +LL | f(|x| match x { tmp => { tmp } }); + | -------------------^^^----- help: consider using a semicolon here + | | | + | | expected `()`, found `i32` + | expected this to be `()` + +error[E0308]: mismatched types + --> $DIR/issue-81943.rs:6:38 + | +LL | ($e:expr) => { match $e { x => { x } } } + | ------------------^----- help: consider using a semicolon here + | | | + | | expected `()`, found `i32` + | expected this to be `()` +LL | } +LL | f(|x| d!(x)); + | ----- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`.