]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_lint/types.rs
Implement RFC 2645 (transparent enums and unions)
[rust.git] / src / librustc_lint / types.rs
index ac18e131c4a3d7aafcf62cb5a1dd0e6b02d6546f..f89a772bef5da55ec48b46ce01cb84aa5e28b327 100644 (file)
@@ -531,8 +531,8 @@ fn ty_is_known_nonnull<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> b
     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),
@@ -627,8 +627,8 @@ fn check_type_for_ffi(&self,
                             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"),
                             };
                         }
 
@@ -668,11 +668,12 @@ fn check_type_for_ffi(&self,
                         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"),
                             };
                         }
 
@@ -690,6 +691,11 @@ fn check_type_for_ffi(&self,
                                 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 => {
@@ -712,14 +718,15 @@ fn check_type_for_ffi(&self,
 
                         // 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"),
                                 };
                             }
                         }
@@ -727,11 +734,16 @@ fn check_type_for_ffi(&self,
                         // 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 { .. } => {