@@ -50,6 +50,7 @@ use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
5050use crate :: lints:: {
5151 BuiltinAnonymousParams , BuiltinConstNoMangle , BuiltinDeprecatedAttrLink ,
5252 BuiltinDeprecatedAttrLinkSuggestion , BuiltinDeprecatedAttrUsed , BuiltinDerefNullptr ,
53+ BuiltinDoubleNegations , BuiltinDoubleNegationsAddParens ,
5354 BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
5455 BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
5556 BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
@@ -1574,6 +1575,58 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
15741575 }
15751576}
15761577
1578+ declare_lint ! {
1579+ /// The `double_negations` lint detects expressions of the form `--x`.
1580+ ///
1581+ /// ### Example
1582+ ///
1583+ /// ```rust
1584+ /// fn main() {
1585+ /// let x = 1;
1586+ /// let _b = --x;
1587+ /// }
1588+ /// ```
1589+ ///
1590+ /// {{produces}}
1591+ ///
1592+ /// ### Explanation
1593+ ///
1594+ /// Negating something twice is usually the same as not negating it at all.
1595+ /// However, a double negation in Rust can easily be confused with the
1596+ /// prefix decrement operator that exists in many languages derived from C.
1597+ /// Use `-(-x)` if you really wanted to negate the value twice.
1598+ ///
1599+ /// To decrement a value, use `x -= 1` instead.
1600+ pub DOUBLE_NEGATIONS ,
1601+ Warn ,
1602+ "detects expressions of the form `--x`"
1603+ }
1604+
1605+ declare_lint_pass ! (
1606+ /// Lint for expressions of the form `--x` that can be confused with C's
1607+ /// prefix decrement operator.
1608+ DoubleNegations => [ DOUBLE_NEGATIONS ]
1609+ ) ;
1610+
1611+ impl EarlyLintPass for DoubleNegations {
1612+ #[ inline]
1613+ fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
1614+ // only lint on the innermost `--` in a chain of `-` operators,
1615+ // even if there are 3 or more negations
1616+ if let ExprKind :: Unary ( UnOp :: Neg , ref inner) = expr. kind
1617+ && let ExprKind :: Unary ( UnOp :: Neg , ref inner2) = inner. kind
1618+ && !matches ! ( inner2. kind, ExprKind :: Unary ( UnOp :: Neg , _) )
1619+ {
1620+ cx. emit_span_lint ( DOUBLE_NEGATIONS , expr. span , BuiltinDoubleNegations {
1621+ add_parens : BuiltinDoubleNegationsAddParens {
1622+ start_span : inner. span . shrink_to_lo ( ) ,
1623+ end_span : inner. span . shrink_to_hi ( ) ,
1624+ } ,
1625+ } ) ;
1626+ }
1627+ }
1628+ }
1629+
15771630declare_lint_pass ! (
15781631 /// Does nothing as a lint pass, but registers some `Lint`s
15791632 /// which are used by other parts of the compiler.
@@ -1592,7 +1645,8 @@ declare_lint_pass!(
15921645 UNSTABLE_FEATURES ,
15931646 UNREACHABLE_PUB ,
15941647 TYPE_ALIAS_BOUNDS ,
1595- TRIVIAL_BOUNDS
1648+ TRIVIAL_BOUNDS ,
1649+ DOUBLE_NEGATIONS
15961650 ]
15971651) ;
15981652
0 commit comments