@@ -58,6 +58,7 @@ use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
5858use crate :: lints:: {
5959 BuiltinAnonymousParams , BuiltinConstNoMangle , BuiltinDeprecatedAttrLink ,
6060 BuiltinDeprecatedAttrLinkSuggestion , BuiltinDeprecatedAttrUsed , BuiltinDerefNullptr ,
61+ BuiltinDoubleNegations , BuiltinDoubleNegationsAddParens ,
6162 BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
6263 BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
6364 BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
@@ -1590,6 +1591,62 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
15901591 }
15911592}
15921593
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+
15931650declare_lint_pass ! (
15941651 /// Does nothing as a lint pass, but registers some `Lint`s
15951652 /// which are used by other parts of the compiler.
@@ -1608,7 +1665,8 @@ declare_lint_pass!(
16081665 UNSTABLE_FEATURES ,
16091666 UNREACHABLE_PUB ,
16101667 TYPE_ALIAS_BOUNDS ,
1611- TRIVIAL_BOUNDS
1668+ TRIVIAL_BOUNDS ,
1669+ DOUBLE_NEGATIONS
16121670 ]
16131671) ;
16141672
0 commit comments