Skip to content

Allow extern types in #[repr(transparent)] structs #55624

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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() {}
12 changes: 11 additions & 1 deletion src/test/ui/repr/repr-transparent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// - repr-transparent-other-reprs.rs
// - repr-transparent-other-items.rs

#![feature(repr_align)]
#![feature(extern_types, repr_align)]

use std::marker::PhantomData;

Expand Down Expand Up @@ -49,4 +49,14 @@ struct ZstAlign32<T>(PhantomData<T>);
#[repr(transparent)]
struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1

extern "C" {
type ExternType;
}

#[repr(transparent)]
struct NontrivialAlignZstExtern([u16; 0], ExternType); //~ ERROR alignment larger than 1

#[repr(transparent)]
struct GenericAlignExtern<T>(ZstAlign32<T>, ExternType); //~ ERROR alignment larger than 1

fn main() {}
14 changes: 13 additions & 1 deletion src/test/ui/repr/repr-transparent.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,19 @@ error[E0691]: zero-sized field in transparent struct has alignment larger than 1
LL | struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
| ^^^^^^^^^^^^^

error: aborting due to 8 previous errors
error[E0691]: zero-sized field in transparent struct has alignment larger than 1
--> $DIR/repr-transparent.rs:57:33
|
LL | struct NontrivialAlignZstExtern([u16; 0], ExternType); //~ ERROR alignment larger than 1
| ^^^^^^^^

error[E0691]: zero-sized field in transparent struct has alignment larger than 1
--> $DIR/repr-transparent.rs:60:30
|
LL | struct GenericAlignExtern<T>(ZstAlign32<T>, ExternType); //~ ERROR alignment larger than 1
| ^^^^^^^^^^^^^

error: aborting due to 10 previous errors

Some errors occurred: E0690, E0691.
For more information about an error, try `rustc --explain E0690`.