]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/mod.rs
Rollup merge of #61698 - davidtwco:ice-const-generic-length, r=varkor
[rust.git] / src / librustc_typeck / check / mod.rs
index 3e480b882d6452501b1156b373faaa8286359507..e35df6cd494a2fbfbb8a251d4d0c10b0eb0573e5 100644 (file)
 use rustc_target::spec::abi::Abi;
 use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{
-    self, AdtKind, CanonicalUserType, Ty, TyCtxt, GenericParamDefKind, Visibility,
+    self, AdtKind, CanonicalUserType, Ty, TyCtxt, Const, GenericParamDefKind, Visibility,
     ToPolyTraitRef, ToPredicate, RegionKind, UserType
 };
 use rustc::ty::adjustment::{
@@ -1309,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);
 }
 
@@ -1806,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));
@@ -1822,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());
         }
     }
 }
@@ -1898,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>,
@@ -1938,8 +1983,11 @@ fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
         })
     }
 
-    fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>)
-                -> Option<ty::Region<'tcx>> {
+    fn re_infer(
+        &self,
+        def: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> Option<ty::Region<'tcx>> {
         let v = match def {
             Some(def) => infer::EarlyBoundRegion(span, def.name),
             None => infer::MiscVariable(span)
@@ -1947,20 +1995,37 @@ fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>)
         Some(self.next_region_var(v))
     }
 
-    fn ty_infer(&self, span: Span) -> Ty<'tcx> {
-        self.next_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::TypeInference,
-            span,
-        })
+    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
+        if let Some(param) = param {
+            if let UnpackedKind::Type(ty) = self.var_for_def(span, param).unpack() {
+                return ty;
+            }
+            unreachable!()
+        } else {
+            self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::TypeInference,
+                span,
+            })
+        }
     }
 
-    fn ty_infer_for_def(&self,
-                        ty_param_def: &ty::GenericParamDef,
-                        span: Span) -> Ty<'tcx> {
-        if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() {
-            return ty;
+    fn ct_infer(
+        &self,
+        ty: Ty<'tcx>,
+        param: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> &'tcx Const<'tcx> {
+        if let Some(param) = param {
+            if let UnpackedKind::Const(ct) = self.var_for_def(span, param).unpack() {
+                return ct;
+            }
+            unreachable!()
+        } else {
+            self.next_const_var(ty, ConstVariableOrigin {
+                kind: ConstVariableOriginKind::ConstInference,
+                span,
+            })
         }
-        unreachable!()
     }
 
     fn projected_ty_from_poly_trait_ref(&self,
@@ -5429,10 +5494,10 @@ pub fn instantiate_value_path(&self,
                     if !infer_args_for_err.contains(&index) {
                         // Check whether the user has provided generic arguments.
                         if let Some(ref data) = segments[index].args {
-                            return (Some(data), segments[index].infer_types);
+                            return (Some(data), segments[index].infer_args);
                         }
                     }
-                    return (None, segments[index].infer_types);
+                    return (None, segments[index].infer_args);
                 }
 
                 (None, true)
@@ -5453,13 +5518,13 @@ pub fn instantiate_value_path(&self,
                 }
             },
             // Provide substitutions for parameters for which arguments are inferred.
-            |substs, param, infer_types| {
+            |substs, param, infer_args| {
                 match param.kind {
                     GenericParamDefKind::Lifetime => {
-                        self.re_infer(span, Some(param)).unwrap().into()
+                        self.re_infer(Some(param), span).unwrap().into()
                     }
                     GenericParamDefKind::Type { has_default, .. } => {
-                        if !infer_types && has_default {
+                        if !infer_args && has_default {
                             // If we have a default, then we it doesn't matter that we're not
                             // inferring the type arguments: we provide the default where any
                             // is missing.