Auto merge of #155473 - scottmcm:tweak_niche_assignment, r=chenyukang,mati865
Prefer `-1` for `None`
Currently we pick "weird" numbers like `1114112` for `None::<char>`. While that's not *wrong*, it's kinda *unnatural* -- a human wouldn't make that choice.
This PR instead picks `-1` for thinge like `None::<char>` -- like [clang's `WEOF`](63ae74b78a/libc/include/llvm-libc-macros/wchar-macros.h (L15)) -- and `None::<bool>` and such.
Any enums with more than one niched value (so not `Result` nor `Option`) remain as they were before. Also we continue to use `0` when that's possible -- `-1` is only preferred when zero *isn't* possible.
---
Inspired when someone in discord posted an example like this <https://rust.godbolt.org/z/W94s9qdYW> and I thought it was odd that we're currently picking `-9223372036854775808` to be the value to store to mark an `Option<Vec<_>>` as `None`. (Especially since that needs an 8-byte immediate on x64, and writing `-1` is only a 4-byte immediate.)
This commit is contained in:
@@ -2054,8 +2054,7 @@ impl Niche {
|
||||
assert!(size.bits() <= 128);
|
||||
let max_value = size.unsigned_int_max();
|
||||
|
||||
let niche = v.end.wrapping_add(1)..v.start;
|
||||
let available = niche.end.wrapping_sub(niche.start) & max_value;
|
||||
let available = v.start.wrapping_sub(v.end).wrapping_sub(1) & max_value;
|
||||
if count > available {
|
||||
return None;
|
||||
}
|
||||
@@ -2083,7 +2082,17 @@ impl Niche {
|
||||
Some((start, Scalar::Initialized { value, valid_range: v.with_end(end) }))
|
||||
};
|
||||
let distance_end_zero = max_value - v.end;
|
||||
if v.start > v.end {
|
||||
// FIXME: this ought to work for `bool` too, but that seems to be hitting a miscompilation
|
||||
// <https://github.com/rust-lang/rust/pull/155473#issuecomment-4302036343>
|
||||
if count == 1 && v != (WrappingRange { start: 0, end: 1 }) {
|
||||
// We only need one, so just pick the one closest to zero.
|
||||
// Not only does that obviously use zero if it's possible, but it also
|
||||
// simplifies testing things like `Option<char>`, since looking for `-1`
|
||||
// is easier than looking for `1114112` (and matches clang's `WEOF`).
|
||||
let next_up = size.sign_extend(v.end.wrapping_add(1)).unsigned_abs();
|
||||
let next_down = size.sign_extend(v.start.wrapping_sub(1)).unsigned_abs();
|
||||
if next_down <= next_up { move_start(v) } else { move_end(v) }
|
||||
} else if v.start > v.end {
|
||||
// zero is unavailable because wrapping occurs
|
||||
move_end(v)
|
||||
} else if v.start <= distance_end_zero {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
//@ only-64bit
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(pattern_types, pattern_type_macro)]
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::num::NonZero;
|
||||
@@ -123,3 +124,14 @@ fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Neve
|
||||
}
|
||||
|
||||
enum Never {}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct NewtypeIndex(std::pat::pattern_type!(u32 is 0..=0xFFFFFF00));
|
||||
|
||||
#[no_mangle]
|
||||
pub fn make_none_newtype_index() -> Option<NewtypeIndex> {
|
||||
// CHECK-LABEL: @make_none_newtype_index
|
||||
// CHECK-NEXT: start:
|
||||
// CHECK-NEXT: ret i32 -1
|
||||
None
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ pub fn opt_bool_eq_discr(a: Option<bool>, b: Option<bool>) -> bool {
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn opt_ord_eq_discr(a: Option<Ordering>, b: Option<Ordering>) -> bool {
|
||||
// CHECK-LABEL: @opt_ord_eq_discr(
|
||||
// CHECK: %[[A:.+]] = icmp ne i8 %a, 2
|
||||
// CHECK: %[[B:.+]] = icmp eq i8 %b, 2
|
||||
// CHECK: %[[A:.+]] = icmp ne i8 %a, -2
|
||||
// CHECK: %[[B:.+]] = icmp eq i8 %b, -2
|
||||
// CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
|
||||
// CHECK: ret i1 %[[R]]
|
||||
|
||||
@@ -58,8 +58,8 @@ pub fn opt_nz32_eq_discr(a: Option<NonZero<u32>>, b: Option<NonZero<u32>>) -> bo
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn opt_ac_eq_discr(a: Option<AC>, b: Option<AC>) -> bool {
|
||||
// CHECK-LABEL: @opt_ac_eq_discr(
|
||||
// CHECK: %[[A:.+]] = icmp ne i8 %a, -128
|
||||
// CHECK: %[[B:.+]] = icmp eq i8 %b, -128
|
||||
// CHECK: %[[A:.+]] = icmp ne i8 %a, -1
|
||||
// CHECK: %[[B:.+]] = icmp eq i8 %b, -1
|
||||
// CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
|
||||
// CHECK: ret i1 %[[R]]
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ use std::cmp::Ordering::{self, *};
|
||||
#[no_mangle]
|
||||
pub fn option_ordering_match(x: Option<Ordering>) -> char {
|
||||
// CHECK: %[[RAW:.+]] = load i8, ptr %x
|
||||
// CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2
|
||||
// CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], -2
|
||||
// CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1
|
||||
// CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1
|
||||
// CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]]
|
||||
|
||||
@@ -82,3 +82,14 @@ pub fn bool_eq(l: Option<bool>, r: Option<bool>) -> bool {
|
||||
// CHECK-NEXT: ret i1
|
||||
l == r
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @bool_ref_eq
|
||||
#[no_mangle]
|
||||
pub fn bool_ref_eq(l: &Option<bool>, r: &Option<bool>) -> bool {
|
||||
// CHECK: start:
|
||||
// CHECK-NEXT: load i8
|
||||
// CHECK-NEXT: load i8
|
||||
// CHECK-NEXT: icmp eq i8
|
||||
// CHECK-NEXT: ret i1
|
||||
l == r
|
||||
}
|
||||
|
||||
@@ -88,3 +88,9 @@ union EmptyUnion {} //~ ERROR: has an unknown layout
|
||||
// (this error is never emitted to users).
|
||||
#[rustc_dump_layout(debug)]
|
||||
type TooGeneric<T> = T; //~ ERROR: does not have a fixed layout
|
||||
|
||||
#[rustc_dump_layout(debug)]
|
||||
type OptBool = Option<bool>; //~ ERROR: layout_of
|
||||
|
||||
#[rustc_dump_layout(debug)]
|
||||
type OptChar = Option<char>; //~ ERROR: layout_of
|
||||
|
||||
@@ -614,6 +614,246 @@ error: the type `T` does not have a fixed layout
|
||||
LL | type TooGeneric<T> = T;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
error: layout_of(Option<bool>) = Layout {
|
||||
size: Size(1 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Scalar(
|
||||
Initialized {
|
||||
value: Int(
|
||||
I8,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=2,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
in_memory_order: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
value: Int(
|
||||
I8,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=2,
|
||||
},
|
||||
),
|
||||
uninhabited: false,
|
||||
variants: Multiple {
|
||||
tag: Initialized {
|
||||
value: Int(
|
||||
I8,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=2,
|
||||
},
|
||||
tag_encoding: Niche {
|
||||
untagged_variant: 1,
|
||||
niche_variants: 0..=0,
|
||||
niche_start: 2,
|
||||
},
|
||||
tag_field: 0,
|
||||
variants: [
|
||||
Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
in_memory_order: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
Layout {
|
||||
size: Size(1 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Scalar(
|
||||
Initialized {
|
||||
value: Int(
|
||||
I8,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=1,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
in_memory_order: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
value: Int(
|
||||
I8,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=1,
|
||||
},
|
||||
),
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 1,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
],
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
}
|
||||
--> $DIR/debug.rs:93:1
|
||||
|
|
||||
LL | type OptBool = Option<bool>;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: layout_of(Option<char>) = Layout {
|
||||
size: Size(4 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(4 bytes),
|
||||
},
|
||||
backend_repr: Scalar(
|
||||
Initialized {
|
||||
value: Int(
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: (..=1114111) | (4294967295..),
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
in_memory_order: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
value: Int(
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: (..=1114111) | (4294967295..),
|
||||
},
|
||||
),
|
||||
uninhabited: false,
|
||||
variants: Multiple {
|
||||
tag: Initialized {
|
||||
value: Int(
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: (..=1114111) | (4294967295..),
|
||||
},
|
||||
tag_encoding: Niche {
|
||||
untagged_variant: 1,
|
||||
niche_variants: 0..=0,
|
||||
niche_start: 4294967295,
|
||||
},
|
||||
tag_field: 0,
|
||||
variants: [
|
||||
Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
in_memory_order: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
Layout {
|
||||
size: Size(4 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(4 bytes),
|
||||
},
|
||||
backend_repr: Scalar(
|
||||
Initialized {
|
||||
value: Int(
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=1114111,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
in_memory_order: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
value: Int(
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=1114111,
|
||||
},
|
||||
),
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 1,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(4 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
],
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(4 bytes),
|
||||
randomization_seed: $SEED,
|
||||
}
|
||||
--> $DIR/debug.rs:96:1
|
||||
|
|
||||
LL | type OptChar = Option<char>;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
||||
@@ -370,7 +370,7 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
|
||||
I16,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=1,
|
||||
valid_range: (..=0) | (65535..),
|
||||
},
|
||||
),
|
||||
uninhabited: false,
|
||||
@@ -380,12 +380,12 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
|
||||
I16,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=1,
|
||||
valid_range: (..=0) | (65535..),
|
||||
},
|
||||
tag_encoding: Niche {
|
||||
untagged_variant: 1,
|
||||
niche_variants: 0..=0,
|
||||
niche_start: 1,
|
||||
niche_start: 65535,
|
||||
},
|
||||
tag_field: 0,
|
||||
variants: [
|
||||
|
||||
@@ -57,7 +57,7 @@ error: layout_of(Option<(*const ()) is !null>) = Layout {
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: (..=0) | (1..),
|
||||
valid_range: 0..=18446744073709551615,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
@@ -77,7 +77,7 @@ error: layout_of(Option<(*const ()) is !null>) = Layout {
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: (..=0) | (1..),
|
||||
valid_range: 0..=18446744073709551615,
|
||||
},
|
||||
tag_encoding: Niche {
|
||||
untagged_variant: 1,
|
||||
|
||||
@@ -99,7 +99,7 @@ error: layout_of(Option<(u32) is 1..>) = Layout {
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: (..=0) | (1..),
|
||||
valid_range: 0..=4294967295,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
@@ -118,7 +118,7 @@ error: layout_of(Option<(u32) is 1..>) = Layout {
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: (..=0) | (1..),
|
||||
valid_range: 0..=4294967295,
|
||||
},
|
||||
tag_encoding: Niche {
|
||||
untagged_variant: 1,
|
||||
@@ -210,7 +210,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout {
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: (..=0) | (1..),
|
||||
valid_range: 0..=4294967295,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
@@ -229,7 +229,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout {
|
||||
I32,
|
||||
false,
|
||||
),
|
||||
valid_range: (..=0) | (1..),
|
||||
valid_range: 0..=4294967295,
|
||||
},
|
||||
tag_encoding: Niche {
|
||||
untagged_variant: 1,
|
||||
|
||||
Reference in New Issue
Block a user