@@ -51,6 +51,7 @@ use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
51
51
use crate :: lints:: {
52
52
BuiltinAnonymousParams , BuiltinConstNoMangle , BuiltinDeprecatedAttrLink ,
53
53
BuiltinDeprecatedAttrLinkSuggestion , BuiltinDeprecatedAttrUsed , BuiltinDerefNullptr ,
54
+ BuiltinDoubleNegations , BuiltinDoubleNegationsAddParens ,
54
55
BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
55
56
BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
56
57
BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
@@ -1555,6 +1556,62 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1555
1556
}
1556
1557
}
1557
1558
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
+
1558
1615
declare_lint_pass ! (
1559
1616
/// Does nothing as a lint pass, but registers some `Lint`s
1560
1617
/// which are used by other parts of the compiler.
@@ -1573,7 +1630,8 @@ declare_lint_pass!(
1573
1630
UNSTABLE_FEATURES ,
1574
1631
UNREACHABLE_PUB ,
1575
1632
TYPE_ALIAS_BOUNDS ,
1576
- TRIVIAL_BOUNDS
1633
+ TRIVIAL_BOUNDS ,
1634
+ DOUBLE_NEGATIONS
1577
1635
]
1578
1636
) ;
1579
1637
0 commit comments