do not print wrapping ranges like normal ranges in diagnostics

This commit is contained in:
Ralf Jung 2018-11-03 12:44:10 +01:00
parent 8315b11b63
commit 9dba743a6a
3 changed files with 85 additions and 50 deletions

View File

@ -10,6 +10,7 @@
use std::fmt::Write; use std::fmt::Write;
use std::hash::Hash; use std::hash::Hash;
use std::ops::RangeInclusive;
use syntax_pos::symbol::Symbol; use syntax_pos::symbol::Symbol;
use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf}; use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf};
@ -122,6 +123,34 @@ fn path_format(path: &Vec<PathElem>) -> String {
out out
} }
// Test if a range that wraps at overflow contains `test`
fn wrapping_range_contains(r: &RangeInclusive<u128>, test: u128) -> bool {
let (lo, hi) = r.clone().into_inner();
if lo > hi {
// Wrapped
(..=hi).contains(&test) || (lo..).contains(&test)
} else {
// Normal
r.contains(&test)
}
}
// Formats such that a sentence like "expected something {}" to mean
// "expected something <in the given range>" makes sense.
fn wrapping_range_format(r: &RangeInclusive<u128>, max_hi: u128) -> String {
let (lo, hi) = r.clone().into_inner();
debug_assert!(hi <= max_hi);
if lo > hi {
format!("less or equal to {}, or greater or equal to {}", hi, lo)
} else {
if hi == max_hi {
format!("greater or equal to {}", lo)
} else {
format!("in the range {:?}", r)
}
}
}
struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a, 'mir, 'tcx>+'rt> { struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a, 'mir, 'tcx>+'rt> {
/// The `path` may be pushed to, but the part that is present when a function /// The `path` may be pushed to, but the part that is present when a function
/// starts must not be changed! `visit_fields` and `visit_array` rely on /// 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>>
"a pointer", "a pointer",
self.path, self.path,
format!( format!(
"something that cannot possibly be outside the (wrapping) range {:?}", "something that cannot possibly fail to be {}",
layout.valid_range wrapping_range_format(&layout.valid_range, max_hi)
) )
); );
} }
@ -440,34 +469,15 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
} }
}; };
// Now compare. This is slightly subtle because this is a special "wrap-around" range. // Now compare. This is slightly subtle because this is a special "wrap-around" range.
use std::ops::RangeInclusive; if wrapping_range_contains(&layout.valid_range, bits) {
let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
if lo > hi {
// wrapping around
if in_range(0..=hi) || in_range(lo..=max_hi) {
Ok(()) Ok(())
} else { } else {
validation_failure!( validation_failure!(
bits, bits,
self.path, self.path,
format!("something in the range {:?} or {:?}", 0..=hi, lo..=max_hi) format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
) )
} }
} else {
if in_range(layout.valid_range.clone()) {
Ok(())
} else {
validation_failure!(
bits,
self.path,
if hi == max_hi {
format!("something greater or equal to {}", lo)
} else {
format!("something in the range {:?}", layout.valid_range)
}
)
}
}
} }
fn visit_aggregate( fn visit_aggregate(

View File

@ -17,39 +17,48 @@ enum Enum {
} }
union TransmuteEnum { union TransmuteEnum {
a: &'static u8, a: &'static u8,
b: Enum, out: Enum,
} }
// A pointer is guaranteed non-null // A pointer is guaranteed non-null
const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b }; const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out };
//~^ ERROR is undefined behavior //~^ ERROR is undefined behavior
// Invalid enum discriminant // (Potentially) invalid enum discriminant
#[repr(usize)] #[repr(usize)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum Enum2 { enum Enum2 {
A = 2, A = 2,
} }
#[repr(transparent)]
#[derive(Copy, Clone)]
struct Wrap<T>(T);
union TransmuteEnum2 { union TransmuteEnum2 {
a: usize, in1: usize,
b: Enum2, in2: &'static u8,
c: (), in3: (),
out1: Enum2,
out2: Wrap<Enum2>, // something wrapping the enum so that we test layout first, not enum
} }
const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b }; const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
//~^ ERROR is undefined behavior
const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
//~^ ERROR is undefined behavior
const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
//~^ ERROR is undefined behavior //~^ ERROR is undefined behavior
// Undef enum discriminant. In an arry to avoid `Scalar` layout. // Undef enum discriminant. In an arry to avoid `Scalar` layout.
const BAD_ENUM3 : [Enum2; 2] = [unsafe { TransmuteEnum2 { c: () }.b }; 2]; const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2];
//~^ ERROR is undefined behavior //~^ ERROR is undefined behavior
// Invalid enum field content (mostly to test printing of apths for enum tuple // Invalid enum field content (mostly to test printing of paths for enum tuple
// variants and tuples). // variants and tuples).
union TransmuteChar { union TransmuteChar {
a: u32, a: u32,
b: char, b: char,
} }
// Need to create something which does not clash with enum layout optimizations. // Need to create something which does not clash with enum layout optimizations.
const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
//~^ ERROR is undefined behavior //~^ ERROR is undefined behavior
fn main() { fn main() {

View File

@ -1,35 +1,51 @@
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:24:1 --> $DIR/ub-enum.rs:24:1
| |
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b }; LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
| |
= 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 = 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
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:38:1 --> $DIR/ub-enum.rs:43:1
| |
LL | const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b }; LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant
| |
= 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 = 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
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:42:1 --> $DIR/ub-enum.rs:45:1
| |
LL | const BAD_ENUM3 : [Enum2; 2] = [unsafe { TransmuteEnum2 { c: () }.b }; 2]; LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
| |
= 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 = 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
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:52:1 --> $DIR/ub-enum.rs:47:1
| |
LL | const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); LL | const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be in the range 2..=2
| |
= 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 = 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
error: aborting due to 4 previous errors error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:51:1
|
LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
|
= 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
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:61:1
|
LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111
|
= 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
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0080`. For more information about this error, try `rustc --explain E0080`.