1
Fork 0

Rollup merge of #136393 - oli-obk:pattern-type-lit-oflo-checks, r=compiler-errors

Fix accidentally not emitting overflowing literals lints anymore in patterns

This was regressed in https://github.com/rust-lang/rust/pull/134228 (not in beta yet).

The issue was that previously we nested `hir::Expr` inside `hir::PatKind::Lit`, so it was linted by the expression code.

So now I've set it up for visitors to be able to directly visit literals and get all literals
This commit is contained in:
Matthias Krüger 2025-02-06 13:09:59 +01:00 committed by GitHub
commit 85a9de5d51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 141 additions and 55 deletions

View file

@ -345,6 +345,9 @@ pub trait Visitor<'v>: Sized {
fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result { fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result {
walk_pat_expr(self, expr) walk_pat_expr(self, expr)
} }
fn visit_lit(&mut self, _hir_id: HirId, _lit: &'v Lit, _negated: bool) -> Self::Result {
Self::Result::output()
}
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
walk_anon_const(self, c) walk_anon_const(self, c)
} }
@ -764,7 +767,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 { 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)); try_visit!(visitor.visit_id(expr.hir_id));
match &expr.kind { match &expr.kind {
PatExprKind::Lit { .. } => V::Result::output(), PatExprKind::Lit { lit, negated } => visitor.visit_lit(expr.hir_id, lit, *negated),
PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c), PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c),
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span), PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span),
} }
@ -912,7 +915,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
try_visit!(visitor.visit_expr(expr)); try_visit!(visitor.visit_expr(expr));
visit_opt!(visitor, visit_ty_unambig, ty); visit_opt!(visitor, visit_ty_unambig, ty);
} }
ExprKind::Lit(_) | ExprKind::Err(_) => {} ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(expression.hir_id, lit, false)),
ExprKind::Err(_) => {}
} }
V::Result::output() V::Result::output()
} }

View file

@ -152,6 +152,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
hir_visit::walk_pat(self, p); 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_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
self.with_lint_attrs(field.hir_id, |cx| hir_visit::walk_expr_field(cx, field)) self.with_lint_attrs(field.hir_id, |cx| hir_visit::walk_expr_field(cx, field))
} }

View file

@ -23,6 +23,7 @@ macro_rules! late_lint_methods {
fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>); fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>);
fn check_arm(a: &'tcx rustc_hir::Arm<'tcx>); fn check_arm(a: &'tcx rustc_hir::Arm<'tcx>);
fn check_pat(a: &'tcx rustc_hir::Pat<'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_expr(a: &'tcx rustc_hir::Expr<'tcx>); fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>);
fn check_expr_post(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>); fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>);

View file

@ -5,7 +5,7 @@ use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, Wrapp
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::DiagMessage; use rustc_errors::DiagMessage;
use rustc_hir::intravisit::VisitorExt; use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{AmbigArg, Expr, ExprKind, LangItem}; use rustc_hir::{AmbigArg, Expr, ExprKind, HirId, LangItem};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton}; use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
use rustc_middle::ty::{ use rustc_middle::ty::{
@ -536,6 +536,16 @@ fn lint_fn_pointer<'tcx>(
} }
impl<'tcx> LateLintPass<'tcx> for TypeLimits { impl<'tcx> LateLintPass<'tcx> for TypeLimits {
fn check_lit(
&mut self,
cx: &LateContext<'tcx>,
hir_id: HirId,
lit: &'tcx hir::Lit,
negated: bool,
) {
lint_literal(cx, self, hir_id, lit.span, lit, negated)
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
match e.kind { match e.kind {
hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
@ -557,7 +567,6 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
} }
} }
} }
hir::ExprKind::Lit(lit) => lint_literal(cx, self, e, lit),
hir::ExprKind::Call(path, [l, r]) hir::ExprKind::Call(path, [l, r])
if let ExprKind::Path(ref qpath) = path.kind if let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()

View file

