@@ -49,16 +49,16 @@ use rustc_trait_selection::traits::{self};
4949use crate :: errors:: BuiltinEllipsisInclusiveRangePatterns ;
5050use crate :: lints:: {
5151 BuiltinAnonymousParams , BuiltinConstNoMangle , BuiltinDeprecatedAttrLink ,
52- BuiltinDeprecatedAttrLinkSuggestion , BuiltinDerefNullptr ,
53- BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
54- BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
55- BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
56- BuiltinMissingCopyImpl , BuiltinMissingDebugImpl , BuiltinMissingDoc , BuiltinMutablesTransmutes ,
57- BuiltinNoMangleGeneric , BuiltinNonShorthandFieldPatterns , BuiltinSpecialModuleNameUsed ,
58- BuiltinTrivialBounds , BuiltinTypeAliasBounds , BuiltinUngatedAsyncFnTrackCaller ,
59- BuiltinUnpermittedTypeInit , BuiltinUnpermittedTypeInitSub , BuiltinUnreachablePub ,
60- BuiltinUnsafe , BuiltinUnstableFeatures , BuiltinUnusedDocComment , BuiltinUnusedDocCommentSub ,
61- BuiltinWhileTrue , InvalidAsmLabel ,
52+ BuiltinDeprecatedAttrLinkSuggestion , BuiltinDerefNullptr , BuiltinDoubleNegations ,
53+ BuiltinDoubleNegationsAddParens , BuiltinEllipsisInclusiveRangePatternsLint ,
54+ BuiltinExplicitOutlives , BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote ,
55+ BuiltinIncompleteFeatures , BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures ,
56+ BuiltinKeywordIdents , BuiltinMissingCopyImpl , BuiltinMissingDebugImpl , BuiltinMissingDoc ,
57+ BuiltinMutablesTransmutes , BuiltinNoMangleGeneric , BuiltinNonShorthandFieldPatterns ,
58+ BuiltinSpecialModuleNameUsed , BuiltinTrivialBounds , BuiltinTypeAliasBounds ,
59+ BuiltinUngatedAsyncFnTrackCaller , BuiltinUnpermittedTypeInit , BuiltinUnpermittedTypeInitSub ,
60+ BuiltinUnreachablePub , BuiltinUnsafe , BuiltinUnstableFeatures , BuiltinUnusedDocComment ,
61+ BuiltinUnusedDocCommentSub , BuiltinWhileTrue , InvalidAsmLabel ,
6262} ;
6363use crate :: nonstandard_style:: { MethodLateContext , method_context} ;
6464use crate :: {
@@ -90,19 +90,11 @@ declare_lint! {
9090
9191declare_lint_pass ! ( WhileTrue => [ WHILE_TRUE ] ) ;
9292
93- /// Traverse through any amount of parenthesis and return the first non-parens expression.
94- fn pierce_parens ( mut expr : & ast:: Expr ) -> & ast:: Expr {
95- while let ast:: ExprKind :: Paren ( sub) = & expr. kind {
96- expr = sub;
97- }
98- expr
99- }
100-
10193impl EarlyLintPass for WhileTrue {
10294 #[ inline]
10395 fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & ast:: Expr ) {
10496 if let ast:: ExprKind :: While ( cond, _, label) = & e. kind
105- && let ast:: ExprKind :: Lit ( token_lit) = pierce_parens ( cond) . kind
97+ && let ast:: ExprKind :: Lit ( token_lit) = cond. peel_parens ( ) . kind
10698 && let token:: Lit { kind : token:: Bool , symbol : kw:: True , .. } = token_lit
10799 && !cond. span . from_expansion ( )
108100 {
@@ -1576,6 +1568,58 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
15761568 }
15771569}
15781570
1571+ declare_lint ! {
1572+ /// The `double_negations` lint detects expressions of the form `--x`.
1573+ ///
1574+ /// ### Example
1575+ ///
1576+ /// ```rust
1577+ /// fn main() {
1578+ /// let x = 1;
1579+ /// let _b = --x;
1580+ /// }
1581+ /// ```
1582+ ///
1583+ /// {{produces}}
1584+ ///
1585+ /// ### Explanation
1586+ ///
1587+ /// Negating something twice is usually the same as not negating it at all.
1588+ /// However, a double negation in Rust can easily be confused with the
1589+ /// prefix decrement operator that exists in many languages derived from C.
1590+ /// Use `-(-x)` if you really wanted to negate the value twice.
1591+ ///
1592+ /// To decrement a value, use `x -= 1` instead.
1593+ pub DOUBLE_NEGATIONS ,
1594+ Warn ,
1595+ "detects expressions of the form `--x`"
1596+ }
1597+
1598+ declare_lint_pass ! (
1599+ /// Lint for expressions of the form `--x` that can be confused with C's
1600+ /// prefix decrement operator.
1601+ DoubleNegations => [ DOUBLE_NEGATIONS ]
1602+ ) ;
1603+
1604+ impl EarlyLintPass for DoubleNegations {
1605+ #[ inline]
1606+ fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
1607+ // only lint on the innermost `--` in a chain of `-` operators,
1608+ // even if there are 3 or more negations
1609+ if let ExprKind :: Unary ( UnOp :: Neg , ref inner) = expr. kind
1610+ && let ExprKind :: Unary ( UnOp :: Neg , ref inner2) = inner. kind
1611+ && !matches ! ( inner2. kind, ExprKind :: Unary ( UnOp :: Neg , _) )
1612+ {
1613+ cx. emit_span_lint ( DOUBLE_NEGATIONS , expr. span , BuiltinDoubleNegations {
1614+ add_parens : BuiltinDoubleNegationsAddParens {
1615+ start_span : inner. span . shrink_to_lo ( ) ,
1616+ end_span : inner. span . shrink_to_hi ( ) ,
1617+ } ,
1618+ } ) ;
1619+ }
1620+ }
1621+ }
1622+
15791623declare_lint_pass ! (
15801624 /// Does nothing as a lint pass, but registers some `Lint`s
15811625 /// which are used by other parts of the compiler.
@@ -1594,7 +1638,8 @@ declare_lint_pass!(
15941638 UNSTABLE_FEATURES ,
15951639 UNREACHABLE_PUB ,
15961640 TYPE_ALIAS_BOUNDS ,
1597- TRIVIAL_BOUNDS
1641+ TRIVIAL_BOUNDS ,
1642+ DOUBLE_NEGATIONS
15981643 ]
15991644) ;
16001645
@@ -2651,7 +2696,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
26512696}
26522697
26532698declare_lint ! {
2654- /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
2699+ /// The `deref_nullptr` lint detects when a null pointer is dereferenced,
26552700 /// which causes [undefined behavior].
26562701 ///
26572702 /// ### Example
0 commit comments