]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/mod.rs
Implement RFC 2645 (transparent enums and unions)
[rust.git] / src / librustc_typeck / check / mod.rs
index 0b558a20ed47e2a088984afbe59891221892acc5..2e53b380cb71a6b8441b4db009c22d0b424be192 100644 (file)
@@ -1310,7 +1310,7 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let def = tcx.adt_def(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
-
+    check_transparent(tcx, span, def_id);
     check_packed(tcx, span, def_id);
 }
 
@@ -1807,8 +1807,43 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De
         return;
     }
 
+    if adt.is_enum() {
+        if !tcx.features().transparent_enums {
+            emit_feature_err(&tcx.sess.parse_sess,
+                             sym::transparent_enums,
+                             sp,
+                             GateIssue::Language,
+                             "transparent enums are unstable");
+        }
+        if adt.variants.len() != 1 {
+            let variant_spans: Vec<_> = adt.variants.iter().map(|variant| {
+                tcx.hir().span_if_local(variant.def_id).unwrap()
+            }).collect();
+            let mut err = struct_span_err!(tcx.sess, sp, E0731,
+                            "transparent enum needs exactly one variant, but has {}",
+                            adt.variants.len());
+            if !variant_spans.is_empty() {
+                err.span_note(variant_spans, &format!("the following variants exist on `{}`",
+                                                      tcx.def_path_str(def_id)));
+            }
+            err.emit();
+            if adt.variants.is_empty() {
+                // Don't bother checking the fields. No variants (and thus no fields) exist.
+                return;
+            }
+        }
+    }
+
+    if adt.is_union() && !tcx.features().transparent_unions {
+        emit_feature_err(&tcx.sess.parse_sess,
+                         sym::transparent_unions,
+                         sp,
+                         GateIssue::Language,
+                         "transparent unions are unstable");
+    }
+
     // For each field, figure out if it's known to be a ZST and align(1)
-    let field_infos = adt.non_enum_variant().fields.iter().map(|field| {
+    let field_infos = adt.all_fields().map(|field| {
         let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
         let param_env = tcx.param_env(field.did);
         let layout = tcx.layout_of(param_env.and(ty));
@@ -1823,16 +1858,24 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De
     let non_zst_count = non_zst_fields.clone().count();
     if non_zst_count != 1 {
         let field_spans: Vec<_> = non_zst_fields.map(|(span, _zst, _align1)| span).collect();
-        struct_span_err!(tcx.sess, sp, E0690,
-                         "transparent struct needs exactly one non-zero-sized field, but has {}",
-                         non_zst_count)
-        .span_note(field_spans, "non-zero-sized field")
-        .emit();
+
+        let mut err = struct_span_err!(tcx.sess, sp, E0690,
+                         "{}transparent {} needs exactly one non-zero-sized field, but has {}",
+                         if adt.is_enum() { "the variant of a " } else { "" },
+                         adt.descr(),
+                         non_zst_count);
+        if !field_spans.is_empty() {
+            err.span_note(field_spans,
+                          &format!("the following non-zero-sized fields exist on `{}`:",
+                                   tcx.def_path_str(def_id)));
+        }
+        err.emit();
     }
     for (span, zst, align1) in field_infos {
         if zst && !align1 {
             span_err!(tcx.sess, span, E0691,
-                      "zero-sized field in transparent struct has alignment larger than 1");
+                      "zero-sized field in transparent {} has alignment larger than 1",
+                      adt.descr());
         }
     }
 }
@@ -1899,6 +1942,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     check_representable(tcx, sp, def_id);
+    check_transparent(tcx, sp, def_id);
 }
 
 fn report_unexpected_variant_res<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,