Skip to content

Commit 71d04a7

Browse files
committed
added error for invalid char cast
1 parent f838cbc commit 71d04a7

File tree

5 files changed

+52
-18
lines changed

5 files changed

+52
-18
lines changed

compiler/rustc_lint/messages.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,11 @@ lint_invalid_asm_label_named = avoid using named labels in inline assembly
440440
.help = only local labels of the form `<number>:` should be used in inline asm
441441
.note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
442442
lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro
443+
444+
lint_invalid_char_cast = cannot cast `{$literal}` to `char`
445+
.note = char must be a valid Unicode scalar value (code points in ranges [0x0, 0xD7FF] or [0xE000, 0x10FFFF]).
446+
.note1 = The gap [0xD800, 0xDFFF] is reserved for UTF-16 surrogates and is invalid.
447+
443448
lint_invalid_crate_type_value = invalid `crate_type` value
444449
.suggestion = did you mean
445450

compiler/rustc_lint/src/lints.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,14 @@ pub(crate) struct OverflowingLiteral<'a> {
17461746
pub lit: String,
17471747
}
17481748

1749+
#[derive(LintDiagnostic)]
1750+
#[diag(lint_invalid_char_cast)]
1751+
#[note]
1752+
#[note(lint_note1)]
1753+
pub(crate) struct InvalidCharCast {
1754+
pub literal: u128,
1755+
}
1756+
17491757
#[derive(LintDiagnostic)]
17501758
#[diag(lint_uses_power_alignment)]
17511759
pub(crate) struct UsesPowerAlignment;

compiler/rustc_lint/src/types/literal.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir};
1010
use crate::LateContext;
1111
use crate::context::LintContext;
1212
use crate::lints::{
13-
OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub,
14-
OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt,
15-
RangeEndpointOutOfRange, UseInclusiveRange,
13+
InvalidCharCast, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign,
14+
OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp,
15+
OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange, UseInclusiveRange,
1616
};
1717
use crate::types::{OVERFLOWING_LITERALS, TypeLimits};
1818

@@ -38,12 +38,18 @@ fn lint_overflowing_range_endpoint<'tcx>(
3838

3939
// We only want to handle exclusive (`..`) ranges,
4040
// which are represented as `ExprKind::Struct`.
41-
let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { return false };
42-
let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false };
41+
let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else {
42+
return false;
43+
};
44+
let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else {
45+
return false;
46+
};
4347
if !is_range_literal(struct_expr) {
4448
return false;
4549
};
46-
let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false };
50+
let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else {
51+
return false;
52+
};
4753

4854
// We can suggest using an inclusive range
4955
// (`..=`) instead only if it is the `end` that is
@@ -61,7 +67,9 @@ fn lint_overflowing_range_endpoint<'tcx>(
6167
};
6268

6369
let sub_sugg = if span.lo() == lit_span.lo() {
64-
let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false };
70+
let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else {
71+
return false;
72+
};
6573
UseInclusiveRange::WithoutParen {
6674
sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
6775
start,
@@ -316,11 +324,19 @@ fn lint_uint_literal<'tcx>(
316324
match par_e.kind {
317325
hir::ExprKind::Cast(..) => {
318326
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
319-
cx.emit_span_lint(
320-
OVERFLOWING_LITERALS,
321-
par_e.span,
322-
OnlyCastu8ToChar { span: par_e.span, literal: lit_val },
323-
);
327+
if lit_val <= 0xFF {
328+
cx.emit_span_lint(
329+
OVERFLOWING_LITERALS,
330+
par_e.span,
331+
OnlyCastu8ToChar { span: par_e.span, literal: lit_val },
332+
);
333+
} else {
334+
cx.emit_span_lint(
335+
OVERFLOWING_LITERALS,
336+
par_e.span,
337+
InvalidCharCast { literal: lit_val },
338+
);
339+
}
324340
return;
325341
}
326342
}

tests/ui/cast/cast-char.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
fn main() {
44
const XYZ: char = 0x1F888 as char;
5-
//~^ ERROR only `u8` can be cast into `char`
5+
//~^ ERROR: cannot cast
66
const XY: char = 129160 as char;
7-
//~^ ERROR only `u8` can be cast into `char`
7+
//~^ ERROR: cannot cast
88
const ZYX: char = '\u{01F888}';
99
println!("{}", XYZ);
1010
}

tests/ui/cast/cast-char.stderr

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
1-
error: only `u8` can be cast into `char`
1+
error: cannot cast `129160` to `char`
22
--> $DIR/cast-char.rs:4:23
33
|
44
LL | const XYZ: char = 0x1F888 as char;
5-
| ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'`
5+
| ^^^^^^^^^^^^^^^
66
|
7+
= note: char must be a valid Unicode scalar value (code points in ranges [0x0, 0xD7FF] or [0xE000, 0x10FFFF]).
8+
= note: The gap [0xD800, 0xDFFF] is reserved for UTF-16 surrogates and is invalid.
79
note: the lint level is defined here
810
--> $DIR/cast-char.rs:1:9
911
|
1012
LL | #![deny(overflowing_literals)]
1113
| ^^^^^^^^^^^^^^^^^^^^
1214

13-
error: only `u8` can be cast into `char`
15+
error: cannot cast `129160` to `char`
1416
--> $DIR/cast-char.rs:6:22
1517
|
1618
LL | const XY: char = 129160 as char;
17-
| ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'`
19+
| ^^^^^^^^^^^^^^
20+
|
21+
= note: char must be a valid Unicode scalar value (code points in ranges [0x0, 0xD7FF] or [0xE000, 0x10FFFF]).
22+
= note: The gap [0xD800, 0xDFFF] is reserved for UTF-16 surrogates and is invalid.
1823

1924
error: aborting due to 2 previous errors
2025

0 commit comments

Comments
 (0)