Skip to content

Commit

Permalink
implement lint double_negations
Browse files Browse the repository at this point in the history
  • Loading branch information
kadiwa4 committed Oct 29, 2024
1 parent 0c33372 commit 608040d
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 6 deletions.
5 changes: 5 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no lo
lint_builtin_deref_nullptr = dereferencing a null pointer
.label = this code causes undefined behavior when executed
lint_builtin_double_negations = use of a double negation
.note = the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
.note_decrement = use `-= 1` if you meant to decrement the value
.add_parens_suggestion = add parentheses for clarity
lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
.suggestion = use `..=` for an inclusive range
Expand Down
56 changes: 55 additions & 1 deletion compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
use crate::lints::{
BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
BuiltinDoubleNegations, BuiltinDoubleNegationsAddParens,
BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
Expand Down Expand Up @@ -1555,6 +1556,58 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
}
}

declare_lint! {
/// The `double_negations` lint detects expressions of the form `--x`.
///
/// ### Example
///
/// ```rust
/// fn main() {
/// let x = 1;
/// let _b = --x;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Negating something twice is usually the same as not negating it at all.
/// However, a double negation in Rust can easily be confused with the
/// prefix decrement operator that exists in many languages derived from C.
/// Use `-(-x)` if you really wanted to negate the value twice.
///
/// To decrement a value, use `x -= 1` instead.
pub DOUBLE_NEGATIONS,
Warn,
"detects expressions of the form `--x`"
}

declare_lint_pass!(
/// Lint for expressions of the form `--x` that can be confused with C's
/// prefix decrement operator.
DoubleNegations => [DOUBLE_NEGATIONS]
);

impl EarlyLintPass for DoubleNegations {
#[inline]
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
// only lint on the innermost `--` in a chain of `-` operators,
// even if there are 3 or more negations
if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
&& let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
&& !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
{
cx.emit_span_lint(DOUBLE_NEGATIONS, expr.span, BuiltinDoubleNegations {
add_parens: BuiltinDoubleNegationsAddParens {
start_span: inner.span.shrink_to_lo(),
end_span: inner.span.shrink_to_hi(),
},
});
}
}
}

declare_lint_pass!(
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
Expand All @@ -1573,7 +1626,8 @@ declare_lint_pass!(
UNSTABLE_FEATURES,
UNREACHABLE_PUB,
TYPE_ALIAS_BOUNDS,
TRIVIAL_BOUNDS
TRIVIAL_BOUNDS,
DOUBLE_NEGATIONS
]
);

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ early_lint_methods!(
UnusedDocComment: UnusedDocComment,
Expr2024: Expr2024,
Precedence: Precedence,
DoubleNegations: DoubleNegations,
]
]
);
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,24 @@ pub(crate) struct BuiltinTrivialBounds<'a> {
pub predicate: Clause<'a>,
}

#[derive(LintDiagnostic)]
#[diag(lint_builtin_double_negations)]
#[note(lint_note)]
#[note(lint_note_decrement)]
pub(crate) struct BuiltinDoubleNegations {
#[subdiagnostic]
pub add_parens: BuiltinDoubleNegationsAddParens,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(lint_add_parens_suggestion, applicability = "maybe-incorrect")]
pub(crate) struct BuiltinDoubleNegationsAddParens {
#[suggestion_part(code = "(")]
pub start_span: Span,
#[suggestion_part(code = ")")]
pub end_span: Span,
}

#[derive(LintDiagnostic)]
pub(crate) enum BuiltinEllipsisInclusiveRangePatternsLint {
#[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/lint/lint-double-negations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//@ check-pass
fn main() {
let x = 1;
-x;
-(-x);
--x; //~ WARN use of a double negation
---x; //~ WARN use of a double negation
let _y = --(-x); //~ WARN use of a double negation
}
42 changes: 42 additions & 0 deletions tests/ui/lint/lint-double-negations.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
warning: use of a double negation
--> $DIR/lint-double-negations.rs:6:5
|
LL | --x;
| ^^^
|
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
= note: use `-= 1` if you meant to decrement the value
= note: `#[warn(double_negations)]` on by default
help: add parentheses for clarity
|
LL | -(-x);
| + +

warning: use of a double negation
--> $DIR/lint-double-negations.rs:7:6
|
LL | ---x;
| ^^^
|
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
= note: use `-= 1` if you meant to decrement the value
help: add parentheses for clarity
|
LL | --(-x);
| + +

warning: use of a double negation
--> $DIR/lint-double-negations.rs:8:14
|
LL | let _y = --(-x);
| ^^^^^^
|
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
= note: use `-= 1` if you meant to decrement the value
help: add parentheses for clarity
|
LL | let _y = -(-(-x));
| + +

warning: 3 warnings emitted

1 change: 1 addition & 0 deletions tests/ui/lint/lint-type-overflow2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

fn main() {
let x2: i8 = --128; //~ ERROR literal out of range for `i8`
//~| WARN use of a double negation

let x = -3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
let x = 3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
Expand Down
24 changes: 19 additions & 5 deletions tests/ui/lint/lint-type-overflow2.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
warning: use of a double negation
--> $DIR/lint-type-overflow2.rs:6:18
|
LL | let x2: i8 = --128;
| ^^^^^
|
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
= note: use `-= 1` if you meant to decrement the value
= note: `#[warn(double_negations)]` on by default
help: add parentheses for clarity
|
LL | let x2: i8 = -(-128);
| + +

error: literal out of range for `i8`
--> $DIR/lint-type-overflow2.rs:6:20
|
Expand All @@ -13,36 +27,36 @@ LL | #![deny(overflowing_literals)]
| ^^^^^^^^^^^^^^^^^^^^

error: literal out of range for `f32`
--> $DIR/lint-type-overflow2.rs:8:14
--> $DIR/lint-type-overflow2.rs:9:14
|
LL | let x = -3.40282357e+38_f32;
| ^^^^^^^^^^^^^^^^^^
|
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`

error: literal out of range for `f32`
--> $DIR/lint-type-overflow2.rs:9:14
--> $DIR/lint-type-overflow2.rs:10:14
|
LL | let x = 3.40282357e+38_f32;
| ^^^^^^^^^^^^^^^^^^
|
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`

error: literal out of range for `f64`
--> $DIR/lint-type-overflow2.rs:10:14
--> $DIR/lint-type-overflow2.rs:11:14
|
LL | let x = -1.7976931348623159e+308_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`

error: literal out of range for `f64`
--> $DIR/lint-type-overflow2.rs:11:14
--> $DIR/lint-type-overflow2.rs:12:14
|
LL | let x = 1.7976931348623159e+308_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`

error: aborting due to 5 previous errors
error: aborting due to 5 previous errors; 1 warning emitted

0 comments on commit 608040d

Please sign in to comment.