diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 29c1d34a125a4..6287f643b75fa 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1869,16 +1869,31 @@ impl StrLit { } } +#[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq)] +#[derive(HashStable_Generic)] +pub enum Sign { + /// A `-` in front of a literal. + Neg, + /// No sign. There are no leading `+` in front of literals. + None, +} + +impl Sign { + pub fn is_neg(&self) -> bool { + matches!(self, Self::Neg) + } +} + /// Type of the integer literal based on provided suffix. #[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq)] #[derive(HashStable_Generic)] pub enum LitIntType { /// e.g. `42_i32`. - Signed(IntTy), + Signed(IntTy, Sign), /// e.g. `42_u32`. Unsigned(UintTy), /// e.g. `42`. - Unsuffixed, + Unsuffixed(Sign), } /// Type of the float literal based on provided suffix. @@ -1913,7 +1928,7 @@ pub enum LitKind { Char(char), /// An integer literal (`1`). Int(Pu128, LitIntType), - /// A float literal (`1.0`, `1f64` or `1E10f64`). The pre-suffix part is + /// A float literal (`1.0`, `-1.0`, `1f64` or `1E10f64`). The pre-suffix part is /// stored as a symbol rather than `f64` so that `LitKind` can impl `Eq` /// and `Hash`. Float(Symbol, LitFloatType), @@ -1964,12 +1979,22 @@ impl LitKind { | LitKind::CStr(..) | LitKind::Byte(..) | LitKind::Char(..) - | LitKind::Int(_, LitIntType::Unsuffixed) + | LitKind::Int(_, LitIntType::Unsuffixed(_)) | LitKind::Float(_, LitFloatType::Unsuffixed) | LitKind::Bool(..) | LitKind::Err(_) => false, } } + + pub fn is_negative(&self) -> bool { + match self { + LitKind::Int(_, LitIntType::Signed(_, sign) | LitIntType::Unsuffixed(sign)) => { + sign.is_neg() + } + LitKind::Float(f, _) => f.as_str().starts_with('-'), + _ => false, + } + } } // N.B., If you change this, you'll probably want to change the corresponding diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 6896ac723fa58..d925a9ae663eb 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -8,6 +8,7 @@ use rustc_lexer::unescape::{ use rustc_span::{Span, Symbol, kw, sym}; use tracing::debug; +use crate::Sign; use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; use crate::token::{self, Token}; @@ -36,6 +37,7 @@ pub enum LitError { InvalidSuffix(Symbol), InvalidIntSuffix(Symbol), InvalidFloatSuffix(Symbol), + InvalidNegation(token::LitKind), NonDecimalFloat(u32), // u32 is the base IntTooLarge(u32), // u32 is the base } @@ -43,6 +45,13 @@ pub enum LitError { impl LitKind { /// Converts literal token into a semantic literal. pub fn from_token_lit(lit: token::Lit) -> Result { + Self::from_token_lit_maybe_negated(lit, Sign::None) + } + + /// Converts literal token into a semantic literal. + /// May optionally include a sign, and will error if a literal + /// other than integer or float literals is negated. + pub fn from_token_lit_maybe_negated(lit: token::Lit, sign: Sign) -> Result { let token::Lit { kind, symbol, suffix } = lit; if let Some(suffix) = suffix && !kind.may_have_suffix() @@ -50,6 +59,10 @@ impl LitKind { return Err(LitError::InvalidSuffix(suffix)); } + if sign.is_neg() && !matches!(kind, token::Integer | token::Float) { + return Err(LitError::InvalidNegation(kind)); + } + // For byte/char/string literals, chars and escapes have already been // checked in the lexer (in `cook_lexer_literal`). So we can assume all // chars and escapes are valid here. @@ -71,8 +84,8 @@ impl LitKind { // There are some valid suffixes for integer and float literals, // so all the handling is done internally. - token::Integer => return integer_lit(symbol, suffix), - token::Float => return float_lit(symbol, suffix), + token::Integer => return integer_lit(symbol, suffix, sign), + token::Float => return float_lit(symbol, suffix, sign), token::Str => { // If there are no characters requiring special treatment we can @@ -189,14 +202,21 @@ impl fmt::Display for LitKind { let symbol = str::from_utf8(bytes).unwrap(); write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?; } - LitKind::Int(n, ty) => { - write!(f, "{n}")?; - match ty { - ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?, - ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?, - ast::LitIntType::Unsuffixed => {} + LitKind::Int(n, ty) => match ty { + ast::LitIntType::Unsigned(ty) => write!(f, "{n}{}", ty.name())?, + ast::LitIntType::Signed(ty, sign) => { + if sign.is_neg() { + write!(f, "-")?; + } + write!(f, "{n}{}", ty.name())? } - } + ast::LitIntType::Unsuffixed(sign) => { + if sign.is_neg() { + write!(f, "-")?; + } + write!(f, "{n}")?; + } + }, LitKind::Float(symbol, ty) => { write!(f, "{symbol}")?; match ty { @@ -269,11 +289,14 @@ fn filtered_float_lit( symbol: Symbol, suffix: Option, base: u32, + sign: Sign, ) -> Result { - debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base); + debug!(?symbol, ?suffix, ?base, ?sign); if base != 10 { return Err(LitError::NonDecimalFloat(base)); } + let symbol = + if sign.is_neg() { Symbol::intern(&format!("-{}", symbol.as_str())) } else { symbol }; Ok(match suffix { Some(suffix) => LitKind::Float( symbol, @@ -289,12 +312,12 @@ fn filtered_float_lit( }) } -fn float_lit(symbol: Symbol, suffix: Option) -> Result { +fn float_lit(symbol: Symbol, suffix: Option, sign: Sign) -> Result { debug!("float_lit: {:?}, {:?}", symbol, suffix); - filtered_float_lit(strip_underscores(symbol), suffix, 10) + filtered_float_lit(strip_underscores(symbol), suffix, 10, sign) } -fn integer_lit(symbol: Symbol, suffix: Option) -> Result { +fn integer_lit(symbol: Symbol, suffix: Option, sign: Sign) -> Result { debug!("integer_lit: {:?}, {:?}", symbol, suffix); let symbol = strip_underscores(symbol); let s = symbol.as_str(); @@ -308,12 +331,12 @@ fn integer_lit(symbol: Symbol, suffix: Option) -> Result match suf { - sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize), - sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8), - sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16), - sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32), - sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64), - sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128), + sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize, sign), + sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8, sign), + sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16, sign), + sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32, sign), + sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64, sign), + sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128, sign), sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize), sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8), sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16), @@ -322,11 +345,18 @@ fn integer_lit(symbol: Symbol, suffix: Option) -> Result ast::LitIntType::Unsigned(ast::UintTy::U128), // `1f64` and `2f32` etc. are valid float literals, and // `fxxx` looks more like an invalid float literal than invalid integer literal. - _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base), + _ if suf.as_str().starts_with('f') => { + return filtered_float_lit(symbol, suffix, base, sign); + } _ => return Err(LitError::InvalidIntSuffix(suf)), }, - _ => ast::LitIntType::Unsuffixed, + _ => ast::LitIntType::Unsuffixed(sign), }; + if let ast::LitIntType::Unsigned(_) = ty + && sign.is_neg() + { + return Err(LitError::InvalidNegation(token::Integer)); + } let s = &s[if base != 10 { 2 } else { 0 }..]; u128::from_str_radix(s, base) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index efbd1711daa92..ffd642c93ed65 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -138,11 +138,26 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Binary(binop, lhs, rhs) } ExprKind::Unary(op, ohs) => { + if let UnOp::Neg = op { + if let ExprKind::Lit(token_lit) = &ohs.kind { + return hir::Expr { + hir_id: expr_hir_id, + kind: hir::ExprKind::Lit(self.lower_lit( + token_lit, + e.span, + Sign::Neg, + )), + span: self.lower_span(e.span), + }; + } + } let op = self.lower_unop(*op); let ohs = self.lower_expr(ohs); hir::ExprKind::Unary(op, ohs) } - ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)), + ExprKind::Lit(token_lit) => { + hir::ExprKind::Lit(self.lower_lit(token_lit, e.span, Sign::None)) + } ExprKind::IncludedBytes(bytes) => { let lit = self.arena.alloc(respan( self.lower_span(e.span), @@ -419,8 +434,9 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, token_lit: &token::Lit, span: Span, + sign: Sign, ) -> &'hir Spanned { - let lit_kind = match LitKind::from_token_lit(*token_lit) { + let lit_kind = match LitKind::from_token_lit_maybe_negated(*token_lit, sign) { Ok(lit_kind) => lit_kind, Err(err) => { let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span); diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 07b94dbc2aebd..9e9fdbc8b5cf0 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -30,12 +30,13 @@ impl<'hir> LoweringContext<'_, 'hir> { Ok(LitKind::Int(n, ty)) => { match ty { // unsuffixed integer literals are assumed to be i32's - LitIntType::Unsuffixed => { - (n <= i32::MAX as u128).then_some(Symbol::intern(&n.to_string())) - } - LitIntType::Signed(int_ty) => { + LitIntType::Unsuffixed(sign) => (matches!(sign, Sign::None) + && n <= i32::MAX as u128) + .then_some(Symbol::intern(&n.to_string())), + LitIntType::Signed(int_ty, sign) => { let max_literal = self.int_ty_max(int_ty); - (n <= max_literal).then_some(Symbol::intern(&n.to_string())) + (matches!(sign, Sign::None) && n <= max_literal) + .then_some(Symbol::intern(&n.to_string())) } LitIntType::Unsigned(uint_ty) => { let max_literal = self.uint_ty_max(uint_ty); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2dcfe7c745da5..25e8288859ba7 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -391,18 +391,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let span = self.lower_span(expr.span); let err = |guar| hir::PatExprKind::Lit { lit: self.arena.alloc(respan(span, LitKind::Err(guar))), - negated: false, }; let kind = match &expr.kind { ExprKind::Lit(lit) => { - hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false } + hir::PatExprKind::Lit { lit: self.lower_lit(lit, span, Sign::None) } } ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)), ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit { lit: self .arena .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))), - negated: false, }, ExprKind::Err(guar) => err(*guar), ExprKind::Dummy => span_bug!(span, "lowered ExprKind::Dummy"), @@ -416,7 +414,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None, )), ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => { - hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true } + hir::PatExprKind::Lit { lit: self.lower_lit(lit, span, Sign::Neg) } } _ => { let pattern_from_macro = expr.is_approximately_pattern(); diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 26ca637faec68..4c676798f7f05 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,5 +1,5 @@ use rustc_abi::Align; -use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; +use rustc_ast::{IntTy, LitIntType, LitKind, Sign, UintTy}; use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; use rustc_span::{Span, Symbol, sym}; @@ -225,7 +225,7 @@ fn parse_repr_align( } fn parse_alignment(node: &LitKind) -> Result { - if let LitKind::Int(literal, LitIntType::Unsuffixed) = node { + if let LitKind::Int(literal, LitIntType::Unsuffixed(Sign::None)) = node { // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first if literal.get().is_power_of_two() { // Only possible error is larger than 2^29 diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 9d34b807ac2fe..cd9d3a4e49d8b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -320,7 +320,7 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> { name: &'a str, #[skip_arg] - int: u128, + int: String, }, #[suggestion( @@ -342,11 +342,13 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> { impl<'a> IncorrectReprFormatGenericCause<'a> { pub(crate) fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option { - match kind { - ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - Some(Self::Int { span, name, int: int.get() }) - } - ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }), + match *kind { + ast::LitKind::Int(int, ast::LitIntType::Unsuffixed(sign)) => Some(Self::Int { + span, + name, + int: if sign.is_neg() { format!("-{}", int.get()) } else { int.get().to_string() }, + }), + ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol }), _ => None, } } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 456f2b9ab31de..12ea2807eddae 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ExprKind, LitIntType, LitKind, UintTy, token}; +use rustc_ast::{ExprKind, LitIntType, LitKind, Sign, UintTy, token}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_session::errors::report_lit_error; use rustc_span::{ErrorGuaranteed, Span}; @@ -51,7 +51,10 @@ fn invalid_type_err( snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet }); dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) } - Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => { + Ok(LitKind::Int( + val, + LitIntType::Unsuffixed(Sign::None) | LitIntType::Unsigned(UintTy::U8), + )) => { assert!(val.get() > u8::MAX.into()); // must be an error dcx.emit_err(ConcatBytesOob { span }) } @@ -79,7 +82,7 @@ fn handle_array_element( match LitKind::from_token_lit(token_lit) { Ok(LitKind::Int( val, - LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8), + LitIntType::Unsuffixed(Sign::None) | LitIntType::Unsigned(UintTy::U8), )) if let Ok(val) = u8::try_from(val.get()) => { return Some(val); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 673740b4aab9f..63e1d72348824 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -4,7 +4,7 @@ use rustc_abi::ExternAbi; use rustc_ast::expand::autodiff_attrs::{ AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, }; -use rustc_ast::{MetaItem, MetaItemInner, attr}; +use rustc_ast::{MetaItem, MetaItemInner, Sign, attr}; use rustc_attr_parsing::ReprAttr::ReprAlign; use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::fx::FxHashMap; @@ -750,8 +750,10 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option { tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span() }); return None; }; - if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = - sole_meta_list.lit() + if let Some(MetaItemLit { + kind: LitKind::Int(ordinal, LitIntType::Unsuffixed(Sign::None)), + .. + }) = sole_meta_list.lit() { // According to the table at // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 1ccb070f83a4b..085dd48f3679f 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -1,6 +1,6 @@ use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenStreamIter, TokenTree}; -use rustc_ast::{LitIntType, LitKind}; +use rustc_ast::{LitIntType, LitKind, Sign}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, PResult}; use rustc_macros::{Decodable, Encodable}; @@ -191,7 +191,7 @@ fn parse_depth<'psess>( .struct_span_err(span, "meta-variable expression depth must be a literal")); }; if let Ok(lit_kind) = LitKind::from_token_lit(*lit) - && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind + && let LitKind::Int(n_u128, LitIntType::Unsuffixed(Sign::None)) = lit_kind && let Ok(n_usize) = usize::try_from(n_u128.get()) { Ok(n_usize) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f0eaec55dbdd3..70c327a8f4d56 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -7,7 +7,7 @@ use rustc_ast::token::CommentKind; use rustc_ast::util::parser::{AssocOp, ExprPrecedence}; use rustc_ast::{ self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType, - LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, + LitKind, Sign, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, }; pub use rustc_ast::{ AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, @@ -1656,9 +1656,6 @@ pub struct PatExpr<'hir> { pub enum PatExprKind<'hir> { Lit { lit: &'hir Lit, - // FIXME: move this into `Lit` and handle negated literal expressions - // once instead of matching on unop neg expressions everywhere. - negated: bool, }, ConstBlock(ConstBlock), /// A path pattern for a unit struct/variant or a (maybe-associated) constant. @@ -2139,6 +2136,13 @@ impl Expr<'_> { | ExprKind::Let(..) | ExprKind::Unary(..) => ExprPrecedence::Prefix, + // `-1.foo()` is `-(1.foo())`, so negative literals must be treated as `(-1).foo()` + ExprKind::Lit(lit) => if lit.node.is_negative() { + ExprPrecedence::Prefix + } else { + ExprPrecedence::Unambiguous + }, + // Never need parens ExprKind::Array(_) | ExprKind::Block(..) @@ -2149,7 +2153,6 @@ impl Expr<'_> { | ExprKind::If(..) | ExprKind::Index(..) | ExprKind::InlineAsm(..) - | ExprKind::Lit(_) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::MethodCall(..) @@ -2242,7 +2245,10 @@ impl Expr<'_> { matches!( self.kind, ExprKind::Lit(Lit { - node: LitKind::Int(_, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::Usize)), + node: LitKind::Int( + _, + LitIntType::Unsuffixed(Sign::None) | LitIntType::Unsigned(UintTy::Usize) + ), .. }) ) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index d5fa7ec366b28..da1957a2b0d4b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -343,7 +343,7 @@ pub trait Visitor<'v>: Sized { fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result { walk_pat_expr(self, expr) } - fn visit_lit(&mut self, _hir_id: HirId, _lit: &'v Lit, _negated: bool) -> Self::Result { + fn visit_lit(&mut self, _hir_id: HirId, _lit: &'v Lit) -> Self::Result { Self::Result::output() } fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { @@ -769,7 +769,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<' pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result { try_visit!(visitor.visit_id(expr.hir_id)); match &expr.kind { - PatExprKind::Lit { lit, negated } => visitor.visit_lit(expr.hir_id, lit, *negated), + PatExprKind::Lit { lit } => visitor.visit_lit(expr.hir_id, lit), PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c), PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span), } @@ -917,7 +917,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_expr(expr)); visit_opt!(visitor, visit_ty_unambig, ty); } - ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(expression.hir_id, lit, false)), + ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(expression.hir_id, lit)), ExprKind::Err(_) => {} } V::Result::output() diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f2331f3fd8e13..7d645d8fdccb3 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1534,6 +1534,7 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) && let hir::ExprKind::Lit(lit) = &tcx.hir_body(expr.body).value.kind && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node && *lit_value != dis.val + && (!lit.node.is_negative() && -(lit_value.get() as i128) != dis.val as i128) { (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)")) } else { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 750770178eef9..fbd347771fc67 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2276,11 +2276,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let lit_input = match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), - hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }), - _ => None, - }, + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty }), _ => None, }; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5c7426d76b31c..185fce1287549 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1852,12 +1852,7 @@ impl<'a> State<'a> { fn print_pat_expr(&mut self, expr: &hir::PatExpr<'_>) { match &expr.kind { - hir::PatExprKind::Lit { lit, negated } => { - if *negated { - self.word("-"); - } - self.print_literal(lit); - } + hir::PatExprKind::Lit { lit } => self.print_literal(lit), hir::PatExprKind::ConstBlock(c) => self.print_inline_const(c), hir::PatExprKind::Path(qpath) => self.print_qpath(qpath, true), } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4815627a0ce0b..7e244be7d6f7f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -6,6 +6,7 @@ //! See [`rustc_hir_analysis::check`] for more context on type checking in general. use rustc_abi::{FIRST_VARIANT, FieldIdx}; +use rustc_ast::Sign; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; @@ -504,7 +505,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; match expr.kind { - ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected), + ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expr.hir_id, expected), ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected), ExprKind::Assign(lhs, rhs, span) => { self.check_expr_assign(expr, expected, lhs, rhs, span) @@ -2983,7 +2984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let ty::Infer(ty::IntVar(_)) = base_ty.kind() && let ExprKind::Lit(Spanned { - node: ast::LitKind::Int(_, ast::LitIntType::Unsuffixed), + node: ast::LitKind::Int(_, ast::LitIntType::Unsuffixed(_)), .. }) = base.kind && !base.span.from_expansion() @@ -3529,7 +3530,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the index is an integer, we can show the actual // fixed expression: if let ExprKind::Lit(lit) = idx.kind - && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node + && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed(Sign::None)) = + lit.node && i.get() < types .len() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 63c1c0608274a..70e839c2e366f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1602,6 +1602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_expr_lit( &self, lit: &hir::Lit, + hir_id: HirId, expected: Expectation<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -1615,9 +1616,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ast::LitKind::Byte(_) => tcx.types.u8, ast::LitKind::Char(_) => tcx.types.char, - ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)), + ast::LitKind::Int(_, ast::LitIntType::Signed(t, _)) => Ty::new_int(tcx, ty::int_ty(t)), ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)), - ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { + ast::LitKind::Int(positive, ast::LitIntType::Unsuffixed(sign)) => { let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Int(_) | ty::Uint(_) => Some(ty), // These exist to direct casts like `0x61 as char` to use @@ -1628,7 +1629,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::FnDef(..) | ty::FnPtr(..) => Some(tcx.types.usize), _ => None, }); - opt_ty.unwrap_or_else(|| self.next_int_var()) + let ty = opt_ty.unwrap_or_else(|| self.next_int_var()); + + if sign.is_neg() { + let cast = if let hir::Node::Expr(parent) = self.tcx.parent_hir_node(hir_id) + && let hir::ExprKind::Cast(..) = parent.kind + { + // `-1 as usize` -> `usize::MAX` + Some(parent.span) + } else { + None + }; + + self.register_bound( + ty, + self.tcx.require_lang_item(hir::LangItem::Neg, Some(lit.span)), + traits::ObligationCause::new( + lit.span, + self.body_id, + ObligationCauseCode::NegLit { cast, positive: positive.get() }, + ), + ); + } + ty } ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => { Ty::new_float(tcx, ty::float_ty(t)) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 35a3491f7c089..4e7fa60367ff9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2,6 +2,7 @@ use core::cmp::min; use core::iter; use hir::def_id::LocalDefId; +use rustc_ast::Sign; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::packed::Pu128; use rustc_errors::{Applicability, Diag, MultiSpan, listify}; @@ -1599,7 +1600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } ExprKind::Lit(Spanned { - node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed), + node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed(Sign::None)), span, }) => { let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { @@ -3058,13 +3059,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`", ); - let close_paren = if expr.precedence() < ExprPrecedence::Unambiguous { - sugg.push((expr.span.shrink_to_lo(), "(".to_string())); - ")" - } else { - "" + let is_negative_int = |expr: &hir::Expr<'_>| match expr.kind { + hir::ExprKind::Unary(hir::UnOp::Neg, ..) => true, + hir::ExprKind::Lit(lit) => lit.node.is_negative(), + _ => false, }; + let close_paren = + if expr.precedence() < ExprPrecedence::Unambiguous || is_negative_int(expr) { + sugg.push((expr.span.shrink_to_lo(), "(".to_string())); + ")" + } else { + "" + }; + let mut cast_suggestion = sugg.clone(); cast_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren} as {expected_ty}"))); let mut into_suggestion = sugg.clone(); @@ -3091,10 +3099,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, )); let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| { - if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false } + if let hir::ExprKind::Lit(lit) = &expr.kind { + lit.node.is_suffixed() && !lit.node.is_negative() + } else { + false + } }; - let is_negative_int = - |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Neg, ..)); let is_uint = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(..)); let in_const_context = self.tcx.hir_is_inside_const_context(expr.hir_id); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index bd0848b991661..ce6f2bf22f380 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2,7 +2,7 @@ use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; use rustc_abi::FieldIdx; -use rustc_ast as ast; +use rustc_ast::{self as ast}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ @@ -582,16 +582,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> { let ty = match <.kind { - rustc_hir::PatExprKind::Lit { lit, negated } => { - let ty = self.check_expr_lit(lit, Expectation::NoExpectation); - if *negated { - self.register_bound( - ty, - self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)), - ObligationCause::dummy_with_span(lt.span), - ); - } - ty + rustc_hir::PatExprKind::Lit { lit } => { + self.check_expr_lit(lit, lt.hir_id, Expectation::NoExpectation) } rustc_hir::PatExprKind::ConstBlock(c) => { self.check_expr_const_block(c, Expectation::NoExpectation) diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 4fc903cf68b88..99ed88233a694 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -1,3 +1,4 @@ +use rustc_ast::{LitIntType, Sign}; use rustc_errors::Applicability; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::infer::InferOk; @@ -117,13 +118,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr, base_expr, adjusted_ty, index_ty ); - if let hir::ExprKind::Unary( - hir::UnOp::Neg, - hir::Expr { - kind: hir::ExprKind::Lit(hir::Lit { node: ast::LitKind::Int(..), .. }), - .. - }, - ) = index_expr.kind + if let hir::ExprKind::Lit(hir::Lit { + node: ast::LitKind::Int(_, LitIntType::Unsuffixed(Sign::Neg)), + .. + }) = index_expr.kind { match adjusted_ty.kind() { ty::Adt(def, _) if self.tcx.is_diagnostic_item(sym::Vec, def.did()) => { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 679367634276d..1d4ccd5dfa649 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -636,7 +636,7 @@ lint_out_of_scope_macro_calls = cannot find macro `{$path}` in the current scope lint_overflowing_bin_hex = literal out of range for `{$ty}` .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` - .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` + .negative_becomes_note = and the value `{$lit}` will become `{$actually}{$ty}` .positive_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` .suggestion = consider using the type `{$suggestion_ty}` instead .sign_bit_suggestion = to use as a negative number (decimal `{$negative_val}`), consider using the type `{$uint_ty}` for the literal and cast it to `{$int_ty}` diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index d22515d62d60e..d14b7dd85f891 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -152,8 +152,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_pat(self, p); } - fn visit_lit(&mut self, hir_id: HirId, lit: &'tcx hir::Lit, negated: bool) { - lint_callback!(self, check_lit, hir_id, lit, negated); + fn visit_lit(&mut self, hir_id: HirId, lit: &'tcx hir::Lit) { + lint_callback!(self, check_lit, hir_id, lit); } fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 409a23d1da039..343e20ccac080 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -23,7 +23,7 @@ macro_rules! late_lint_methods { fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>); fn check_arm(a: &'tcx rustc_hir::Arm<'tcx>); fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>); - fn check_lit(hir_id: rustc_hir::HirId, a: &'tcx rustc_hir::Lit, negated: bool); + fn check_lit(hir_id: rustc_hir::HirId, a: &'tcx rustc_hir::Lit); fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>); fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>); fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index cb83d405cc3ed..dfb7ff8753343 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -536,18 +536,8 @@ fn lint_fn_pointer<'tcx>( } impl<'tcx> LateLintPass<'tcx> for TypeLimits { - fn check_lit( - &mut self, - cx: &LateContext<'tcx>, - hir_id: HirId, - lit: &'tcx hir::Lit, - negated: bool, - ) { - if negated { - self.negated_expr_id = Some(hir_id); - self.negated_expr_span = Some(lit.span); - } - lint_literal(cx, self, hir_id, lit.span, lit, negated); + fn check_lit(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, lit: &'tcx hir::Lit) { + lint_literal(cx, self, hir_id, lit.span, lit); } fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) { @@ -636,8 +626,12 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { hir::ExprKind::Lit(li) => match li.node { ast::LitKind::Int( v, - ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed, - ) => v.get() as i128, + ast::LitIntType::Signed(_, sign) + | ast::LitIntType::Unsuffixed(sign), + ) => { + let v = v.get() as i128; + if sign.is_neg() { v.wrapping_neg() } else { v } + } _ => return true, }, _ => bug!(), diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index 3e4532a6dbeef..e3387ce9da136 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -54,9 +54,9 @@ fn lint_overflowing_range_endpoint<'tcx>( use rustc_ast::{LitIntType, LitKind}; let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Signed(s, _)) => s.name_str(), LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsuffixed) => "", + LitKind::Int(_, LitIntType::Unsuffixed(_)) => "", _ => bug!(), }; @@ -115,12 +115,16 @@ pub(crate) fn uint_ty_range(uint_ty: ty::UintTy) -> (u128, u128) { fn get_bin_hex_repr(cx: &LateContext<'_>, lit: &hir::Lit) -> Option { let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?; - let firstch = src.chars().next()?; + let mut chars = src.chars(); + let mut firstch = chars.next()?; + + if firstch == '-' { + firstch = chars.next()?; + } if firstch == '0' { - match src.chars().nth(1) { - Some('x' | 'b') => return Some(src), - _ => return None, + if let 'x' | 'b' = chars.next()? { + return Some(src); } } @@ -279,11 +283,8 @@ fn lint_int_literal<'tcx>( } let span = if negative { type_limits.negated_expr_span.unwrap() } else { span }; - let lit = cx - .sess() - .source_map() - .span_to_snippet(span) - .unwrap_or_else(|_| if negative { format!("-{v}") } else { v.to_string() }); + let lit = if negative { format!("-{v}") } else { v.to_string() }; + // FIXME: Don't suggest unsigned types for negative literals let help = get_type_suggestion(cx.typeck_results().node_type(hir_id), v, negative) .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); @@ -304,10 +305,10 @@ fn lint_uint_literal<'tcx>( ) { let uint_type = t.normalize(cx.sess().target.pointer_width); let (min, max) = uint_ty_range(uint_type); - let lit_val: u128 = match lit.node { + let lit_val = match lit.node { // _v is u8, within range by definition ast::LitKind::Byte(_v) => return, - ast::LitKind::Int(v, _) => v.get(), + ast::LitKind::Int(v, _lit) => v.get(), _ => bug!(), }; @@ -340,7 +341,7 @@ fn lint_uint_literal<'tcx>( Integer::from_uint_ty(cx, t).size(), repr_str, lit_val, - false, + lit.node.is_negative(), ); return; } @@ -363,25 +364,36 @@ fn lint_uint_literal<'tcx>( pub(crate) fn lint_literal<'tcx>( cx: &LateContext<'tcx>, - type_limits: &TypeLimits, + type_limits: &mut TypeLimits, hir_id: HirId, span: Span, lit: &hir::Lit, - negated: bool, ) { match *cx.typeck_results().node_type(hir_id).kind() { ty::Int(t) => { match lit.node { - ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { + ast::LitKind::Int( + v, + ast::LitIntType::Signed(_, sign) | ast::LitIntType::Unsuffixed(sign), + ) => { + let mut span = span; + if sign.is_neg() { + if type_limits.negated_expr_id == Some(hir_id) { + // Double negation is just the value again, so we treat it + // as if there were no negations for oflo lint purposes. + type_limits.negated_expr_id = None; + span = type_limits.negated_expr_span.take().unwrap(); + } else { + type_limits.negated_expr_id = Some(hir_id); + type_limits.negated_expr_span = Some(span); + } + } lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get()) } _ => bug!(), }; } - ty::Uint(t) => { - assert!(!negated); - lint_uint_literal(cx, hir_id, span, lit, t) - } + ty::Uint(t) => lint_uint_literal(cx, hir_id, span, lit, t), ty::Float(t) => { let (is_infinite, sym) = match lit.node { ast::LitKind::Float(v, _) => match t { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 88a88847e6b8b..d05705018ca68 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2423,9 +2423,6 @@ pub fn rendered_const<'tcx>(tcx: TyCtxt<'tcx>, body: &hir::Body<'_>, def_id: Loc fn classify(expr: &hir::Expr<'_>) -> Classification { match &expr.kind { - hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - if matches!(expr.kind, hir::ExprKind::Lit(_)) { Literal } else { Complex } - } hir::ExprKind::Lit(_) => Literal, hir::ExprKind::Tup([]) => Simple, hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(expr), .. }, _) => { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index c48cfffa05cc4..c8a4768146fdf 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -80,8 +80,6 @@ pub struct LitToConstInput<'tcx> { pub lit: &'tcx LitKind, /// The type of the constant. pub ty: Ty<'tcx>, - /// If the constant is negative. - pub neg: bool, } #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e5592de81cd78..2f2c4a28af6af 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -499,7 +499,6 @@ pub enum ExprKind<'tcx> { /// A literal. Literal { lit: &'tcx hir::Lit, - neg: bool, }, /// For literals that don't correspond to anything in the HIR NonHirLiteral { diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index a9df4d1625be3..759957962f034 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -145,7 +145,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( movability: _, fake_reads: _, }) => {} - Literal { lit: _, neg: _ } => {} + Literal { lit: _ } => {} NonHirLiteral { lit: _, user_ty: _ } => {} ZstLiteral { user_ty: _ } => {} NamedConst { def_id: _, args: _, user_ty: _ } => {} diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index d033ecc75dbe5..0cf14075da2d7 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -13,9 +13,8 @@ use std::hash::{Hash, Hasher}; use std::sync::Arc; use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed}; -use rustc_hir as hir; -use rustc_hir::HirId; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, HirId}; use rustc_macros::{ Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, }; @@ -393,6 +392,17 @@ pub enum ObligationCauseCode<'tcx> { output_ty: Option>, }, + /// A negated literal being checked for whether the type implements `Neg`. + NegLit { + /// `Some` if this was a `-1 as type` cast. + /// Spans the entire cast. + cast: Option, + /// Positive value of the literal + #[type_visitable(ignore)] + #[type_foldable(identity)] + positive: u128, + }, + AscribeUserTypeProvePredicate(Span), RustCall, diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index 91e284604b68c..a71cfd65af800 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -248,7 +248,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { }, ); let name = parse_by_kind!(self, name, _, "debuginfo", - ExprKind::Literal { lit, neg: false } => lit, + ExprKind::Literal { lit } => lit, ); let Some(name) = name.node.str() else { return Err(ParseError { diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 84c9297e65898..5ce284ddd5f7d 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -1,7 +1,7 @@ //! See docs in build/expr/mod.rs use rustc_abi::Size; -use rustc_ast as ast; +use rustc_ast::{self as ast, LitIntType, Sign}; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{Allocation, CTFE_ALLOC_SALT, LitToConstInput, Scalar}; use rustc_middle::mir::*; @@ -48,8 +48,8 @@ pub(crate) fn as_constant_inner<'tcx>( ) -> ConstOperand<'tcx> { let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; match *kind { - ExprKind::Literal { lit, neg } => { - let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }); + ExprKind::Literal { lit } => { + let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty }); ConstOperand { span, user_ty: None, const_ } } @@ -99,7 +99,7 @@ pub(crate) fn as_constant_inner<'tcx>( #[instrument(skip(tcx, lit_input))] fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> { - let LitToConstInput { lit, ty, neg } = lit_input; + let LitToConstInput { lit, ty } = lit_input; if let Err(guar) = ty.error_reported() { return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)); @@ -144,14 +144,18 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) } - (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => trunc(n.get(), *ui), - (ast::LitKind::Int(n, _), ty::Int(i)) => trunc( - if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }, + ( + ast::LitKind::Int(n, LitIntType::Unsigned(_) | LitIntType::Unsuffixed(Sign::None)), + ty::Uint(ui), + ) => trunc(n.get(), *ui), + ( + &ast::LitKind::Int(n, LitIntType::Signed(_, sign) | LitIntType::Unsuffixed(sign)), + ty::Int(i), + ) => trunc( + if sign.is_neg() { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }, i.to_unsigned(), ), - (ast::LitKind::Float(n, _), ty::Float(fty)) => { - parse_float_into_constval(*n, *fty, neg).unwrap() - } + (ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty).unwrap(), (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), (ast::LitKind::Err(guar), _) => { diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 949559549345f..8f34350afc569 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -1043,32 +1043,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -fn parse_float_into_constval<'tcx>( - num: Symbol, - float_ty: ty::FloatTy, - neg: bool, -) -> Option> { - parse_float_into_scalar(num, float_ty, neg).map(|s| ConstValue::Scalar(s.into())) +fn parse_float_into_constval<'tcx>(num: Symbol, float_ty: ty::FloatTy) -> Option> { + parse_float_into_scalar(num, float_ty).map(|s| ConstValue::Scalar(s.into())) } -pub(crate) fn parse_float_into_scalar( - num: Symbol, - float_ty: ty::FloatTy, - neg: bool, -) -> Option { +pub(crate) fn parse_float_into_scalar(num: Symbol, float_ty: ty::FloatTy) -> Option { let num = num.as_str(); match float_ty { // FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64` ty::FloatTy::F16 => { - let mut f = num.parse::().ok()?; - if neg { - f = -f; - } + let f = num.parse::().ok()?; Some(ScalarInt::from(f)) } ty::FloatTy::F32 => { let Ok(rust_f) = num.parse::() else { return None }; - let mut f = num + let f = num .parse::() .unwrap_or_else(|e| panic!("apfloat::ieee::Single failed to parse `{num}`: {e:?}")); @@ -1083,15 +1072,11 @@ pub(crate) fn parse_float_into_scalar( rust_f.to_bits() ); - if neg { - f = -f; - } - Some(ScalarInt::from(f)) } ty::FloatTy::F64 => { let Ok(rust_f) = num.parse::() else { return None }; - let mut f = num + let f = num .parse::() .unwrap_or_else(|e| panic!("apfloat::ieee::Double failed to parse `{num}`: {e:?}")); @@ -1106,18 +1091,11 @@ pub(crate) fn parse_float_into_scalar( rust_f.to_bits() ); - if neg { - f = -f; - } - Some(ScalarInt::from(f)) } // FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64` ty::FloatTy::F128 => { - let mut f = num.parse::().ok()?; - if neg { - f = -f; - } + let f = num.parse::().ok()?; Some(ScalarInt::from(f)) } } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b3210813703ca..f53ea94eaab36 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,5 +1,5 @@ use rustc_abi::Size; -use rustc_ast::{self as ast}; +use rustc_ast::{self as ast, LitIntType, Sign}; use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::interpret::LitToConstInput; @@ -12,7 +12,7 @@ pub(crate) fn lit_to_const<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, ) -> ty::Const<'tcx> { - let LitToConstInput { lit, ty, neg } = lit_input; + let LitToConstInput { lit, ty } = lit_input; if let Err(guar) = ty.error_reported() { return ty::Const::new_error(tcx, guar); @@ -55,20 +55,26 @@ pub(crate) fn lit_to_const<'tcx>( let bytes = data as &[u8]; ty::ValTree::from_raw_bytes(tcx, bytes) } - (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => { + ( + ast::LitKind::Int(n, LitIntType::Unsigned(_) | LitIntType::Unsuffixed(Sign::None)), + ty::Uint(ui), + ) => { let scalar_int = trunc(n.get(), *ui); ty::ValTree::from_scalar_int(tcx, scalar_int) } - (ast::LitKind::Int(n, _), ty::Int(i)) => { + ( + &ast::LitKind::Int(n, LitIntType::Signed(_, sign) | LitIntType::Unsuffixed(sign)), + ty::Int(i), + ) => { let scalar_int = trunc( - if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }, + if sign.is_neg() { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }, i.to_unsigned(), ); ty::ValTree::from_scalar_int(tcx, scalar_int) } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, (*b).into()), (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = parse_float_into_scalar(*n, *fty, neg).unwrap_or_else(|| { + let bits = parse_float_into_scalar(*n, *fty).unwrap_or_else(|| { tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) }); ty::ValTree::from_scalar_int(tcx, bits) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 88877d05ffadf..599f1e6efdb8e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -492,7 +492,7 @@ impl<'tcx> ThirBuildCx<'tcx> { } } - hir::ExprKind::Lit(lit) => ExprKind::Literal { lit, neg: false }, + hir::ExprKind::Lit(lit) => ExprKind::Literal { lit }, hir::ExprKind::Binary(op, lhs, rhs) => { if self.typeck_results.is_method_call(expr) { @@ -561,8 +561,6 @@ impl<'tcx> ThirBuildCx<'tcx> { if self.typeck_results.is_method_call(expr) { let arg = self.mirror_expr(arg); self.overloaded_operator(expr, Box::new([arg])) - } else if let hir::ExprKind::Lit(lit) = arg.kind { - ExprKind::Literal { lit, neg: true } } else { ExprKind::Unary { op: UnOp::Neg, arg: self.mirror_expr(arg) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8dc3f998e0916..bb3af64c9ddfb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -179,12 +179,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // We need to inspect the original expression, because if we only inspect the output of // `eval_bits`, an overflowed value has already been wrapped around. // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint. - let hir::PatExprKind::Lit { lit, negated } = expr.kind else { + let hir::PatExprKind::Lit { lit } = expr.kind else { return Ok(()); }; let LitKind::Int(lit_val, _) = lit.node else { return Ok(()); }; + let negated = lit.node.is_negative(); let (min, max): (i128, u128) = match ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&self.tcx, *ity).size(); @@ -631,18 +632,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// - Inline const blocks (e.g. `const { 1 + 1 }`) /// - Literals, possibly negated (e.g. `-128u8`, `"hello"`) fn lower_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> { - let (lit, neg) = match &expr.kind { + let lit = match &expr.kind { hir::PatExprKind::Path(qpath) => { return self.lower_path(qpath, expr.hir_id, expr.span).kind; } hir::PatExprKind::ConstBlock(anon_const) => { return self.lower_inline_const(anon_const, expr.hir_id, expr.span); } - hir::PatExprKind::Lit { lit, negated } => (lit, *negated), + hir::PatExprKind::Lit { lit } => lit, }; let ct_ty = self.typeck_results.node_type(expr.hir_id); - let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; + let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index cd56d93afcf75..74d5fffb6d500 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -501,12 +501,8 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_closure_expr(&**closure_expr, depth_lvl + 2); print_indented!(self, "}", depth_lvl); } - Literal { lit, neg } => { - print_indented!( - self, - format!("Literal( lit: {:?}, neg: {:?})\n", lit, neg), - depth_lvl - ); + Literal { lit } => { + print_indented!(self, format!("Literal( lit: {lit:?} )\n"), depth_lvl); } NonHirLiteral { lit, user_ty } => { print_indented!(self, "NonHirLiteral {", depth_lvl); diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 74b8087e07769..8f967a4540fd0 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -64,6 +64,9 @@ session_invalid_int_literal_width = invalid width `{$width}` for integer literal session_invalid_literal_suffix = suffixes on {$kind} literals are invalid .label = invalid suffix `{$suffix}` +session_invalid_negation = cannot negate `{$kind}` literal + .note = only signed integer literals and float literals can be negated + session_invalid_num_literal_base_prefix = invalid base prefix for number literal .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase .suggestion = try making the prefix lowercase diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 71d8dbe44fed0..e98a072bf65dd 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -335,6 +335,15 @@ struct IntLiteralTooLarge { limit: String, } +#[derive(Diagnostic)] +#[diag(session_invalid_negation)] +#[note] +struct InvalidNegation { + #[primary_span] + span: Span, + kind: &'static str, +} + #[derive(Diagnostic)] #[diag(session_hexadecimal_float_literal_not_supported)] struct HexadecimalFloatLiteralNotSupported { @@ -440,6 +449,9 @@ pub fn report_lit_error( }; dcx.emit_err(IntLiteralTooLarge { span, limit }) } + LitError::InvalidNegation(kind) => { + dcx.emit_err(InvalidNegation { span, kind: kind.descr() }) + } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 596f794568c5d..08c6b899e1996 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -25,7 +25,9 @@ use rustc_middle::ty::print::{ }; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast}; use rustc_middle::{bug, span_bug}; +use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; +use rustc_type_ir::UintTy; use tracing::{debug, instrument}; use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; @@ -2747,6 +2749,51 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); self.suggest_tuple_wrapping(err, root_obligation, obligation); + + self.suggest_trailing_unop_to_binop(err, span, trait_predicate, obligation); + } + } + + fn suggest_trailing_unop_to_binop( + &self, + err: &mut Diag<'_>, + span: Span, + trait_predicate: ty::PolyTraitPredicate<'tcx>, + obligation: &PredicateObligation<'tcx>, + ) { + if Some(trait_predicate.def_id()) != self.tcx.lang_items().neg_trait() { + return; + } + let sp = self.tcx.sess.source_map().start_point(span).with_parent(None); + if let Some(sp) = self.tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) { + // If the previous expression was a block expression, suggest parentheses + // (turning this into a binary subtraction operation instead.) + // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs) + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); + return; + } + let self_ty = trait_predicate.self_ty().skip_binder(); + if let ty::Uint(u) = self_ty.kind() { + err.note("unsigned values cannot be negated"); + if let ObligationCauseCode::NegLit { cast, positive } = obligation.cause.code() { + let bitwidth = u.bit_width().unwrap_or(self.tcx.data_layout.pointer_size.bits()); + let shift = 128 - bitwidth; + let shifted = -(((*positive as i128) << shift) >> shift); + let trimmed = ((shifted as u128) << shift) >> shift; + let suggestion = if shifted.count_ones() == 128 { + format!("{self_ty}::MAX") + } else if let UintTy::U8 = u { + trimmed.to_string() + } else { + format!("0x{trimmed:x}") + }; + err.span_suggestion_verbose( + cast.unwrap_or(span), + format!("you may have meant to the wrapped-around value of type `{self_ty}`"), + suggestion, + Applicability::MaybeIncorrect, + ); + } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c7e71a626dc51..245feffcf4ca0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2691,6 +2691,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::CheckAssociatedTypeBounds { .. } | ObligationCauseCode::LetElse | ObligationCauseCode::BinOp { .. } + | ObligationCauseCode::NegLit { .. } | ObligationCauseCode::AscribeUserTypeProvePredicate(..) | ObligationCauseCode::DropImpl | ObligationCauseCode::ConstParam(_) diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index ece796b3c71ce..ba3b0297c546b 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -118,9 +118,9 @@ fn recurse_build<'tcx>( | &ExprKind::WrapUnsafeBinder { .. } => { todo!("FIXME(unsafe_binders)") } - &ExprKind::Literal { lit, neg } => { + &ExprKind::Literal { lit } => { let sp = node.span; - tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) + tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty }) } &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(tcx, lit); diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index fe7ff2d9ede6a..b7e17acbb5acf 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -663,6 +663,10 @@ rem_impl_float! { f16 f32 f64 f128 } /// ``` #[lang = "neg"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented( + message = "cannot apply unary operator `-` to type `{Self}`", + label = "cannot apply unary operator `-`" +)] #[doc(alias = "-")] pub trait Neg { /// The resulting type after applying the `-` operator. diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 26dc101e4b590..8cb8914e3932a 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,5 +1,5 @@ use rustc_ast::ast::LitIntType; -use rustc_ast::{MetaItemInner, MetaItemLit, Path, Safety, StrStyle}; +use rustc_ast::{MetaItemInner, MetaItemLit, Path, Safety, Sign, StrStyle}; use rustc_span::symbol::{Ident, kw}; use rustc_span::{DUMMY_SP, create_default_session_globals_then}; use thin_vec::thin_vec; @@ -325,7 +325,7 @@ fn test_parse_err() { assert!(Cfg::parse(&mi).is_err()); let five = Symbol::intern("5"); - let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed)); + let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed(Sign::None))); assert!(Cfg::parse(&mi).is_err()); }) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 34656b26ce28c..073267137b9d5 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -462,12 +462,6 @@ pub(crate) fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { if let hir::ExprKind::Lit(_) = &expr.kind { return true; } - - if let hir::ExprKind::Unary(hir::UnOp::Neg, expr) = &expr.kind - && let hir::ExprKind::Lit(_) = &expr.kind - { - return true; - } } false diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 95f64b74044b1..92a2dcb6ecf42 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -76,7 +76,7 @@ impl ApproxConstant { } impl<'tcx> LateLintPass<'tcx> for ApproxConstant { - fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) { + fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit) { match lit.node { LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"), diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 7885f171461d7..57eebc7777048 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -6,7 +6,7 @@ use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_t use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp}; +use rustc_hir::{Expr, ExprKind, Node, Path, QPath, TyKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; use std::ops::ControlFlow; @@ -99,7 +99,7 @@ pub(super) fn check<'tcx>( return false; } - if let Some(lit) = get_numeric_literal(cast_expr) { + if let ExprKind::Lit(lit) = cast_expr.kind { let literal_str = &cast_str; if let LitKind::Int(n, _) = lit.node @@ -118,7 +118,7 @@ pub(super) fn check<'tcx>( } match lit.node { - LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => { + LitKind::Int(_, LitIntType::Unsuffixed(_)) if cast_to.is_integral() => { lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to); return false; }, @@ -126,7 +126,7 @@ pub(super) fn check<'tcx>( lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to); return false; }, - LitKind::Int(_, LitIntType::Signed(_) | LitIntType::Unsigned(_)) + LitKind::Int(_, LitIntType::Signed(..) | LitIntType::Unsigned(_)) | LitKind::Float(_, LitFloatType::Suffixed(_)) if cast_from.kind() == cast_to.kind() => { @@ -214,20 +214,6 @@ fn lint_unnecessary_cast( ); } -fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> { - match expr.kind { - ExprKind::Lit(lit) => Some(lit), - ExprKind::Unary(UnOp::Neg, e) => { - if let ExprKind::Lit(lit) = e.kind { - Some(lit) - } else { - None - } - }, - _ => None, - } -} - /// Returns the mantissa bits wide of a fp type. /// Will return 0 if the type is not a fp fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 784214c29af9f..ecaf7fc763a24 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::numeric_literal; use clippy_utils::source::snippet_opt; +use rustc_ast::Sign; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt}; @@ -88,7 +89,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false))) && matches!( lit.node, - LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) + LitKind::Int(_, LitIntType::Unsuffixed(Sign::None)) | LitKind::Float(_, LitFloatType::Unsuffixed) ) { let (suffix, is_float) = match lit_ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs index 41d2b18803d95..7fb9718e37eeb 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -2,6 +2,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; +use rustc_ast::Sign; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; @@ -70,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { && clippy_utils::SpanlessEq::new(cx).eq_expr(l, target) && BinOpKind::Add == op1.node && let ExprKind::Lit(lit) = value.kind - && let LitKind::Int(Pu128(1), LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(Pu128(1), LitIntType::Unsuffixed(Sign::None)) = lit.node && block.expr.is_none() { let mut app = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index a5185d38e7c33..8d309d76e8313 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -1,5 +1,6 @@ use clippy_utils::ty::{has_iter_method, implements_trait}; use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; +use rustc_ast::Sign; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_expr, walk_local}; @@ -192,7 +193,7 @@ impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> { InitializeVisitorState::Declared(name, mut ty) => { if ty.is_none() { if let ExprKind::Lit(Spanned { - node: LitKind::Int(_, LitIntType::Unsuffixed), + node: LitKind::Int(_, LitIntType::Unsuffixed(Sign::None)), .. }) = rhs.kind { diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs index 04357cdd8f663..cd248ca238d61 100644 --- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs @@ -133,12 +133,9 @@ fn differ_by_one(small_expr: &Expr<'_>, large_expr: &Expr<'_>) -> bool { && let ExprKind::Lit(large) = large_expr.kind && let LitKind::Int(s, _) = small.node && let LitKind::Int(l, _) = large.node + && small.node.is_negative() == large.node.is_negative() { Some(l.get()) == s.get().checked_add(1) - } else if let ExprKind::Unary(UnOp::Neg, small_inner_expr) = small_expr.kind - && let ExprKind::Unary(UnOp::Neg, large_inner_expr) = large_expr.kind - { - differ_by_one(large_inner_expr, small_inner_expr) } else { false } @@ -179,18 +176,9 @@ fn build_suggestion( && matches!( lhs.kind, ExprKind::Lit(Spanned { - node: LitKind::Int(_, LitIntType::Unsuffixed), + node: LitKind::Int(_, LitIntType::Unsuffixed(_)), .. - }) | ExprKind::Unary( - UnOp::Neg, - Expr { - kind: ExprKind::Lit(Spanned { - node: LitKind::Int(_, LitIntType::Unsuffixed), - .. - }), - .. - } - ) + }) ) { format!("_{}", cx.typeck_results().expr_ty(rhs)) } else { diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 38106277a88fe..f9e95745f8fa9 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -202,14 +202,8 @@ fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { } fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange { - if let PatExprKind::Lit { - lit: start_lit, - negated: false, - } = &start.kind - && let PatExprKind::Lit { - lit: end_lit, - negated: false, - } = &end.kind + if let PatExprKind::Lit { lit: start_lit } = &start.kind + && let PatExprKind::Lit { lit: end_lit } = &end.kind { check_lit_range(start_lit, end_lit) } else { diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index bf4f2bff3195d..25b2792591d0f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -38,12 +38,12 @@ declare_clippy_lint! { declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]); fn expr_as_i128(expr: &PatExpr<'_>) -> Option { - if let PatExprKind::Lit { lit, negated } = expr.kind + if let PatExprKind::Lit { lit } = expr.kind && let LitKind::Int(num, _) = lit.node { // Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now. let n = i128::try_from(num.get()).ok()?; - Some(if negated { -n } else { n }) + Some(if lit.node.is_negative() { -n } else { n }) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 41e4c75f843e5..86b8e44135a8f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -317,7 +317,7 @@ impl<'a> NormalizedPat<'a> { }, PatKind::Expr(e) => match &e.kind { // TODO: Handle negative integers. They're currently treated as a wild match. - PatExprKind::Lit { lit, negated: false } => match lit.node { + PatExprKind::Lit { lit } if !lit.node.is_negative() => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), @@ -334,7 +334,7 @@ impl<'a> NormalizedPat<'a> { let start = match start { None => 0, Some(e) => match &e.kind { - PatExprKind::Lit { lit, negated: false } => match lit.node { + PatExprKind::Lit { lit } if !lit.node.is_negative() => match lit.node { LitKind::Int(val, _) => val.get(), LitKind::Char(val) => val.into(), LitKind::Byte(val) => val.into(), @@ -346,7 +346,7 @@ impl<'a> NormalizedPat<'a> { let (end, bounds) = match end { None => (u128::MAX, RangeEnd::Included), Some(e) => match &e.kind { - PatExprKind::Lit { lit, negated: false } => match lit.node { + PatExprKind::Lit { lit } if !lit.node.is_negative() => match lit.node { LitKind::Int(val, _) => (val.get(), bounds), LitKind::Char(val) => (val.into(), bounds), LitKind::Byte(val) => (val.into(), bounds), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index df1b83cbb516a..7f67f1961fe0f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -86,7 +86,7 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<( for arm in arms { if let PatKind::Expr(PatExpr { - kind: PatExprKind::Lit { lit, negated: false }, + kind: PatExprKind::Lit { lit }, .. }) = arm.pat.kind && let LitKind::Str(symbol, _) = lit.node diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs index 7e65d586110e5..2df16b5a80e7a 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -198,11 +198,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }, // Example: `5 => 5` (PatKind::Expr(pat_expr_expr), ExprKind::Lit(expr_spanned)) => { - if let PatExprKind::Lit { - lit: pat_spanned, - negated: false, - } = &pat_expr_expr.kind - { + if let PatExprKind::Lit { lit: pat_spanned } = &pat_expr_expr.kind { return pat_spanned.node == expr_spanned.node; } }, diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 722ea7042dd7f..28130baa06b77 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -75,7 +75,7 @@ fn find_match_true<'tcx>( message: &'static str, ) { if let PatKind::Expr(lit) = pat.kind - && let PatExprKind::Lit { lit, negated: false } = lit.kind + && let PatExprKind::Lit { lit } = lit.kind && let LitKind::Bool(pat_is_true) = lit.node { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 2f46eaaabb364..bf6b009a8e8ec 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -127,7 +127,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp let pat_ref_count = match pat.kind { // string literals are already a reference. PatKind::Expr(PatExpr { - kind: PatExprKind::Lit { lit, negated: false }, + kind: PatExprKind::Lit { lit }, .. }) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1, _ => pat_ref_count, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 13918ed11b87d..67e9aa5bee3f3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -112,6 +112,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { return Some(MinMax::Max); } + let check_min = check_min || lit.node.is_negative(); if check_min && value == minval { return Some(MinMax::Min); } @@ -125,12 +126,6 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { return r; } - if ty.is_signed() { - if let hir::ExprKind::Unary(hir::UnOp::Neg, val) = &expr.kind { - return check_lit(val, true); - } - } - None } @@ -141,12 +136,8 @@ enum Sign { } fn lit_sign(expr: &hir::Expr<'_>) -> Option { - if let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = &expr.kind { - if let hir::ExprKind::Lit(..) = &inner.kind { - return Some(Sign::Neg); - } - } else if let hir::ExprKind::Lit(..) = &expr.kind { - return Some(Sign::Pos); + if let hir::ExprKind::Lit(lit) = &expr.kind { + return Some(if lit.node.is_negative() { Sign::Neg } else { Sign::Pos }); } None diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs index d318462e58415..ef2916b4c8489 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs @@ -1,3 +1,4 @@ +use rustc_ast::Sign; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; @@ -41,7 +42,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // check if argument of `SeekFrom::Current` is `0` if let ExprKind::Lit(lit) = arg.kind - && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed(Sign::None)) = lit.node { return true; } diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7b1dd9e58c50e..112f1a62b5aad 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified}; +use rustc_ast::Sign; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; @@ -31,7 +32,7 @@ pub(super) fn check<'tcx>( && let Some(ctor_call_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Start), ctor_call_id) && let ExprKind::Lit(lit) = arg.kind - && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed(Sign::None)) = lit.node { let method_call_span = expr.span.with_lo(name_span.lo()); span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index f880f1f329ff7..6936d73adf2c9 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -411,9 +411,9 @@ impl MiscEarlyLints { let lit_kind = LitKind::from_token_lit(lit); if let Ok(LitKind::Int(value, lit_int_type)) = lit_kind { let suffix = match lit_int_type { - LitIntType::Signed(ty) => ty.name_str(), + LitIntType::Signed(ty, _) => ty.name_str(), LitIntType::Unsigned(ty) => ty.name_str(), - LitIntType::Unsuffixed => "", + LitIntType::Unsuffixed(_) => "", }; literal_suffix::check(cx, span, &lit_snip, suffix, "integer"); if lit_snip.starts_with("0x") { diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index 429afff9b6642..dc5397bce969f 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -1,10 +1,10 @@ -use clippy_utils::consts::{self, Constant}; +use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::has_enclosing_paren; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -40,28 +40,34 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::Binary(ref op, left, right) = e.kind { if BinOpKind::Mul == op.node { - match (&left.kind, &right.kind) { - (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {}, - (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right), - (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left), - _ => {}, - } + check_mul(cx, e.span, left, right); + check_mul(cx, e.span, right, left); } } } } fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { + let ccx = ConstEvalCtxt::new(cx); + let Some(ty) = cx.typeck_results().expr_ty_opt(lit) else { + return; + }; if let ExprKind::Lit(l) = lit.kind - && consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1) + && let Some(c) = ccx.lit_to_mir_constant(&l.node, ty) + && ccx.constant_negate(&c, ty) == Some(Constant::Int(1)) && cx.typeck_results().expr_ty(exp).is_integral() { let mut applicability = Applicability::MachineApplicable; let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); + let (snip, sign) = if let Some(snip) = snip.strip_prefix('-') { + (snip, "") + } else { + (&snip[..], "-") + }; let suggestion = if !from_macro && exp.precedence() < ExprPrecedence::Prefix && !has_enclosing_paren(&snip) { - format!("-({snip})") + format!("{sign}({snip})") } else { - format!("-{snip}") + format!("{sign}{snip}") }; span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs index 2d989b1cf0ba0..d7620a9ce69d9 100644 --- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs @@ -4,7 +4,7 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_trait_def_id, is_no_std_crate}; -use rustc_ast::{LitIntType, LitKind, UintTy}; +use rustc_ast::{LitIntType, LitKind, Sign, UintTy}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; @@ -111,7 +111,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { && implements_trait(cx, ty, copy_def_id, &[]) && let ExprKind::Lit(lit_kind) = end.expr.kind && let LitKind::Int(.., suffix_type) = lit_kind.node - && let LitIntType::Unsigned(UintTy::Usize) | LitIntType::Unsuffixed = suffix_type + && let LitIntType::Unsigned(UintTy::Usize) | LitIntType::Unsuffixed(Sign::None) = suffix_type { true } else { diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs index 694ad4f6347bb..c01c847dcb11f 100644 --- a/src/tools/clippy/clippy_lints/src/string_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr< return ControlFlow::Break(()); } if arm.pat.walk_short(|pat| match pat.kind { - PatKind::Expr(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => { + PatKind::Expr(expr) if let PatExprKind::Lit { lit } = expr.kind => { if let LitKind::Char(_) = lit.node { set_char_spans.push(lit.span); } diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs index f0b8abf9af664..286068ac716c2 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -4,7 +4,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg; use rustc_ast as ast; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, UnOp}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>( e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, - mut arg: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, const_context: bool, msrv: &Msrv, ) -> bool { @@ -31,10 +31,6 @@ pub(super) fn check<'tcx>( |diag| { let mut sugg = sugg::Sugg::hir(cx, arg, ".."); - if let ExprKind::Unary(UnOp::Neg, inner_expr) = &arg.kind { - arg = inner_expr; - } - if let ExprKind::Lit(lit) = &arg.kind // if the expression is a float literal and it is unsuffixed then // add a suffix so the suggestion is valid and unambiguous diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 5fc166438e84a..7e0eb3c6d2576 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -294,9 +294,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { LitKind::Byte(b) => kind!("Byte({b})"), LitKind::Int(i, suffix) => { let int_ty = match suffix { - LitIntType::Signed(int_ty) => format!("LitIntType::Signed(IntTy::{int_ty:?})"), + LitIntType::Signed(int_ty, sign) => { + format!("LitIntType::Signed(IntTy::{int_ty:?}, {sign:?})") + }, LitIntType::Unsigned(uint_ty) => format!("LitIntType::Unsigned(UintTy::{uint_ty:?})"), - LitIntType::Unsuffixed => String::from("LitIntType::Unsuffixed"), + LitIntType::Unsuffixed(sign) => format!("LitIntType::Unsuffixed({sign:?})"), }; kind!("Int({i}, {int_ty})"); }, @@ -648,10 +650,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ($($t:tt)*) => (kind(format_args!($($t)*))); } match lit.value.kind { - PatExprKind::Lit { lit, negated } => { + PatExprKind::Lit { lit } => { bind!(self, lit); - bind!(self, negated); - kind!("Lit{{ref {lit}, {negated} }}"); + kind!("Lit{{ref {lit} }}"); self.lit(lit); }, PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"), diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 4f48fb3b8a969..005f278109b96 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -82,7 +82,7 @@ fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) { LitKind::ByteStr(_, StrStyle::Raw(_)) => (Pat::Str("br#\""), Pat::Str("#")), LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")), LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")), - LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")), + LitKind::Int(_, LitIntType::Signed(IntTy::Isize, _)) => (Pat::Num, Pat::Str("isize")), LitKind::Int(_, LitIntType::Unsigned(UintTy::Usize)) => (Pat::Num, Pat::Str("usize")), LitKind::Int(..) => (Pat::Num, Pat::Num), LitKind::Float(..) => (Pat::Num, Pat::Str("")), diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index dd149c4a29b9f..3e6d8a293d63f 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -301,30 +301,33 @@ impl Constant<'_> { } } -/// Parses a `LitKind` to a `Constant`. -pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option>) -> Constant<'tcx> { - match *lit { - LitKind::Str(ref is, _) => Constant::Str(is.to_string()), - LitKind::Byte(b) => Constant::Int(u128::from(b)), - LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Arc::clone(s)), - LitKind::Char(c) => Constant::Char(c), - LitKind::Int(n, _) => Constant::Int(n.get()), - LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { - // FIXME(f16_f128): just use `parse()` directly when available for `f16`/`f128` - ast::FloatTy::F16 => Constant::parse_f16(is.as_str()), - ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()), - ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()), - ast::FloatTy::F128 => Constant::parse_f128(is.as_str()), - }, - LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() { - ty::Float(FloatTy::F16) => Constant::parse_f16(is.as_str()), - ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()), - ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()), - ty::Float(FloatTy::F128) => Constant::parse_f128(is.as_str()), - _ => bug!(), - }, - LitKind::Bool(b) => Constant::Bool(b), - LitKind::Err(_) => Constant::Err, +impl<'tcx> ConstEvalCtxt<'tcx> { + /// Parses a `LitKind` to a `Constant`. + pub fn lit_to_mir_constant(&self, lit: &LitKind, ty: Ty<'tcx>) -> Option> { + Some(match *lit { + LitKind::Str(ref is, _) => Constant::Str(is.to_string()), + LitKind::Byte(b) => Constant::Int(u128::from(b)), + LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Arc::clone(s)), + LitKind::Char(c) => Constant::Char(c), + LitKind::Int(n, _) if lit.is_negative() => self.constant_negate(&Constant::Int(n.get()), ty)?, + LitKind::Int(n, _) => Constant::Int(n.get()), + LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { + // FIXME(f16_f128): just use `parse()` directly when available for `f16`/`f128` + ast::FloatTy::F16 => Constant::parse_f16(is.as_str()), + ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()), + ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()), + ast::FloatTy::F128 => Constant::parse_f128(is.as_str()), + }, + LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.kind() { + ty::Float(FloatTy::F16) => Constant::parse_f16(is.as_str()), + ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()), + ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()), + ty::Float(FloatTy::F128) => Constant::parse_f128(is.as_str()), + _ => bug!(), + }, + LitKind::Bool(b) => Constant::Bool(b), + LitKind::Err(_) => Constant::Err, + }) } } @@ -443,14 +446,9 @@ impl<'tcx> ConstEvalCtxt<'tcx> { pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option> { match &pat_expr.kind { - PatExprKind::Lit { lit, negated } => { - let ty = self.typeck.node_type_opt(pat_expr.hir_id); - let val = lit_to_mir_constant(&lit.node, ty); - if *negated { - self.constant_negate(&val, ty?) - } else { - Some(val) - } + PatExprKind::Lit { lit } => { + let ty = self.typeck.node_type_opt(pat_expr.hir_id)?; + self.lit_to_mir_constant(&lit.node, ty) }, PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir_body(*body).value), PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id), @@ -488,7 +486,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { if is_direct_expn_of(e.span, "cfg").is_some() { None } else { - Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e))) + self.lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e)?) } }, ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec), @@ -602,7 +600,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } } - fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> { + pub fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> { use self::Constant::{F32, F64, Int}; match *o { Int(value) => { diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 0ac675345ae0c..165685bdf0275 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -491,16 +491,7 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool { match (&left.kind, &right.kind) { - ( - &PatExprKind::Lit { - lit: left, - negated: left_neg, - }, - &PatExprKind::Lit { - lit: right, - negated: right_neg, - }, - ) => left_neg == right_neg && left.node == right.node, + (&PatExprKind::Lit { lit: left }, &PatExprKind::Lit { lit: right }) => left.node == right.node, (PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body), (PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right), (PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false, @@ -1096,10 +1087,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_pat_expr(&mut self, lit: &PatExpr<'_>) { std::mem::discriminant(&lit.kind).hash(&mut self.s); match &lit.kind { - PatExprKind::Lit { lit, negated } => { - lit.node.hash(&mut self.s); - negated.hash(&mut self.s); - }, + PatExprKind::Lit { lit } => lit.node.hash(&mut self.s), PatExprKind::ConstBlock(c) => self.hash_body(c.body), PatExprKind::Path(qpath) => self.hash_qpath(qpath), } diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index bb2a628211000..9c77ed4c05097 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -234,9 +234,9 @@ fn lit_suffix_length(lit_kind: &LitKind) -> Option { debug_assert!(lit_kind.is_numeric()); let suffix = match lit_kind { LitKind::Int(_, int_lit_kind) => match int_lit_kind { - LitIntType::Signed(int_ty) => Some(int_ty.name_str()), + LitIntType::Signed(int_ty, _) => Some(int_ty.name_str()), LitIntType::Unsigned(uint_ty) => Some(uint_ty.name_str()), - LitIntType::Unsuffixed => None, + LitIntType::Unsuffixed(_) => None, }, LitKind::Float(_, float_lit_kind) => match float_lit_kind { LitFloatType::Suffixed(float_ty) => Some(float_ty.name_str()), diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index d5e0e2e3436e2..1d774baf92e9b 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -131,6 +131,7 @@ impl<'a> Sugg<'a> { | ExprKind::Closure { .. } | ExprKind::Unary(..) | ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)), + | ExprKind::Lit(lit) if lit.node.is_negative() => Sugg::MaybeParen(get_snippet(expr.span)), ExprKind::Continue(..) | ExprKind::Yield(..) | ExprKind::Array(..) diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout index eed704e82fe1b..c976d7badd59c 100644 --- a/src/tools/clippy/tests/ui/author.stdout +++ b/src/tools/clippy/tests/ui/author.stdout @@ -4,7 +4,7 @@ if let StmtKind::Let(local) = stmt.kind && let TyKind::Path(ref qpath) = cast_ty.kind && match_qpath(qpath, &["char"]) && let ExprKind::Lit(ref lit) = expr.kind - && let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(69, LitIntType::Unsuffixed(None)) = lit.node && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "x" { diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 54325f9776c52..2c1181aacf8f0 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -3,7 +3,7 @@ if let ExprKind::Block(block, None) = expr.kind && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init && let ExprKind::Lit(ref lit) = init.kind - && let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node + && let LitKind::Int(42, LitIntType::Signed(IntTy::I32, None)) = lit.node && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "x" && let StmtKind::Let(local1) = block.stmts[1].kind diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui/author/call.stdout index 59d4da490fe54..334d2c1927294 100644 --- a/src/tools/clippy/tests/ui/author/call.stdout +++ b/src/tools/clippy/tests/ui/author/call.stdout @@ -5,9 +5,9 @@ if let StmtKind::Let(local) = stmt.kind && match_qpath(qpath, &["{{root}}", "std", "cmp", "min"]) && args.len() == 2 && let ExprKind::Lit(ref lit) = args[0].kind - && let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(3, LitIntType::Unsuffixed(None)) = lit.node && let ExprKind::Lit(ref lit1) = args[1].kind - && let LitKind::Int(4, LitIntType::Unsuffixed) = lit1.node + && let LitKind::Int(4, LitIntType::Unsuffixed(None)) = lit1.node && let PatKind::Wild = local.pat.kind { // report your lint here diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout index 8ffdf8862027b..e101b0d7dba02 100644 --- a/src/tools/clippy/tests/ui/author/if.stdout +++ b/src/tools/clippy/tests/ui/author/if.stdout @@ -10,9 +10,9 @@ if let StmtKind::Let(local) = stmt.kind && let ExprKind::Binary(op, left, right) = e.kind && BinOpKind::Eq == op.node && let ExprKind::Lit(ref lit1) = left.kind - && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node + && let LitKind::Int(1, LitIntType::Unsuffixed(None)) = lit1.node && let ExprKind::Lit(ref lit2) = right.kind - && let LitKind::Int(1, LitIntType::Unsuffixed) = lit2.node + && let LitKind::Int(1, LitIntType::Unsuffixed(None)) = lit2.node && block.expr.is_none() && let ExprKind::Block(block1, None) = else_expr.kind && block1.stmts.len() == 1 @@ -20,9 +20,9 @@ if let StmtKind::Let(local) = stmt.kind && let ExprKind::Binary(op1, left1, right1) = e1.kind && BinOpKind::Eq == op1.node && let ExprKind::Lit(ref lit3) = left1.kind - && let LitKind::Int(2, LitIntType::Unsuffixed) = lit3.node + && let LitKind::Int(2, LitIntType::Unsuffixed(None)) = lit3.node && let ExprKind::Lit(ref lit4) = right1.kind - && let LitKind::Int(2, LitIntType::Unsuffixed) = lit4.node + && let LitKind::Int(2, LitIntType::Unsuffixed(None)) = lit4.node && block1.expr.is_none() && let PatKind::Wild = local.pat.kind { @@ -31,7 +31,7 @@ if let StmtKind::Let(local) = stmt.kind if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind && let ExprKind::Let(let_expr) = cond.kind && let PatKind::Expr(lit_expr) = let_expr.pat.kind - && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind + && let PatExprKind::Lit{ref lit } = lit_expr.kind && let LitKind::Bool(true) = lit.node && let ExprKind::Path(ref qpath) = let_expr.init.kind && match_qpath(qpath, &["a"]) diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout index c94eb171f52b9..0f2f896d4fee3 100644 --- a/src/tools/clippy/tests/ui/author/loop.stdout +++ b/src/tools/clippy/tests/ui/author/loop.stdout @@ -6,10 +6,10 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && fields.len() == 2 && fields[0].ident.as_str() == "start" && let ExprKind::Lit(ref lit) = fields[0].expr.kind - && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(0, LitIntType::Unsuffixed(None)) = lit.node && fields[1].ident.as_str() == "end" && let ExprKind::Lit(ref lit1) = fields[1].expr.kind - && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node + && let LitKind::Int(10, LitIntType::Unsuffixed(None)) = lit1.node && let ExprKind::Block(block, None) = body.kind && block.stmts.len() == 1 && let StmtKind::Let(local) = block.stmts[0].kind @@ -29,10 +29,10 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && fields.len() == 2 && fields[0].ident.as_str() == "start" && let ExprKind::Lit(ref lit) = fields[0].expr.kind - && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(0, LitIntType::Unsuffixed(None)) = lit.node && fields[1].ident.as_str() == "end" && let ExprKind::Lit(ref lit1) = fields[1].expr.kind - && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node + && let LitKind::Int(10, LitIntType::Unsuffixed(None)) = lit1.node && let ExprKind::Block(block, None) = body.kind && block.stmts.len() == 1 && let StmtKind::Semi(e) = block.stmts[0].kind @@ -49,10 +49,10 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && fields.len() == 2 && fields[0].ident.as_str() == "start" && let ExprKind::Lit(ref lit) = fields[0].expr.kind - && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(0, LitIntType::Unsuffixed(None)) = lit.node && fields[1].ident.as_str() == "end" && let ExprKind::Lit(ref lit1) = fields[1].expr.kind - && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node + && let LitKind::Int(10, LitIntType::Unsuffixed(None)) = lit1.node && let ExprKind::Block(block, None) = body.kind && block.stmts.len() == 1 && let StmtKind::Semi(e) = block.stmts[0].kind @@ -77,7 +77,7 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While: } if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr) && let PatKind::Expr(lit_expr) = let_pat.kind - && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind + && let PatExprKind::Lit{ref lit } = lit_expr.kind && let LitKind::Bool(true) = lit.node && let ExprKind::Path(ref qpath) = let_expr.kind && match_qpath(qpath, &["a"]) diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout index 3f9be297c33c5..3237dff0f70f3 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout @@ -6,10 +6,10 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && fields.len() == 2 && fields[0].ident.as_str() == "start" && let ExprKind::Lit(ref lit) = fields[0].expr.kind - && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(0, LitIntType::Unsuffixed(None)) = lit.node && fields[1].ident.as_str() == "end" && let ExprKind::Lit(ref lit1) = fields[1].expr.kind - && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node + && let LitKind::Int(1, LitIntType::Unsuffixed(None)) = lit1.node && let ExprKind::Block(block, None) = body.kind && block.stmts.len() == 1 && let StmtKind::Semi(e) = block.stmts[0].kind diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout index acb3b140dfa13..7c02d70076313 100644 --- a/src/tools/clippy/tests/ui/author/matches.stdout +++ b/src/tools/clippy/tests/ui/author/matches.stdout @@ -2,24 +2,24 @@ if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = init.kind && let ExprKind::Lit(ref lit) = scrutinee.kind - && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node + && let LitKind::Int(42, LitIntType::Unsuffixed(None)) = lit.node && arms.len() == 3 && let PatKind::Expr(lit_expr) = arms[0].pat.kind - && let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind - && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node + && let PatExprKind::Lit{ref lit1 } = lit_expr.kind + && let LitKind::Int(16, LitIntType::Unsuffixed(None)) = lit1.node && arms[0].guard.is_none() && let ExprKind::Lit(ref lit2) = arms[0].body.kind - && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node + && let LitKind::Int(5, LitIntType::Unsuffixed(None)) = lit2.node && let PatKind::Expr(lit_expr1) = arms[1].pat.kind - && let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind - && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node + && let PatExprKind::Lit{ref lit3 } = lit_expr1.kind + && let LitKind::Int(17, LitIntType::Unsuffixed(None)) = lit3.node && arms[1].guard.is_none() && let ExprKind::Block(block, None) = arms[1].body.kind && block.stmts.len() == 1 && let StmtKind::Let(local1) = block.stmts[0].kind && let Some(init1) = local1.init && let ExprKind::Lit(ref lit4) = init1.kind - && let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node + && let LitKind::Int(3, LitIntType::Unsuffixed(None)) = lit4.node && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind && name.as_str() == "x" && let Some(trailing_expr) = block.expr @@ -28,7 +28,7 @@ if let StmtKind::Let(local) = stmt.kind && let PatKind::Wild = arms[2].pat.kind && arms[2].guard.is_none() && let ExprKind::Lit(ref lit5) = arms[2].body.kind - && let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node + && let LitKind::Int(1, LitIntType::Unsuffixed(None)) = lit5.node && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind && name1.as_str() == "a" { diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui/author/repeat.stdout index f2c6b3f807f1b..f3a070ce73af6 100644 --- a/src/tools/clippy/tests/ui/author/repeat.stdout +++ b/src/tools/clippy/tests/ui/author/repeat.stdout @@ -4,7 +4,7 @@ if let ExprKind::Repeat(value, length) = expr.kind && let ConstArgKind::Anon(anon_const) = length.kind && expr1 = &cx.tcx.hir_body(anon_const.body).value && let ExprKind::Lit(ref lit1) = expr1.kind - && let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node + && let LitKind::Int(5, LitIntType::Unsuffixed(None)) = lit1.node { // report your lint here } diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout index b66bbccb3cf1b..5388accb1cd84 100644 --- a/src/tools/clippy/tests/ui/author/struct.stdout +++ b/src/tools/clippy/tests/ui/author/struct.stdout @@ -10,12 +10,12 @@ if let ExprKind::Struct(qpath, fields, None) = expr.kind && block.stmts.is_empty() && let Some(trailing_expr) = block.expr && let ExprKind::Lit(ref lit1) = trailing_expr.kind - && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node + && let LitKind::Int(1, LitIntType::Unsuffixed(None)) = lit1.node && let ExprKind::Block(block1, None) = else_expr.kind && block1.stmts.is_empty() && let Some(trailing_expr1) = block1.expr && let ExprKind::Lit(ref lit2) = trailing_expr1.kind - && let LitKind::Int(0, LitIntType::Unsuffixed) = lit2.node + && let LitKind::Int(0, LitIntType::Unsuffixed(None)) = lit2.node { // report your lint here } @@ -24,8 +24,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind && fields.len() == 1 && fields[0].ident.as_str() == "field" && let PatKind::Expr(lit_expr) = fields[0].pat.kind - && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind - && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node + && let PatExprKind::Lit{ref lit } = lit_expr.kind + && let LitKind::Int(1, LitIntType::Unsuffixed(None)) = lit.node && arm.guard.is_none() && let ExprKind::Block(block, None) = arm.body.kind && block.stmts.is_empty() @@ -37,8 +37,8 @@ if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind && match_qpath(qpath, &["TestTuple"]) && fields.len() == 1 && let PatKind::Expr(lit_expr) = fields[0].kind - && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind - && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node + && let PatExprKind::Lit{ref lit } = lit_expr.kind + && let LitKind::Int(1, LitIntType::Unsuffixed(None)) = lit.node && arm.guard.is_none() && let ExprKind::Block(block, None) = arm.body.kind && block.stmts.is_empty() diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.stderr b/src/tools/clippy/tests/ui/lossy_float_literal.stderr index 118351a62d00c..79acdded6d40b 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.stderr +++ b/src/tools/clippy/tests/ui/lossy_float_literal.stderr @@ -61,10 +61,10 @@ LL + let _ = 16_777_220_f32; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:19:19 + --> tests/ui/lossy_float_literal.rs:19:18 | LL | let _: f32 = -16_777_219.0; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | help: consider changing the type or replacing it with | @@ -121,10 +121,10 @@ LL + let _ = 9_007_199_254_740_992_f64; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:25:19 + --> tests/ui/lossy_float_literal.rs:25:18 | LL | let _: f64 = -9_007_199_254_740_993.0; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider changing the type or replacing it with | diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed index 01c58151bc946..04e1901c950c9 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed @@ -57,7 +57,7 @@ fn issue_13950() { let _ = x.div_ceil(8); let y = -33i32; - let _ = y.div_ceil(-7); - let _ = y.div_ceil(-7); - let _ = y.div_ceil(-7); + let _ = (y + -8) / -7; + let _ = (-8 + y) / -7; + let _ = (y - 8) / -7; } diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr index 807cfd82724e5..7cd4e5d91088a 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr @@ -121,23 +121,5 @@ error: manually reimplementing `div_ceil` LL | let _ = (7 + x) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` -error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:60:13 - | -LL | let _ = (y + -8) / -7; - | ^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` - -error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:61:13 - | -LL | let _ = (-8 + y) / -7; - | ^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` - -error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:62:13 - | -LL | let _ = (y - 8) / -7; - | ^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` - -error: aborting due to 23 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed index 18716e93d1e9c..16950fc69bf3c 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed @@ -40,7 +40,7 @@ fn main() { std::iter::repeat_with(|| do_something()).take(upper_fn() + 1); std::iter::repeat_with(|| do_something()).take(upper_fn() - 2); std::iter::repeat_with(|| do_something()).take(upper_fn() - 1); - (-3..9).map(|_| do_something()); + std::iter::repeat_with(|| do_something()).take(6); std::iter::repeat_with(|| do_something()).take(0); std::iter::repeat_with(|| do_something()).take(1); std::iter::repeat_with(|| do_something()).take((1 << 4) - 0); diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.stderr b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.stderr index 840515f95df48..74cfce8e59b97 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.stderr +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.stderr @@ -161,6 +161,18 @@ LL - (2..=upper_fn()).map(|_| do_something()); LL + std::iter::repeat_with(|| do_something()).take(upper_fn() - 1); | +error: map of a closure that does not depend on its parameter over a range + --> tests/ui/map_with_unused_argument_over_ranges.rs:43:5 + | +LL | (-3..9).map(|_| do_something()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the explicit range and use `repeat_with` and `take` + | +LL - (-3..9).map(|_| do_something()); +LL + std::iter::repeat_with(|| do_something()).take(6); + | + error: map of a closure that does not depend on its parameter over a range --> tests/ui/map_with_unused_argument_over_ranges.rs:44:5 | @@ -221,5 +233,5 @@ LL - (0..10).map(|_| 3); LL + std::iter::repeat(3).take(10); | -error: aborting due to 18 previous errors +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/modulo_one.stderr b/src/tools/clippy/tests/ui/modulo_one.stderr index aedcf24eae71e..3e94780c45ff2 100644 --- a/src/tools/clippy/tests/ui/modulo_one.stderr +++ b/src/tools/clippy/tests/ui/modulo_one.stderr @@ -21,12 +21,24 @@ LL | 10 % 1; = note: `-D clippy::modulo-one` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::modulo_one)]` +error: any number modulo 1 will be 0 + --> tests/ui/modulo_one.rs:11:5 + | +LL | 10 % -1; + | ^^^^^^^ + error: any number modulo -1 will panic/overflow or result in 0 --> tests/ui/modulo_one.rs:11:5 | LL | 10 % -1; | ^^^^^^^ +error: any number modulo 1 will be 0 + --> tests/ui/modulo_one.rs:15:5 + | +LL | i32::MIN % (-1); + | ^^^^^^^^^^^^^^^ + error: any number modulo -1 will panic/overflow or result in 0 --> tests/ui/modulo_one.rs:15:5 | @@ -51,5 +63,5 @@ error: any number modulo -1 will panic/overflow or result in 0 LL | INT_MIN % NEG_ONE; | ^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/neg_multiply.fixed b/src/tools/clippy/tests/ui/neg_multiply.fixed index 52edea73afbb7..1297d3fdb6bd3 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.fixed +++ b/src/tools/clippy/tests/ui/neg_multiply.fixed @@ -40,7 +40,7 @@ fn main() { -(3_usize as i32); -(3_usize as i32); - -1 * -1; // should be ok + 1; // should be ok X * -1; // should be ok -1 * X; // should also be ok diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr index 13226c7c37b3f..7267647f18568 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.stderr +++ b/src/tools/clippy/tests/ui/neg_multiply.stderr @@ -49,5 +49,19 @@ error: this multiplication by -1 can be written more succinctly LL | (3_usize as i32) * -1; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3_usize as i32)` -error: aborting due to 8 previous errors +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:43:5 + | +LL | -1 * -1; // should be ok + | ^^^^^^^ help: consider using: `1` + +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:43:5 + | +LL | -1 * -1; // should be ok + | ^^^^^^^ help: consider using: `1` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed index c43e50761bd52..84125827f6496 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed @@ -196,9 +196,9 @@ mod fixable { type I32Alias = i32; fn issue_9380() { - let _: i32 = -1_i32; + let _: i32 = { -(1) }; let _: f32 = -(1) as f32; - let _: i64 = -1_i64; + let _: i64 = { -(1) }; let _: i64 = -(1.0) as i64; let _ = -(1 + 1) as i64; diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr index 80fd5c13d8185..dea5cf43f689e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr @@ -211,17 +211,17 @@ error: casting to the same type is unnecessary (`i32` -> `i32`) LL | let _ = &(x as i32); | ^^^^^^^^^^ help: try: `{ x }` -error: casting integer literal to `i32` is unnecessary +error: casting to the same type is unnecessary (`i32` -> `i32`) --> tests/ui/unnecessary_cast.rs:199:22 | LL | let _: i32 = -(1) as i32; - | ^^^^^^^^^^^ help: try: `-1_i32` + | ^^^^^^^^^^^ help: try: `{ -(1) }` -error: casting integer literal to `i64` is unnecessary +error: casting to the same type is unnecessary (`i64` -> `i64`) --> tests/ui/unnecessary_cast.rs:201:22 | LL | let _: i64 = -(1) as i64; - | ^^^^^^^^^^^ help: try: `-1_i64` + | ^^^^^^^^^^^ help: try: `{ -(1) }` error: casting float literal to `f64` is unnecessary --> tests/ui/unnecessary_cast.rs:208:22 diff --git a/tests/crashes/133966.rs b/tests/ui/consts/invalid_wide_ptr.rs similarity index 50% rename from tests/crashes/133966.rs rename to tests/ui/consts/invalid_wide_ptr.rs index 25a881ae99b4f..52feb35756252 100644 --- a/tests/crashes/133966.rs +++ b/tests/ui/consts/invalid_wide_ptr.rs @@ -1,3 +1,6 @@ -//@ known-bug: #133966 pub struct Data([[&'static str]; 5_i32]); +//~^ ERROR: mismatched types +//~| ERROR: the size for values of type `[&'static str]` const _: &'static Data = unsafe { &*(&[] as *const Data) }; + +fn main() {} diff --git a/tests/ui/consts/invalid_wide_ptr.stderr b/tests/ui/consts/invalid_wide_ptr.stderr new file mode 100644 index 0000000000000..d7962c2642b8a --- /dev/null +++ b/tests/ui/consts/invalid_wide_ptr.stderr @@ -0,0 +1,25 @@ +error[E0277]: the size for values of type `[&'static str]` cannot be known at compilation time + --> $DIR/invalid_wide_ptr.rs:1:17 + | +LL | pub struct Data([[&'static str]; 5_i32]); + | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[&'static str]` + = note: slice and array elements must have `Sized` type + +error[E0308]: mismatched types + --> $DIR/invalid_wide_ptr.rs:1:34 + | +LL | pub struct Data([[&'static str]; 5_i32]); + | ^^^^^ expected `usize`, found `i32` + | +help: change the type of the numeric literal from `i32` to `usize` + | +LL - pub struct Data([[&'static str]; 5_i32]); +LL + pub struct Data([[&'static str]; 5_usize]); + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/enum/enum-discrim-too-small.stderr b/tests/ui/enum/enum-discrim-too-small.stderr index 40205d95b1f89..4973cba7c9f5a 100644 --- a/tests/ui/enum/enum-discrim-too-small.stderr +++ b/tests/ui/enum/enum-discrim-too-small.stderr @@ -1,35 +1,99 @@ -error[E0600]: cannot apply unary operator `-` to type `u8` +error[E0277]: cannot apply unary operator `-` to type `u8` --> $DIR/enum-discrim-too-small.rs:5:11 | LL | Cu8 = -23, | ^^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `u8` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated +help: you may have meant to the wrapped-around value of type `u8` + | +LL - Cu8 = -23, +LL + Cu8 = 233, + | -error[E0600]: cannot apply unary operator `-` to type `u16` +error[E0277]: cannot apply unary operator `-` to type `u16` --> $DIR/enum-discrim-too-small.rs:13:12 | LL | Cu16 = -22333, | ^^^^^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `u16` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated +help: you may have meant to the wrapped-around value of type `u16` + | +LL - Cu16 = -22333, +LL + Cu16 = 0xa8c3, + | -error[E0600]: cannot apply unary operator `-` to type `u32` +error[E0277]: cannot apply unary operator `-` to type `u32` --> $DIR/enum-discrim-too-small.rs:21:12 | LL | Cu32 = -2_000_000_000, | ^^^^^^^^^^^^^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `u32` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated +help: you may have meant to the wrapped-around value of type `u32` + | +LL - Cu32 = -2_000_000_000, +LL + Cu32 = 0x88ca6c00, + | -error[E0600]: cannot apply unary operator `-` to type `u64` +error[E0277]: cannot apply unary operator `-` to type `u64` --> $DIR/enum-discrim-too-small.rs:29:12 | LL | Cu32 = -2_000_000_000, | ^^^^^^^^^^^^^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `u64` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated +help: you may have meant to the wrapped-around value of type `u64` + | +LL - Cu32 = -2_000_000_000, +LL + Cu32 = 0xffffffff88ca6c00, + | error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0600`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/enum/enum-discrim-too-small2.stderr b/tests/ui/enum/enum-discrim-too-small2.stderr index f79f7a043d688..f33f7db8f8950 100644 --- a/tests/ui/enum/enum-discrim-too-small2.stderr +++ b/tests/ui/enum/enum-discrim-too-small2.stderr @@ -27,7 +27,7 @@ error: literal out of range for `i32` LL | Ci32 = 3_000_000_000, | ^^^^^^^^^^^^^ | - = note: the literal `3_000_000_000` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = note: the literal `3000000000` does not fit into the type `i32` whose range is `-2147483648..=2147483647` = help: consider using the type `u32` instead error: literal out of range for `i64` diff --git a/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr b/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr index a6e0e668261cb..75d3bb331b189 100644 --- a/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr +++ b/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr @@ -1,11 +1,22 @@ -error[E0600]: cannot apply unary operator `-` to type `usize` +error[E0277]: cannot apply unary operator `-` to type `usize` --> $DIR/feature-gate-negate-unsigned.rs:10:23 | LL | let _max: usize = -1; | ^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `usize` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated -help: you may have meant the maximum value of `usize` +help: you may have meant to the wrapped-around value of type `usize` | LL - let _max: usize = -1; LL + let _max: usize = usize::MAX; @@ -21,4 +32,5 @@ LL | let _y = -x; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0600`. +Some errors have detailed explanations: E0277, E0600. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr index 7d9c5b8165169..d82c8921b0e0f 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -76,12 +76,13 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable LL + #![feature(trivial_bounds)] | -error[E0277]: the trait bound `String: Neg` is not satisfied +error[E0277]: cannot apply unary operator `-` to type `String` --> $DIR/feature-gate-trivial_bounds.rs:36:38 | LL | fn use_op(s: String) -> String where String: ::std::ops::Neg { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Neg` is not implemented for `String` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `String` = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | diff --git a/tests/ui/lint/lint-type-overflow.stderr b/tests/ui/lint/lint-type-overflow.stderr index 971c3eb9b2e3b..9a8ea46bfa52a 100644 --- a/tests/ui/lint/lint-type-overflow.stderr +++ b/tests/ui/lint/lint-type-overflow.stderr @@ -43,7 +43,7 @@ error: literal out of range for `i8` LL | let x3: i8 = -(129); | ^^^^^^ | - = note: the literal `-(129)` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `-129` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `i16` instead error: literal out of range for `i8` @@ -70,7 +70,7 @@ error: literal out of range for `i8` LL | let x = 128_i8; | ^^^^^^ | - = note: the literal `128_i8` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `u8` instead error: literal out of range for `i8` @@ -79,7 +79,7 @@ error: literal out of range for `i8` LL | let x = -129_i8; | ^^^^^^^ | - = note: the literal `-129_i8` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `-129` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `i16` instead error: literal out of range for `i32` @@ -97,7 +97,7 @@ error: literal out of range for `i32` LL | let x = 2147483648_i32; | ^^^^^^^^^^^^^^ | - = note: the literal `2147483648_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = note: the literal `2147483648` does not fit into the type `i32` whose range is `-2147483648..=2147483647` = help: consider using the type `u32` instead error: literal out of range for `i32` @@ -115,7 +115,7 @@ error: literal out of range for `i32` LL | let x = -2147483649_i32; | ^^^^^^^^^^^^^^^ | - = note: the literal `-2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = note: the literal `-2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647` = help: consider using the type `i64` instead error: literal out of range for `i32` @@ -133,7 +133,7 @@ error: literal out of range for `i64` LL | let x = 9223372036854775808_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `9223372036854775808_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = note: the literal `9223372036854775808` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` = help: consider using the type `u64` instead error: literal out of range for `i64` @@ -142,7 +142,7 @@ error: literal out of range for `i64` LL | let x = 18446744073709551615_i64; | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `18446744073709551615_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = note: the literal `18446744073709551615` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` = help: consider using the type `u64` instead error: literal out of range for `i64` @@ -160,7 +160,7 @@ error: literal out of range for `i64` LL | let x = -9223372036854775809_i64; | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `-9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = note: the literal `-9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` = help: consider using the type `i128` instead error: aborting due to 18 previous errors diff --git a/tests/ui/lint/lint-type-overflow2.stderr b/tests/ui/lint/lint-type-overflow2.stderr index 2cfb18e9fe924..710e9c84d33e1 100644 --- a/tests/ui/lint/lint-type-overflow2.stderr +++ b/tests/ui/lint/lint-type-overflow2.stderr @@ -13,10 +13,10 @@ LL | let x2: i8 = -(-128); | + + error: literal out of range for `i8` - --> $DIR/lint-type-overflow2.rs:6:20 + --> $DIR/lint-type-overflow2.rs:6:18 | LL | let x2: i8 = --128; - | ^^^ + | ^^^^^ | = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `u8` instead @@ -27,12 +27,12 @@ LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ error: literal out of range for `f32` - --> $DIR/lint-type-overflow2.rs:9:14 + --> $DIR/lint-type-overflow2.rs:9:13 | LL | let x = -3.40282357e+38_f32; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | - = note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY` + = note: the literal `-3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY` error: literal out of range for `f32` --> $DIR/lint-type-overflow2.rs:10:14 @@ -43,12 +43,12 @@ LL | let x = 3.40282357e+38_f32; = note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY` error: literal out of range for `f64` - --> $DIR/lint-type-overflow2.rs:11:14 + --> $DIR/lint-type-overflow2.rs:11:13 | LL | let x = -1.7976931348623159e+308_f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY` + = note: the literal `-1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY` error: literal out of range for `f64` --> $DIR/lint-type-overflow2.rs:12:14 diff --git a/tests/ui/lint/type-overflow.stderr b/tests/ui/lint/type-overflow.stderr index 4d6403b1e7db2..95d06d6dde0a8 100644 --- a/tests/ui/lint/type-overflow.stderr +++ b/tests/ui/lint/type-overflow.stderr @@ -4,7 +4,7 @@ warning: literal out of range for `i8` LL | let error = 255i8; | ^^^^^ | - = note: the literal `255i8` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `255` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `u8` instead note: the lint level is defined here --> $DIR/type-overflow.rs:2:9 @@ -77,22 +77,22 @@ LL | let fail = 0x8000_0000_0000_0000_0000_0000_0000_0000; = help: consider using the type `u128` instead warning: literal out of range for `i32` - --> $DIR/type-overflow.rs:31:17 + --> $DIR/type-overflow.rs:31:16 | LL | let fail = -0x8000_0000_0000_0000_0000_0000_0000_0000; // issue #131849 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i32` + = note: the literal `-0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i32` = note: and the value `-0x8000_0000_0000_0000_0000_0000_0000_0000` will become `0i32` = help: consider using the type `i128` instead warning: literal out of range for `i128` - --> $DIR/type-overflow.rs:35:17 + --> $DIR/type-overflow.rs:35:16 | LL | let fail = -0x8000_0000_0000_0000_0000_0000_0000_0001i128; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0001i128` (decimal `170141183460469231731687303715884105729`) does not fit into the type `i128` + = note: the literal `-0x8000_0000_0000_0000_0000_0000_0000_0001i128` (decimal `170141183460469231731687303715884105729`) does not fit into the type `i128` = note: and the value `-0x8000_0000_0000_0000_0000_0000_0000_0001i128` will become `170141183460469231731687303715884105727i128` warning: literal out of range for `i8` @@ -101,7 +101,7 @@ warning: literal out of range for `i8` LL | let fail = 340282366920938463463374607431768211455i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `340282366920938463463374607431768211455i8` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `340282366920938463463374607431768211455` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `u128` instead warning: literal out of range for `i32` @@ -118,12 +118,12 @@ LL | let fail = 0x8FFF_FFFF_FFFF_FFFEu32 as i32; | ++++++++++ warning: literal out of range for `i8` - --> $DIR/type-overflow.rs:46:17 + --> $DIR/type-overflow.rs:46:16 | LL | let fail = -0b1111_1111i8; - | ^^^^^^^^^^^^^ help: consider using the type `i16` instead: `0b1111_1111i16` + | ^^^^^^^^^^^^^^ help: consider using the type `i16` instead: `-0b1111_1111i16` | - = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into the type `i8` + = note: the literal `-0b1111_1111i8` (decimal `255`) does not fit into the type `i8` = note: and the value `-0b1111_1111i8` will become `1i8` warning: 11 warnings emitted diff --git a/tests/ui/parser/expr-as-stmt.stderr b/tests/ui/parser/expr-as-stmt.stderr index 76a83aa0161bb..af4abaa0208bf 100644 --- a/tests/ui/parser/expr-as-stmt.stderr +++ b/tests/ui/parser/expr-as-stmt.stderr @@ -151,12 +151,23 @@ help: you might have meant to return this value LL | {return 2;} - 2 | ++++++ + -error[E0600]: cannot apply unary operator `-` to type `u32` +error[E0277]: cannot apply unary operator `-` to type `u32` --> $DIR/expr-as-stmt.rs:36:9 | LL | {2} - 2 | ^^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `u32` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others help: parentheses are required to parse this as an expression | LL | ({2}) - 2 @@ -244,5 +255,5 @@ LL | unsafe { return 1; } + unsafe { 1 } error: aborting due to 22 previous errors -Some errors have detailed explanations: E0308, E0600, E0614. -For more information about an error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0277, E0308, E0614. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 910582ae4d9e9..e795dfa984e08 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -135,7 +135,7 @@ body: temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: - Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false) + Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) } ) } } @@ -187,7 +187,7 @@ body: temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: - Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false) + Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) } ) } } @@ -231,7 +231,7 @@ body: temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: - Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false) + Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) } ) } } diff --git a/tests/ui/type/pattern_types/signed_ranges.rs b/tests/ui/type/pattern_types/signed_ranges.rs index 3725fbda7292a..c60a3f848a70f 100644 --- a/tests/ui/type/pattern_types/signed_ranges.rs +++ b/tests/ui/type/pattern_types/signed_ranges.rs @@ -7,18 +7,18 @@ type Sign = pattern_type!(u32 is -10..); //~^ ERROR: cannot apply unary operator `-` type SignedChar = pattern_type!(char is -'A'..); -//~^ ERROR: cannot apply unary operator `-` +//~^ ERROR: cannot negate `char` literal fn main() { match 42_u8 { -10..253 => {} - //~^ ERROR `u8: Neg` is not satisfied + //~^ ERROR cannot apply unary operator `-` to type `u8` _ => {} } match 'A' { -'\0'..'a' => {} - //~^ ERROR `char: Neg` is not satisfied + //~^ ERROR cannot negate `char` literal _ => {} } } diff --git a/tests/ui/type/pattern_types/signed_ranges.stderr b/tests/ui/type/pattern_types/signed_ranges.stderr index 79bf8501b639f..0e040f433844a 100644 --- a/tests/ui/type/pattern_types/signed_ranges.stderr +++ b/tests/ui/type/pattern_types/signed_ranges.stderr @@ -1,9 +1,26 @@ -error[E0277]: the trait bound `u8: Neg` is not satisfied +error: cannot negate `char` literal + --> $DIR/signed_ranges.rs:9:41 + | +LL | type SignedChar = pattern_type!(char is -'A'..); + | ^^^^ + | + = note: only signed integer literals and float literals can be negated + +error: cannot negate `char` literal + --> $DIR/signed_ranges.rs:20:9 + | +LL | -'\0'..'a' => {} + | ^^^^^ + | + = note: only signed integer literals and float literals can be negated + +error[E0277]: cannot apply unary operator `-` to type `u8` --> $DIR/signed_ranges.rs:14:9 | LL | -10..253 => {} - | ^^^ the trait `Neg` is not implemented for `u8` + | ^^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `u8` = help: the following other types implement trait `Neg`: &f128 &f16 @@ -14,28 +31,37 @@ LL | -10..253 => {} &i32 &i64 and 12 others - -error[E0277]: the trait bound `char: Neg` is not satisfied - --> $DIR/signed_ranges.rs:20:9 + = note: unsigned values cannot be negated +help: you may have meant to the wrapped-around value of type `u8` + | +LL - -10..253 => {} +LL + 246..253 => {} | -LL | -'\0'..'a' => {} - | ^^^^^ the trait `Neg` is not implemented for `char` -error[E0600]: cannot apply unary operator `-` to type `u32` +error[E0277]: cannot apply unary operator `-` to type `u32` --> $DIR/signed_ranges.rs:6:34 | LL | type Sign = pattern_type!(u32 is -10..); | ^^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `u32` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated - -error[E0600]: cannot apply unary operator `-` to type `char` - --> $DIR/signed_ranges.rs:9:41 +help: you may have meant to the wrapped-around value of type `u32` + | +LL - type Sign = pattern_type!(u32 is -10..); +LL + type Sign = pattern_type!(u32 is 0xfffffff6..); | -LL | type SignedChar = pattern_type!(char is -'A'..); - | ^^^^ cannot apply unary operator `-` error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0600. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unop/unop-neg-bool.rs b/tests/ui/unop/unop-neg-bool.rs index 6f1f1aba45930..b113a06b08a51 100644 --- a/tests/ui/unop/unop-neg-bool.rs +++ b/tests/ui/unop/unop-neg-bool.rs @@ -1,3 +1,4 @@ fn main() { - -true; //~ ERROR cannot apply unary operator `-` to type `bool` + -{ true }; //~ ERROR cannot apply unary operator `-` to type `bool` + -true; //~ ERROR cannot negate `boolean` literal } diff --git a/tests/ui/unop/unop-neg-bool.stderr b/tests/ui/unop/unop-neg-bool.stderr index 9bc5e7dcf2268..bf759fdcb0bb2 100644 --- a/tests/ui/unop/unop-neg-bool.stderr +++ b/tests/ui/unop/unop-neg-bool.stderr @@ -1,9 +1,17 @@ +error: cannot negate `boolean` literal + --> $DIR/unop-neg-bool.rs:3:5 + | +LL | -true; + | ^^^^^ + | + = note: only signed integer literals and float literals can be negated + error[E0600]: cannot apply unary operator `-` to type `bool` --> $DIR/unop-neg-bool.rs:2:5 | -LL | -true; - | ^^^^^ cannot apply unary operator `-` +LL | -{ true }; + | ^^^^^^^^^ cannot apply unary operator `-` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0600`. diff --git a/tests/ui/unpretty/box.stdout b/tests/ui/unpretty/box.stdout index 92155d0c73b9d..624b624d5ff26 100644 --- a/tests/ui/unpretty/box.stdout +++ b/tests/ui/unpretty/box.stdout @@ -65,7 +65,7 @@ body: temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/box.rs:7:33: 7:34 (#0) kind: - Literal( lit: Spanned { node: Int(Pu128(1), Unsuffixed), span: $DIR/box.rs:7:33: 7:34 (#0) }, neg: false) + Literal( lit: Spanned { node: Int(Pu128(1), Unsuffixed(None)), span: $DIR/box.rs:7:33: 7:34 (#0) } ) } } diff --git a/tests/ui/unsigned-literal-negation.stderr b/tests/ui/unsigned-literal-negation.stderr index 0bedbc1accd3b..05a2fc1505963 100644 --- a/tests/ui/unsigned-literal-negation.stderr +++ b/tests/ui/unsigned-literal-negation.stderr @@ -1,37 +1,70 @@ -error[E0600]: cannot apply unary operator `-` to type `usize` +error[E0277]: cannot apply unary operator `-` to type `usize` --> $DIR/unsigned-literal-negation.rs:2:13 | LL | let x = -1 as usize; | ^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `usize` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated -help: you may have meant the maximum value of `usize` +help: you may have meant to the wrapped-around value of type `usize` | LL - let x = -1 as usize; LL + let x = usize::MAX; | -error[E0600]: cannot apply unary operator `-` to type `usize` - --> $DIR/unsigned-literal-negation.rs:3:13 +error[E0277]: cannot apply unary operator `-` to type `usize` + --> $DIR/unsigned-literal-negation.rs:3:14 | LL | let x = (-1) as usize; - | ^^^^ cannot apply unary operator `-` + | ^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `usize` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated -help: you may have meant the maximum value of `usize` +help: you may have meant to the wrapped-around value of type `usize` | LL - let x = (-1) as usize; LL + let x = usize::MAX; | -error[E0600]: cannot apply unary operator `-` to type `u32` +error[E0277]: cannot apply unary operator `-` to type `u32` --> $DIR/unsigned-literal-negation.rs:4:18 | LL | let x: u32 = -1; | ^^ cannot apply unary operator `-` | + = help: the trait `Neg` is not implemented for `u32` + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others = note: unsigned values cannot be negated -help: you may have meant the maximum value of `u32` +help: you may have meant to the wrapped-around value of type `u32` | LL - let x: u32 = -1; LL + let x: u32 = u32::MAX; @@ -39,4 +72,4 @@ LL + let x: u32 = u32::MAX; error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0600`. +For more information about this error, try `rustc --explain E0277`.