Skip to content

Commit 0e67c75

Browse files
committed
reject projecting to fields whose offset we cannot compute
1 parent 6ba7c5c commit 0e67c75

File tree

8 files changed

+103
-82
lines changed

8 files changed

+103
-82
lines changed

compiler/rustc_codegen_ssa/src/mir/place.rs

+4-19
Original file line numberDiff line numberDiff line change
@@ -141,27 +141,12 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
141141
};
142142

143143
// Simple cases, which don't need DST adjustment:
144-
// * no metadata available - just log the case
145-
// * known alignment - sized types, `[T]`, `str` or a foreign type
146-
// * packed struct - there is no alignment padding
144+
// * known alignment - sized types, `[T]`, `str`
145+
// * offset 0 -- rounding up to alignment cannot change the offset
147146
match field.ty.kind() {
148-
_ if self.llextra.is_none() => {
149-
debug!(
150-
"unsized field `{}`, of `{:?}` has no metadata for adjustment",
151-
ix, self.llval
152-
);
153-
return simple();
154-
}
155147
_ if field.is_sized() => return simple(),
156-
ty::Slice(..) | ty::Str | ty::Foreign(..) => return simple(),
157-
ty::Adt(def, _) => {
158-
if def.repr().packed() {
159-
// FIXME(eddyb) generalize the adjustment when we
160-
// start supporting packing to larger alignments.
161-
assert_eq!(self.layout.align.abi.bytes(), 1);
162-
return simple();
163-
}
164-
}
148+
ty::Slice(..) | ty::Str => return simple(),
149+
_ if offset.bytes() == 0 => return simple(),
165150
_ => {}
166151
}
167152

compiler/rustc_const_eval/src/interpret/projection.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,15 @@ where
164164
// happens at run-time so that's okay.
165165
match self.size_and_align_of(&base_meta, &field_layout)? {
166166
Some((_, align)) => (base_meta, offset.align_to(align)),
167-
None => {
168-
// For unsized types with an extern type tail we perform no adjustments.
169-
// NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
170-
assert!(matches!(base_meta, MemPlaceMeta::None));
167+
None if offset == Size::ZERO => {
168+
// If the offset is 0, then rounding it up to alignment wouldn't change anything,
169+
// so we can do this even for types where we cannot determine the alignment.
171170
(base_meta, offset)
172171
}
172+
None => {
173+
// We don't know the alignment of this field, so we cannot adjust.
174+
throw_unsup_format!("`extern type` does not have a known offset")
175+
}
173176
}
174177
} else {
175178
// base_meta could be present; we might be accessing a sized field of an unsized
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Test that we can handle unsized types with an extern type tail part.
2+
// Regression test for issue #91827.
3+
4+
#![feature(extern_types)]
5+
6+
use std::ptr::addr_of;
7+
8+
extern "C" {
9+
type Opaque;
10+
}
11+
12+
struct Newtype(Opaque);
13+
14+
struct S {
15+
i: i32,
16+
a: Opaque,
17+
}
18+
19+
const NEWTYPE: () = unsafe {
20+
// Projecting to the newtype works, because it is always at offset 0.
21+
let x: &Newtype = unsafe { &*(1usize as *const Newtype) };
22+
let field = &x.0;
23+
};
24+
25+
const OFFSET: () = unsafe {
26+
// This needs to compute the field offset, but we don't know the type's alignment, so this fail.
27+
let x: &S = unsafe { &*(1usize as *const S) };
28+
let field = &x.a; //~ERROR: evaluation of constant value failed
29+
//~| does not have a known offset
30+
};
31+
32+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0080]: evaluation of constant value failed
2+
--> $DIR/issue-91827-extern-types-field-offset.rs:28:17
3+
|
4+
LL | let field = &x.a;
5+
| ^^^^ `extern type` does not have a known offset
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0080`.

tests/ui/consts/const-eval/issue-91827-extern-types.rs

-59
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0080]: could not evaluate static initializer
2+
--> $DIR/issue-91827-extern-types.rs:50:15
3+
|
4+
LL | unsafe { (addr_of!(list.tail) as *const u8).offset_from(list as *const List<T> as *const u8) }
5+
| ^^^^^^^^^^^^^^^^^^^ `extern type` does not have known offset
6+
|
7+
note: inside `tail_offset::<u128>`
8+
--> $DIR/issue-91827-extern-types.rs:50:15
9+
|
10+
LL | unsafe { (addr_of!(list.tail) as *const u8).offset_from(list as *const List<T> as *const u8) }
11+
| ^^^^^^^^^^^^^^^^^^^
12+
note: inside `A_TAIL_OFFSET`
13+
--> $DIR/issue-91827-extern-types.rs:47:35
14+
|
15+
LL | pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list());
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^
17+
= note: this error originates in the macro `addr_of` (in Nightly builds, run with -Z macro-backtrace for more info)
18+
19+
error: aborting due to 1 previous error
20+
21+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// run-fail
2+
// check-run-results
3+
// normalize-stderr-test "panicking\.rs:\d+:\d+:" -> "panicking.rs:"
4+
#![feature(extern_types)]
5+
6+
extern "C" {
7+
type Opaque;
8+
}
9+
10+
struct Newtype(Opaque);
11+
12+
struct S {
13+
i: i32,
14+
a: Opaque,
15+
}
16+
17+
fn main() {
18+
// Projecting to the newtype works, because it is always at offset 0.
19+
let x: &Newtype = unsafe { &*(1usize as *const Newtype) };
20+
let field = &x.0;
21+
22+
// This needs to compute the field offset, but we don't know the type's alignment,
23+
// so this panics.
24+
let x: &S = unsafe { &*(1usize as *const S) };
25+
let field = &x.a;
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
thread 'main' panicked at library/core/src/panicking.rs:
2+
attempted to compute the size or alignment of extern type `Opaque`
3+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
4+
thread caused non-unwinding panic. aborting.

0 commit comments

Comments
 (0)