@@ -51,6 +51,7 @@ use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
5151use crate :: lints:: {
5252 BuiltinAnonymousParams , BuiltinConstNoMangle , BuiltinDeprecatedAttrLink ,
5353 BuiltinDeprecatedAttrLinkSuggestion , BuiltinDeprecatedAttrUsed , BuiltinDerefNullptr ,
54+ BuiltinDoubleNegations , BuiltinDoubleNegationsAddParens ,
5455 BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
5556 BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
5657 BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
@@ -1555,6 +1556,62 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
15551556 }
15561557}
15571558
1559+ declare_lint ! {
1560+ /// The `double_negations` lint detects expressions of the form `--x`.
1561+ ///
1562+ /// ### Example
1563+ ///
1564+ /// ```rust
1565+ /// fn main() {
1566+ /// let x = 1;
1567+ /// let _b = --x;
1568+ /// }
1569+ /// ```
1570+ ///
1571+ /// {{produces}}
1572+ ///
1573+ /// ### Explanation
1574+ ///
1575+ /// Negating something twice is usually the same as not negating it at all.
1576+ /// However, a double negation in Rust can easily be confused with the
1577+ /// prefix decrement operator that exists in many languages derived from C.
1578+ /// Use `-(-x)` if you really wanted to negate the value twice.
1579+ ///
1580+ /// To decrement a value, use `x -= 1` instead.
1581+ pub DOUBLE_NEGATIONS ,
1582+ Warn ,
1583+ "detects expressions of the form `--x`"
1584+ }
1585+
1586+ declare_lint_pass ! (
1587+ /// Lint for expressions of the form `--x` that can be confused with C's
1588+ /// prefix decrement operator.
1589+ DoubleNegations => [ DOUBLE_NEGATIONS ]
1590+ ) ;
1591+
1592+ impl EarlyLintPass for DoubleNegations {
1593+ #[ inline]
1594+ fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
1595+ // only lint on the innermost `--` in a chain of `-` operators,
1596+ // even if there are 3 or more negations
1597+ if let ExprKind :: Unary ( UnOp :: Neg , ref inner) = expr. kind
1598+ && let ExprKind :: Unary ( UnOp :: Neg , ref inner2) = inner. kind
1599+ && !matches ! ( inner2. kind, ExprKind :: Unary ( UnOp :: Neg , _) )
1600+ {
1601+ cx. emit_span_lint (
1602+ DOUBLE_NEGATIONS ,
1603+ expr. span ,
1604+ BuiltinDoubleNegations {
1605+ add_parens : BuiltinDoubleNegationsAddParens {
1606+ start_span : inner. span . shrink_to_lo ( ) ,
1607+ end_span : inner. span . shrink_to_hi ( ) ,
1608+ } ,
1609+ } ,
1610+ ) ;
1611+ }
1612+ }
1613+ }
1614+
15581615declare_lint_pass ! (
15591616 /// Does nothing as a lint pass, but registers some `Lint`s
15601617 /// which are used by other parts of the compiler.
@@ -1573,7 +1630,8 @@ declare_lint_pass!(
15731630 UNSTABLE_FEATURES ,
15741631 UNREACHABLE_PUB ,
15751632 TYPE_ALIAS_BOUNDS ,
1576- TRIVIAL_BOUNDS
1633+ TRIVIAL_BOUNDS ,
1634+ DOUBLE_NEGATIONS
15771635 ]
15781636) ;
15791637
0 commit comments