Skip to content

Commit 4326cb6

Browse files
committed
implement lint double_negation
1 parent 7e7240a commit 4326cb6

File tree

8 files changed

+117
-10
lines changed

8 files changed

+117
-10
lines changed

compiler/rustc_lint/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no lo
7979
lint_builtin_deref_nullptr = dereferencing a null pointer
8080
.label = this code causes undefined behavior when executed
8181
82+
lint_builtin_double_negation = use of a double negation
83+
lint_builtin_double_negation_help = consider adding parentheses between the negation operators or using the `-=` operator if you meant to decrement the value
84+
lint_builtin_double_negation_note = the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
85+
8286
lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
8387
.suggestion = use `..=` for an inclusive range
8488

compiler/rustc_lint/src/builtin.rs

+51-5
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ use crate::{
2626
lints::{
2727
BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle,
2828
BuiltinDeprecatedAttrLink, BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed,
29-
BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
30-
BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
31-
BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
32-
BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
29+
BuiltinDerefNullptr, BuiltinDoubleNegation, BuiltinEllipsisInclusiveRangePatternsLint,
30+
BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
31+
BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
32+
BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
3333
BuiltinMutablesTransmutes, BuiltinNamedAsmLabel, BuiltinNoMangleGeneric,
3434
BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds,
3535
BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion,
@@ -1627,6 +1627,51 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
16271627
}
16281628
}
16291629

1630+
declare_lint! {
1631+
/// The `double_negation` lint detects expressions of the form `--x`.
1632+
///
1633+
/// ### Example
1634+
///
1635+
/// ```rust
1636+
/// fn main() {
1637+
/// let x = 1;
1638+
/// let _b = --x;
1639+
/// }
1640+
/// ```
1641+
///
1642+
/// {{produces}}
1643+
///
1644+
/// ### Explanation
1645+
///
1646+
/// Negating something twice is usually the same as not negating it at all.
1647+
/// However, a double negation in Rust can easily be confused with the
1648+
/// prefix decrement operator that exists in many languages derived from C.
1649+
/// Use `-(-x)` if you really wanted to negate the value twice.
1650+
///
1651+
/// To decrement a value, use `x -= 1` instead.
1652+
pub DOUBLE_NEGATION,
1653+
Warn,
1654+
"detects expressions of the form `--x`"
1655+
}
1656+
1657+
declare_lint_pass!(
1658+
/// Lint for expressions of the form `--x` that can be confused with C's
1659+
/// prefix decrement operator.
1660+
DoubleNegation => [DOUBLE_NEGATION]
1661+
);
1662+
1663+
impl EarlyLintPass for DoubleNegation {
1664+
#[inline]
1665+
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
1666+
if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
1667+
&& let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
1668+
&& !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
1669+
{
1670+
cx.emit_span_lint(DOUBLE_NEGATION, expr.span, BuiltinDoubleNegation);
1671+
}
1672+
}
1673+
}
1674+
16301675
declare_lint_pass!(
16311676
/// Does nothing as a lint pass, but registers some `Lint`s
16321677
/// which are used by other parts of the compiler.
@@ -1646,7 +1691,8 @@ declare_lint_pass!(
16461691
UNSTABLE_FEATURES,
16471692
UNREACHABLE_PUB,
16481693
TYPE_ALIAS_BOUNDS,
1649-
TRIVIAL_BOUNDS
1694+
TRIVIAL_BOUNDS,
1695+
DOUBLE_NEGATION
16501696
]
16511697
);
16521698

compiler/rustc_lint/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ early_lint_methods!(
170170
IncompleteInternalFeatures: IncompleteInternalFeatures,
171171
RedundantSemicolons: RedundantSemicolons,
172172
UnusedDocComment: UnusedDocComment,
173+
DoubleNegation: DoubleNegation,
173174
]
174175
]
175176
);

compiler/rustc_lint/src/lints.rs

+6
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ pub struct BuiltinTrivialBounds<'a> {
348348
pub predicate: Clause<'a>,
349349
}
350350

