Skip to content

Commit 8cd9dfa

Browse files
committed
Fix ScalarInt to char conversion
to avoid panic for invalid Unicode scalar values
1 parent 30b3f35 commit 8cd9dfa

File tree

3 files changed

+52
-22
lines changed

3 files changed

+52
-22
lines changed

compiler/rustc_middle/src/ty/consts/int.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,22 @@ impl From<char> for ScalarInt {
294294
}
295295
}
296296

297+
/// Error returned when a conversion from ScalarInt to char fails.
298+
#[derive(Debug)]
299+
pub struct CharTryFromScalarInt;
300+
297301
impl TryFrom<ScalarInt> for char {
298-
type Error = Size;
302+
type Error = CharTryFromScalarInt;
303+
299304
#[inline]
300-
fn try_from(int: ScalarInt) -> Result<Self, Size> {
301-
int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
302-
.map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
305+
fn try_from(int: ScalarInt) -> Result<Self, Self::Error> {
306+
let Ok(bits) = int.to_bits(Size::from_bytes(std::mem::size_of::<char>())) else {
307+
return Err(CharTryFromScalarInt);
308+
};
309+
match char::from_u32(bits.try_into().unwrap()) {
310+
Some(c) => Ok(c),
311+
None => Err(CharTryFromScalarInt),
312+
}
303313
}
304314
}
305315

src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff

+31-17
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,53 @@
55
let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11
66
let _1: std::option::Option<()>; // in scope 0 at $DIR/invalid_constant.rs:16:5: 16:12
77
let mut _2: std::option::Option<std::option::Option<()>>; // in scope 0 at $DIR/invalid_constant.rs:16:7: 16:11
8-
scope 1 (inlined f) { // at $DIR/invalid_constant.rs:16:5: 16:12
9-
debug x => _2; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
10-
let mut _3: isize; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
11-
let _4: std::option::Option<()>; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
12-
scope 2 {
13-
debug y => _4; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
8+
let _3: main::Union; // in scope 0 at $DIR/invalid_constant.rs:22:9: 22:22
9+
scope 1 {
10+
debug _invalid_char => _3; // in scope 1 at $DIR/invalid_constant.rs:22:9: 22:22
11+
}
12+
scope 2 (inlined f) { // at $DIR/invalid_constant.rs:16:5: 16:12
13+
debug x => _2; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
14+
let mut _4: isize; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
15+
let _5: std::option::Option<()>; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
16+
scope 3 {
17+
debug y => _5; // in scope 3 at $DIR/invalid_constant.rs:16:5: 16:12
1418
}
1519
}
1620

1721
bb0: {
1822
discriminant(_2) = 0; // scope 0 at $DIR/invalid_constant.rs:16:7: 16:11
19-
- _3 = discriminant(_2); // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
20-
- switchInt(move _3) -> [0_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
21-
+ _3 = const 0_isize; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
22-
+ switchInt(const 0_isize) -> [0_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
23+
- _4 = discriminant(_2); // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
24+
- switchInt(move _4) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
25+
+ _4 = const 0_isize; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
26+
+ switchInt(const 0_isize) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
2327
}
2428

2529
bb1: {
26-
nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 17:2
27-
return; // scope 0 at $DIR/invalid_constant.rs:17:2: 17:2
30+
- _3 = const { Union { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:22:25: 22:58
31+
+ _3 = const main::Union { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:22:25: 22:58
32+
// ty::Const
33+
// + ty: main::Union
34+
- // + val: Unevaluated(main::{constant#0}, [main::Union], None)
35+
+ // + val: Value(Scalar(0x00110001))
36+
// mir::Constant
37+
// + span: $DIR/invalid_constant.rs:22:25: 22:58
38+
- // + literal: Const { ty: main::Union, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:8 ~ invalid_constant[726d]::main::{constant#0}), const_param_did: None }, substs: [main::Union], promoted: None }) }
39+
+ // + literal: Const { ty: main::Union, val: Value(Scalar(0x00110001)) }
40+
nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 23:2
41+
return; // scope 0 at $DIR/invalid_constant.rs:23:2: 23:2
2842
}
2943

3044
bb2: {
31-
- _4 = ((_2 as Some).0: std::option::Option<()>); // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
32-
- _1 = _4; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
33-
+ _4 = const Scalar(0x02): Option::<()>; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
45+
- _5 = ((_2 as Some).0: std::option::Option<()>); // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
46+
- _1 = _5; // scope 3 at $DIR/invalid_constant.rs:16:5: 16:12
47+
+ _5 = const Scalar(0x02): Option::<()>; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
3448
+ // ty::Const
3549
+ // + ty: std::option::Option<()>
3650
+ // + val: Value(Scalar(0x02))
3751
+ // mir::Constant
3852
+ // + span: $DIR/invalid_constant.rs:16:5: 16:12
3953
+ // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) }
40-
+ _1 = const Scalar(0x02): Option::<()>; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
54+
+ _1 = const Scalar(0x02): Option::<()>; // scope 3 at $DIR/invalid_constant.rs:16:5: 16:12
4155
+ // ty::Const
4256
+ // + ty: std::option::Option<()>
4357
+ // + val: Value(Scalar(0x02))
@@ -48,7 +62,7 @@
4862
}
4963

5064
bb3: {
51-
discriminant(_1) = 0; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
65+
discriminant(_1) = 0; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
5266
goto -> bb1; // scope 0 at $DIR/invalid_constant.rs:9:17: 9:21
5367
}
5468
}

src/test/mir-opt/const_prop/invalid_constant.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// by constant propagation. Regression test for issue #93688.
33
//
44
// compile-flags: -Copt-level=0 -Zinline-mir
5-
5+
#![feature(inline_const)]
66
#[inline(always)]
77
pub fn f(x: Option<Option<()>>) -> Option<()> {
88
match x {
@@ -14,4 +14,10 @@ pub fn f(x: Option<Option<()>>) -> Option<()> {
1414
// EMIT_MIR invalid_constant.main.ConstProp.diff
1515
fn main() {
1616
f(None);
17+
18+
union Union {
19+
int: u32,
20+
chr: char,
21+
}
22+
let _invalid_char = const { Union { int: 0x110001 } };
1723
}

0 commit comments

Comments
 (0)