Skip to content

Commit 1bf0340

Browse files
committed
Allow extern types in #[repr(transparent)] structs
Fixes rust-lang#55541
1 parent 5eda136 commit 1bf0340

File tree

4 files changed

+61
-6
lines changed

4 files changed

+61
-6
lines changed

src/librustc/ty/sty.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
15781578
}
15791579
}
15801580

1581+
pub fn is_transparent(&self) -> bool {
1582+
match self.sty {
1583+
Adt(def, _) => def.repr.transparent(),
1584+
_ => false,
1585+
}
1586+
}
1587+
15811588
pub fn sequence_element_type(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
15821589
match self.sty {
15831590
Array(ty, _) | Slice(ty) => ty,

src/librustc_mir/interpret/eval_context.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
368368
);
369369

370370
// Recurse to get the size of the dynamically sized field (must be
371-
// the last field). Can't have foreign types here, how would we
372-
// adjust alignment and size for them?
371+
// the last field). Can't have foreign types here unless they're
372+
// in a #[repr(transparent)] struct, otherwise how would we adjust
373+
// alignment and size for them?
373374
let field = layout.field(self, layout.fields.count() - 1)?;
374-
let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)?
375+
let unsized_size_and_align = self.size_and_align_of(metadata, field)?;
376+
if unsized_size_and_align.is_none() && layout.ty.is_transparent() {
377+
return Ok(None);
378+
}
379+
let (unsized_size, unsized_align) = unsized_size_and_align
375380
.expect("Fields cannot be extern types");
376381

377382
// FIXME (#26403, #27023): We should be adding padding

src/librustc_mir/interpret/place.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,13 @@ where
359359
// Offset may need adjustment for unsized fields
360360
let (meta, offset) = if field_layout.is_unsized() {
361361
// re-use parent metadata to determine dynamic field layout
362-
let (_, align) = self.size_and_align_of(base.meta, field_layout)?
363-
.expect("Fields cannot be extern types");
364-
(base.meta, offset.abi_align(align))
362+
let size_and_align = self.size_and_align_of(base.meta, field_layout)?;
363+
if size_and_align.is_none() && base.layout.ty.is_transparent() {
364+
(base.meta, offset)
365+
} else {
366+
let (_, align) = size_and_align.expect("Fields cannot be extern types");
367+
(base.meta, offset.abi_align(align))
368+
}
365369
} else {
366370
// base.meta could be present; we might be accessing a sized field of an unsized
367371
// struct.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// run-pass
12+
#![allow(dead_code)]
13+
14+
// Test that extern types can be used as fields within a transparent struct. See issue #55541.
15+
16+
#![feature(const_transmute, extern_types)]
17+
18+
extern {
19+
type A;
20+
}
21+
unsafe impl Sync for A {}
22+
23+
#[repr(transparent)]
24+
struct Foo(A);
25+
26+
#[repr(transparent)]
27+
struct Bar(std::marker::PhantomData<u64>, A);
28+
29+
static FOO: &'static Foo = {
30+
static VALUE: usize = b'F' as usize;
31+
unsafe { std::mem::transmute(&VALUE) }
32+
};
33+
34+
static BAR: &'static Bar = {
35+
static VALUE: usize = b'B' as usize;
36+
unsafe { std::mem::transmute(&VALUE) }
37+
};
38+
39+
fn main() {}

0 commit comments

Comments
 (0)