351+
#[derive(LintDiagnostic)]
352+
#[diag(lint_builtin_double_negation)]
353+
#[note(lint_builtin_double_negation_note)]
354+
#[help(lint_builtin_double_negation_help)]
355+
pub struct BuiltinDoubleNegation;
356+
351357
#[derive(LintDiagnostic)]
352358
pub enum BuiltinEllipsisInclusiveRangePatternsLint {
353359
#[diag(lint_builtin_ellipsis_inclusive_range_patterns)]

tests/ui/lint/lint-double-negation.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ check-pass
2+
fn main() {
3+
let x = 1;
4+
-x;
5+
-(-x);
6+
--x; //~ WARN use of a double negation
7+
---x; //~ WARN use of a double negation
8+
let _y = --(-x); //~ WARN use of a double negation
9+
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
warning: use of a double negation
2+
--> $DIR/lint-double-negation.rs:6:5
3+
|
4+
LL | --x;
5+
| ^^^
6+
|
7+
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
8+
= help: consider adding parentheses between the negation operators or using the `-=` operator if you meant to decrement the value
9+
= note: `#[warn(double_negation)]` on by default
10+
11+
warning: use of a double negation
12+
--> $DIR/lint-double-negation.rs:7:6
13+
|
14+
LL | ---x;
15+
| ^^^
16+
|
17+
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
18+
= help: consider adding parentheses between the negation operators or using the `-=` operator if you meant to decrement the value
19+
20+
warning: use of a double negation
21+
--> $DIR/lint-double-negation.rs:8:14
22+
|
23+
LL | let _y = --(-x);
24+
| ^^^^^^
25+
|
26+
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
27+
= help: consider adding parentheses between the negation operators or using the `-=` operator if you meant to decrement the value
28+
29+
warning: 3 warnings emitted
30+

tests/ui/lint/lint-type-overflow2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
fn main() {
66
let x2: i8 = --128; //~ ERROR literal out of range for `i8`
7+
//~| WARN use of a double negation
78

89
let x = -3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
910
let x = 3.40282357e+38_f32; //~ ERROR literal out of range for `f32`

tests/ui/lint/lint-type-overflow2.stderr

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
warning: use of a double negation
2+
--> $DIR/lint-type-overflow2.rs:6:18
3+
|
4+
LL | let x2: i8 = --128;
5+
| ^^^^^
6+
|
7+
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
8+
= help: consider adding parentheses between the negation operators or using the `-=` operator if you meant to decrement the value
9+
= note: `#[warn(double_negation)]` on by default
10+
111
error: literal out of range for `i8`
212
--> $DIR/lint-type-overflow2.rs:6:20
313
|
@@ -13,36 +23,36 @@ LL | #![deny(overflowing_literals)]
1323
| ^^^^^^^^^^^^^^^^^^^^
1424

1525
error: literal out of range for `f32`
16-
--> $DIR/lint-type-overflow2.rs:8:14
26+
--> $DIR/lint-type-overflow2.rs:9:14
1727
|
1828
LL | let x = -3.40282357e+38_f32;
1929
| ^^^^^^^^^^^^^^^^^^
2030
|
2131
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
2232

2333
error: literal out of range for `f32`
24-
--> $DIR/lint-type-overflow2.rs:9:14
34+
--> $DIR/lint-type-overflow2.rs:10:14
2535
|
2636
LL | let x = 3.40282357e+38_f32;
2737
| ^^^^^^^^^^^^^^^^^^
2838
|
2939
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
3040

3141
error: literal out of range for `f64`
32-
--> $DIR/lint-type-overflow2.rs:10:14
42+
--> $DIR/lint-type-overflow2.rs:11:14
3343
|
3444
LL | let x = -1.7976931348623159e+308_f64;
3545
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
3646
|
3747
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
3848

3949
error: literal out of range for `f64`
40-
--> $DIR/lint-type-overflow2.rs:11:14
50+
--> $DIR/lint-type-overflow2.rs:12:14
4151
|
4252
LL | let x = 1.7976931348623159e+308_f64;
4353
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
4454
|
4555
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
4656

47-
error: aborting due to 5 previous errors
57+
error: aborting due to 5 previous errors; 1 warning emitted
4858

0 commit comments

Comments
 (0)