Skip to content

Commit 64ce698

Browse files
authored
Rollup merge of #91910 - tmiasko:miri-extern-type, r=RalfJung
miri: lift restriction on extern types being the only field in a struct Fixes #91827. r? ````@RalfJung````
2 parents 24b75e7 + fd47d24 commit 64ce698

File tree

3 files changed

+69
-27
lines changed

3 files changed

+69
-27
lines changed

compiler/rustc_const_eval/src/interpret/eval_context.rs

+3-13
Original file line numberDiff line numberDiff line change
@@ -616,19 +616,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
616616
match self.size_and_align_of(metadata, &field)? {
617617
Some(size_and_align) => size_and_align,
618618
None => {
619-
// A field with extern type. If this field is at offset 0, we behave
620-
// like the underlying extern type.
621-
// FIXME: Once we have made decisions for how to handle size and alignment
622-
// of `extern type`, this should be adapted. It is just a temporary hack
623-
// to get some code to work that probably ought to work.
624-
if sized_size == Size::ZERO {
625-
return Ok(None);
626-
} else {
627-
span_bug!(
628-
self.cur_span(),
629-
"Fields cannot be extern types, unless they are at offset 0"
630-
)
631-
}
619+
// A field with an extern type. We don't know the actual dynamic size
620+
// or the alignment.
621+
return Ok(None);
632622
}
633623
};
634624

compiler/rustc_const_eval/src/interpret/place.rs

+8-14
Original file line numberDiff line numberDiff line change
@@ -362,21 +362,15 @@ where
362362
// Re-use parent metadata to determine dynamic field layout.
363363
// With custom DSTS, this *will* execute user-defined code, but the same
364364
// happens at run-time so that's okay.
365-
let align = match self.size_and_align_of(&base.meta, &field_layout)? {
366-
Some((_, align)) => align,
367-
None if offset == Size::ZERO => {
368-
// An extern type at offset 0, we fall back to its static alignment.
369-
// FIXME: Once we have made decisions for how to handle size and alignment
370-
// of `extern type`, this should be adapted. It is just a temporary hack
371-
// to get some code to work that probably ought to work.
372-
field_layout.align.abi
365+
match self.size_and_align_of(&base.meta, &field_layout)? {
366+
Some((_, align)) => (base.meta, offset.align_to(align)),
367+
None => {
368+
// For unsized types with an extern type tail we perform no adjustments.
369+
// NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
370+
assert!(matches!(base.meta, MemPlaceMeta::None));
371+
(base.meta, offset)
373372
}
374-
None => span_bug!(
375-
self.cur_span(),
376-
"cannot compute offset for extern type field at non-0 offset"
377-
),
378-
};
379-
(base.meta, offset.align_to(align))
373+
}
380374
} else {
381375
// base.meta could be present; we might be accessing a sized field of an unsized
382376
// struct.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// run-pass
2+
//
3+
// Test that we can handle unsized types with an extern type tail part.
4+
// Regression test for issue #91827.
5+
6+
#![feature(const_ptr_offset_from)]
7+
#![feature(const_slice_from_raw_parts)]
8+
#![feature(extern_types)]
9+
10+
use std::ptr::addr_of;
11+
12+
extern "C" {
13+
type Opaque;
14+
}
15+
16+
unsafe impl Sync for Opaque {}
17+
18+
#[repr(C)]
19+
pub struct List<T> {
20+
len: usize,
21+
data: [T; 0],
22+
tail: Opaque,
23+
}
24+
25+
#[repr(C)]
26+
pub struct ListImpl<T, const N: usize> {
27+
len: usize,
28+
data: [T; N],
29+
}
30+
31+
impl<T> List<T> {
32+
const fn as_slice(&self) -> &[T] {
33+
unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.len) }
34+
}
35+
}
36+
37+
impl<T, const N: usize> ListImpl<T, N> {
38+
const fn as_list(&self) -> &List<T> {
39+
unsafe { std::mem::transmute(self) }
40+
}
41+
}
42+
43+
pub static A: ListImpl<u128, 3> = ListImpl {
44+
len: 3,
45+
data: [5, 6, 7],
46+
};
47+
pub static A_REF: &'static List<u128> = A.as_list();
48+
pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list());
49+
50+
const fn tail_offset<T>(list: &List<T>) -> isize {
51+
unsafe { (addr_of!(list.tail) as *const u8).offset_from(list as *const List<T> as *const u8) }
52+
}
53+
54+
fn main() {
55+
assert_eq!(A_REF.as_slice(), &[5, 6, 7]);
56+
// Check that interpreter and code generation agree about the position of the tail field.
57+
assert_eq!(A_TAIL_OFFSET, tail_offset(A_REF));
58+
}

0 commit comments

Comments
 (0)