Skip to content

Commit

Permalink
Allow extern types in #[repr(transparent)] structs
Browse files Browse the repository at this point in the history
  • Loading branch information
mjbshaw committed Nov 2, 2018
1 parent 5eda136 commit 1bf0340
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 6 deletions.
7 changes: 7 additions & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1578,6 +1578,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}
}

pub fn is_transparent(&self) -> bool {
match self.sty {
Adt(def, _) => def.repr.transparent(),
_ => false,
}
}

pub fn sequence_element_type(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
match self.sty {
Array(ty, _) | Slice(ty) => ty,
Expand Down
11 changes: 8 additions & 3 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
);

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

// FIXME (#26403, #27023): We should be adding padding
Expand Down
10 changes: 7 additions & 3 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,9 +359,13 @@ where
// Offset may need adjustment for unsized fields
let (meta, offset) = if field_layout.is_unsized() {
// re-use parent metadata to determine dynamic field layout
let (_, align) = self.size_and_align_of(base.meta, field_layout)?
.expect("Fields cannot be extern types");
(base.meta, offset.abi_align(align))
let size_and_align = self.size_and_align_of(base.meta, field_layout)?;
if size_and_align.is_none() && base.layout.ty.is_transparent() {
(base.meta, offset)
} else {
let (_, align) = size_and_align.expect("Fields cannot be extern types");
(base.meta, offset.abi_align(align))
}
} else {
// base.meta could be present; we might be accessing a sized field of an unsized
// struct.
Expand Down
39 changes: 39 additions & 0 deletions src/test/run-pass/extern/extern-types-in-transparent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-pass
#![allow(dead_code)]

// Test that extern types can be used as fields within a transparent struct. See issue #55541.

#![feature(const_transmute, extern_types)]

extern {
type A;
}
unsafe impl Sync for A {}

#[repr(transparent)]
struct Foo(A);

#[repr(transparent)]
struct Bar(std::marker::PhantomData<u64>, A);

static FOO: &'static Foo = {
static VALUE: usize = b'F' as usize;
unsafe { std::mem::transmute(&VALUE) }
};

static BAR: &'static Bar = {
static VALUE: usize = b'B' as usize;
unsafe { std::mem::transmute(&VALUE) }
};

fn main() {}

0 comments on commit 1bf0340

Please sign in to comment.