@ -1,8 +1,10 @@
use hir::{ExprKind, Node, is_range_literal}; use hir::{ExprKind, Node, is_range_literal};
use rustc_abi::{Integer, Size}; use rustc_abi::{Integer, Size};
use rustc_hir::HirId;
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::{bug, ty}; use rustc_middle::{bug, ty};
use rustc_span::Span;
use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
use crate::LateContext; use crate::LateContext;
@ -21,21 +23,22 @@ fn lint_overflowing_range_endpoint<'tcx>(
lit: &hir::Lit, lit: &hir::Lit,
lit_val: u128, lit_val: u128,
max: u128, max: u128,
expr: &'tcx hir::Expr<'tcx>, hir_id: HirId,
lit_span: Span,
ty: &str, ty: &str,
) -> bool { ) -> bool {
// Look past casts to support cases like `0..256 as u8` // Look past casts to support cases like `0..256 as u8`
let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.parent_hir_node(expr.hir_id) let (hir_id, span) = if let Node::Expr(par_expr) = cx.tcx.parent_hir_node(hir_id)
&& let ExprKind::Cast(_, _) = par_expr.kind && let ExprKind::Cast(_, _) = par_expr.kind
{ {
(par_expr, expr.span) (par_expr.hir_id, par_expr.span)
} else { } else {
(expr, expr.span) (hir_id, lit_span)
}; };
// We only want to handle exclusive (`..`) ranges, // We only want to handle exclusive (`..`) ranges,
// which are represented as `ExprKind::Struct`. // which are represented as `ExprKind::Struct`.
let Node::ExprField(field) = cx.tcx.parent_hir_node(expr.hir_id) else { return false }; let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { return false };
let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false }; let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false };
if !is_range_literal(struct_expr) { if !is_range_literal(struct_expr) {
return false; return false;
@ -45,7 +48,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
// We can suggest using an inclusive range // We can suggest using an inclusive range
// (`..=`) instead only if it is the `end` that is // (`..=`) instead only if it is the `end` that is
// overflowing and only by 1. // overflowing and only by 1.
if !(end.expr.hir_id == expr.hir_id && lit_val - 1 == max) { if !(end.expr.hir_id == hir_id && lit_val - 1 == max) {
return false; return false;
}; };
@ -57,7 +60,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
_ => bug!(), _ => bug!(),
}; };
let sub_sugg = if expr.span.lo() == lit_span.lo() { let sub_sugg = if span.lo() == lit_span.lo() {
let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false }; let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false };
UseInclusiveRange::WithoutParen { UseInclusiveRange::WithoutParen {
sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()), sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
@ -67,7 +70,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
} }
} else { } else {
UseInclusiveRange::WithParen { UseInclusiveRange::WithParen {
eq_sugg: expr.span.shrink_to_lo(), eq_sugg: span.shrink_to_lo(),
lit_sugg: lit_span, lit_sugg: lit_span,
literal: lit_val - 1, literal: lit_val - 1,
suffix, suffix,
@ -125,7 +128,8 @@ fn get_bin_hex_repr(cx: &LateContext<'_>, lit: &hir::Lit) -> Option<String> {
fn report_bin_hex_error( fn report_bin_hex_error(
cx: &LateContext<'_>, cx: &LateContext<'_>,
expr: &hir::Expr<'_>, hir_id: HirId,
span: Span,
ty: attr::IntType, ty: attr::IntType,
size: Size, size: Size,
repr_str: String, repr_str: String,
@ -144,11 +148,11 @@ fn report_bin_hex_error(
}; };
let sign = let sign =
if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive }; if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive };
let sub = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative).map( let sub = get_type_suggestion(cx.typeck_results().node_type(hir_id), val, negative).map(
|suggestion_ty| { |suggestion_ty| {
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos); let (sans_suffix, _) = repr_str.split_at(pos);
OverflowingBinHexSub::Suggestion { span: expr.span, suggestion_ty, sans_suffix } OverflowingBinHexSub::Suggestion { span, suggestion_ty, sans_suffix }
} else { } else {
OverflowingBinHexSub::Help { suggestion_ty } OverflowingBinHexSub::Help { suggestion_ty }
} }
@ -156,7 +160,7 @@ fn report_bin_hex_error(
); );
let sign_bit_sub = (!negative) let sign_bit_sub = (!negative)
.then(|| { .then(|| {
let ty::Int(int_ty) = cx.typeck_results().node_type(expr.hir_id).kind() else { let ty::Int(int_ty) = cx.typeck_results().node_type(hir_id).kind() else {
return None; return None;
}; };
@ -177,7 +181,7 @@ fn report_bin_hex_error(
}; };
Some(OverflowingBinHexSignBitSub { Some(OverflowingBinHexSignBitSub {
span: expr.span, span,
lit_no_suffix, lit_no_suffix,
negative_val: actually.clone(), negative_val: actually.clone(),
int_ty: int_ty.name_str(), int_ty: int_ty.name_str(),
@ -186,7 +190,7 @@ fn report_bin_hex_error(
}) })
.flatten(); .flatten();
cx.emit_span_lint(OVERFLOWING_LITERALS, expr.span, OverflowingBinHex { cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingBinHex {
ty: t, ty: t,
lit: repr_str.clone(), lit: repr_str.clone(),
dec: val, dec: val,
@ -236,15 +240,17 @@ fn literal_to_i128(val: u128, negative: bool) -> Option<i128> {
fn lint_int_literal<'tcx>( fn lint_int_literal<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
type_limits: &TypeLimits, type_limits: &TypeLimits,
e: &'tcx hir::Expr<'tcx>, hir_id: HirId,
span: Span,
lit: &hir::Lit, lit: &hir::Lit,
t: ty::IntTy, t: ty::IntTy,
v: u128, v: u128,
negated: bool,
) { ) {
let int_type = t.normalize(cx.sess().target.pointer_width); let int_type = t.normalize(cx.sess().target.pointer_width);
let (min, max) = int_ty_range(int_type); let (min, max) = int_ty_range(int_type);
let max = max as u128; let max = max as u128;
let negative = type_limits.negated_expr_id == Some(e.hir_id); let negative = negated ^ (type_limits.negated_expr_id == Some(hir_id));
// Detect literal value out of range [min, max] inclusive // Detect literal value out of range [min, max] inclusive
// avoiding use of -min to prevent overflow/panic // avoiding use of -min to prevent overflow/panic
@ -252,7 +258,8 @@ fn lint_int_literal<'tcx>(
if let Some(repr_str) = get_bin_hex_repr(cx, lit) { if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
report_bin_hex_error( report_bin_hex_error(
cx, cx,
e, hir_id,
span,
attr::IntType::SignedInt(ty::ast_int_ty(t)), attr::IntType::SignedInt(ty::ast_int_ty(t)),
Integer::from_int_ty(cx, t).size(), Integer::from_int_ty(cx, t).size(),
repr_str, repr_str,
@ -262,18 +269,18 @@ fn lint_int_literal<'tcx>(
return; return;
} }
if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) { if lint_overflowing_range_endpoint(cx, lit, v, max, hir_id, span, t.name_str()) {
// The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`. // The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`.
return; return;
} }
let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span }; let span = if negative { type_limits.negated_expr_span.unwrap() } else { span };
let lit = cx let lit = cx
.sess() .sess()
.source_map() .source_map()
.span_to_snippet(span) .span_to_snippet(span)
.unwrap_or_else(|_| if negative { format!("-{v}") } else { v.to_string() }); .unwrap_or_else(|_| if negative { format!("-{v}") } else { v.to_string() });
let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) let help = get_type_suggestion(cx.typeck_results().node_type(hir_id), v, negative)
.map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingInt { cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingInt {
@ -288,7 +295,8 @@ fn lint_int_literal<'tcx>(
fn lint_uint_literal<'tcx>( fn lint_uint_literal<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
e: &'tcx hir::Expr<'tcx>, hir_id: HirId,
span: Span,
lit: &hir::Lit, lit: &hir::Lit,
t: ty::UintTy, t: ty::UintTy,
) { ) {
@ -302,7 +310,7 @@ fn lint_uint_literal<'tcx>(
}; };
if lit_val < min || lit_val > max { if lit_val < min || lit_val > max {
if let Node::Expr(par_e) = cx.tcx.parent_hir_node(e.hir_id) { if let Node::Expr(par_e) = cx.tcx.parent_hir_node(hir_id) {
match par_e.kind { match par_e.kind {
hir::ExprKind::Cast(..) => { hir::ExprKind::Cast(..) => {
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
@ -316,14 +324,15 @@ fn lint_uint_literal<'tcx>(
_ => {} _ => {}
} }
} }
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) { if lint_overflowing_range_endpoint(cx, lit, lit_val, max, hir_id, span, t.name_str()) {
// The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`. // The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`.
return; return;
} }
if let Some(repr_str) = get_bin_hex_repr(cx, lit) { if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
report_bin_hex_error( report_bin_hex_error(
cx, cx,
e, hir_id,
span,
attr::IntType::UnsignedInt(ty::ast_uint_ty(t)), attr::IntType::UnsignedInt(ty::ast_uint_ty(t)),
Integer::from_uint_ty(cx, t).size(), Integer::from_uint_ty(cx, t).size(),
repr_str, repr_str,
@ -332,7 +341,7 @@ fn lint_uint_literal<'tcx>(
); );
return; return;
} }
cx.emit_span_lint(OVERFLOWING_LITERALS, e.span, OverflowingUInt { cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingUInt {
ty: t.name_str(), ty: t.name_str(),
lit: cx lit: cx
.sess() .sess()
@ -348,19 +357,24 @@ fn lint_uint_literal<'tcx>(
pub(crate) fn lint_literal<'tcx>( pub(crate) fn lint_literal<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
type_limits: &TypeLimits, type_limits: &TypeLimits,
e: &'tcx hir::Expr<'tcx>, hir_id: HirId,
span: Span,
lit: &hir::Lit, lit: &hir::Lit,
negated: bool,
) { ) {
match *cx.typeck_results().node_type(e.hir_id).kind() { match *cx.typeck_results().node_type(hir_id).kind() {
ty::Int(t) => { ty::Int(t) => {
match lit.node { match lit.node {
ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => {
lint_int_literal(cx, type_limits, e, lit, t, v.get()) lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get(), negated)
} }
_ => bug!(), _ => bug!(),
}; };
} }
ty::Uint(t) => lint_uint_literal(cx, e, lit, t), ty::Uint(t) => {
assert!(!negated);
lint_uint_literal(cx, hir_id, span, lit, t)
}
ty::Float(t) => { ty::Float(t) => {
let (is_infinite, sym) = match lit.node { let (is_infinite, sym) = match lit.node {
ast::LitKind::Float(v, _) => match t { ast::LitKind::Float(v, _) => match t {
@ -374,7 +388,7 @@ pub(crate) fn lint_literal<'tcx>(
_ => bug!(), _ => bug!(),
}; };
if is_infinite == Ok(true) { if is_infinite == Ok(true) {
cx.emit_span_lint(OVERFLOWING_LITERALS, e.span, OverflowingLiteral { cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingLiteral {
ty: t.name_str(), ty: t.name_str(),
lit: cx lit: cx
.sess() .sess()

View file

@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_attr_parsing::RustcVersion; use rustc_attr_parsing::RustcVersion;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{HirId, Lit};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::symbol; use rustc_span::{Span, symbol};
use std::f64::consts as f64; use std::f64::consts as f64;
declare_clippy_lint! { declare_clippy_lint! {
@ -73,22 +73,28 @@ impl ApproxConstant {
msrv: conf.msrv.clone(), msrv: conf.msrv.clone(),
} }
} }
}
fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { impl<'tcx> LateLintPass<'tcx> for ApproxConstant {
match *lit { fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) {
match lit.node {
LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
FloatTy::F16 => self.check_known_consts(cx, e, s, "f16"), FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"),
FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"), FloatTy::F32 => self.check_known_consts(cx, lit.span, s, "f32"),
FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"), FloatTy::F64 => self.check_known_consts(cx, lit.span, s, "f64"),
FloatTy::F128 => self.check_known_consts(cx, e, s, "f128"), FloatTy::F128 => self.check_known_consts(cx, lit.span, s, "f128"),
}, },
// FIXME(f16_f128): add `f16` and `f128` when these types become stable. // FIXME(f16_f128): add `f16` and `f128` when these types become stable.
LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"), LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, lit.span, s, "f{32, 64}"),
_ => (), _ => (),
} }
} }
fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) { extract_msrv_attr!(LateContext);
}
impl ApproxConstant {
fn check_known_consts(&self, cx: &LateContext<'_>, span: Span, s: symbol::Symbol, module: &str) {
let s = s.as_str(); let s = s.as_str();
if s.parse::<f64>().is_ok() { if s.parse::<f64>().is_ok() {
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
@ -96,7 +102,7 @@ impl ApproxConstant {
span_lint_and_help( span_lint_and_help(
cx, cx,
APPROX_CONSTANT, APPROX_CONSTANT,
e.span, span,
format!("approximate value of `{module}::consts::{name}` found"), format!("approximate value of `{module}::consts::{name}` found"),
None, None,
"consider using the constant directly", "consider using the constant directly",
@ -110,16 +116,6 @@ impl ApproxConstant {
impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]); impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]);
impl<'tcx> LateLintPass<'tcx> for ApproxConstant {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::Lit(lit) = &e.kind {
self.check_lit(cx, &lit.node, e);
}
}
extract_msrv_attr!(LateContext);
}
/// Returns `false` if the number of significant figures in `value` are /// Returns `false` if the number of significant figures in `value` are
/// less than `min_digits`; otherwise, returns true if `value` is equal /// less than `min_digits`; otherwise, returns true if `value` is equal
/// to `constant`, rounded to the number of digits present in `value`. /// to `constant`, rounded to the number of digits present in `value`.

View file

@ -0,0 +1,21 @@
//! Check that overflowing literals are in patterns are rejected
#![feature(pattern_types)]
#![feature(pattern_type_macro)]
use std::pat::pattern_type;
type TooBig = pattern_type!(u8 is 500..);
//~^ ERROR: literal out of range for `u8`
type TooSmall = pattern_type!(i8 is -500..);
//~^ ERROR: literal out of range for `i8`
type TooBigSigned = pattern_type!(i8 is 200..);
//~^ ERROR: literal out of range for `i8`
fn main() {
match 5_u8 {
500 => {}
//~^ ERROR literal out of range for `u8`
_ => {}
}
}

View file

@ -0,0 +1,37 @@
error: literal out of range for `u8`
--> $DIR/overflowing-literals.rs:8:35
|
LL | type TooBig = pattern_type!(u8 is 500..);
| ^^^
|
= note: the literal `500` does not fit into the type `u8` whose range is `0..=255`
= note: `#[deny(overflowing_literals)]` on by default
error: literal out of range for `i8`
--> $DIR/overflowing-literals.rs:10:37
|
LL | type TooSmall = pattern_type!(i8 is -500..);
| ^^^^
|
= note: the literal `-500` 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`
--> $DIR/overflowing-literals.rs:12:41
|
LL | type TooBigSigned = pattern_type!(i8 is 200..);
| ^^^
|
= note: the literal `200` 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 `u8`
--> $DIR/overflowing-literals.rs:17:9
|
LL | 500 => {}
| ^^^
|
= note: the literal `500` does not fit into the type `u8` whose range is `0..=255`
error: aborting due to 4 previous errors