Skip to content

Commit 37967d9

Browse files
unused_parens now fires on cast
fix broken test refactor: replace bool params with single enum param bless add more test case fix lint implementation correct test case bless bless fix in test case fix in library add test case unused_parens now fires on cast
1 parent f217411 commit 37967d9

File tree

16 files changed

+346
-30
lines changed

16 files changed

+346
-30
lines changed

compiler/rustc_lint/src/unused.rs

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,7 @@ enum UnusedDelimsCtx {
572572
AnonConst,
573573
MatchArmExpr,
574574
IndexExpr,
575+
CastExpr,
575576
}
576577

577578
impl From<UnusedDelimsCtx> for &'static str {
@@ -592,10 +593,18 @@ impl From<UnusedDelimsCtx> for &'static str {
592593
UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
593594
UnusedDelimsCtx::MatchArmExpr => "match arm expression",
594595
UnusedDelimsCtx::IndexExpr => "index expression",
596+
UnusedDelimsCtx::CastExpr => "cast expression",
595597
}
596598
}
597599
}
598600

601+
#[derive(Copy, Clone, Eq, PartialEq)]
602+
enum UnusedDelimCtxFollowedTokenKind {
603+
Block,
604+
Else,
605+
Cast,
606+
}
607+
599608
/// Used by both `UnusedParens` and `UnusedBraces` to prevent code duplication.
600609
trait UnusedDelimLint {
601610
const DELIM_STR: &'static str;
@@ -629,9 +638,14 @@ trait UnusedDelimLint {
629638

630639
fn is_expr_delims_necessary(
631640
inner: &ast::Expr,
632-
followed_by_block: bool,
633-
followed_by_else: bool,
641+
followed_token: Option<UnusedDelimCtxFollowedTokenKind>,
634642
) -> bool {
643+
let followed_by_block =
644+
matches!(followed_token, Some(UnusedDelimCtxFollowedTokenKind::Block));
645+
let followed_by_else =
646+
matches!(followed_token, Some(UnusedDelimCtxFollowedTokenKind::Else));
647+
let followed_by_cast =
648+
matches!(followed_token, Some(UnusedDelimCtxFollowedTokenKind::Cast));
635649
if followed_by_else {
636650
match inner.kind {
637651
ast::ExprKind::Binary(op, ..) if op.node.lazy() => return true,
@@ -640,6 +654,20 @@ trait UnusedDelimLint {
640654
}
641655
}
642656

657+
if followed_by_cast {
658+
match inner.kind {
659+
// `as` has higher precedence than any binary operator
660+
ast::ExprKind::Binary(..)
661+
// #88519
662+
| ast::ExprKind::Block(..)
663+
| ast::ExprKind::Match(..)
664+
| ast::ExprKind::If(..)
665+
// #51185
666+
| ast::ExprKind::Closure(..) => return true,
667+
_ => {}
668+
}
669+
}
670+
643671
// Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`.
644672
{
645673
let mut innermost = inner;
@@ -964,9 +992,18 @@ impl UnusedDelimLint for UnusedParens {
964992
) {
965993
match value.kind {
966994
ast::ExprKind::Paren(ref inner) => {
967-
let followed_by_else = ctx == UnusedDelimsCtx::AssignedValueLetElse;
968-
if !Self::is_expr_delims_necessary(inner, followed_by_block, followed_by_else)
969-
&& value.attrs.is_empty()
995+
if !Self::is_expr_delims_necessary(
996+
inner,
997+
if followed_by_block {
998+
Some(UnusedDelimCtxFollowedTokenKind::Block)
999+
} else if ctx == UnusedDelimsCtx::AssignedValueLetElse {
1000+
Some(UnusedDelimCtxFollowedTokenKind::Else)
1001+
} else if ctx == UnusedDelimsCtx::CastExpr {
1002+
Some(UnusedDelimCtxFollowedTokenKind::Cast)
1003+
} else {
1004+
None
1005+
},
1006+
) && value.attrs.is_empty()
9701007
&& !value.span.from_expansion()
9711008
&& (ctx != UnusedDelimsCtx::LetScrutineeExpr
9721009
|| !matches!(inner.kind, ast::ExprKind::Binary(
@@ -989,6 +1026,15 @@ impl UnusedDelimLint for UnusedParens {
9891026
false,
9901027
);
9911028
}
1029+
ast::ExprKind::Cast(ref expr, _) => self.check_unused_delims_expr(
1030+
cx,
1031+
expr,
1032+
UnusedDelimsCtx::CastExpr,
1033+
followed_by_block,
1034+
None,
1035+
None,
1036+
),
1037+
9921038
_ => {}
9931039
}
9941040
}
@@ -1248,10 +1294,12 @@ impl UnusedDelimLint for UnusedBraces {
12481294
// FIXME(const_generics): handle paths when #67075 is fixed.
12491295
if let [stmt] = inner.stmts.as_slice() {
12501296
if let ast::StmtKind::Expr(ref expr) = stmt.kind {
1251-
if !Self::is_expr_delims_necessary(expr, followed_by_block, false)
1252-
&& (ctx != UnusedDelimsCtx::AnonConst
1253-
|| (matches!(expr.kind, ast::ExprKind::Lit(_))
1254-
&& !expr.span.from_expansion()))
1297+
if !Self::is_expr_delims_necessary(
1298+
expr,
1299+
followed_by_block.then_some(UnusedDelimCtxFollowedTokenKind::Block),
1300+
) && (ctx != UnusedDelimsCtx::AnonConst
1301+
|| (matches!(expr.kind, ast::ExprKind::Lit(_))
1302+
&& !expr.span.from_expansion()))
12551303
&& !cx.sess().source_map().is_multiline(value.span)
12561304
&& value.attrs.is_empty()
12571305
&& !value.span.from_expansion()

library/alloc/src/sync.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ mod tests;
5555
/// This is a global invariant, and also applies when using a compare-exchange loop.
5656
///
5757
/// See comment in `Arc::clone`.
58-
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
58+
const MAX_REFCOUNT: usize = isize::MAX as usize;
5959

6060
/// The error in case either counter reaches above `MAX_REFCOUNT`, and we can `panic` safely.
6161
const INTERNAL_OVERFLOW_ERROR: &str = "Arc counter overflow";

library/core/src/num/dec2flt/number.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl Number {
6363
// normal fast path
6464
let value = F::from_u64(self.mantissa);
6565
if self.exponent < 0 {
66-
value / F::pow10_fast_path((-self.exponent) as _)
66+
value / F::pow10_fast_path(-self.exponent as _)
6767
} else {
6868
value * F::pow10_fast_path(self.exponent as _)
6969
}

library/core/src/num/dec2flt/parse.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn parse_8digits(mut v: u64) -> u64 {
2222
v = (v * 10) + (v >> 8); // will not overflow, fits in 63 bits
2323
let v1 = (v & MASK).wrapping_mul(MUL1);
2424
let v2 = ((v >> 16) & MASK).wrapping_mul(MUL2);
25-
((v1.wrapping_add(v2) >> 32) as u32) as u64
25+
(v1.wrapping_add(v2) >> 32) as u32 as u64
2626
}
2727

2828
/// Parse digits until a non-digit character is found.

library/core/src/num/dec2flt/slow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
6464
_ => 1,
6565
}
6666
} else {
67-
get_shift((-d.decimal_point) as _)
67+
get_shift(-d.decimal_point as _)
6868
};
6969
d.left_shift(shift);
7070
if d.decimal_point > Decimal::DECIMAL_POINT_RANGE {

library/std/src/io/buffered/bufreader.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,8 @@ impl<R: ?Sized + Seek> BufReader<R> {
244244
pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
245245
let pos = self.buf.pos() as u64;
246246
if offset < 0 {
247-
if let Some(_) = pos.checked_sub((-offset) as u64) {
248-
self.buf.unconsume((-offset) as usize);
247+
if let Some(_) = pos.checked_sub(-offset as u64) {
248+
self.buf.unconsume(-offset as usize);
249249
return Ok(());
250250
}
251251
} else if let Some(new_pos) = pos.checked_add(offset as u64) {

library/std/src/sys/unix/os.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ extern "C" {
7373
/// Returns the platform-specific value of errno
7474
#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
7575
pub fn errno() -> i32 {
76-
unsafe { (*errno_location()) as i32 }
76+
unsafe { *errno_location() as i32 }
7777
}
7878

7979
/// Sets the platform-specific value of errno

tests/ui/const-ptr/allowed_slices.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 1) };
2020
pub static S3: &[MaybeUninit<&u32>] = unsafe { from_raw_parts(&D1, 1) };
2121

2222
// Reinterpreting data is fine, as long as layouts match
23-
pub static S4: &[u8] = unsafe { from_raw_parts((&D0) as *const _ as _, 3) };
23+
pub static S4: &[u8] = unsafe { from_raw_parts(&D0 as *const _ as _, 3) };
2424
// This is only valid because D1 has uninitialized bytes, if it was an initialized pointer,
2525
// that would reinterpret pointers as integers which is UB in CTFE.
26-
pub static S5: &[MaybeUninit<u8>] = unsafe { from_raw_parts((&D1) as *const _ as _, 2) };
26+
pub static S5: &[MaybeUninit<u8>] = unsafe { from_raw_parts(&D1 as *const _ as _, 2) };
2727
// Even though u32 and [bool; 4] have different layouts, D0 has a value that
2828
// is valid as [bool; 4], so this is not UB (it's basically a transmute)
29-
pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
29+
pub static S6: &[bool] = unsafe { from_raw_parts(&D0 as *const _ as _, 4) };
3030

3131
// Structs are considered single allocated objects,
3232
// as long as you don't reinterpret padding as initialized

tests/ui/consts/issue-27890.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// run-pass
2-
static PLUS_ONE: &'static (dyn Fn(i32) -> i32 + Sync) = (&|x: i32| { x + 1 })
2+
static PLUS_ONE: &'static (dyn Fn(i32) -> i32 + Sync) = &(|x: i32| { x + 1 })
33
as &'static (dyn Fn(i32) -> i32 + Sync);
44

55
fn main() {

tests/ui/lint/unused_parens_cast.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// check-pass
2+
3+
#![warn(unused_parens)]
4+
5+
struct Foo(f32);
6+
7+
impl Foo {
8+
pub fn f32(self) -> f32 {
9+
64.0f32
10+
}
11+
}
12+
13+
fn bar() -> f32 {
14+
3.0f32
15+
}
16+
17+
mod inner {
18+
pub mod yet_inner {
19+
pub mod most_inner {
20+
pub static VERY_LONG_PATH: f32 = 99.0f32;
21+
}
22+
}
23+
}
24+
25+
fn basic_test() {
26+
// should fire
27+
let one = 1.0f32;
28+
let _ = (one) as f64;
29+
//~^ WARN unnecessary parentheses around cast expression
30+
let _ = (inner::yet_inner::most_inner::VERY_LONG_PATH) as f64;
31+
//~^ WARN unnecessary parentheses around cast expression
32+
let _ = (Foo(1.0f32).0) as f64;
33+
//~^ WARN unnecessary parentheses around cast expression
34+
let _ = (Foo(1.0f32).f32()) as f64;
35+
//~^ WARN unnecessary parentheses around cast expression
36+
let _ = (bar()) as f64;
37+
//~^ WARN unnecessary parentheses around cast expression
38+
let baz = [4.0f32];
39+
let _ = (baz[0]) as f64;
40+
//~^ WARN unnecessary parentheses around cast expression
41+
let _ = (-1.0f32) as f64;
42+
//~^ WARN unnecessary parentheses around cast expression
43+
let x = Box::new(-1.0f32);
44+
let _ = (*x) as f64;
45+
//~^ WARN unnecessary parentheses around cast expression
46+
// cast is left-assoc
47+
let _ = (true as u8) as u16;
48+
//~^ WARN unnecessary parentheses around cast expression
49+
// should not fire
50+
let _ = (1.0f32 * 2.0f32) as f64;
51+
let _ = (1.0f32 / 2.0f32) as f64;
52+
let _ = (1.0f32 % 2.0f32) as f64;
53+
let _ = (1.0f32 + 2.0f32) as f64;
54+
let _ = (1.0f32 - 2.0f32) as f64;
55+
let _ = (42 << 1) as i64;
56+
let _ = (42 >> 1) as i64;
57+
let _ = (42 & 0x1F) as f64;
58+
let _ = (42 ^ 0x1F) as f64;
59+
let _ = (42 | 0x1F) as f64;
60+
let _ = (1.0f32 == 2.0f32) as u8;
61+
let _ = (1.0f32 != 2.0f32) as u8;
62+
let _ = (1.0f32 < 2.0f32) as u8;
63+
let _ = (1.0f32 > 2.0f32) as u8;
64+
let _ = (1.0f32 <= 2.0f32) as u8;
65+
let _ = (1.0f32 >= 2.0f32) as u8;
66+
let _ = (true && false) as u8;
67+
let _ = (true || false) as u8;
68+
// skipped range: `as`-cast does not allow non-primitive cast
69+
// also skipped compound operator
70+
}
71+
72+
fn issue_88519() {
73+
let _ = ({ 1 }) as i64;
74+
let _ = (match 0 { x => x }) as i64;
75+
let _ = (if true { 16 } else { 42 }) as i64;
76+
}
77+
78+
fn issue_51185() -> impl Into<for<'a> fn(&'a ())> {
79+
// removing parens will change semantics, and make compile does not pass
80+
(|_| {}) as for<'a> fn(&'a ())
81+
}
82+
83+
fn issue_clippy_10557() {
84+
let x = 0f32;
85+
let y = 0f32;
86+
let width = 100f32;
87+
let height = 100f32;
88+
89+
new_rect((x) as f64, (y) as f64, (width) as f64, (height) as f64);
90+
//~^ WARN unnecessary parentheses around cast expression
91+
//~^^ WARN unnecessary parentheses around cast expression
92+
//~^^^ WARN unnecessary parentheses around cast expression
93+
//~^^^^ WARN unnecessary parentheses around cast expression
94+
}
95+
96+
fn new_rect(x: f64, y: f64, width: f64, height: f64) {
97+
98+
}
99+
100+
fn main() {
101+
}

0 commit comments

Comments
 (0)