Rollup merge of #103759 - cjgillot:adt-collect, r=davidtwco
Use `adt_def` during type collection. This removes a wrapper which is close to what `adt_def` does.
This commit is contained in:
commit
09f4f7c8f0
4 changed files with 113 additions and 164 deletions
|
@ -6,7 +6,7 @@ use super::*;
|
|||
use rustc_attr as attr;
|
||||
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{ItemKind, Node, PathSegment};
|
||||
|
@ -75,7 +75,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
check_simd(tcx, span, def_id);
|
||||
}
|
||||
|
||||
check_transparent(tcx, span, def);
|
||||
check_transparent(tcx, def);
|
||||
check_packed(tcx, span, def);
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
def.destructor(tcx); // force the destructor to be evaluated
|
||||
check_transparent(tcx, span, def);
|
||||
check_transparent(tcx, def);
|
||||
check_union_fields(tcx, span, def_id);
|
||||
check_packed(tcx, span, def);
|
||||
}
|
||||
|
@ -506,11 +506,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
|
|||
tcx.ensure().typeck(id.owner_id.def_id);
|
||||
}
|
||||
DefKind::Enum => {
|
||||
let item = tcx.hir().item(id);
|
||||
let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else {
|
||||
return;
|
||||
};
|
||||
check_enum(tcx, &enum_definition.variants, item.owner_id.def_id);
|
||||
check_enum(tcx, id.owner_id.def_id);
|
||||
}
|
||||
DefKind::Fn => {} // entirely within check_item_body
|
||||
DefKind::Impl => {
|
||||
|
@ -1026,7 +1022,7 @@ pub(super) fn check_packed_inner(
|
|||
None
|
||||
}
|
||||
|
||||
pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) {
|
||||
pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
|
||||
if !adt.repr().transparent() {
|
||||
return;
|
||||
}
|
||||
|
@ -1035,14 +1031,14 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
|
|||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::transparent_unions,
|
||||
sp,
|
||||
tcx.def_span(adt.did()),
|
||||
"transparent unions are unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
if adt.variants().len() != 1 {
|
||||
bad_variant_count(tcx, adt, sp, adt.did());
|
||||
bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
|
||||
if adt.variants().is_empty() {
|
||||
// Don't bother checking the fields. No variants (and thus no fields) exist.
|
||||
return;
|
||||
|
@ -1103,7 +1099,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
|
|||
.filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
|
||||
let non_zst_count = non_zst_fields.clone().count();
|
||||
if non_zst_count >= 2 {
|
||||
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
|
||||
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
|
||||
}
|
||||
let incompatible_zst_fields =
|
||||
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
|
||||
|
@ -1143,12 +1139,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
|
|||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) {
|
||||
fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let sp = tcx.def_span(def_id);
|
||||
def.destructor(tcx); // force the destructor to be evaluated
|
||||
|
||||
if vs.is_empty() {
|
||||
if def.variants().is_empty() {
|
||||
if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
|
@ -1156,7 +1151,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
|
|||
E0084,
|
||||
"unsupported representation for zero-variant enum"
|
||||
)
|
||||
.span_label(sp, "zero-variant enum")
|
||||
.span_label(tcx.def_span(def_id), "zero-variant enum")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
@ -1167,88 +1162,96 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
|
|||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::repr128,
|
||||
sp,
|
||||
tcx.def_span(def_id),
|
||||
"repr with 128-bit type is unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
for v in vs {
|
||||
if let Some(ref e) = v.disr_expr {
|
||||
tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
|
||||
for v in def.variants() {
|
||||
if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
|
||||
tcx.ensure().typeck(discr_def_id.expect_local());
|
||||
}
|
||||
}
|
||||
|
||||
if tcx.adt_def(def_id).repr().int.is_none() {
|
||||
let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
|
||||
if def.repr().int.is_none() {
|
||||
let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind, CtorKind::Const);
|
||||
let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
|
||||
|
||||
let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
|
||||
let has_non_units = vs.iter().any(|var| !is_unit(var));
|
||||
let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
|
||||
let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
|
||||
let has_non_units = def.variants().iter().any(|var| !is_unit(var));
|
||||
let disr_units = def.variants().iter().any(|var| is_unit(&var) && has_disr(&var));
|
||||
let disr_non_unit = def.variants().iter().any(|var| !is_unit(&var) && has_disr(&var));
|
||||
|
||||
if disr_non_unit || (disr_units && has_non_units) {
|
||||
let mut err =
|
||||
struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
tcx.def_span(def_id),
|
||||
E0732,
|
||||
"`#[repr(inttype)]` must be specified"
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
|
||||
|
||||
check_transparent(tcx, sp, def);
|
||||
detect_discriminant_duplicate(tcx, def);
|
||||
check_transparent(tcx, def);
|
||||
}
|
||||
|
||||
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
|
||||
fn detect_discriminant_duplicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
|
||||
vs: &'tcx [hir::Variant<'tcx>],
|
||||
self_span: Span,
|
||||
) {
|
||||
fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
|
||||
// Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
|
||||
// Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
|
||||
let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
|
||||
let var = &vs[idx]; // HIR for the duplicate discriminant
|
||||
let (span, display_discr) = match var.disr_expr {
|
||||
Some(ref expr) => {
|
||||
let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| {
|
||||
let var = adt.variant(idx); // HIR for the duplicate discriminant
|
||||
let (span, display_discr) = match var.discr {
|
||||
ty::VariantDiscr::Explicit(discr_def_id) => {
|
||||
// In the case the discriminant is both a duplicate and overflowed, let the user know
|
||||
if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
|
||||
if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local())
|
||||
&& let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
|
||||
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
|
||||
&& *lit_value != dis.val
|
||||
{
|
||||
(tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
|
||||
// Otherwise, format the value as-is
|
||||
(tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
|
||||
} else {
|
||||
(tcx.hir().span(expr.hir_id), format!("`{dis}`"))
|
||||
// Otherwise, format the value as-is
|
||||
(tcx.def_span(discr_def_id), format!("`{dis}`"))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// This should not happen.
|
||||
ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),
|
||||
ty::VariantDiscr::Relative(distance_to_explicit) => {
|
||||
// At this point we know this discriminant is a duplicate, and was not explicitly
|
||||
// assigned by the user. Here we iterate backwards to fetch the HIR for the last
|
||||
// explicitly assigned discriminant, and letting the user know that this was the
|
||||
// increment startpoint, and how many steps from there leading to the duplicate
|
||||
if let Some((n, hir::Variant { span, ident, .. })) =
|
||||
vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
|
||||
if let Some(explicit_idx) =
|
||||
idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)
|
||||
{
|
||||
let ve_ident = var.ident;
|
||||
let n = n + 1;
|
||||
let sp = if n > 1 { "variants" } else { "variant" };
|
||||
let explicit_variant = adt.variant(explicit_idx);
|
||||
let ve_ident = var.name;
|
||||
let ex_ident = explicit_variant.name;
|
||||
let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };
|
||||
|
||||
err.span_label(
|
||||
*span,
|
||||
format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
|
||||
tcx.def_span(explicit_variant.def_id),
|
||||
format!(
|
||||
"discriminant for `{ve_ident}` incremented from this startpoint \
|
||||
(`{ex_ident}` + {distance_to_explicit} {sp} later \
|
||||
=> `{ve_ident}` = {dis})"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
(vs[idx].span, format!("`{dis}`"))
|
||||
(tcx.def_span(var.def_id), format!("`{dis}`"))
|
||||
}
|
||||
};
|
||||
|
||||
err.span_label(span, format!("{display_discr} assigned here"));
|
||||
};
|
||||
|
||||
let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();
|
||||
|
||||
// Here we loop through the discriminants, comparing each discriminant to another.
|
||||
// When a duplicate is detected, we instantiate an error and point to both
|
||||
// initial and duplicate value. The duplicate discriminant is then discarded by swapping
|
||||
|
@ -1257,29 +1260,29 @@ fn detect_discriminant_duplicate<'tcx>(
|
|||
// style as we are mutating `discrs` on the fly).
|
||||
let mut i = 0;
|
||||
while i < discrs.len() {
|
||||
let hir_var_i_idx = discrs[i].0.index();
|
||||
let var_i_idx = discrs[i].0;
|
||||
let mut error: Option<DiagnosticBuilder<'_, _>> = None;
|
||||
|
||||
let mut o = i + 1;
|
||||
while o < discrs.len() {
|
||||
let hir_var_o_idx = discrs[o].0.index();
|
||||
let var_o_idx = discrs[o].0;
|
||||
|
||||
if discrs[i].1.val == discrs[o].1.val {
|
||||
let err = error.get_or_insert_with(|| {
|
||||
let mut ret = struct_span_err!(
|
||||
tcx.sess,
|
||||
self_span,
|
||||
tcx.def_span(adt.did()),
|
||||
E0081,
|
||||
"discriminant value `{}` assigned more than once",
|
||||
discrs[i].1,
|
||||
);
|
||||
|
||||
report(discrs[i].1, hir_var_i_idx, &mut ret);
|
||||
report(discrs[i].1, var_i_idx, &mut ret);
|
||||
|
||||
ret
|
||||
});
|
||||
|
||||
report(discrs[o].1, hir_var_o_idx, err);
|
||||
report(discrs[o].1, var_o_idx, err);
|
||||
|
||||
// Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
|
||||
discrs[o] = *discrs.last().unwrap();
|
||||
|
|
|
@ -218,19 +218,16 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
|||
hir::ItemKind::Const(ty, ..) => {
|
||||
check_item_type(tcx, def_id, ty.span, false);
|
||||
}
|
||||
hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
|
||||
check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
|
||||
|
||||
hir::ItemKind::Struct(_, ref ast_generics) => {
|
||||
check_type_defn(tcx, item, false);
|
||||
check_variances_for_type_defn(tcx, item, ast_generics);
|
||||
}
|
||||
hir::ItemKind::Union(ref struct_def, ref ast_generics) => {
|
||||
check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
|
||||
|
||||
hir::ItemKind::Union(_, ref ast_generics) => {
|
||||
check_type_defn(tcx, item, true);
|
||||
check_variances_for_type_defn(tcx, item, ast_generics);
|
||||
}
|
||||
hir::ItemKind::Enum(ref enum_def, ref ast_generics) => {
|
||||
check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def));
|
||||
|
||||
hir::ItemKind::Enum(_, ref ast_generics) => {
|
||||
check_type_defn(tcx, item, true);
|
||||
check_variances_for_type_defn(tcx, item, ast_generics);
|
||||
}
|
||||
hir::ItemKind::Trait(..) => {
|
||||
|
@ -1037,27 +1034,25 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> {
|
|||
}
|
||||
|
||||
/// In a type definition, we check that to ensure that the types of the fields are well-formed.
|
||||
fn check_type_defn<'tcx, F>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: &hir::Item<'tcx>,
|
||||
all_sized: bool,
|
||||
mut lookup_fields: F,
|
||||
) where
|
||||
F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
|
||||
{
|
||||
fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) {
|
||||
let _ = tcx.representability(item.owner_id.def_id);
|
||||
let adt_def = tcx.adt_def(item.owner_id);
|
||||
|
||||
enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
|
||||
let variants = lookup_fields(wfcx);
|
||||
let packed = tcx.adt_def(item.owner_id).repr().packed();
|
||||
let variants = adt_def.variants();
|
||||
let packed = adt_def.repr().packed();
|
||||
|
||||
for variant in &variants {
|
||||
for variant in variants.iter() {
|
||||
// All field types must be well-formed.
|
||||
for field in &variant.fields {
|
||||
let field_id = field.did.expect_local();
|
||||
let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
|
||||
else { bug!() };
|
||||
let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
|
||||
wfcx.register_wf_obligation(
|
||||
field.span,
|
||||
Some(WellFormedLoc::Ty(field.def_id)),
|
||||
field.ty.into(),
|
||||
hir_ty.span,
|
||||
Some(WellFormedLoc::Ty(field_id)),
|
||||
ty.into(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1065,7 +1060,7 @@ fn check_type_defn<'tcx, F>(
|
|||
// intermediate types must be sized.
|
||||
let needs_drop_copy = || {
|
||||
packed && {
|
||||
let ty = variant.fields.last().unwrap().ty;
|
||||
let ty = tcx.type_of(variant.fields.last().unwrap().did);
|
||||
let ty = tcx.erase_regions(ty);
|
||||
if ty.needs_infer() {
|
||||
tcx.sess
|
||||
|
@ -1084,27 +1079,31 @@ fn check_type_defn<'tcx, F>(
|
|||
variant.fields[..variant.fields.len() - unsized_len].iter().enumerate()
|
||||
{
|
||||
let last = idx == variant.fields.len() - 1;
|
||||
let field_id = field.did.expect_local();
|
||||
let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
|
||||
else { bug!() };
|
||||
let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
|
||||
wfcx.register_bound(
|
||||
traits::ObligationCause::new(
|
||||
field.span,
|
||||
hir_ty.span,
|
||||
wfcx.body_id,
|
||||
traits::FieldSized {
|
||||
adt_kind: match item_adt_kind(&item.kind) {
|
||||
Some(i) => i,
|
||||
None => bug!(),
|
||||
},
|
||||
span: field.span,
|
||||
span: hir_ty.span,
|
||||
last,
|
||||
},
|
||||
),
|
||||
wfcx.param_env,
|
||||
field.ty,
|
||||
ty,
|
||||
tcx.require_lang_item(LangItem::Sized, None),
|
||||
);
|
||||
}
|
||||
|
||||
// Explicit `enum` discriminant values must const-evaluate successfully.
|
||||
if let Some(discr_def_id) = variant.explicit_discr {
|
||||
if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr {
|
||||
let cause = traits::ObligationCause::new(
|
||||
tcx.def_span(discr_def_id),
|
||||
wfcx.body_id,
|
||||
|
@ -1114,7 +1113,7 @@ fn check_type_defn<'tcx, F>(
|
|||
cause,
|
||||
wfcx.param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
|
||||
ty::Const::from_anon_const(tcx, discr_def_id),
|
||||
ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
|
||||
))
|
||||
.to_predicate(tcx),
|
||||
));
|
||||
|
@ -1925,56 +1924,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
|
|||
items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ADT
|
||||
|
||||
// FIXME(eddyb) replace this with getting fields/discriminants through `ty::AdtDef`.
|
||||
struct AdtVariant<'tcx> {
|
||||
/// Types of fields in the variant, that must be well-formed.
|
||||
fields: Vec<AdtField<'tcx>>,
|
||||
|
||||
/// Explicit discriminant of this variant (e.g. `A = 123`),
|
||||
/// that must evaluate to a constant value.
|
||||
explicit_discr: Option<LocalDefId>,
|
||||
}
|
||||
|
||||
struct AdtField<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
|
||||
// FIXME(eddyb) replace this with getting fields through `ty::AdtDef`.
|
||||
fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> {
|
||||
let fields = struct_def
|
||||
.fields()
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let def_id = self.tcx().hir().local_def_id(field.hir_id);
|
||||
let field_ty = self.tcx().type_of(def_id);
|
||||
let field_ty = self.normalize(field.ty.span, None, field_ty);
|
||||
debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
|
||||
AdtField { ty: field_ty, span: field.ty.span, def_id }
|
||||
})
|
||||
.collect();
|
||||
AdtVariant { fields, explicit_discr: None }
|
||||
}
|
||||
|
||||
fn enum_variants(&self, enum_def: &hir::EnumDef<'_>) -> Vec<AdtVariant<'tcx>> {
|
||||
enum_def
|
||||
.variants
|
||||
.iter()
|
||||
.map(|variant| AdtVariant {
|
||||
fields: self.non_enum_variant(&variant.data).fields,
|
||||
explicit_discr: variant
|
||||
.disr_expr
|
||||
.map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn error_392(
|
||||
tcx: TyCtxt<'_>,
|
||||
span: Span,
|
||||
|
|
|
@ -604,11 +604,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Enum(ref enum_definition, _) => {
|
||||
hir::ItemKind::Enum(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants);
|
||||
convert_enum_variant_types(tcx, def_id.to_def_id());
|
||||
}
|
||||
hir::ItemKind::Impl { .. } => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
|
@ -640,7 +640,8 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
}
|
||||
|
||||
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
|
||||
convert_variant_ctor(tcx, ctor_hir_id);
|
||||
let ctor_def_id = tcx.hir().local_def_id(ctor_hir_id);
|
||||
convert_variant_ctor(tcx, ctor_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -750,37 +751,34 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) {
|
||||
let def_id = tcx.hir().local_def_id(ctor_id);
|
||||
fn convert_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
}
|
||||
|
||||
fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::Variant<'_>]) {
|
||||
fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let repr_type = def.repr().discr_type();
|
||||
let initial = repr_type.initial_discriminant(tcx);
|
||||
let mut prev_discr = None::<Discr<'_>>;
|
||||
|
||||
// fill the discriminant values and field types
|
||||
for variant in variants {
|
||||
for variant in def.variants() {
|
||||
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
|
||||
prev_discr = Some(
|
||||
if let Some(ref e) = variant.disr_expr {
|
||||
let expr_did = tcx.hir().local_def_id(e.hir_id);
|
||||
def.eval_explicit_discr(tcx, expr_did.to_def_id())
|
||||
if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr {
|
||||
def.eval_explicit_discr(tcx, const_def_id)
|
||||
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
|
||||
Some(discr)
|
||||
} else {
|
||||
struct_span_err!(tcx.sess, variant.span, E0370, "enum discriminant overflowed")
|
||||
.span_label(
|
||||
variant.span,
|
||||
format!("overflowed on value after {}", prev_discr.unwrap()),
|
||||
)
|
||||
let span = tcx.def_span(variant.def_id);
|
||||
struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed")
|
||||
.span_label(span, format!("overflowed on value after {}", prev_discr.unwrap()))
|
||||
.note(&format!(
|
||||
"explicitly set `{} = {}` if that is desired outcome",
|
||||
variant.ident, wrapped_discr
|
||||
tcx.item_name(variant.def_id),
|
||||
wrapped_discr
|
||||
))
|
||||
.emit();
|
||||
None
|
||||
|
@ -788,17 +786,16 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::V
|
|||
.unwrap_or(wrapped_discr),
|
||||
);
|
||||
|
||||
for f in variant.data.fields() {
|
||||
let def_id = tcx.hir().local_def_id(f.hir_id);
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
for f in &variant.fields {
|
||||
tcx.ensure().generics_of(f.did);
|
||||
tcx.ensure().type_of(f.did);
|
||||
tcx.ensure().predicates_of(f.did);
|
||||
}
|
||||
|
||||
// Convert the ctor, if any. This also registers the variant as
|
||||
// an item.
|
||||
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
|
||||
convert_variant_ctor(tcx, ctor_hir_id);
|
||||
if let Some(ctor_def_id) = variant.ctor_def_id {
|
||||
convert_variant_ctor(tcx, ctor_def_id.expect_local());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ LL | First = -1,
|
|||
| -- `-1` assigned here
|
||||
LL |
|
||||
LL | Second = -2,
|
||||
| ----------- discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
|
||||
| ------ discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
|
||||
LL |
|
||||
LL | Last,
|
||||
| ---- `-1` assigned here
|
||||
|
@ -53,7 +53,7 @@ LL | V4 = 0,
|
|||
| - `0` assigned here
|
||||
LL |
|
||||
LL | V5 = -2,
|
||||
| ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
|
||||
| -- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
|
||||
...
|
||||
LL | V7,
|
||||
| -- `0` assigned here
|
||||
|
@ -68,7 +68,7 @@ LL | V5 = -2,
|
|||
| -- `-2` assigned here
|
||||
...
|
||||
LL | V8 = -3,
|
||||
| ------- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
|
||||
| -- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
|
||||
LL |
|
||||
LL | V9,
|
||||
| -- `-2` assigned here
|
||||
|
|
Loading…
Add table
Reference in a new issue