@@ -50,6 +50,7 @@ use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
50
50
use crate :: lints:: {
51
51
BuiltinAnonymousParams , BuiltinConstNoMangle , BuiltinDeprecatedAttrLink ,
52
52
BuiltinDeprecatedAttrLinkSuggestion , BuiltinDeprecatedAttrUsed , BuiltinDerefNullptr ,
53
+ BuiltinDoubleNegations , BuiltinDoubleNegationsAddParens ,
53
54
BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
54
55
BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
55
56
BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
@@ -1574,6 +1575,58 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1574
1575
}
1575
1576
}
1576
1577
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
+
1577
1630
declare_lint_pass ! (
1578
1631
/// Does nothing as a lint pass, but registers some `Lint`s
1579
1632
/// which are used by other parts of the compiler.
@@ -1592,7 +1645,8 @@ declare_lint_pass!(
1592
1645
UNSTABLE_FEATURES ,
1593
1646
UNREACHABLE_PUB ,
1594
1647
TYPE_ALIAS_BOUNDS ,
1595
- TRIVIAL_BOUNDS
1648
+ TRIVIAL_BOUNDS ,
1649
+ DOUBLE_NEGATIONS
1596
1650
]
1597
1651
) ;
1598
1652
0 commit comments