match ty.sty {
ty::FnPtr(_) => true,
ty::Ref(..) => true,
- ty::Adt(field_def, substs) if field_def.repr.transparent() && field_def.is_struct() => {
- for field in &field_def.non_enum_variant().fields {
+ ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
+ for field in field_def.all_fields() {
let field_ty = tcx.normalize_erasing_regions(
ParamEnv::reveal_all(),
field.ty(tcx, substs),
return FfiUnsafe {
ty: ty,
reason: "this struct has unspecified layout",
- help: Some("consider adding a #[repr(C)] or #[repr(transparent)] \
- attribute to this struct"),
+ help: Some("consider adding a `#[repr(C)]` or \
+ `#[repr(transparent)]` attribute to this struct"),
};
}
if all_phantom { FfiPhantom(ty) } else { FfiSafe }
}
AdtKind::Union => {
- if !def.repr.c() {
+ if !def.repr.c() && !def.repr.transparent() {
return FfiUnsafe {
ty: ty,
reason: "this union has unspecified layout",
- help: Some("consider adding a #[repr(C)] attribute to this union"),
+ help: Some("consider adding a `#[repr(C)]` or \
+ `#[repr(transparent)]` attribute to this union"),
};
}
ParamEnv::reveal_all(),
field.ty(cx, substs),
);
+ // repr(transparent) types are allowed to have arbitrary ZSTs, not just
+ // PhantomData -- skip checking all ZST fields.
+ if def.repr.transparent() && is_zst(cx, field.did, field_ty) {
+ continue;
+ }
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {
// Check for a repr() attribute to specify the size of the
// discriminant.
- if !def.repr.c() && def.repr.int.is_none() {
+ if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() {
// Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, ty, def, substs) {
return FfiUnsafe {
ty: ty,
reason: "enum has no representation hint",
- help: Some("consider adding a #[repr(...)] attribute \
- to this enum"),
+ help: Some("consider adding a `#[repr(C)]`, \
+ `#[repr(transparent)]`, or integer `#[repr(...)]` \
+ attribute to this enum"),
};
}
}
// Check the contained variants.
for variant in &def.variants {
for field in &variant.fields {
- let arg = cx.normalize_erasing_regions(
+ let field_ty = cx.normalize_erasing_regions(
ParamEnv::reveal_all(),
field.ty(cx, substs),
);
- let r = self.check_type_for_ffi(cache, arg);
+ // repr(transparent) types are allowed to have arbitrary ZSTs, not
+ // just PhantomData -- skip checking all ZST fields.
+ if def.repr.transparent() && is_zst(cx, field.did, field_ty) {
+ continue;
+ }
+ let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
FfiUnsafe { .. } => {