Skip to content

Commit 9dba743

Browse files
committed
do not print wrapping ranges like normal ranges in diagnostics
1 parent 8315b11 commit 9dba743

File tree

3 files changed

+85
-50
lines changed

3 files changed

+85
-50
lines changed

src/librustc_mir/interpret/validity.rs

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use std::fmt::Write;
1212
use std::hash::Hash;
13+
use std::ops::RangeInclusive;
1314

1415
use syntax_pos::symbol::Symbol;
1516
use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf};
@@ -122,6 +123,34 @@ fn path_format(path: &Vec<PathElem>) -> String {
122123
out
123124
}
124125

126+
// Test if a range that wraps at overflow contains `test`
127+
fn wrapping_range_contains(r: &RangeInclusive<u128>, test: u128) -> bool {
128+
let (lo, hi) = r.clone().into_inner();
129+
if lo > hi {
130+
// Wrapped
131+
(..=hi).contains(&test) || (lo..).contains(&test)
132+
} else {
133+
// Normal
134+
r.contains(&test)
135+
}
136+
}
137+
138+
// Formats such that a sentence like "expected something {}" to mean
139+
// "expected something <in the given range>" makes sense.
140+
fn wrapping_range_format(r: &RangeInclusive<u128>, max_hi: u128) -> String {
141+
let (lo, hi) = r.clone().into_inner();
142+
debug_assert!(hi <= max_hi);
143+
if lo > hi {
144+
format!("less or equal to {}, or greater or equal to {}", hi, lo)
145+
} else {
146+
if hi == max_hi {
147+
format!("greater or equal to {}", lo)
148+
} else {
149+
format!("in the range {:?}", r)
150+
}
151+
}
152+
}
153+
125154
struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a, 'mir, 'tcx>+'rt> {
126155
/// The `path` may be pushed to, but the part that is present when a function
127156
/// starts must not be changed! `visit_fields` and `visit_array` rely on
@@ -428,8 +457,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
428457
"a pointer",
429458
self.path,
430459
format!(
431-
"something that cannot possibly be outside the (wrapping) range {:?}",
432-
layout.valid_range
460+
"something that cannot possibly fail to be {}",
461+
wrapping_range_format(&layout.valid_range, max_hi)
433462
)
434463
);
435464
}
@@ -440,33 +469,14 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
440469
}
441470
};
442471
// Now compare. This is slightly subtle because this is a special "wrap-around" range.
443-
use std::ops::RangeInclusive;
444-
let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
445-
if lo > hi {
446-
// wrapping around
447-
if in_range(0..=hi) || in_range(lo..=max_hi) {
448-
Ok(())
449-
} else {
450-
validation_failure!(
451-
bits,
452-
self.path,
453-
format!("something in the range {:?} or {:?}", 0..=hi, lo..=max_hi)
454-
)
455-
}
472+
if wrapping_range_contains(&layout.valid_range, bits) {
473+
Ok(())
456474
} else {
457-
if in_range(layout.valid_range.clone()) {
458-
Ok(())
459-
} else {
460-
validation_failure!(
461-
bits,
462-
self.path,
463-
if hi == max_hi {
464-
format!("something greater or equal to {}", lo)
465-
} else {
466-
format!("something in the range {:?}", layout.valid_range)
467-
}
468-
)
469-
}
475+
validation_failure!(
476+
bits,
477+
self.path,
478+
format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
479+
)
470480
}
471481
}
472482

src/test/ui/consts/const-eval/ub-enum.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,48 @@ enum Enum {
1717
}
1818
union TransmuteEnum {
1919
a: &'static u8,
20-
b: Enum,
20+
out: Enum,
2121
}
2222

2323
// A pointer is guaranteed non-null
24-
const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
24+
const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out };
2525
//~^ ERROR is undefined behavior
2626

27-
// Invalid enum discriminant
27+
// (Potentially) invalid enum discriminant
2828
#[repr(usize)]
2929
#[derive(Copy, Clone)]
3030
enum Enum2 {
3131
A = 2,
3232
}
33+
#[repr(transparent)]
34+
#[derive(Copy, Clone)]
35+
struct Wrap<T>(T);
3336
union TransmuteEnum2 {
34-
a: usize,
35-
b: Enum2,
36-
c: (),
37+
in1: usize,
38+
in2: &'static u8,
39+
in3: (),
40+
out1: Enum2,
41+
out2: Wrap<Enum2>, // something wrapping the enum so that we test layout first, not enum
3742
}
38-
const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
43+
const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
44+
//~^ ERROR is undefined behavior
45+
const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
46+
//~^ ERROR is undefined behavior
47+
const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
3948
//~^ ERROR is undefined behavior
4049

4150
// Undef enum discriminant. In an arry to avoid `Scalar` layout.
42-
const BAD_ENUM3 : [Enum2; 2] = [unsafe { TransmuteEnum2 { c: () }.b }; 2];
51+
const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2];
4352
//~^ ERROR is undefined behavior
4453

45-
// Invalid enum field content (mostly to test printing of apths for enum tuple
54+
// Invalid enum field content (mostly to test printing of paths for enum tuple
4655
// variants and tuples).
4756
union TransmuteChar {
4857
a: u32,
4958
b: char,
5059
}
5160
// Need to create something which does not clash with enum layout optimizations.
52-
const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
61+
const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
5362
//~^ ERROR is undefined behavior
5463

5564
fn main() {
Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,51 @@
11
error[E0080]: it is undefined behavior to use this value
22
--> $DIR/ub-enum.rs:24:1
33
|
4-
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
4+
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
66
|
77
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-enum.rs:38:1
10+
--> $DIR/ub-enum.rs:43:1
1111
|
12-
LL | const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant
12+
LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant
1414
|
1515
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
1616

1717
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/ub-enum.rs:42:1
18+
--> $DIR/ub-enum.rs:45:1
1919
|
20-
LL | const BAD_ENUM3 : [Enum2; 2] = [unsafe { TransmuteEnum2 { c: () }.b }; 2];
21-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
20+
LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
2222
|
2323
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
2424

2525
error[E0080]: it is undefined behavior to use this value
26-
--> $DIR/ub-enum.rs:52:1
26+
--> $DIR/ub-enum.rs:47:1
2727
|
28-
LL | const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
29-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111
28+
LL | const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be in the range 2..=2
3030
|
3131
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
3232

33-
error: aborting due to 4 previous errors
33+
error[E0080]: it is undefined behavior to use this value
34+
--> $DIR/ub-enum.rs:51:1
35+
|
36+
LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2];
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
38+
|
39+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
40+
41+
error[E0080]: it is undefined behavior to use this value
42+
--> $DIR/ub-enum.rs:61:1
43+
|
44+
LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111
46+
|
47+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
48+
49+
error: aborting due to 6 previous errors
3450

3551
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)