@@ -58,6 +58,7 @@ use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
58
58
use crate :: lints:: {
59
59
BuiltinAnonymousParams , BuiltinConstNoMangle , BuiltinDeprecatedAttrLink ,
60
60
BuiltinDeprecatedAttrLinkSuggestion , BuiltinDeprecatedAttrUsed , BuiltinDerefNullptr ,
61
+ BuiltinDoubleNegations , BuiltinDoubleNegationsAddParens ,
61
62
BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
62
63
BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
63
64
BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
@@ -1590,6 +1591,62 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1590
1591
}
1591
1592
}
1592
1593
1594
+ declare_lint ! {
1595
+ /// The `double_negations` lint detects expressions of the form `--x`.
1596
+ ///
1597
+ /// ### Example
1598
+ ///
1599
+ /// ```rust
1600
+ /// fn main() {
1601
+ /// let x = 1;
1602
+ /// let _b = --x;
1603
+ /// }
1604
+ /// ```
1605
+ ///
1606
+ /// {{produces}}
1607
+ ///
1608
+ /// ### Explanation
1609
+ ///
1610
+ /// Negating something twice is usually the same as not negating it at all.
1611
+ /// However, a double negation in Rust can easily be confused with the
1612
+ /// prefix decrement operator that exists in many languages derived from C.
1613
+ /// Use `-(-x)` if you really wanted to negate the value twice.
1614
+ ///
1615
+ /// To decrement a value, use `x -= 1` instead.
1616
+ pub DOUBLE_NEGATIONS ,
1617
+ Warn ,
1618
+ "detects expressions of the form `--x`"
1619
+ }
1620
+
1621
+ declare_lint_pass ! (
1622
+ /// Lint for expressions of the form `--x` that can be confused with C's
1623
+ /// prefix decrement operator.
1624
+ DoubleNegations => [ DOUBLE_NEGATIONS ]
1625
+ ) ;
1626
+
1627
+ impl EarlyLintPass for DoubleNegations {
1628
+ #[ inline]
1629
+ fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
1630
+ // only lint on the innermost `--` in a chain of `-` operators,
1631
+ // even if there are 3 or more negations
1632
+ if let ExprKind :: Unary ( UnOp :: Neg , ref inner) = expr. kind
1633
+ && let ExprKind :: Unary ( UnOp :: Neg , ref inner2) = inner. kind
1634
+ && !matches ! ( inner2. kind, ExprKind :: Unary ( UnOp :: Neg , _) )
1635
+ {
1636
+ cx. emit_span_lint (
1637
+ DOUBLE_NEGATIONS ,
1638
+ expr. span ,
1639
+ BuiltinDoubleNegations {
1640
+ add_parens : BuiltinDoubleNegationsAddParens {
1641
+ start_span : inner. span . shrink_to_lo ( ) ,
1642
+ end_span : inner. span . shrink_to_hi ( ) ,
1643
+ } ,
1644
+ } ,
1645
+ ) ;
1646
+ }
1647
+ }
1648
+ }
1649
+
1593
1650
declare_lint_pass ! (
1594
1651
/// Does nothing as a lint pass, but registers some `Lint`s
1595
1652
/// which are used by other parts of the compiler.
@@ -1608,7 +1665,8 @@ declare_lint_pass!(
1608
1665
UNSTABLE_FEATURES ,
1609
1666
UNREACHABLE_PUB ,
1610
1667
TYPE_ALIAS_BOUNDS ,
1611
- TRIVIAL_BOUNDS
1668
+ TRIVIAL_BOUNDS ,
1669
+ DOUBLE_NEGATIONS
1612
1670
]
1613
1671
) ;
1614
1672
0 commit comments