reject projecting to fields whose offset we cannot compute
This commit is contained in:
parent
b1613ebc43
commit
9ef1e35166
7 changed files with 85 additions and 75 deletions
|
@ -99,6 +99,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
||||||
let offset = self.layout.fields.offset(ix);
|
let offset = self.layout.fields.offset(ix);
|
||||||
let effective_field_align = self.align.restrict_for_offset(offset);
|
let effective_field_align = self.align.restrict_for_offset(offset);
|
||||||
|
|
||||||
|
// `simple` is called when we don't need to adjust the offset to
|
||||||
|
// the dynamic alignment of the field.
|
||||||
let mut simple = || {
|
let mut simple = || {
|
||||||
let llval = match self.layout.abi {
|
let llval = match self.layout.abi {
|
||||||
_ if offset.bytes() == 0 => {
|
_ if offset.bytes() == 0 => {
|
||||||
|
@ -141,28 +143,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Simple cases, which don't need DST adjustment:
|
// Simple cases, which don't need DST adjustment:
|
||||||
// * no metadata available - just log the case
|
// * known alignment - sized types, `[T]`, `str`
|
||||||
// * known alignment - sized types, `[T]`, `str` or a foreign type
|
// * offset 0 -- rounding up to alignment cannot change the offset
|
||||||
// Note that looking at `field.align` is incorrect since that is not necessarily equal
|
// Note that looking at `field.align` is incorrect since that is not necessarily equal
|
||||||
// to the dynamic alignment of the type.
|
// to the dynamic alignment of the type.
|
||||||
match field.ty.kind() {
|
match field.ty.kind() {
|
||||||
_ if self.llextra.is_none() => {
|
|
||||||
debug!(
|
|
||||||
"unsized field `{}`, of `{:?}` has no metadata for adjustment",
|
|
||||||
ix, self.llval
|
|
||||||
);
|
|
||||||
return simple();
|
|
||||||
}
|
|
||||||
_ if field.is_sized() => return simple(),
|
_ if field.is_sized() => return simple(),
|
||||||
ty::Slice(..) | ty::Str | ty::Foreign(..) => return simple(),
|
ty::Slice(..) | ty::Str => return simple(),
|
||||||
|
_ if offset.bytes() == 0 => return simple(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to get the pointer manually now.
|
// We need to get the pointer manually now.
|
||||||
// We do this by casting to a `*i8`, then offsetting it by the appropriate amount.
|
// We do this by casting to a `*i8`, then offsetting it by the appropriate amount.
|
||||||
// We do this instead of, say, simply adjusting the pointer from the result of a GEP
|
// We do this instead of, say, simply adjusting the pointer from the result of a GEP
|
||||||
// because the field may have an arbitrary alignment in the LLVM representation
|
// because the field may have an arbitrary alignment in the LLVM representation.
|
||||||
// anyway.
|
|
||||||
//
|
//
|
||||||
// To demonstrate:
|
// To demonstrate:
|
||||||
//
|
//
|
||||||
|
|
|
@ -174,12 +174,15 @@ where
|
||||||
};
|
};
|
||||||
(base_meta, offset.align_to(align))
|
(base_meta, offset.align_to(align))
|
||||||
}
|
}
|
||||||
None => {
|
None if offset == Size::ZERO => {
|
||||||
// For unsized types with an extern type tail we perform no adjustments.
|
// If the offset is 0, then rounding it up to alignment wouldn't change anything,
|
||||||
// NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
|
// so we can do this even for types where we cannot determine the alignment.
|
||||||
assert!(matches!(base_meta, MemPlaceMeta::None));
|
|
||||||
(base_meta, offset)
|
(base_meta, offset)
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
|
// We don't know the alignment of this field, so we cannot adjust.
|
||||||
|
throw_unsup_format!("`extern type` does not have a known offset")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// base_meta could be present; we might be accessing a sized field of an unsized
|
// base_meta could be present; we might be accessing a sized field of an unsized
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Test that we can handle unsized types with an extern type tail part.
|
||||||
|
// Regression test for issue #91827.
|
||||||
|
|
||||||
|
#![feature(extern_types)]
|
||||||
|
|
||||||
|
use std::ptr::addr_of;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
type Opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Newtype(Opaque);
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
i: i32,
|
||||||
|
a: Opaque,
|
||||||
|
}
|
||||||
|
|
||||||
|
const NEWTYPE: () = unsafe {
|
||||||
|
// Projecting to the newtype works, because it is always at offset 0.
|
||||||
|
let x: &Newtype = unsafe { &*(1usize as *const Newtype) };
|
||||||
|
let field = &x.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const OFFSET: () = unsafe {
|
||||||
|
// This needs to compute the field offset, but we don't know the type's alignment, so this fail.
|
||||||
|
let x: &S = unsafe { &*(1usize as *const S) };
|
||||||
|
let field = &x.a; //~ERROR: evaluation of constant value failed
|
||||||
|
//~| does not have a known offset
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0080]: evaluation of constant value failed
|
||||||
|
--> $DIR/issue-91827-extern-types-field-offset.rs:28:17
|
||||||
|
|
|
||||||
|
LL | let field = &x.a;
|
||||||
|
| ^^^^ `extern type` does not have a known offset
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0080`.
|
|
@ -1,59 +0,0 @@
|
||||||
// run-pass
|
|
||||||
//
|
|
||||||
// Test that we can handle unsized types with an extern type tail part.
|
|
||||||
// Regression test for issue #91827.
|
|
||||||
|
|
||||||
#![feature(extern_types)]
|
|
||||||
|
|
||||||
use std::ptr::addr_of;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
type Opaque;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Sync for Opaque {}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct List<T> {
|
|
||||||
len: usize,
|
|
||||||
data: [T; 0],
|
|
||||||
tail: Opaque,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct ListImpl<T, const N: usize> {
|
|
||||||
len: usize,
|
|
||||||
data: [T; N],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> List<T> {
|
|
||||||
const fn as_slice(&self) -> &[T] {
|
|
||||||
unsafe {
|
|
||||||
let ptr = addr_of!(self.tail) as *const T;
|
|
||||||
std::slice::from_raw_parts(ptr, self.len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, const N: usize> ListImpl<T, N> {
|
|
||||||
const fn as_list(&self) -> &List<T> {
|
|
||||||
unsafe { std::mem::transmute(self) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static A: ListImpl<u128, 3> = ListImpl {
|
|
||||||
len: 3,
|
|
||||||
data: [5, 6, 7],
|
|
||||||
};
|
|
||||||
pub static A_REF: &'static List<u128> = A.as_list();
|
|
||||||
pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list());
|
|
||||||
|
|
||||||
const fn tail_offset<T>(list: &List<T>) -> isize {
|
|
||||||
unsafe { (addr_of!(list.tail) as *const u8).offset_from(list as *const List<T> as *const u8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
assert_eq!(A_REF.as_slice(), &[5, 6, 7]);
|
|
||||||
// Check that interpreter and code generation agree about the position of the tail field.
|
|
||||||
assert_eq!(A_TAIL_OFFSET, tail_offset(A_REF));
|
|
||||||
}
|
|
26
tests/ui/extern/extern-types-field-offset.rs
vendored
Normal file
26
tests/ui/extern/extern-types-field-offset.rs
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// run-fail
|
||||||
|
// check-run-results
|
||||||
|
// normalize-stderr-test "panicking\.rs:\d+:\d+:" -> "panicking.rs:"
|
||||||
|
#![feature(extern_types)]
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
type Opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Newtype(Opaque);
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
i: i32,
|
||||||
|
a: Opaque,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Projecting to the newtype works, because it is always at offset 0.
|
||||||
|
let x: &Newtype = unsafe { &*(1usize as *const Newtype) };
|
||||||
|
let field = &x.0;
|
||||||
|
|
||||||
|
// This needs to compute the field offset, but we don't know the type's alignment,
|
||||||
|
// so this panics.
|
||||||
|
let x: &S = unsafe { &*(1usize as *const S) };
|
||||||
|
let field = &x.a;
|
||||||
|
}
|
4
tests/ui/extern/extern-types-field-offset.run.stderr
vendored
Normal file
4
tests/ui/extern/extern-types-field-offset.run.stderr
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
thread 'main' panicked at library/core/src/panicking.rs:
|
||||||
|
attempted to compute the size or alignment of extern type `Opaque`
|
||||||
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
|
thread caused non-unwinding panic. aborting.
|
Loading…
Add table
Add a link
Reference in a new issue