diff --git a/Cargo.lock b/Cargo.lock index b54566e7176b0..8a0991059d5b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5405,15 +5405,15 @@ dependencies = [ [[package]] name = "unicode-script" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b2c5c29e805da6817f5af6a627d65adb045cebf05cccd5a3493d6109454391c" +checksum = "58b33414ea8db4b7ea0343548dbdc31d27aef06beacf7044a87e564d9b0feb7d" [[package]] name = "unicode-security" -version = "0.0.3" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5f9011bbed9c13372bc8df618b55a38138445199caf3b61d432c6859c36dee0" +checksum = "5d87c28edc5b263377e448d6cdcb935c06b95413d8013ba6fae470558ccab18f" dependencies = [ "unicode-normalization", "unicode-script", diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2298958b88101..5d09018759191 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1917,6 +1917,15 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] pub fn discriminant_value(v: &T) -> ::Discriminant; + /// Returns the number of variants of the type `T` cast to a `usize`; + /// if `T` has no variants, returns 0. Uninhabited variants will be counted. + /// + /// The to-be-stabilized version of this intrinsic is + /// [`std::mem::variant_count`](../../std/mem/fn.variant_count.html) + #[rustc_const_unstable(feature = "variant_count", issue = "73662")] + #[cfg(not(bootstrap))] + pub fn variant_count() -> usize; + /// Rust's "try catch" construct which invokes the function pointer `try_fn` /// with the data pointer `data`. /// @@ -1960,6 +1969,12 @@ extern "rust-intrinsic" { pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; } +#[rustc_const_unstable(feature = "variant_count", issue = "73662")] +#[cfg(bootstrap)] +pub const fn variant_count() -> usize { + 0 +} + // Some functions are defined here because they accidentally got made // available in this module on stable. See . // (`transmute` also falls into this category, but it cannot be wrapped due to the diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4eb2fdbd07868..2b26e5303a89c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -124,6 +124,7 @@ #![feature(unsized_locals)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(variant_count)] #![feature(doc_alias)] #![feature(mmx_target_feature)] #![feature(tbm_target_feature)] diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 066bb8b3dc787..1bd7ae3a34ebb 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -999,3 +999,33 @@ impl fmt::Debug for Discriminant { pub const fn discriminant(v: &T) -> Discriminant { Discriminant(intrinsics::discriminant_value(v)) } + +/// Returns the number of variants in the enum type `T`. +/// +/// If `T` is not an enum, calling this function will not result in undefined behavior, but the +/// return value is unspecified. Equally, if `T` is an enum with more variants than `usize::MAX` +/// the return value is unspecified. Uninhabited variants will be counted. +/// +/// # Examples +/// +/// ``` +/// # #![feature(never_type)] +/// # #![feature(variant_count)] +/// +/// use std::mem; +/// +/// enum Void {} +/// enum Foo { A(&'static str), B(i32), C(i32) } +/// +/// assert_eq!(mem::variant_count::(), 0); +/// assert_eq!(mem::variant_count::(), 3); +/// +/// assert_eq!(mem::variant_count::>(), 2); +/// assert_eq!(mem::variant_count::>(), 2); +/// ``` +#[inline(always)] +#[unstable(feature = "variant_count", issue = "73662")] +#[rustc_const_unstable(feature = "variant_count", issue = "73662")] +pub const fn variant_count() -> usize { + intrinsics::variant_count::() +} diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 395b3879cfd0c..64a506a6377f2 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -316,7 +316,6 @@ impl *const T { /// differently have not been explored. This method should not be used to introduce such /// differences, and it should also not be stabilized before we have a better understanding /// of this issue. - /// ``` #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] @@ -349,7 +348,6 @@ impl *const T { /// differently have not been explored. This method should not be used to introduce such /// differences, and it should also not be stabilized before we have a better understanding /// of this issue. - /// ``` #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index b86ef5b13b353..6b5cd9fdb854d 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -294,7 +294,6 @@ impl *mut T { /// differently have not been explored. This method should not be used to introduce such /// differences, and it should also not be stabilized before we have a better understanding /// of this issue. - /// ``` #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] @@ -327,7 +326,6 @@ impl *mut T { /// differently have not been explored. This method should not be used to introduce such /// differences, and it should also not be stabilized before we have a better understanding /// of this issue. - /// ``` #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index c69aafe687cf8..233a9ba8e506e 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1459,6 +1459,86 @@ impl [T] { m >= n && needle == &self[m - n..] } + /// Returns a subslice with the prefix removed. + /// + /// Returns [`None`] if slice does not start with `prefix`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = [10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30])); + /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30])); + /// assert_eq!(v.strip_prefix(&[50]), None); + /// assert_eq!(v.strip_prefix(&[10, 50]), None); + /// ``` + /// + /// This method returns the original slice if `prefix` is an empty slice: + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[]), Some(v)); + /// let v: &[u8] = &[]; + /// assert_eq!(v.strip_prefix(&[]), Some(v)); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[unstable(feature = "slice_strip", issue = "73413")] + pub fn strip_prefix(&self, prefix: &[T]) -> Option<&[T]> + where + T: PartialEq, + { + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return Some(tail); + } + } + None + } + + /// Returns a subslice with the suffix removed. + /// + /// Returns [`None`] if slice does not end with `suffix`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = [10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40])); + /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10])); + /// assert_eq!(v.strip_suffix(&[50]), None); + /// assert_eq!(v.strip_suffix(&[50, 30]), None); + /// ``` + /// + /// This method returns the original slice if `suffix` is an empty slice: + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[]), Some(v)); + /// let v: &[u8] = &[]; + /// assert_eq!(v.strip_suffix(&[]), Some(v)); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[unstable(feature = "slice_strip", issue = "73413")] + pub fn strip_suffix(&self, suffix: &[T]) -> Option<&[T]> + where + T: PartialEq, + { + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return Some(head); + } + } + None + } + /// Binary searches this sorted slice for a given element. /// /// If the value is found then [`Result::Ok`] is returned, containing the diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index e98d709539d79..99fbb1ee3ea83 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -335,6 +335,8 @@ pub enum GenericParamKind { }, Const { ty: P, + /// Span of the `const` keyword. + kw_span: Span, }, } diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index b812f2dadf6d4..6c128f0176f66 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -475,7 +475,7 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments } } - Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { + Some(TokenTree::Token(Token { kind: token::Interpolated(nt, _), .. })) => match *nt { token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index 2ffef9d48c181..3fd2815daa14f 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -656,7 +656,7 @@ pub fn noop_visit_token(t: &mut Token, vis: &mut T) { *span = ident.span; return; // Avoid visiting the span for the second time. } - token::Interpolated(nt) => { + token::Interpolated(nt, _) => { let mut nt = Lrc::make_mut(nt); vis.visit_interpolated(&mut nt); } @@ -762,7 +762,7 @@ pub fn noop_flat_map_generic_param( GenericParamKind::Type { default } => { visit_opt(default, |default| vis.visit_ty(default)); } - GenericParamKind::Const { ty } => { + GenericParamKind::Const { ty, kw_span: _ } => { vis.visit_ty(ty); } } diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index a5b9c2a95bbea..89be3e6e212cc 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -182,6 +182,15 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool { .contains(&name) } +/// A hack used to pass AST fragments to attribute and derive macros +/// as a single nonterminal token instead of a token stream. +/// FIXME: It needs to be removed, but there are some compatibility issues (see #73345). +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +pub enum FlattenGroup { + Yes, + No, +} + #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ @@ -236,7 +245,7 @@ pub enum TokenKind { /// treat regular and interpolated lifetime identifiers in the same way. Lifetime(Symbol), - Interpolated(Lrc), + Interpolated(Lrc, FlattenGroup), // Can be expanded into several tokens. /// A doc comment. @@ -343,7 +352,7 @@ impl Token { /// if they keep spans or perform edition checks. pub fn uninterpolated_span(&self) -> Span { match &self.kind { - Interpolated(nt) => nt.span(), + Interpolated(nt, _) => nt.span(), _ => self.span, } } @@ -382,7 +391,7 @@ impl Token { ModSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => match **nt { + Interpolated(ref nt, _) => match **nt { NtLiteral(..) | NtExpr(..) | NtBlock(..) | @@ -408,7 +417,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path ModSep => true, // global path - Interpolated(ref nt) => match **nt { + Interpolated(ref nt, _) => match **nt { NtTy(..) | NtPath(..) => true, _ => false, }, @@ -420,7 +429,7 @@ impl Token { pub fn can_begin_const_arg(&self) -> bool { match self.kind { OpenDelim(Brace) => true, - Interpolated(ref nt) => match **nt { + Interpolated(ref nt, _) => match **nt { NtExpr(..) | NtBlock(..) | NtLiteral(..) => true, _ => false, }, @@ -455,7 +464,7 @@ impl Token { match self.uninterpolate().kind { Literal(..) | BinOp(Minus) => true, Ident(name, false) if name.is_bool_lit() => true, - Interpolated(ref nt) => match &**nt { + Interpolated(ref nt, _) => match &**nt { NtLiteral(_) => true, NtExpr(e) => match &e.kind { ast::ExprKind::Lit(_) => true, @@ -476,7 +485,7 @@ impl Token { // otherwise returns the original token. pub fn uninterpolate(&self) -> Cow<'_, Token> { match &self.kind { - Interpolated(nt) => match **nt { + Interpolated(nt, _) => match **nt { NtIdent(ident, is_raw) => { Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)) } @@ -523,7 +532,7 @@ impl Token { /// Returns `true` if the token is an interpolated path. fn is_path(&self) -> bool { - if let Interpolated(ref nt) = self.kind { + if let Interpolated(ref nt, _) = self.kind { if let NtPath(..) = **nt { return true; } @@ -535,7 +544,7 @@ impl Token { /// That is, is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { - if let Interpolated(ref nt) = self.kind { + if let Interpolated(ref nt, _) = self.kind { if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt { return true; } @@ -546,7 +555,7 @@ impl Token { // Is the token an interpolated block (`$b:block`)? pub fn is_whole_block(&self) -> bool { - if let Interpolated(ref nt) = self.kind { + if let Interpolated(ref nt, _) = self.kind { if let NtBlock(..) = **nt { return true; } @@ -724,7 +733,7 @@ impl Token { b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate) } - (&Interpolated(_), &Interpolated(_)) => false, + (&Interpolated(..), &Interpolated(..)) => false, _ => panic!("forgot to add a token?"), } diff --git a/src/librustc_ast/util/literal.rs b/src/librustc_ast/util/literal.rs index 4428d09902b92..ea59f867c59d2 100644 --- a/src/librustc_ast/util/literal.rs +++ b/src/librustc_ast/util/literal.rs @@ -205,7 +205,7 @@ impl Lit { token::Lit::new(token::Bool, name, None) } token::Literal(lit) => lit, - token::Interpolated(ref nt) => { + token::Interpolated(ref nt, _) => { if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt { if let ast::ExprKind::Lit(lit) = &expr.kind { return Ok(lit.clone()); diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 39b14ac458832..863f525bdc8f3 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1027,7 +1027,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_token(&mut self, token: Token) -> TokenStream { match token.kind { - token::Interpolated(nt) => { + token::Interpolated(nt, _) => { let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span); self.lower_token_stream(tts) } @@ -2230,7 +2230,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(param.ident), kind) } - GenericParamKind::Const { ref ty } => { + GenericParamKind::Const { ref ty, kw_span: _ } => { let ty = self .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { this.lower_ty(&ty, ImplTraitContext::disallowed()) diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 8eb125e444053..975881d9a0ac0 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -1135,9 +1135,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { generics.params.iter().map(|param| { let ident = Some(param.ident.to_string()); let (kind, ident) = match ¶m.kind { - GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident), - GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident), - GenericParamKind::Const { ref ty } => { + GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident), + GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident), + GenericParamKind::Const { ref ty, kw_span: _ } => { let ty = pprust::ty_to_string(ty); (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty))) } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index b1abc08aa67b0..86faa1f086ce2 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -266,7 +266,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) token::Shebang(s) => format!("/* shebang: {}*/", s), token::Unknown(s) => s.to_string(), - token::Interpolated(ref nt) => nonterminal_to_string(nt), + token::Interpolated(ref nt, _) => nonterminal_to_string(nt), } } @@ -2578,7 +2578,7 @@ impl<'a> State<'a> { s.print_type(default) } } - ast::GenericParamKind::Const { ref ty } => { + ast::GenericParamKind::Const { ref ty, kw_span: _ } => { s.word_space("const"); s.print_ident(param.ident); s.s.space(); diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs index 9660cade38241..dc21be3b296aa 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/src/librustc_builtin_macros/deriving/mod.rs @@ -123,7 +123,7 @@ fn inject_impl_of_structural_trait( *default = None; ast::GenericArg::Type(cx.ty_ident(span, param.ident)) } - ast::GenericParamKind::Const { ty: _ } => { + ast::GenericParamKind::Const { ty: _, kw_span: _ } => { ast::GenericArg::Const(cx.const_ident(span, param.ident)) } }) diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 0a1cc31044a22..130c0cf1877c6 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -206,7 +206,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } "size_of" | "pref_align_of" | "min_align_of" | "needs_drop" | "type_id" - | "type_name" => { + | "type_name" | "variant_count" => { let value = self .tcx .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 6a5e23adafa53..162585360fbda 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -446,6 +446,7 @@ E0762: include_str!("./error_codes/E0762.md"), E0763: include_str!("./error_codes/E0763.md"), E0764: include_str!("./error_codes/E0764.md"), E0765: include_str!("./error_codes/E0765.md"), +E0766: include_str!("./error_codes/E0766.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0766.md b/src/librustc_error_codes/error_codes/E0766.md new file mode 100644 index 0000000000000..4e775df2cac4d --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0766.md @@ -0,0 +1,13 @@ +A double quote byte string (`b"`) was not terminated. + +Erroneous code example: + +```compile_fail,E0766 +let s = b"; // error! +``` + +To fix this error, add the missing double quote at the end of the string: + +``` +let s = b""; // ok! +``` diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index a57ae798ffceb..d4c756c9ec7f8 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -4,7 +4,7 @@ use crate::module::DirectoryOwnership; use rustc_ast::ast::{self, Attribute, NodeId, PatKind}; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token; +use rustc_ast::token::{self, FlattenGroup}; use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; @@ -142,7 +142,7 @@ impl Annotatable { | Annotatable::StructField(..) | Annotatable::Variant(..) => panic!("unexpected annotatable"), }; - TokenTree::token(token::Interpolated(Lrc::new(nt)), DUMMY_SP).into() + TokenTree::token(token::Interpolated(Lrc::new(nt), FlattenGroup::Yes), DUMMY_SP).into() } pub fn expect_item(self) -> P { @@ -374,7 +374,7 @@ where impl MutVisitor for AvoidInterpolatedIdents { fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) { if let tokenstream::TokenTree::Token(token) = tt { - if let token::Interpolated(nt) = &token.kind { + if let token::Interpolated(nt, _) = &token.kind { if let token::NtIdent(ident, is_raw) = **nt { *tt = tokenstream::TokenTree::token( token::Ident(ident.name, is_raw), diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index 968f7c8e273a3..c90a438c25ece 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -785,12 +785,12 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool { sym::literal => token.can_begin_literal_maybe_minus(), sym::vis => match token.kind { // The follow-set of :vis + "priv" keyword + interpolated - token::Comma | token::Ident(..) | token::Interpolated(_) => true, + token::Comma | token::Ident(..) | token::Interpolated(..) => true, _ => token.can_begin_type(), }, sym::block => match token.kind { token::OpenDelim(token::Brace) => true, - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt, _) => match **nt { token::NtItem(_) | token::NtPat(_) | token::NtTy(_) @@ -804,7 +804,7 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool { }, sym::path | sym::meta => match token.kind { token::ModSep | token::Ident(..) => true, - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt, _) => match **nt { token::NtPath(_) | token::NtMeta(_) => true, _ => may_be_ident(&nt), }, @@ -823,12 +823,12 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool { token::ModSep | // path token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) - token::Interpolated(ref nt) => may_be_ident(nt), + token::Interpolated(ref nt, _) => may_be_ident(nt), _ => false, }, sym::lifetime => match token.kind { token::Lifetime(_) => true, - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt, _) => match **nt { token::NtLifetime(_) | token::NtTT(_) => true, _ => false, }, diff --git a/src/librustc_expand/mbe/transcribe.rs b/src/librustc_expand/mbe/transcribe.rs index e2d3d5c4d644e..486f0a6420d6e 100644 --- a/src/librustc_expand/mbe/transcribe.rs +++ b/src/librustc_expand/mbe/transcribe.rs @@ -4,7 +4,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use rustc_ast::ast::MacCall; use rustc_ast::mut_visit::{self, MutVisitor}; -use rustc_ast::token::{self, NtTT, Token}; +use rustc_ast::token::{self, FlattenGroup, NtTT, Token}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -240,7 +240,10 @@ pub(super) fn transcribe<'a>( result.push(tt.clone().into()); } else { marker.visit_span(&mut sp); - let token = TokenTree::token(token::Interpolated(nt.clone()), sp); + let token = TokenTree::token( + token::Interpolated(nt.clone(), FlattenGroup::No), + sp, + ); result.push(token.into()); } } else { diff --git a/src/librustc_expand/proc_macro.rs b/src/librustc_expand/proc_macro.rs index df7bf9438c3d0..1e26c832a2621 100644 --- a/src/librustc_expand/proc_macro.rs +++ b/src/librustc_expand/proc_macro.rs @@ -2,7 +2,7 @@ use crate::base::{self, *}; use crate::proc_macro_server; use rustc_ast::ast::{self, ItemKind, MetaItemKind, NestedMetaItem}; -use rustc_ast::token; +use rustc_ast::token::{self, FlattenGroup}; use rustc_ast::tokenstream::{self, TokenStream}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, ErrorReported}; @@ -102,7 +102,7 @@ impl MultiItemModifier for ProcMacroDerive { } } - let token = token::Interpolated(Lrc::new(token::NtItem(item))); + let token = token::Interpolated(Lrc::new(token::NtItem(item)), FlattenGroup::Yes); let input = tokenstream::TokenTree::token(token, DUMMY_SP).into(); let server = proc_macro_server::Rustc::new(ecx); diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index ea55674045c0f..c88b5a37f718a 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -1,7 +1,7 @@ use crate::base::ExtCtxt; use rustc_ast::ast; -use rustc_ast::token; +use rustc_ast::token::{self, FlattenGroup}; use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; use rustc_ast::util::comments; use rustc_ast_pretty::pprust; @@ -60,7 +60,12 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> let Token { kind, span } = match tree { tokenstream::TokenTree::Delimited(span, delim, tts) => { let delimiter = Delimiter::from_internal(delim); - return TokenTree::Group(Group { delimiter, stream: tts, span }); + return TokenTree::Group(Group { + delimiter, + stream: tts, + span, + flatten: FlattenGroup::No, + }); } tokenstream::TokenTree::Token(token) => token, }; @@ -167,6 +172,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> delimiter: Delimiter::Bracket, stream, span: DelimSpan::from_single(span), + flatten: FlattenGroup::No, })); if style == ast::AttrStyle::Inner { stack.push(tt!(Punct::new('!', false))); @@ -174,12 +180,13 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> tt!(Punct::new('#', false)) } - Interpolated(nt) => { + Interpolated(nt, flatten) => { let stream = nt_to_tokenstream(&nt, sess, span); TokenTree::Group(Group { delimiter: Delimiter::None, stream, span: DelimSpan::from_single(span), + flatten, }) } @@ -195,7 +202,7 @@ impl ToInternal for TokenTree { let (ch, joint, span) = match self { TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span), - TokenTree::Group(Group { delimiter, stream, span }) => { + TokenTree::Group(Group { delimiter, stream, span, .. }) => { return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream) .into(); } @@ -283,6 +290,10 @@ pub struct Group { delimiter: Delimiter, stream: TokenStream, span: DelimSpan, + /// A hack used to pass AST fragments to attribute and derive macros + /// as a single nonterminal token instead of a token stream. + /// FIXME: It needs to be removed, but there are some compatibility issues (see #73345). + flatten: FlattenGroup, } #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -437,14 +448,12 @@ impl server::TokenStreamIter for Rustc<'_> { let next = iter.cursor.next_with_joint()?; Some(TokenTree::from_internal((next, self.sess, &mut iter.stack))) })?; - // HACK: The condition "dummy span + group with empty delimiter" represents an AST - // fragment approximately converted into a token stream. This may happen, for - // example, with inputs to proc macro attributes, including derives. Such "groups" - // need to flattened during iteration over stream's token trees. - // Eventually this needs to be removed in favor of keeping original token trees - // and not doing the roundtrip through AST. + // A hack used to pass AST fragments to attribute and derive macros + // as a single nonterminal token instead of a token stream. + // Such token needs to be "unwrapped" and not represented as a delimited group. + // FIXME: It needs to be removed, but there are some compatibility issues (see #73345). if let TokenTree::Group(ref group) = tree { - if group.delimiter == Delimiter::None && group.span.entire().is_dummy() { + if matches!(group.flatten, FlattenGroup::Yes) { iter.cursor.append(group.stream.clone()); continue; } @@ -456,7 +465,12 @@ impl server::TokenStreamIter for Rustc<'_> { impl server::Group for Rustc<'_> { fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group { - Group { delimiter, stream, span: DelimSpan::from_single(server::Span::call_site(self)) } + Group { + delimiter, + stream, + span: DelimSpan::from_single(server::Span::call_site(self)), + flatten: FlattenGroup::No, + } } fn delimiter(&mut self, group: &Self::Group) -> Delimiter { group.delimiter diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index ada6f2a9381dc..58c15257326ae 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" [dependencies] log = "0.4" -unicode-security = "0.0.3" +unicode-security = "0.0.5" rustc_middle = { path = "../librustc_middle" } rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_attr = { path = "../librustc_attr" } diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index 064b0255397ce..30dbd069c29bd 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -1,9 +1,7 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast::ast; use rustc_data_structures::fx::FxHashMap; -use rustc_span::symbol::{Ident, SymbolStr}; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; +use rustc_span::symbol::SymbolStr; declare_lint! { pub NON_ASCII_IDENTS, @@ -19,158 +17,256 @@ declare_lint! { crate_level_only } -// FIXME: Change this to warn. declare_lint! { pub CONFUSABLE_IDENTS, - Allow, + Warn, "detects visually confusable pairs between identifiers", crate_level_only } -declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]); - -enum CowBoxSymStr { - Interned(SymbolStr), - Owned(Box), -} - -impl Deref for CowBoxSymStr { - type Target = str; - - fn deref(&self) -> &str { - match self { - CowBoxSymStr::Interned(interned) => interned, - CowBoxSymStr::Owned(ref owned) => owned, - } - } -} - -impl Hash for CowBoxSymStr { - #[inline] - fn hash(&self, state: &mut H) { - Hash::hash(&**self, state) - } -} - -impl PartialEq for CowBoxSymStr { - #[inline] - fn eq(&self, other: &CowBoxSymStr) -> bool { - PartialEq::eq(&**self, &**other) - } -} - -impl Eq for CowBoxSymStr {} - -fn calc_skeleton(symbol_str: SymbolStr, buffer: &'_ mut String) -> CowBoxSymStr { - use std::mem::swap; - use unicode_security::confusable_detection::skeleton; - buffer.clear(); - buffer.extend(skeleton(&symbol_str)); - if symbol_str == *buffer { - CowBoxSymStr::Interned(symbol_str) - } else { - let mut owned = String::new(); - swap(buffer, &mut owned); - CowBoxSymStr::Owned(owned.into_boxed_str()) - } -} - -fn is_in_ascii_confusable_closure(c: char) -> bool { - // FIXME: move this table to `unicode_security` crate. - // data here corresponds to Unicode 13. - const ASCII_CONFUSABLE_CLOSURE: &[(u64, u64)] = &[(0x00, 0x7f), (0xba, 0xba), (0x2080, 0x2080)]; - let c = c as u64; - for &(range_start, range_end) in ASCII_CONFUSABLE_CLOSURE { - if c >= range_start && c <= range_end { - return true; - } - } - false +declare_lint! { + pub MIXED_SCRIPT_CONFUSABLES, + Warn, + "detects Unicode scripts whose mixed script confusables codepoints are solely used", + crate_level_only } -fn is_in_ascii_confusable_closure_relevant_list(c: char) -> bool { - // FIXME: move this table to `unicode_security` crate. - // data here corresponds to Unicode 13. - const ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST: &[u64] = &[ - 0x22, 0x25, 0x27, 0x2f, 0x30, 0x31, 0x49, 0x4f, 0x60, 0x6c, 0x6d, 0x6e, 0x72, 0x7c, 0xba, - 0x2080, - ]; - let c = c as u64; - for &item in ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST { - if c == item { - return true; - } - } - false -} +declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS, MIXED_SCRIPT_CONFUSABLES]); impl EarlyLintPass for NonAsciiIdents { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { use rustc_session::lint::Level; - if cx.builder.lint_level(CONFUSABLE_IDENTS).0 == Level::Allow { + use rustc_span::Span; + use std::collections::BTreeMap; + use unicode_security::GeneralSecurityProfile; + use utils::CowBoxSymStr; + + let check_non_ascii_idents = cx.builder.lint_level(NON_ASCII_IDENTS).0 != Level::Allow; + let check_uncommon_codepoints = + cx.builder.lint_level(UNCOMMON_CODEPOINTS).0 != Level::Allow; + let check_confusable_idents = cx.builder.lint_level(CONFUSABLE_IDENTS).0 != Level::Allow; + let check_mixed_script_confusables = + cx.builder.lint_level(MIXED_SCRIPT_CONFUSABLES).0 != Level::Allow; + + if !check_non_ascii_idents + && !check_uncommon_codepoints + && !check_confusable_idents + && !check_mixed_script_confusables + { return; } + + let mut has_non_ascii_idents = false; let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock(); - let mut symbol_strs_and_spans = Vec::with_capacity(symbols.len()); - let mut in_fast_path = true; - for (symbol, sp) in symbols.iter() { - // fast path + for (symbol, &sp) in symbols.iter() { let symbol_str = symbol.as_str(); - if !symbol_str.chars().all(is_in_ascii_confusable_closure) { - // fallback to slow path. - symbol_strs_and_spans.clear(); - in_fast_path = false; - break; + if symbol_str.is_ascii() { + continue; } - if symbol_str.chars().any(is_in_ascii_confusable_closure_relevant_list) { - symbol_strs_and_spans.push((symbol_str, *sp)); + has_non_ascii_idents = true; + cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| { + lint.build("identifier contains non-ASCII characters").emit() + }); + if check_uncommon_codepoints + && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed) + { + cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| { + lint.build("identifier contains uncommon Unicode codepoints").emit() + }) } } - if !in_fast_path { - // slow path - for (symbol, sp) in symbols.iter() { + + if has_non_ascii_idents && check_confusable_idents { + let mut skeleton_map: FxHashMap = + FxHashMap::with_capacity_and_hasher(symbols.len(), Default::default()); + let mut str_buf = String::new(); + for (symbol, &sp) in symbols.iter() { + fn calc_skeleton(symbol_str: &SymbolStr, buffer: &mut String) -> CowBoxSymStr { + use std::mem::replace; + use unicode_security::confusable_detection::skeleton; + buffer.clear(); + buffer.extend(skeleton(symbol_str)); + if *symbol_str == *buffer { + CowBoxSymStr::Interned(symbol_str.clone()) + } else { + let owned = replace(buffer, String::new()); + CowBoxSymStr::Owned(owned.into_boxed_str()) + } + } let symbol_str = symbol.as_str(); - symbol_strs_and_spans.push((symbol_str, *sp)); + let is_ascii = symbol_str.is_ascii(); + let skeleton = calc_skeleton(&symbol_str, &mut str_buf); + skeleton_map + .entry(skeleton) + .and_modify(|(existing_symbolstr, existing_span, existing_is_ascii)| { + if !*existing_is_ascii || !is_ascii { + cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| { + lint.build(&format!( + "identifier pair considered confusable between `{}` and `{}`", + existing_symbolstr, symbol_str + )) + .span_label( + *existing_span, + "this is where the previous identifier occurred", + ) + .emit(); + }); + } + if *existing_is_ascii && !is_ascii { + *existing_symbolstr = symbol_str.clone(); + *existing_span = sp; + *existing_is_ascii = is_ascii; + } + }) + .or_insert((symbol_str, sp, is_ascii)); } } - drop(symbols); - symbol_strs_and_spans.sort_by_key(|x| x.0.clone()); - let mut skeleton_map = - FxHashMap::with_capacity_and_hasher(symbol_strs_and_spans.len(), Default::default()); - let mut str_buf = String::new(); - for (symbol_str, sp) in symbol_strs_and_spans { - let skeleton = calc_skeleton(symbol_str.clone(), &mut str_buf); - skeleton_map - .entry(skeleton) - .and_modify(|(existing_symbolstr, existing_span)| { - cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| { - lint.build(&format!( - "identifier pair considered confusable between `{}` and `{}`", - existing_symbolstr, symbol_str - )) - .span_label( - *existing_span, - "this is where the previous identifier occurred", - ) - .emit(); + + if has_non_ascii_idents && check_mixed_script_confusables { + use unicode_security::is_potential_mixed_script_confusable_char; + use unicode_security::mixed_script::AugmentedScriptSet; + + #[derive(Clone)] + enum ScriptSetUsage { + Suspicious(Vec, Span), + Verified, + } + + let mut script_states: FxHashMap = + FxHashMap::default(); + let latin_augmented_script_set = AugmentedScriptSet::for_char('A'); + script_states.insert(latin_augmented_script_set, ScriptSetUsage::Verified); + + let mut has_suspicous = false; + for (symbol, &sp) in symbols.iter() { + let symbol_str = symbol.as_str(); + for ch in symbol_str.chars() { + if ch.is_ascii() { + // all ascii characters are covered by exception. + continue; + } + if !GeneralSecurityProfile::identifier_allowed(ch) { + // this character is covered by `uncommon_codepoints` lint. + continue; + } + let augmented_script_set = AugmentedScriptSet::for_char(ch); + script_states + .entry(augmented_script_set) + .and_modify(|existing_state| { + if let ScriptSetUsage::Suspicious(ch_list, _) = existing_state { + if is_potential_mixed_script_confusable_char(ch) { + ch_list.push(ch); + } else { + *existing_state = ScriptSetUsage::Verified; + } + } + }) + .or_insert_with(|| { + if !is_potential_mixed_script_confusable_char(ch) { + ScriptSetUsage::Verified + } else { + has_suspicous = true; + ScriptSetUsage::Suspicious(vec![ch], sp) + } + }); + } + } + + if has_suspicous { + let verified_augmented_script_sets = script_states + .iter() + .flat_map(|(k, v)| match v { + ScriptSetUsage::Verified => Some(*k), + _ => None, + }) + .collect::>(); + + // we're sorting the output here. + let mut lint_reports: BTreeMap<(Span, Vec), AugmentedScriptSet> = + BTreeMap::new(); + + 'outerloop: for (augment_script_set, usage) in script_states { + let (mut ch_list, sp) = match usage { + ScriptSetUsage::Verified => continue, + ScriptSetUsage::Suspicious(ch_list, sp) => (ch_list, sp), + }; + + if augment_script_set.is_all() { + continue; + } + + for existing in verified_augmented_script_sets.iter() { + if existing.is_all() { + continue; + } + let mut intersect = *existing; + intersect.intersect_with(augment_script_set); + if !intersect.is_empty() && !intersect.is_all() { + continue 'outerloop; + } + } + + ch_list.sort(); + ch_list.dedup(); + lint_reports.insert((sp, ch_list), augment_script_set); + } + + for ((sp, ch_list), script_set) in lint_reports { + cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| { + let message = format!( + "The usage of Script Group `{}` in this crate consists solely of mixed script confusables", + script_set); + let mut note = "The usage includes ".to_string(); + for (idx, ch) in ch_list.into_iter().enumerate() { + if idx != 0 { + note += ", "; + } + let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); + note += &char_info; + } + note += "."; + lint.build(&message).note(¬e).note("Please recheck to make sure their usages are indeed what you want.").emit() }); - }) - .or_insert((symbol_str, sp)); + } + } } } - fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { - use unicode_security::GeneralSecurityProfile; - let name_str = ident.name.as_str(); - if name_str.is_ascii() { - return; +} + +mod utils { + use rustc_span::symbol::SymbolStr; + use std::hash::{Hash, Hasher}; + use std::ops::Deref; + + pub(super) enum CowBoxSymStr { + Interned(SymbolStr), + Owned(Box), + } + + impl Deref for CowBoxSymStr { + type Target = str; + + fn deref(&self) -> &str { + match self { + CowBoxSymStr::Interned(interned) => interned, + CowBoxSymStr::Owned(ref owned) => owned, + } + } + } + + impl Hash for CowBoxSymStr { + #[inline] + fn hash(&self, state: &mut H) { + Hash::hash(&**self, state) } - cx.struct_span_lint(NON_ASCII_IDENTS, ident.span, |lint| { - lint.build("identifier contains non-ASCII characters").emit() - }); - if !name_str.chars().all(GeneralSecurityProfile::identifier_allowed) { - cx.struct_span_lint(UNCOMMON_CODEPOINTS, ident.span, |lint| { - lint.build("identifier contains uncommon Unicode codepoints").emit() - }) + } + + impl PartialEq for CowBoxSymStr { + #[inline] + fn eq(&self, other: &CowBoxSymStr) -> bool { + PartialEq::eq(&**self, &**other) } } + + impl Eq for CowBoxSymStr {} } diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index ada48bc147e47..d25f8bd1b8c58 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -293,11 +293,9 @@ fn main() { } } - // LLVM requires symbols from this library, but apparently they're not printed - // during llvm-config? + // Libstdc++ depends on pthread which Rust doesn't link on MinGW + // since nothing else requires it. if target.contains("windows-gnu") { - println!("cargo:rustc-link-lib=static-nobundle=gcc_s"); println!("cargo:rustc-link-lib=static-nobundle=pthread"); - println!("cargo:rustc-link-lib=dylib=uuid"); } } diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 8d7944004c75e..60a1fe0b19870 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -156,6 +156,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("variable moved due to use{}", move_spans.describe()), ); } + if let UseSpans::PatUse(span) = move_spans { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "borrow this field in the pattern to avoid moving {}", + self.describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "the value".to_string()) + ), + "ref ".to_string(), + Applicability::MachineApplicable, + ); + } + if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() { let sess = self.infcx.tcx.sess; if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) { @@ -198,11 +212,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => true, }; - if needs_note { - let mpi = self.move_data.moves[move_out_indices[0]].path; - let place = &self.move_data.move_paths[mpi].place; + let mpi = self.move_data.moves[move_out_indices[0]].path; + let place = &self.move_data.move_paths[mpi].place; + let ty = place.ty(self.body, self.infcx.tcx).ty; + + if is_loop_move { + if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind { + // We have a `&mut` ref, we need to reborrow on each iteration (#62112). + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "consider creating a fresh reborrow of {} here", + self.describe_place(moved_place) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "the mutable reference".to_string()), + ), + "&mut *".to_string(), + Applicability::MachineApplicable, + ); + } + } - let ty = place.ty(self.body, self.infcx.tcx).ty; + if needs_note { let opt_name = self.describe_place_with_options(place.as_ref(), IncludingDowncast(true)); let note_msg = match opt_name { diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs index 5253acbba7f1c..849fd63998db4 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs @@ -509,7 +509,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Used in a closure. (LaterUseKind::ClosureCapture, var_span) } - UseSpans::OtherUse(span) => { + UseSpans::PatUse(span) | UseSpans::OtherUse(span) => { let block = &self.body.basic_blocks()[location.block]; let kind = if let Some(&Statement { diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index ca8e54ea28649..388076a9d60af 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -542,20 +542,26 @@ pub(super) enum UseSpans { // The span of the first use of the captured variable inside the closure. var_span: Span, }, - // This access has a single span associated to it: common case. + /// This access is caused by a `match` or `if let` pattern. + PatUse(Span), + /// This access has a single span associated to it: common case. OtherUse(Span), } impl UseSpans { pub(super) fn args_or_use(self) -> Span { match self { - UseSpans::ClosureUse { args_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::ClosureUse { args_span: span, .. } + | UseSpans::PatUse(span) + | UseSpans::OtherUse(span) => span, } } pub(super) fn var_or_use(self) -> Span { match self { - UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::ClosureUse { var_span: span, .. } + | UseSpans::PatUse(span) + | UseSpans::OtherUse(span) => span, } } @@ -624,7 +630,7 @@ impl UseSpans { { match self { closure @ UseSpans::ClosureUse { .. } => closure, - UseSpans::OtherUse(_) => if_other(), + UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(), } } } @@ -741,7 +747,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - OtherUse(stmt.source_info.span) + if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { + PatUse(stmt.source_info.span) + } else { + OtherUse(stmt.source_info.span) + } } /// Finds the span of arguments of a closure (within `maybe_closure_span`) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 6ac1e6be03674..88ba28dab82e1 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -69,6 +69,13 @@ crate fn eval_nullary_intrinsic<'tcx>( ConstValue::from_machine_usize(n, &tcx) } sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)), + sym::variant_count => { + if let ty::Adt(ref adt, _) = tp_ty.kind { + ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx) + } else { + ConstValue::from_machine_usize(0u64, &tcx) + } + } other => bug!("`{}` is not a zero arg intrinsic", other), }) } @@ -109,10 +116,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::needs_drop | sym::size_of | sym::type_id - | sym::type_name => { + | sym::type_name + | sym::variant_count => { let gid = GlobalId { instance, promoted: None }; let ty = match intrinsic_name { - sym::min_align_of | sym::pref_align_of | sym::size_of => self.tcx.types.usize, + sym::min_align_of | sym::pref_align_of | sym::size_of | sym::variant_count => { + self.tcx.types.usize + } sym::needs_drop => self.tcx.types.bool, sym::type_id => self.tcx.types.u64, sym::type_name => self.tcx.mk_static_str(), diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 8e74c3847bc90..5050f03bea9b2 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -367,12 +367,15 @@ impl<'a> StringReader<'a> { } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { - self.fatal_span_( - start + BytePos(1), - suffix_start, - "unterminated double quote byte string", - ) - .raise() + self.sess + .span_diagnostic + .struct_span_fatal_with_code( + self.mk_sp(start + BytePos(1), suffix_start), + "unterminated double quote byte string", + error_code!(E0766), + ) + .emit(); + FatalError.raise(); } (token::ByteStr, Mode::ByteStr, 2, 1) // b" " } diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index 803f14a2a228a..b8cb146145b98 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -155,7 +155,7 @@ impl<'a> Parser<'a> { /// The delimiters or `=` are still put into the resulting token stream. pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { let item = match self.token.kind { - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt, _) => match **nt { Nonterminal::NtMeta(ref item) => Some(item.clone().into_inner()), _ => None, }, @@ -254,7 +254,7 @@ impl<'a> Parser<'a> { /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { let nt_meta = match self.token.kind { - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt, _) => match **nt { token::NtMeta(ref e) => Some(e.clone()), _ => None, }, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 49a5c8801766c..2745b18a8cd51 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -26,7 +26,7 @@ use std::mem; /// `token::Interpolated` tokens. macro_rules! maybe_whole_expr { ($p:expr) => { - if let token::Interpolated(nt) = &$p.token.kind { + if let token::Interpolated(nt, _) = &$p.token.kind { match &**nt { token::NtExpr(e) | token::NtLiteral(e) => { let e = e.clone(); diff --git a/src/librustc_parse/parser/generics.rs b/src/librustc_parse/parser/generics.rs index 04b64d93c70dd..47794746126da 100644 --- a/src/librustc_parse/parser/generics.rs +++ b/src/librustc_parse/parser/generics.rs @@ -47,21 +47,21 @@ impl<'a> Parser<'a> { } fn parse_const_param(&mut self, preceding_attrs: Vec) -> PResult<'a, GenericParam> { - let lo = self.token.span; + let const_span = self.token.span; self.expect_keyword(kw::Const)?; let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; - self.sess.gated_spans.gate(sym::const_generics, lo.to(self.prev_token.span)); + self.sess.gated_spans.gate(sym::const_generics, const_span.to(self.prev_token.span)); Ok(GenericParam { ident, id: ast::DUMMY_NODE_ID, attrs: preceding_attrs.into(), bounds: Vec::new(), - kind: GenericParamKind::Const { ty }, + kind: GenericParamKind::Const { ty, kw_span: const_span }, is_placeholder: false, }) } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 6f13d7994d17d..10df16964da08 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1780,7 +1780,7 @@ impl<'a> Parser<'a> { fn is_named_param(&self) -> bool { let offset = match self.token.kind { - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt, _) => match **nt { token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), _ => 0, }, diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 7811d5fb741b2..04074479a21a4 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -54,7 +54,7 @@ enum BlockMode { #[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { - if let token::Interpolated(nt) = &$p.token.kind { + if let token::Interpolated(nt, _) = &$p.token.kind { if let token::$constructor(x) = &**nt { let $x = x.clone(); $p.bump(); @@ -69,7 +69,7 @@ macro_rules! maybe_whole { macro_rules! maybe_recover_from_interpolated_ty_qpath { ($self: expr, $allow_qpath_recovery: expr) => { if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) { - if let token::Interpolated(nt) = &$self.token.kind { + if let token::Interpolated(nt, _) = &$self.token.kind { if let token::NtTy(ty) = &**nt { let ty = ty.clone(); $self.bump(); @@ -922,7 +922,7 @@ impl<'a> Parser<'a> { if self.eat(&token::Eq) { let eq_span = self.prev_token.span; let mut is_interpolated_expr = false; - if let token::Interpolated(nt) = &self.token.kind { + if let token::Interpolated(nt, _) = &self.token.kind { if let token::NtExpr(..) = **nt { is_interpolated_expr = true; } diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index 6603d0afc0248..742183d369735 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -515,7 +515,7 @@ impl<'a> Parser<'a> { self.recover_additional_muts(); // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. - if let token::Interpolated(ref nt) = self.token.kind { + if let token::Interpolated(ref nt, _) = self.token.kind { if let token::NtPat(_) = **nt { self.expected_ident_found().emit(); } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index ef43f597eab47..72faa68d0b243 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1325,7 +1325,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { } fn visit_token(&mut self, t: Token) { - if let token::Interpolated(nt) = t.kind { + if let token::Interpolated(nt, _) = t.kind { if let token::NtExpr(ref expr) = *nt { if let ast::ExprKind::MacCall(..) = expr.kind { self.visit_invoc(expr.id); diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index f1063f42c91ec..dc8d1a8d3fdf9 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -256,7 +256,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { } fn visit_token(&mut self, t: Token) { - if let token::Interpolated(nt) = t.kind { + if let token::Interpolated(nt, _) = t.kind { if let token::NtExpr(ref expr) = *nt { if let ExprKind::MacCall(..) = expr.kind { self.visit_macro_invoc(expr.id); diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 6f769c3c59cae..b8fb813ea155f 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -536,8 +536,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { for param in &generics.params { match param.kind { - GenericParamKind::Lifetime { .. } => self.visit_generic_param(param), - GenericParamKind::Type { ref default, .. } => { + GenericParamKind::Lifetime => self.visit_generic_param(param), + GenericParamKind::Type { ref default } => { for bound in ¶m.bounds { self.visit_param_bound(bound); } @@ -551,7 +551,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Allow all following defaults to refer to this type parameter. default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name)); } - GenericParamKind::Const { ref ty } => { + GenericParamKind::Const { ref ty, kw_span: _ } => { for bound in ¶m.bounds { self.visit_param_bound(bound); } diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs index ddbc95fb1b0b8..f4e5da4d54f46 100644 --- a/src/librustc_session/parse.rs +++ b/src/librustc_session/parse.rs @@ -13,6 +13,7 @@ use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{MultiSpan, Span, Symbol}; +use std::collections::BTreeMap; use std::path::PathBuf; use std::str; @@ -63,7 +64,7 @@ impl GatedSpans { #[derive(Default)] pub struct SymbolGallery { /// All symbols occurred and their first occurrance span. - pub symbols: Lock>, + pub symbols: Lock>, } impl SymbolGallery { diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index fa1368b104c7e..857734037afe7 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -832,6 +832,7 @@ symbols! { v1, val, var, + variant_count, vec, Vec, version, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index ef6c7c14404a7..1c0b22ca7370b 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -75,7 +75,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely" | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32" - | "maxnumf64" | "type_name" => hir::Unsafety::Normal, + | "maxnumf64" | "type_name" | "variant_count" => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } } @@ -137,7 +137,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let unsafety = intrinsic_operation_unsafety(&name[..]); let (n_tps, inputs, output) = match &name[..] { "breakpoint" => (0, Vec::new(), tcx.mk_unit()), - "size_of" | "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize), + "size_of" | "pref_align_of" | "min_align_of" | "variant_count" => { + (1, Vec::new(), tcx.types.usize) + } "size_of_val" | "min_align_of_val" => { (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize) } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 59bb206678f51..62a23298c1b9f 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1408,6 +1408,7 @@ function defocusSearchBar() { addClass(actives[currentTab][0].previousElementSibling, "highlighted"); removeClass(actives[currentTab][0], "highlighted"); + e.preventDefault(); } else if (e.which === 40) { // down if (!actives[currentTab].length) { var results = document.getElementById("results").childNodes; @@ -1421,6 +1422,7 @@ function defocusSearchBar() { addClass(actives[currentTab][0].nextElementSibling, "highlighted"); removeClass(actives[currentTab][0], "highlighted"); } + e.preventDefault(); } else if (e.which === 13) { // return if (actives[currentTab].length) { document.location.href = diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 6d98c4d01c040..f987eb67ea5f2 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -913,10 +913,28 @@ mod match_keyword {} // /// Organize code into [modules]. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// Use `mod` to create new [modules] to encapsulate code, including other +/// modules: +/// +/// ``` +/// mod foo { +/// mod bar { +/// type MyType = (u8, u8); +/// fn baz() {} +/// } +/// } +/// ``` +/// +/// Like [`struct`]s and [`enum`]s, a module and its content are private by +/// default, unaccessible to code outside of the module. /// +/// To learn more about allowing access, see the documentation for the [`pub`] +/// keyword. +/// +/// [`enum`]: keyword.enum.html +/// [`pub`]: keyword.pub.html +/// [`struct`]: keyword.struct.html /// [modules]: ../reference/items/modules.html -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod mod_keyword {} #[doc(keyword = "move")] @@ -965,11 +983,61 @@ mod move_keyword {} #[doc(keyword = "mut")] // -/// A mutable binding, reference, or pointer. +/// A mutable variable, reference, or pointer. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// `mut` can be used in several situations. The first is mutable variables, +/// which can be used anywhere you can bind a value to a variable name. Some +/// examples: /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// ```rust +/// // A mutable variable in the parameter list of a function. +/// fn foo(mut x: u8, y: u8) -> u8 { +/// x += y; +/// x +/// } +/// +/// // Modifying a mutable variable. +/// # #[allow(unused_assignments)] +/// let mut a = 5; +/// a = 6; +/// +/// assert_eq!(foo(3, 4), 7); +/// assert_eq!(a, 6); +/// ``` +/// +/// The second is mutable references. They can be created from `mut` variables +/// and must be unique: no other variables can have a mutable reference, nor a +/// shared reference. +/// +/// ```rust +/// // Taking a mutable reference. +/// fn push_two(v: &mut Vec) { +/// v.push(2); +/// } +/// +/// // A mutable reference cannot be taken to a non-mutable variable. +/// let mut v = vec![0, 1]; +/// // Passing a mutable reference. +/// push_two(&mut v); +/// +/// assert_eq!(v, vec![0, 1, 2]); +/// ``` +/// +/// ```rust,compile_fail,E0502 +/// let mut v = vec![0, 1]; +/// let mut_ref_v = &mut v; +/// ##[allow(unused)] +/// let ref_v = &v; +/// mut_ref_v.push(2); +/// ``` +/// +/// Mutable raw pointers work much like mutable references, with the added +/// possibility of not pointing to a valid object. The syntax is `*mut Type`. +/// +/// More information on mutable references and pointers can be found in``` +/// [Reference]. +/// +/// [Reference]: ../reference/types/pointer.html#mutable-references-mut mod mut_keyword {} #[doc(keyword = "pub")] @@ -1000,9 +1068,55 @@ mod ref_keyword {} // /// Return a value from a function. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// A `return` marks the end of an execution path in a function: /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// ``` +/// fn foo() -> i32 { +/// return 3; +/// } +/// assert_eq!(foo(), 3); +/// ``` +/// +/// `return` is not needed when the returned value is the last expression in the +/// function. In this case the `;` is omitted: +/// +/// ``` +/// fn foo() -> i32 { +/// 3 +/// } +/// assert_eq!(foo(), 3); +/// ``` +/// +/// `return` returns from the function immediately (an "early return"): +/// +/// ```no_run +/// use std::fs::File; +/// use std::io::{Error, ErrorKind, Read, Result}; +/// +/// fn main() -> Result<()> { +/// let mut file = match File::open("foo.txt") { +/// Ok(f) => f, +/// Err(e) => return Err(e), +/// }; +/// +/// let mut contents = String::new(); +/// let size = match file.read_to_string(&mut contents) { +/// Ok(s) => s, +/// Err(e) => return Err(e), +/// }; +/// +/// if contents.contains("impossible!") { +/// return Err(Error::new(ErrorKind::Other, "oh no!")); +/// } +/// +/// if size > 9000 { +/// return Err(Error::new(ErrorKind::Other, "over 9000!")); +/// } +/// +/// assert_eq!(contents, "Hello, world!"); +/// Ok(()) +/// } +/// ``` mod return_keyword {} #[doc(keyword = "self")] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index d22ac1d538584..97d62d958ca4f 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -170,7 +170,7 @@ pub fn take_hook() -> Box) + 'static + Sync + Send> { fn default_hook(info: &PanicInfo<'_>) { // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. - let backtrace_env = if update_panic_count(0) >= 2 { + let backtrace_env = if panic_count::get() >= 2 { RustBacktrace::Print(backtrace_rs::PrintFmt::Full) } else { backtrace::rust_backtrace_env() @@ -221,19 +221,65 @@ fn default_hook(info: &PanicInfo<'_>) { #[cfg(not(test))] #[doc(hidden)] #[unstable(feature = "update_panic_count", issue = "none")] -pub fn update_panic_count(amt: isize) -> usize { +pub mod panic_count { use crate::cell::Cell; - thread_local! { static PANIC_COUNT: Cell = Cell::new(0) } + use crate::sync::atomic::{AtomicUsize, Ordering}; + + // Panic count for the current thread. + thread_local! { static LOCAL_PANIC_COUNT: Cell = Cell::new(0) } + + // Sum of panic counts from all threads. The purpose of this is to have + // a fast path in `is_zero` (which is used by `panicking`). Access to + // this variable can be always be done with relaxed ordering because + // it is always guaranteed that, if `GLOBAL_PANIC_COUNT` is zero, + // `LOCAL_PANIC_COUNT` will be zero. + static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0); + + pub fn increase() -> usize { + GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed); + LOCAL_PANIC_COUNT.with(|c| { + let next = c.get() + 1; + c.set(next); + next + }) + } + + pub fn decrease() -> usize { + GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed); + LOCAL_PANIC_COUNT.with(|c| { + let next = c.get() - 1; + c.set(next); + next + }) + } - PANIC_COUNT.with(|c| { - let next = (c.get() as isize + amt) as usize; - c.set(next); - next - }) + pub fn get() -> usize { + LOCAL_PANIC_COUNT.with(|c| c.get()) + } + + #[inline] + pub fn is_zero() -> bool { + if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) == 0 { + // Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads + // (including the current one) will have `LOCAL_PANIC_COUNT` + // equal to zero, so TLS access can be avoided. + true + } else { + is_zero_slow_path() + } + } + + // Slow path is in a separate function to reduce the amount of code + // inlined from `is_zero`. + #[inline(never)] + #[cold] + fn is_zero_slow_path() -> bool { + LOCAL_PANIC_COUNT.with(|c| c.get() == 0) + } } #[cfg(test)] -pub use realstd::rt::update_panic_count; +pub use realstd::rt::panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. pub unsafe fn r#try R>(f: F) -> Result> { @@ -283,7 +329,7 @@ pub unsafe fn r#try R>(f: F) -> Result> #[cold] unsafe fn cleanup(payload: *mut u8) -> Box { let obj = Box::from_raw(__rust_panic_cleanup(payload)); - update_panic_count(-1); + panic_count::decrease(); obj } @@ -312,8 +358,9 @@ pub unsafe fn r#try R>(f: F) -> Result> } /// Determines whether the current thread is unwinding because of panic. +#[inline] pub fn panicking() -> bool { - update_panic_count(0) != 0 + !panic_count::is_zero() } /// The entry point for panicking with a formatted message. @@ -445,7 +492,7 @@ fn rust_panic_with_hook( message: Option<&fmt::Arguments<'_>>, location: &Location<'_>, ) -> ! { - let panics = update_panic_count(1); + let panics = panic_count::increase(); // If this is the third nested call (e.g., panics == 2, this is 0-indexed), // the panic hook probably triggered the last panic, otherwise the @@ -495,7 +542,7 @@ fn rust_panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. pub fn rust_panic_without_hook(payload: Box) -> ! { - update_panic_count(1); + panic_count::increase(); struct RewrapBox(Box); diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 2426b2dead712..fb825ab16ebd7 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -15,7 +15,7 @@ #![doc(hidden)] // Re-export some of our utilities which are expected by other crates. -pub use crate::panicking::{begin_panic, begin_panic_fmt, update_panic_count}; +pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count}; // To reduce the generated code of the new `lang_start`, this function is doing // the real work. diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr index 422d1605aa46b..604143b4e7efd 100644 --- a/src/test/ui/borrowck/issue-41962.stderr +++ b/src/test/ui/borrowck/issue-41962.stderr @@ -5,6 +5,10 @@ LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `maybe.0` + | +LL | if let Some(ref thing) = maybe { + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/move-in-pattern-mut.rs b/src/test/ui/borrowck/move-in-pattern-mut.rs new file mode 100644 index 0000000000000..175eb3b7a04d1 --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern-mut.rs @@ -0,0 +1,23 @@ +// Issue #63988 +#[derive(Debug)] +struct S; +fn foo(_: Option) {} + +enum E { + V { + s: S, + } +} +fn bar(_: E) {} + +fn main() { + let s = Some(S); + if let Some(mut x) = s { + x = S; + } + foo(s); //~ ERROR use of moved value: `s` + let mut e = E::V { s: S }; + let E::V { s: mut x } = e; + x = S; + bar(e); //~ ERROR use of moved value: `e` +} diff --git a/src/test/ui/borrowck/move-in-pattern-mut.stderr b/src/test/ui/borrowck/move-in-pattern-mut.stderr new file mode 100644 index 0000000000000..391638444c3bd --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern-mut.stderr @@ -0,0 +1,33 @@ +error[E0382]: use of moved value: `s` + --> $DIR/move-in-pattern-mut.rs:18:9 + | +LL | if let Some(mut x) = s { + | ----- value moved here +... +LL | foo(s); + | ^ value used here after partial move + | + = note: move occurs because value has type `S`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `s.0` + | +LL | if let Some(ref mut x) = s { + | ^^^ + +error[E0382]: use of moved value: `e` + --> $DIR/move-in-pattern-mut.rs:22:9 + | +LL | let E::V { s: mut x } = e; + | ----- value moved here +LL | x = S; +LL | bar(e); + | ^ value used here after partial move + | + = note: move occurs because value has type `S`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `e.s` + | +LL | let E::V { s: ref mut x } = e; + | ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/move-in-pattern.fixed b/src/test/ui/borrowck/move-in-pattern.fixed new file mode 100644 index 0000000000000..f55fdcc5f90e8 --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern.fixed @@ -0,0 +1,24 @@ +// run-rustfix +// Issue #63988 +#[derive(Debug)] +struct S; +fn foo(_: Option) {} + +enum E { + V { + s: S, + } +} +fn bar(_: E) {} + +fn main() { + let s = Some(S); + if let Some(ref x) = s { + let _ = x; + } + foo(s); //~ ERROR use of moved value: `s` + let e = E::V { s: S }; + let E::V { s: ref x } = e; + let _ = x; + bar(e); //~ ERROR use of moved value: `e` +} diff --git a/src/test/ui/borrowck/move-in-pattern.rs b/src/test/ui/borrowck/move-in-pattern.rs new file mode 100644 index 0000000000000..7ad04b9490c25 --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern.rs @@ -0,0 +1,24 @@ +// run-rustfix +// Issue #63988 +#[derive(Debug)] +struct S; +fn foo(_: Option) {} + +enum E { + V { + s: S, + } +} +fn bar(_: E) {} + +fn main() { + let s = Some(S); + if let Some(x) = s { + let _ = x; + } + foo(s); //~ ERROR use of moved value: `s` + let e = E::V { s: S }; + let E::V { s: x } = e; + let _ = x; + bar(e); //~ ERROR use of moved value: `e` +} diff --git a/src/test/ui/borrowck/move-in-pattern.stderr b/src/test/ui/borrowck/move-in-pattern.stderr new file mode 100644 index 0000000000000..c5cb24455eb61 --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern.stderr @@ -0,0 +1,33 @@ +error[E0382]: use of moved value: `s` + --> $DIR/move-in-pattern.rs:19:9 + | +LL | if let Some(x) = s { + | - value moved here +... +LL | foo(s); + | ^ value used here after partial move + | + = note: move occurs because value has type `S`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `s.0` + | +LL | if let Some(ref x) = s { + | ^^^ + +error[E0382]: use of moved value: `e` + --> $DIR/move-in-pattern.rs:23:9 + | +LL | let E::V { s: x } = e; + | - value moved here +LL | let _ = x; +LL | bar(e); + | ^ value used here after partial move + | + = note: move occurs because value has type `S`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `e.s` + | +LL | let E::V { s: ref x } = e; + | ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.fixed b/src/test/ui/borrowck/mut-borrow-in-loop-2.fixed new file mode 100644 index 0000000000000..ceeba30a90f29 --- /dev/null +++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.fixed @@ -0,0 +1,35 @@ +// run-rustfix +#![allow(dead_code)] + +struct Events(R); + +struct Other; + +pub trait Trait { + fn handle(value: T) -> Self; +} + +// Blanket impl. (If you comment this out, compiler figures out that it +// is passing an `&mut` to a method that must be expecting an `&mut`, +// and injects an auto-reborrow.) +impl Trait for T where T: From { + fn handle(_: U) -> Self { unimplemented!() } +} + +impl<'a, R> Trait<&'a mut Events> for Other { + fn handle(_: &'a mut Events) -> Self { unimplemented!() } +} + +fn this_compiles<'a, R>(value: &'a mut Events) { + for _ in 0..3 { + Other::handle(&mut *value); + } +} + +fn this_does_not<'a, R>(value: &'a mut Events) { + for _ in 0..3 { + Other::handle(&mut *value); //~ ERROR use of moved value: `value` + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.rs b/src/test/ui/borrowck/mut-borrow-in-loop-2.rs new file mode 100644 index 0000000000000..d13fb7e567939 --- /dev/null +++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.rs @@ -0,0 +1,35 @@ +// run-rustfix +#![allow(dead_code)] + +struct Events(R); + +struct Other; + +pub trait Trait { + fn handle(value: T) -> Self; +} + +// Blanket impl. (If you comment this out, compiler figures out that it +// is passing an `&mut` to a method that must be expecting an `&mut`, +// and injects an auto-reborrow.) +impl Trait for T where T: From { + fn handle(_: U) -> Self { unimplemented!() } +} + +impl<'a, R> Trait<&'a mut Events> for Other { + fn handle(_: &'a mut Events) -> Self { unimplemented!() } +} + +fn this_compiles<'a, R>(value: &'a mut Events) { + for _ in 0..3 { + Other::handle(&mut *value); + } +} + +fn this_does_not<'a, R>(value: &'a mut Events) { + for _ in 0..3 { + Other::handle(value); //~ ERROR use of moved value: `value` + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr new file mode 100644 index 0000000000000..fa1b741394acb --- /dev/null +++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr @@ -0,0 +1,17 @@ +error[E0382]: use of moved value: `value` + --> $DIR/mut-borrow-in-loop-2.rs:31:23 + | +LL | fn this_does_not<'a, R>(value: &'a mut Events) { + | ----- move occurs because `value` has type `&mut Events`, which does not implement the `Copy` trait +LL | for _ in 0..3 { +LL | Other::handle(value); + | ^^^^^ value moved here, in previous iteration of loop + | +help: consider creating a fresh reborrow of `value` here + | +LL | Other::handle(&mut *value); + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/consts/const-variant-count.rs b/src/test/ui/consts/const-variant-count.rs new file mode 100644 index 0000000000000..455419d2c7f1d --- /dev/null +++ b/src/test/ui/consts/const-variant-count.rs @@ -0,0 +1,47 @@ +// run-pass +#![allow(dead_code)] +#![feature(variant_count)] +#![feature(never_type)] + +use std::mem::variant_count; + +enum Void {} + +enum Foo { + A, + B, + C, +} + +enum Bar { + A, + B, + C, + D(usize), + E { field_1: usize, field_2: Foo }, +} + +struct Baz { + a: u32, + b: *const u8, +} + +const TEST_VOID: usize = variant_count::(); +const TEST_FOO: usize = variant_count::(); +const TEST_BAR: usize = variant_count::(); + +const NO_ICE_STRUCT: usize = variant_count::(); +const NO_ICE_BOOL: usize = variant_count::(); +const NO_ICE_PRIM: usize = variant_count::<*const u8>(); + +fn main() { + assert_eq!(TEST_VOID, 0); + assert_eq!(TEST_FOO, 3); + assert_eq!(TEST_BAR, 5); + assert_eq!(variant_count::(), 0); + assert_eq!(variant_count::(), 3); + assert_eq!(variant_count::(), 5); + assert_eq!(variant_count::>(), 2); + assert_eq!(variant_count::>(), 2); + assert_eq!(variant_count::>(), 2); +} diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs index 12093837d2630..e15ed2e70b896 100644 --- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs @@ -2,8 +2,14 @@ #![deny(confusable_idents)] #![allow(uncommon_codepoints, non_upper_case_globals)] -const s: usize = 42; //~ ERROR identifier pair considered confusable +const s: usize = 42; fn main() { - let s = "rust"; + let s = "rust"; //~ ERROR identifier pair considered confusable + not_affected(); +} + +fn not_affected() { + let s1 = 1; + let sl = 'l'; } diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr index 40ee18acb3cd4..218f94f7b5829 100644 --- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr @@ -1,11 +1,11 @@ -error: identifier pair considered confusable between `s` and `s` - --> $DIR/lint-confusable-idents.rs:5:7 +error: identifier pair considered confusable between `s` and `s` + --> $DIR/lint-confusable-idents.rs:8:9 | LL | const s: usize = 42; - | ^^ + | -- this is where the previous identifier occurred ... LL | let s = "rust"; - | - this is where the previous identifier occurred + | ^ | note: the lint level is defined here --> $DIR/lint-confusable-idents.rs:2:9 diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs new file mode 100644 index 0000000000000..a5b45466da5ca --- /dev/null +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs @@ -0,0 +1,20 @@ +// check-pass +#![feature(non_ascii_idents)] +#![deny(mixed_script_confusables)] + +struct ΑctuallyNotLatin; + +fn main() { + let λ = 42; // this usage of Greek confirms that Greek is used intentionally. +} + +mod роре { + const エ: &'static str = "アイウ"; + + // this usage of Katakana confirms that Katakana is used intentionally. + fn ニャン() { + let д: usize = 100; // this usage of Cyrillic confirms that Cyrillic is used intentionally. + + println!("meow!"); + } +} diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs new file mode 100644 index 0000000000000..4637b03f250de --- /dev/null +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs @@ -0,0 +1,15 @@ +#![feature(non_ascii_idents)] +#![deny(mixed_script_confusables)] + +struct ΑctuallyNotLatin; +//~^ ERROR The usage of Script Group `Greek` in this crate consists solely of + +fn main() { + let v = ΑctuallyNotLatin; +} + +mod роре { +//~^ ERROR The usage of Script Group `Cyrillic` in this crate consists solely of + const エ: &'static str = "アイウ"; + //~^ ERROR The usage of Script Group `Japanese, Katakana` in this crate consists solely of +} diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr new file mode 100644 index 0000000000000..6f75a1ece3766 --- /dev/null +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr @@ -0,0 +1,34 @@ +error: The usage of Script Group `Greek` in this crate consists solely of mixed script confusables + --> $DIR/lint-mixed-script-confusables.rs:4:8 + | +LL | struct ΑctuallyNotLatin; + | ^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-mixed-script-confusables.rs:2:9 + | +LL | #![deny(mixed_script_confusables)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: The usage includes 'Α' (U+0391). + = note: Please recheck to make sure their usages are indeed what you want. + +error: The usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables + --> $DIR/lint-mixed-script-confusables.rs:11:5 + | +LL | mod роре { + | ^^^^ + | + = note: The usage includes 'е' (U+0435), 'о' (U+043E), 'р' (U+0440). + = note: Please recheck to make sure their usages are indeed what you want. + +error: The usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables + --> $DIR/lint-mixed-script-confusables.rs:13:11 + | +LL | const エ: &'static str = "アイウ"; + | ^^ + | + = note: The usage includes 'エ' (U+30A8). + = note: Please recheck to make sure their usages are indeed what you want. + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.rs index 057329a0a650c..20d00cf701a15 100644 --- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.rs +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.rs @@ -7,5 +7,7 @@ fn coöperation() {} //~ ERROR identifier contains non-ASCII characters fn main() { let naïveté = 2; //~ ERROR identifier contains non-ASCII characters - println!("{}", naïveté); //~ ERROR identifier contains non-ASCII characters + + // using the same identifier the second time won't trigger the lint. + println!("{}", naïveté); } diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.stderr index 6c9f0866c017a..048b6ff5d687f 100644 --- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.stderr +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.stderr @@ -22,11 +22,5 @@ error: identifier contains non-ASCII characters LL | let naïveté = 2; | ^^^^^^^ -error: identifier contains non-ASCII characters - --> $DIR/lint-non-ascii-idents.rs:10:20 - | -LL | println!("{}", naïveté); - | ^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs index 7ac0d035d5bf1..b5e251e047b5a 100644 --- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs @@ -7,5 +7,7 @@ fn dijkstra() {} //~ ERROR identifier contains uncommon Unicode codepoints fn main() { let ㇻㇲㇳ = "rust"; //~ ERROR identifier contains uncommon Unicode codepoints - println!("{}", ㇻㇲㇳ); //~ ERROR identifier contains uncommon Unicode codepoints + + // using the same identifier the second time won't trigger the lint. + println!("{}", ㇻㇲㇳ); } diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr index b270bd1f051c2..05ea3d5de7dbc 100644 --- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr @@ -22,11 +22,5 @@ error: identifier contains uncommon Unicode codepoints LL | let ㇻㇲㇳ = "rust"; | ^^^^^^ -error: identifier contains uncommon Unicode codepoints - --> $DIR/lint-uncommon-codepoints.rs:10:20 - | -LL | println!("{}", ㇻㇲㇳ); - | ^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr index fb8562d00ead1..952985fcddee6 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr @@ -8,6 +8,10 @@ LL | consume(node) + r | ^^^^ value used here after partial move | = note: move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `node.next.0` + | +LL | Some(ref right) => consume(right), + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr index 2b15da3710e62..4f36a4ccab28f 100644 --- a/src/test/ui/nll/issue-53807.stderr +++ b/src/test/ui/nll/issue-53807.stderr @@ -5,6 +5,10 @@ LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `maybe.0` + | +LL | if let Some(ref thing) = maybe { + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/byte-string-literals.stderr b/src/test/ui/parser/byte-string-literals.stderr index ca964cd4b8f21..9be9064414796 100644 --- a/src/test/ui/parser/byte-string-literals.stderr +++ b/src/test/ui/parser/byte-string-literals.stderr @@ -22,7 +22,7 @@ error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte LL | b"é"; | ^ -error: unterminated double quote byte string +error[E0766]: unterminated double quote byte string --> $DIR/byte-string-literals.rs:7:6 | LL | b"a @@ -32,3 +32,4 @@ LL | | } error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0766`. diff --git a/src/test/ui/parser/issue-62524.rs b/src/test/ui/parser/issue-62524.rs index 57de4b87b0fe6..5259dfe2e656c 100644 --- a/src/test/ui/parser/issue-62524.rs +++ b/src/test/ui/parser/issue-62524.rs @@ -1,4 +1,6 @@ // ignore-tidy-trailing-newlines // error-pattern: aborting due to 3 previous errors +#![allow(uncommon_codepoints)] + y![ Ϥ, \ No newline at end of file diff --git a/src/test/ui/parser/issue-62524.stderr b/src/test/ui/parser/issue-62524.stderr index 8191c9682cefd..d5e07622b11b9 100644 --- a/src/test/ui/parser/issue-62524.stderr +++ b/src/test/ui/parser/issue-62524.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-62524.rs:4:3 + --> $DIR/issue-62524.rs:6:3 | LL | y![ | - unclosed delimiter @@ -7,7 +7,7 @@ LL | Ϥ, | ^ error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-62524.rs:3:3 + --> $DIR/issue-62524.rs:5:3 | LL | y![ | ___^ @@ -24,7 +24,7 @@ LL | Ϥ,; | ^ error: cannot find macro `y` in this scope - --> $DIR/issue-62524.rs:3:1 + --> $DIR/issue-62524.rs:5:1 | LL | y![ | ^ diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index f2186b9298e68..8a6ea8e91a25a 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -46,6 +46,10 @@ LL | Some(_z @ ref _y) => {} | value moved here | = note: move occurs because value has type `X`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `x.0` + | +LL | Some(ref _z @ ref _y) => {} + | ^^^ error[E0382]: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19 @@ -57,6 +61,10 @@ LL | Some(_z @ ref mut _y) => {} | value moved here | = note: move occurs because value has type `X`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `x.0` + | +LL | Some(ref _z @ ref mut _y) => {} + | ^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index f819e671436ec..5058998f2a7c1 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -357,6 +357,10 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here | = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving the value + | +LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} + | ^^^ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 @@ -379,6 +383,10 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here | = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving the value + | +LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} + | ^^^ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30 @@ -412,6 +420,10 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here | = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving the value + | +LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} + | ^^^ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 @@ -434,6 +446,10 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here | = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving the value + | +LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} + | ^^^ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30 diff --git a/src/test/ui/ref-suggestion.stderr b/src/test/ui/ref-suggestion.stderr index 9ff8e21bb58bd..97d2c174d9adb 100644 --- a/src/test/ui/ref-suggestion.stderr +++ b/src/test/ui/ref-suggestion.stderr @@ -28,6 +28,10 @@ LL | x; | ^ value used here after partial move | = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `x.0.0` + | +LL | (Some(ref y), ()) => {}, + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/utf8_idents.rs b/src/test/ui/utf8_idents.rs index f59d5502aae30..6c54086cc2009 100644 --- a/src/test/ui/utf8_idents.rs +++ b/src/test/ui/utf8_idents.rs @@ -1,3 +1,5 @@ +#![allow(mixed_script_confusables)] + fn foo< 'β, //~ ERROR non-ascii idents are not fully supported γ //~ ERROR non-ascii idents are not fully supported diff --git a/src/test/ui/utf8_idents.stderr b/src/test/ui/utf8_idents.stderr index 877412df8fa1c..2fc0b1c39effb 100644 --- a/src/test/ui/utf8_idents.stderr +++ b/src/test/ui/utf8_idents.stderr @@ -1,5 +1,5 @@ error[E0658]: non-ascii idents are not fully supported - --> $DIR/utf8_idents.rs:2:5 + --> $DIR/utf8_idents.rs:4:5 | LL | 'β, | ^^ @@ -8,7 +8,7 @@ LL | 'β, = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable error[E0658]: non-ascii idents are not fully supported - --> $DIR/utf8_idents.rs:3:5 + --> $DIR/utf8_idents.rs:5:5 | LL | γ | ^ @@ -17,7 +17,7 @@ LL | γ = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable error[E0658]: non-ascii idents are not fully supported - --> $DIR/utf8_idents.rs:8:5 + --> $DIR/utf8_idents.rs:10:5 | LL | δ: usize | ^ @@ -26,7 +26,7 @@ LL | δ: usize = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable error[E0658]: non-ascii idents are not fully supported - --> $DIR/utf8_idents.rs:12:9 + --> $DIR/utf8_idents.rs:14:9 | LL | let α = 0.00001f64; | ^ @@ -35,7 +35,7 @@ LL | let α = 0.00001f64; = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable warning: type parameter `γ` should have an upper camel case name - --> $DIR/utf8_idents.rs:3:5 + --> $DIR/utf8_idents.rs:5:5 | LL | γ | ^ help: convert the identifier to upper camel case: `Γ` diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index e60e2a81e070b..e19a79dd8dad1 100755 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -476,7 +476,7 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool { && match (&l.kind, &r.kind) { (Lifetime, Lifetime) => true, (Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)), - (Const { ty: l }, Const { ty: r }) => eq_ty(l, r), + (Const { ty: l, kw_span: _ }, Const { ty: r, kw_span: _ }) => eq_ty(l, r), _ => false, } && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))