Skip to content

Commit 3029e09

Browse files
authored
Rollup merge of #131698 - the8472:remove-set-discriminant-hack, r=RalfJung
use stores of the correct size to set discriminants Resolves an old HACK /FIXME. Note that I haven't worked much with codegen so I'm not sure if I'm using the functions correctly and I was surprised seeing out-of-range values being fed into `const_uint_big` but apparently they're wrapped implicitly? By making it explicit we can pass in-range values instead.
2 parents e93e096 + 26d7b5d commit 3029e09

File tree

3 files changed

+61
-8
lines changed

3 files changed

+61
-8
lines changed

compiler/rustc_codegen_ssa/src/mir/place.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_abi::Primitive::{Int, Pointer};
2-
use rustc_abi::{Align, FieldsShape, Size, TagEncoding, VariantIdx, Variants};
2+
use rustc_abi::{Align, BackendRepr, FieldsShape, Size, TagEncoding, VariantIdx, Variants};
3+
use rustc_middle::mir::interpret::Scalar;
34
use rustc_middle::mir::tcx::PlaceTy;
45
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
56
use rustc_middle::ty::{self, Ty};
@@ -385,15 +386,22 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
385386
if variant_index != untagged_variant {
386387
let niche = self.project_field(bx, tag_field);
387388
let niche_llty = bx.cx().immediate_backend_type(niche.layout);
389+
let BackendRepr::Scalar(scalar) = niche.layout.backend_repr else {
390+
bug!("expected a scalar placeref for the niche");
391+
};
392+
// We are supposed to compute `niche_value.wrapping_add(niche_start)` wrapping
393+
// around the `niche`'s type.
394+
// The easiest way to do that is to do wrapping arithmetic on `u128` and then
395+
// masking off any extra bits that occur because we did the arithmetic with too many bits.
388396
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
389397
let niche_value = (niche_value as u128).wrapping_add(niche_start);
390-
// FIXME(eddyb): check the actual primitive type here.
391-
let niche_llval = if niche_value == 0 {
392-
// HACK(eddyb): using `c_null` as it works on all types.
393-
bx.cx().const_null(niche_llty)
394-
} else {
395-
bx.cx().const_uint_big(niche_llty, niche_value)
396-
};
398+
let niche_value = niche_value & niche.layout.size.unsigned_int_max();
399+
400+
let niche_llval = bx.cx().scalar_to_backend(
401+
Scalar::from_uint(niche_value, niche.layout.size),
402+
scalar,
403+
niche_llty,
404+
);
397405
OperandValue::Immediate(niche_llval).store(bx, niche);
398406
}
399407
}
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//@ run-pass
2+
//! Check that we can codegen setting and getting discriminants, including non-null niches,
3+
//! for enums with a pointer-like ABI. This used to crash llvm.
4+
5+
#![feature(rustc_attrs)]
6+
use std::{ptr, mem};
7+
8+
9+
#[rustc_layout_scalar_valid_range_start(1)]
10+
#[rustc_layout_scalar_valid_range_end(100)]
11+
#[derive(Copy, Clone)]
12+
struct PointerWithRange(#[allow(dead_code)] *const u8);
13+
14+
15+
fn main() {
16+
let val = unsafe { PointerWithRange(ptr::without_provenance(90)) };
17+
18+
let ptr = Some(val);
19+
assert!(ptr.is_some());
20+
let raw = unsafe { mem::transmute::<_, usize>(ptr) };
21+
assert_eq!(raw, 90);
22+
23+
let ptr = Some(Some(val));
24+
assert!(ptr.is_some());
25+
assert!(ptr.unwrap().is_some());
26+
let raw = unsafe { mem::transmute::<_, usize>(ptr) };
27+
assert_eq!(raw, 90);
28+
29+
let ptr: Option<PointerWithRange> = None;
30+
assert!(ptr.is_none());
31+
let raw = unsafe { mem::transmute::<_, usize>(ptr) };
32+
assert!(!(1..=100).contains(&raw));
33+
34+
let ptr: Option<Option<PointerWithRange>> = None;
35+
assert!(ptr.is_none());
36+
let raw = unsafe { mem::transmute::<_, usize>(ptr) };
37+
assert!(!(1..=100).contains(&raw));
38+
}

tests/ui/structs-enums/type-sizes.rs

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![allow(dead_code)]
66
#![feature(never_type)]
77
#![feature(pointer_is_aligned_to)]
8+
#![feature(rustc_attrs)]
89

910
use std::mem::size_of;
1011
use std::num::NonZero;
@@ -237,6 +238,10 @@ struct VecDummy {
237238
len: usize,
238239
}
239240

241+
#[rustc_layout_scalar_valid_range_start(1)]
242+
#[rustc_layout_scalar_valid_range_end(100)]
243+
struct PointerWithRange(#[allow(dead_code)] *const u8);
244+
240245
pub fn main() {
241246
assert_eq!(size_of::<u8>(), 1 as usize);
242247
assert_eq!(size_of::<u32>(), 4 as usize);
@@ -354,4 +359,6 @@ pub fn main() {
354359
assert!(ptr::from_ref(&v.a).addr() > ptr::from_ref(&v.b).addr());
355360

356361

362+
assert_eq!(size_of::<Option<PointerWithRange>>(), size_of::<PointerWithRange>());
363+
assert_eq!(size_of::<Option<Option<PointerWithRange>>>(), size_of::<PointerWithRange>());
357364
}

0 commit comments

Comments
 (0)