Rewrite representability
This commit is contained in:
parent
e42c4d7218
commit
ff940db666
61 changed files with 537 additions and 744 deletions
|
@ -3552,7 +3552,6 @@ dependencies = [
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"rustc_target",
|
"rustc_target",
|
||||||
"rustc_trait_selection",
|
"rustc_trait_selection",
|
||||||
"rustc_ty_utils",
|
|
||||||
"rustc_type_ir",
|
"rustc_type_ir",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|
|
@ -26,7 +26,6 @@ rustc_span = { path = "../rustc_span" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
rustc_infer = { path = "../rustc_infer" }
|
rustc_infer = { path = "../rustc_infer" }
|
||||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||||
rustc_ty_utils = { path = "../rustc_ty_utils" }
|
|
||||||
rustc_lint = { path = "../rustc_lint" }
|
rustc_lint = { path = "../rustc_lint" }
|
||||||
rustc_serialize = { path = "../rustc_serialize" }
|
rustc_serialize = { path = "../rustc_serialize" }
|
||||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||||
|
|
|
@ -31,7 +31,6 @@ use rustc_span::{self, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||||
use rustc_ty_utils::representability::{self, Representability};
|
|
||||||
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
@ -381,7 +380,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
let def = tcx.adt_def(def_id);
|
let def = tcx.adt_def(def_id);
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
def.destructor(tcx); // force the destructor to be evaluated
|
def.destructor(tcx); // force the destructor to be evaluated
|
||||||
check_representable(tcx, span, def_id);
|
let _ = tcx.representability(def_id);
|
||||||
|
|
||||||
if def.repr().simd() {
|
if def.repr().simd() {
|
||||||
check_simd(tcx, span, def_id);
|
check_simd(tcx, span, def_id);
|
||||||
|
@ -395,7 +394,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
let def = tcx.adt_def(def_id);
|
let def = tcx.adt_def(def_id);
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
def.destructor(tcx); // force the destructor to be evaluated
|
def.destructor(tcx); // force the destructor to be evaluated
|
||||||
check_representable(tcx, span, def_id);
|
let _ = tcx.representability(def_id);
|
||||||
check_transparent(tcx, span, def);
|
check_transparent(tcx, span, def);
|
||||||
check_union_fields(tcx, span, def_id);
|
check_union_fields(tcx, span, def_id);
|
||||||
check_packed(tcx, span, def);
|
check_packed(tcx, span, def);
|
||||||
|
@ -1151,27 +1150,6 @@ fn check_impl_items_against_trait<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether a type can be represented in memory. In particular, it
|
|
||||||
/// identifies types that contain themselves without indirection through a
|
|
||||||
/// pointer, which would mean their size is unbounded.
|
|
||||||
pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
|
|
||||||
let rty = tcx.type_of(item_def_id);
|
|
||||||
|
|
||||||
// Check that it is possible to represent this type. This call identifies
|
|
||||||
// (1) types that contain themselves and (2) types that contain a different
|
|
||||||
// recursive type. It is only necessary to throw an error on those that
|
|
||||||
// contain themselves. For case 2, there must be an inner type that will be
|
|
||||||
// caught by case 1.
|
|
||||||
match representability::ty_is_representable(tcx, rty, sp, None) {
|
|
||||||
Representability::SelfRecursive(spans) => {
|
|
||||||
recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Representability::Representable | Representability::ContainsRecursive => (),
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
|
pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
|
||||||
let t = tcx.type_of(def_id);
|
let t = tcx.type_of(def_id);
|
||||||
if let ty::Adt(def, substs) = t.kind()
|
if let ty::Adt(def, substs) = t.kind()
|
||||||
|
@ -1509,7 +1487,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
|
||||||
|
|
||||||
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
|
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
|
||||||
|
|
||||||
check_representable(tcx, sp, def_id);
|
let _ = tcx.representability(def_id);
|
||||||
check_transparent(tcx, sp, def);
|
check_transparent(tcx, sp, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,6 @@ use rustc_span::{self, BytePos, Span, Symbol};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
|
|
||||||
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
|
|
@ -25,6 +25,9 @@ macro_rules! pluralize {
|
||||||
($x:expr) => {
|
($x:expr) => {
|
||||||
if $x != 1 { "s" } else { "" }
|
if $x != 1 { "s" } else { "" }
|
||||||
};
|
};
|
||||||
|
("has", $x:expr) => {
|
||||||
|
if $x == 1 { "has" } else { "have" }
|
||||||
|
};
|
||||||
("is", $x:expr) => {
|
("is", $x:expr) => {
|
||||||
if $x == 1 { "is" } else { "are" }
|
if $x == 1 { "is" } else { "are" }
|
||||||
};
|
};
|
||||||
|
|
|
@ -210,6 +210,7 @@ provide! { tcx, def_id, other, cdata,
|
||||||
lookup_const_stability => { table }
|
lookup_const_stability => { table }
|
||||||
lookup_default_body_stability => { table }
|
lookup_default_body_stability => { table }
|
||||||
lookup_deprecation_entry => { table }
|
lookup_deprecation_entry => { table }
|
||||||
|
params_in_repr => { table }
|
||||||
unused_generic_params => { table }
|
unused_generic_params => { table }
|
||||||
opt_def_kind => { table_direct }
|
opt_def_kind => { table_direct }
|
||||||
impl_parent => { table }
|
impl_parent => { table }
|
||||||
|
|
|
@ -1156,6 +1156,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
if let DefKind::Trait | DefKind::TraitAlias = def_kind {
|
if let DefKind::Trait | DefKind::TraitAlias = def_kind {
|
||||||
record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
|
record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
|
||||||
}
|
}
|
||||||
|
if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
|
||||||
|
let params_in_repr = self.tcx.params_in_repr(def_id);
|
||||||
|
record!(self.tables.params_in_repr[def_id] <- params_in_repr);
|
||||||
|
}
|
||||||
if should_encode_trait_impl_trait_tys(tcx, def_id)
|
if should_encode_trait_impl_trait_tys(tcx, def_id)
|
||||||
&& let Ok(table) = self.tcx.collect_trait_impl_trait_tys(def_id)
|
&& let Ok(table) = self.tcx.collect_trait_impl_trait_tys(def_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,8 @@ use rustc_hir::def::{CtorKind, DefKind};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
|
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
|
||||||
use rustc_hir::definitions::DefKey;
|
use rustc_hir::definitions::DefKey;
|
||||||
use rustc_hir::lang_items;
|
use rustc_hir::lang_items;
|
||||||
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
|
use rustc_index::bit_set::{BitSet, FiniteBitSet};
|
||||||
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_middle::metadata::ModChild;
|
use rustc_middle::metadata::ModChild;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||||
|
@ -383,6 +384,7 @@ define_tables! {
|
||||||
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
|
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
|
||||||
expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
|
expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
|
||||||
unused_generic_params: Table<DefIndex, LazyValue<FiniteBitSet<u32>>>,
|
unused_generic_params: Table<DefIndex, LazyValue<FiniteBitSet<u32>>>,
|
||||||
|
params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
|
||||||
repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
|
repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
|
||||||
// `def_keys` and `def_path_hashes` represent a lazy version of a
|
// `def_keys` and `def_path_hashes` represent a lazy version of a
|
||||||
// `DefPathTable`. This allows us to avoid deserializing an entire
|
// `DefPathTable`. This allows us to avoid deserializing an entire
|
||||||
|
|
|
@ -103,6 +103,7 @@ macro_rules! arena_types {
|
||||||
[] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
|
[] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
|
||||||
|
|
||||||
[decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>,
|
[decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>,
|
||||||
|
[] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
|
||||||
]);
|
]);
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,6 +301,32 @@ rustc_queries! {
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether a type is representable or infinitely sized
|
||||||
|
query representability(_: LocalDefId) -> rustc_middle::ty::Representability {
|
||||||
|
desc { "checking if {:?} is representable", tcx.def_path_str(key.to_def_id()) }
|
||||||
|
// infinitely sized types will cause a cycle
|
||||||
|
cycle_delay_bug
|
||||||
|
// we don't want recursive representability calls to be forced with
|
||||||
|
// incremental compilation because, if a cycle occurs, we need the
|
||||||
|
// entire cycle to be in memory for diagnostics
|
||||||
|
anon
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An implementation detail for the `representability` query
|
||||||
|
query representability_adt_ty(_: Ty<'tcx>) -> rustc_middle::ty::Representability {
|
||||||
|
desc { "checking if {:?} is representable", key }
|
||||||
|
cycle_delay_bug
|
||||||
|
anon
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set of param indexes for type params that are in the type's representation
|
||||||
|
query params_in_repr(key: DefId) -> rustc_index::bit_set::BitSet<u32> {
|
||||||
|
desc { "finding type parameters in the representation" }
|
||||||
|
arena_cache
|
||||||
|
no_hash
|
||||||
|
separate_provide_extern
|
||||||
|
}
|
||||||
|
|
||||||
/// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
|
/// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
|
||||||
query thir_body(key: ty::WithOptConstParam<LocalDefId>)
|
query thir_body(key: ty::WithOptConstParam<LocalDefId>)
|
||||||
-> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed>
|
-> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed>
|
||||||
|
|
|
@ -566,3 +566,10 @@ impl<'tcx> AdtDef<'tcx> {
|
||||||
ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
|
ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[derive(HashStable)]
|
||||||
|
pub enum Representability {
|
||||||
|
Representable,
|
||||||
|
Infinite,
|
||||||
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ trivially_parameterized_over_tcx! {
|
||||||
rustc_hir::def::DefKind,
|
rustc_hir::def::DefKind,
|
||||||
rustc_hir::def_id::DefIndex,
|
rustc_hir::def_id::DefIndex,
|
||||||
rustc_hir::definitions::DefKey,
|
rustc_hir::definitions::DefKey,
|
||||||
|
rustc_index::bit_set::BitSet<u32>,
|
||||||
rustc_index::bit_set::FiniteBitSet<u32>,
|
rustc_index::bit_set::FiniteBitSet<u32>,
|
||||||
rustc_session::cstore::ForeignModule,
|
rustc_session::cstore::ForeignModule,
|
||||||
rustc_session::cstore::LinkagePreference,
|
rustc_session::cstore::LinkagePreference,
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyCtxt};
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::DefKind;
|
||||||
|
use rustc_middle::ty::Representability;
|
||||||
|
use rustc_middle::ty::{self, AdtSizedConstraint, DefIdTree, Ty, TyCtxt};
|
||||||
|
use rustc_query_system::query::QueryInfo;
|
||||||
use rustc_query_system::Value;
|
use rustc_query_system::Value;
|
||||||
|
use rustc_span::def_id::LocalDefId;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
|
impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
|
||||||
fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
|
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
|
||||||
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
|
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
|
||||||
// FIXME: Represent the above fact in the trait system somehow.
|
// FIXME: Represent the above fact in the trait system somehow.
|
||||||
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
|
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
|
||||||
|
@ -10,7 +20,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
|
impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
|
||||||
fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
|
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
|
||||||
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
|
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
|
||||||
// FIXME: Represent the above fact in the trait system somehow.
|
// FIXME: Represent the above fact in the trait system somehow.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -22,7 +32,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
|
impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
|
||||||
fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
|
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
|
||||||
// SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
|
// SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
|
||||||
// FIXME: Represent the above fact in the trait system somehow.
|
// FIXME: Represent the above fact in the trait system somehow.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -34,7 +44,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
|
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
|
||||||
fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
|
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
|
||||||
let err = tcx.ty_error();
|
let err = tcx.ty_error();
|
||||||
// FIXME(compiler-errors): It would be nice if we could get the
|
// FIXME(compiler-errors): It would be nice if we could get the
|
||||||
// query key, so we could at least generate a fn signature that
|
// query key, so we could at least generate a fn signature that
|
||||||
|
@ -52,3 +62,153 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
|
||||||
unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
|
unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
|
||||||
|
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo]) -> Self {
|
||||||
|
let mut item_and_field_ids = Vec::new();
|
||||||
|
let mut representable_ids = FxHashSet::default();
|
||||||
|
for info in cycle {
|
||||||
|
if info.query.name == "representability"
|
||||||
|
&& let Some(field_id) = info.query.def_id
|
||||||
|
&& let Some(field_id) = field_id.as_local()
|
||||||
|
&& let Some(DefKind::Field) = info.query.def_kind
|
||||||
|
{
|
||||||
|
let parent_id = tcx.parent(field_id.to_def_id());
|
||||||
|
let item_id = match tcx.def_kind(parent_id) {
|
||||||
|
DefKind::Variant => tcx.parent(parent_id),
|
||||||
|
_ => parent_id,
|
||||||
|
};
|
||||||
|
item_and_field_ids.push((item_id.expect_local(), field_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for info in cycle {
|
||||||
|
if info.query.name == "representability_adt_ty"
|
||||||
|
&& let Some(def_id) = info.query.ty_adt_id
|
||||||
|
&& let Some(def_id) = def_id.as_local()
|
||||||
|
&& !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
|
||||||
|
{
|
||||||
|
representable_ids.insert(def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recursive_type_error(tcx, item_and_field_ids, &representable_ids);
|
||||||
|
Representability::Infinite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// item_and_field_ids should form a cycle where each field contains the
|
||||||
|
// type in the next element in the list
|
||||||
|
pub fn recursive_type_error(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>,
|
||||||
|
representable_ids: &FxHashSet<LocalDefId>,
|
||||||
|
) {
|
||||||
|
const ITEM_LIMIT: usize = 5;
|
||||||
|
|
||||||
|
// Rotate the cycle so that the item with the lowest span is first
|
||||||
|
let start_index = item_and_field_ids
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.min_by_key(|&(_, &(id, _))| tcx.def_span(id))
|
||||||
|
.unwrap()
|
||||||
|
.0;
|
||||||
|
item_and_field_ids.rotate_left(start_index);
|
||||||
|
|
||||||
|
let cycle_len = item_and_field_ids.len();
|
||||||
|
let show_cycle_len = cycle_len.min(ITEM_LIMIT);
|
||||||
|
|
||||||
|
let mut err_span = MultiSpan::from_spans(
|
||||||
|
item_and_field_ids[..show_cycle_len]
|
||||||
|
.iter()
|
||||||
|
.map(|(id, _)| tcx.def_span(id.to_def_id()))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
let mut suggestion = Vec::with_capacity(show_cycle_len * 2);
|
||||||
|
for i in 0..show_cycle_len {
|
||||||
|
let (_, field_id) = item_and_field_ids[i];
|
||||||
|
let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len];
|
||||||
|
// Find the span(s) that contain the next item in the cycle
|
||||||
|
let hir_id = tcx.hir().local_def_id_to_hir_id(field_id);
|
||||||
|
let hir::Node::Field(field) = tcx.hir().get(hir_id) else { bug!("expected field") };
|
||||||
|
let mut found = Vec::new();
|
||||||
|
find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids);
|
||||||
|
|
||||||
|
// Couldn't find the type. Maybe it's behind a type alias?
|
||||||
|
// In any case, we'll just suggest boxing the whole field.
|
||||||
|
if found.is_empty() {
|
||||||
|
found.push(field.ty.span);
|
||||||
|
}
|
||||||
|
|
||||||
|
for span in found {
|
||||||
|
err_span.push_span_label(span, "recursive without indirection");
|
||||||
|
// FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
|
||||||
|
suggestion.push((span.shrink_to_lo(), "Box<".to_string()));
|
||||||
|
suggestion.push((span.shrink_to_hi(), ">".to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let items_list = {
|
||||||
|
let mut s = String::new();
|
||||||
|
for (i, (item_id, _)) in item_and_field_ids.iter().enumerate() {
|
||||||
|
let path = tcx.def_path_str(item_id.to_def_id());
|
||||||
|
write!(&mut s, "`{path}`").unwrap();
|
||||||
|
if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT {
|
||||||
|
write!(&mut s, " and {} more", cycle_len - 5).unwrap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if cycle_len > 1 && i < cycle_len - 2 {
|
||||||
|
s.push_str(", ");
|
||||||
|
} else if cycle_len > 1 && i == cycle_len - 2 {
|
||||||
|
s.push_str(" and ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s
|
||||||
|
};
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
err_span,
|
||||||
|
E0072,
|
||||||
|
"recursive type{} {} {} infinite size",
|
||||||
|
pluralize!(cycle_len),
|
||||||
|
items_list,
|
||||||
|
pluralize!("has", cycle_len),
|
||||||
|
);
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle",
|
||||||
|
suggestion,
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_item_ty_spans(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
ty: &hir::Ty<'_>,
|
||||||
|
needle: LocalDefId,
|
||||||
|
spans: &mut Vec<Span>,
|
||||||
|
seen_representable: &FxHashSet<LocalDefId>,
|
||||||
|
) {
|
||||||
|
match ty.kind {
|
||||||
|
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
|
||||||
|
if let Some(def_id) = path.res.opt_def_id() {
|
||||||
|
let check_params = def_id.as_local().map_or(true, |def_id| {
|
||||||
|
if def_id == needle {
|
||||||
|
spans.push(ty.span);
|
||||||
|
}
|
||||||
|
seen_representable.contains(&def_id)
|
||||||
|
});
|
||||||
|
if check_params && let Some(args) = path.segments.last().unwrap().args {
|
||||||
|
let params_in_repr = tcx.params_in_repr(def_id);
|
||||||
|
for (i, arg) in args.args.iter().enumerate() {
|
||||||
|
if let hir::GenericArg::Type(ty) = arg && params_in_repr.contains(i as u32) {
|
||||||
|
find_item_ty_spans(tcx, ty, needle, spans, seen_representable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hir::TyKind::Array(ty, _) => find_item_ty_spans(tcx, ty, needle, spans, seen_representable),
|
||||||
|
hir::TyKind::Tup(tys) => {
|
||||||
|
tys.iter().for_each(|ty| find_item_ty_spans(tcx, ty, needle, spans, seen_representable))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,10 @@ pub trait Key {
|
||||||
fn key_as_def_id(&self) -> Option<DefId> {
|
fn key_as_def_id(&self) -> Option<DefId> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ty_adt_id(&self) -> Option<DefId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Key for () {
|
impl Key for () {
|
||||||
|
@ -407,6 +411,12 @@ impl<'tcx> Key for Ty<'tcx> {
|
||||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||||
DUMMY_SP
|
DUMMY_SP
|
||||||
}
|
}
|
||||||
|
fn ty_adt_id(&self) -> Option<DefId> {
|
||||||
|
match self.kind() {
|
||||||
|
ty::Adt(adt, _) => Some(adt.did()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Key for TyAndLayout<'tcx> {
|
impl<'tcx> Key for TyAndLayout<'tcx> {
|
||||||
|
|
|
@ -318,13 +318,12 @@ pub(crate) fn create_query_frame<
|
||||||
} else {
|
} else {
|
||||||
Some(key.default_span(*tcx))
|
Some(key.default_span(*tcx))
|
||||||
};
|
};
|
||||||
|
let def_id = key.key_as_def_id();
|
||||||
let def_kind = if kind == dep_graph::DepKind::opt_def_kind {
|
let def_kind = if kind == dep_graph::DepKind::opt_def_kind {
|
||||||
// Try to avoid infinite recursion.
|
// Try to avoid infinite recursion.
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
key.key_as_def_id()
|
def_id.and_then(|def_id| def_id.as_local()).and_then(|def_id| tcx.opt_def_kind(def_id))
|
||||||
.and_then(|def_id| def_id.as_local())
|
|
||||||
.and_then(|def_id| tcx.opt_def_kind(def_id))
|
|
||||||
};
|
};
|
||||||
let hash = || {
|
let hash = || {
|
||||||
tcx.with_stable_hashing_context(|mut hcx| {
|
tcx.with_stable_hashing_context(|mut hcx| {
|
||||||
|
@ -334,8 +333,9 @@ pub(crate) fn create_query_frame<
|
||||||
hasher.finish::<u64>()
|
hasher.finish::<u64>()
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
let ty_adt_id = key.ty_adt_id();
|
||||||
|
|
||||||
QueryStackFrame::new(name, description, span, def_kind, hash)
|
QueryStackFrame::new(name, description, span, def_id, def_kind, ty_adt_id, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode)
|
fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode)
|
||||||
|
|
|
@ -551,7 +551,7 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
|
||||||
#[cold]
|
#[cold]
|
||||||
pub(crate) fn report_cycle<'a>(
|
pub(crate) fn report_cycle<'a>(
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
CycleError { usage, cycle: stack }: CycleError,
|
CycleError { usage, cycle: stack }: &CycleError,
|
||||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||||
assert!(!stack.is_empty());
|
assert!(!stack.is_empty());
|
||||||
|
|
||||||
|
@ -569,10 +569,10 @@ pub(crate) fn report_cycle<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cycle_usage = None;
|
let mut cycle_usage = None;
|
||||||
if let Some((span, query)) = usage {
|
if let Some((span, ref query)) = *usage {
|
||||||
cycle_usage = Some(crate::error::CycleUsage {
|
cycle_usage = Some(crate::error::CycleUsage {
|
||||||
span: query.default_span(span),
|
span: query.default_span(span),
|
||||||
usage: query.description,
|
usage: query.description.to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
|
||||||
use rustc_data_structures::sync::Lock;
|
use rustc_data_structures::sync::Lock;
|
||||||
use rustc_errors::Diagnostic;
|
use rustc_errors::Diagnostic;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use thin_vec::ThinVec;
|
use thin_vec::ThinVec;
|
||||||
|
|
||||||
|
@ -29,7 +30,9 @@ pub struct QueryStackFrame {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
def_kind: Option<DefKind>,
|
pub def_id: Option<DefId>,
|
||||||
|
pub def_kind: Option<DefKind>,
|
||||||
|
pub ty_adt_id: Option<DefId>,
|
||||||
/// This hash is used to deterministically pick
|
/// This hash is used to deterministically pick
|
||||||
/// a query to remove cycles in the parallel compiler.
|
/// a query to remove cycles in the parallel compiler.
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
|
@ -42,14 +45,18 @@ impl QueryStackFrame {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
description: String,
|
description: String,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
|
def_id: Option<DefId>,
|
||||||
def_kind: Option<DefKind>,
|
def_kind: Option<DefKind>,
|
||||||
|
ty_adt_id: Option<DefId>,
|
||||||
_hash: impl FnOnce() -> u64,
|
_hash: impl FnOnce() -> u64,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
span,
|
span,
|
||||||
|
def_id,
|
||||||
def_kind,
|
def_kind,
|
||||||
|
ty_adt_id,
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
hash: _hash(),
|
hash: _hash(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ where
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn mk_cycle<CTX, V, R>(
|
fn mk_cycle<CTX, V, R>(
|
||||||
tcx: CTX,
|
tcx: CTX,
|
||||||
error: CycleError,
|
cycle_error: CycleError,
|
||||||
handler: HandleCycleError,
|
handler: HandleCycleError,
|
||||||
cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
|
cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
|
||||||
) -> R
|
) -> R
|
||||||
|
@ -128,13 +128,14 @@ where
|
||||||
V: std::fmt::Debug + Value<CTX::DepContext>,
|
V: std::fmt::Debug + Value<CTX::DepContext>,
|
||||||
R: Clone,
|
R: Clone,
|
||||||
{
|
{
|
||||||
let error = report_cycle(tcx.dep_context().sess(), error);
|
let error = report_cycle(tcx.dep_context().sess(), &cycle_error);
|
||||||
let value = handle_cycle_error(*tcx.dep_context(), error, handler);
|
let value = handle_cycle_error(*tcx.dep_context(), &cycle_error, error, handler);
|
||||||
cache.store_nocache(value)
|
cache.store_nocache(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_cycle_error<CTX, V>(
|
fn handle_cycle_error<CTX, V>(
|
||||||
tcx: CTX,
|
tcx: CTX,
|
||||||
|
cycle_error: &CycleError,
|
||||||
mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
|
mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||||
handler: HandleCycleError,
|
handler: HandleCycleError,
|
||||||
) -> V
|
) -> V
|
||||||
|
@ -146,7 +147,7 @@ where
|
||||||
match handler {
|
match handler {
|
||||||
Error => {
|
Error => {
|
||||||
error.emit();
|
error.emit();
|
||||||
Value::from_cycle_error(tcx)
|
Value::from_cycle_error(tcx, &cycle_error.cycle)
|
||||||
}
|
}
|
||||||
Fatal => {
|
Fatal => {
|
||||||
error.emit();
|
error.emit();
|
||||||
|
@ -155,7 +156,7 @@ where
|
||||||
}
|
}
|
||||||
DelayBug => {
|
DelayBug => {
|
||||||
error.delay_as_bug();
|
error.delay_as_bug();
|
||||||
Value::from_cycle_error(tcx)
|
Value::from_cycle_error(tcx, &cycle_error.cycle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::dep_graph::DepContext;
|
use crate::dep_graph::DepContext;
|
||||||
|
use crate::query::QueryInfo;
|
||||||
|
|
||||||
pub trait Value<CTX: DepContext>: Sized {
|
pub trait Value<CTX: DepContext>: Sized {
|
||||||
fn from_cycle_error(tcx: CTX) -> Self;
|
fn from_cycle_error(tcx: CTX, cycle: &[QueryInfo]) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CTX: DepContext, T> Value<CTX> for T {
|
impl<CTX: DepContext, T> Value<CTX> for T {
|
||||||
default fn from_cycle_error(tcx: CTX) -> T {
|
default fn from_cycle_error(tcx: CTX, _: &[QueryInfo]) -> T {
|
||||||
tcx.sess().abort_if_errors();
|
tcx.sess().abort_if_errors();
|
||||||
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
|
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
|
||||||
// non-trivial to define it earlier.
|
// non-trivial to define it earlier.
|
||||||
|
|
|
@ -2741,82 +2741,6 @@ impl<'v> Visitor<'v> for FindTypeParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recursive_type_with_infinite_size_error<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
type_def_id: DefId,
|
|
||||||
spans: Vec<(Span, Option<hir::HirId>)>,
|
|
||||||
) {
|
|
||||||
assert!(type_def_id.is_local());
|
|
||||||
let span = tcx.def_span(type_def_id);
|
|
||||||
let path = tcx.def_path_str(type_def_id);
|
|
||||||
let mut err =
|
|
||||||
struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
|
|
||||||
err.span_label(span, "recursive type has infinite size");
|
|
||||||
for &(span, _) in &spans {
|
|
||||||
err.span_label(span, "recursive without indirection");
|
|
||||||
}
|
|
||||||
let msg = format!(
|
|
||||||
"insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable",
|
|
||||||
path,
|
|
||||||
);
|
|
||||||
if spans.len() <= 4 {
|
|
||||||
// FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
|
|
||||||
err.multipart_suggestion(
|
|
||||||
&msg,
|
|
||||||
spans
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|(span, field_id)| {
|
|
||||||
if let Some(generic_span) = get_option_generic_from_field_id(tcx, field_id) {
|
|
||||||
// If we match an `Option` and can grab the span of the Option's generic, then
|
|
||||||
// suggest boxing the generic arg for a non-null niche optimization.
|
|
||||||
vec![
|
|
||||||
(generic_span.shrink_to_lo(), "Box<".to_string()),
|
|
||||||
(generic_span.shrink_to_hi(), ">".to_string()),
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
vec![
|
|
||||||
(span.shrink_to_lo(), "Box<".to_string()),
|
|
||||||
(span.shrink_to_hi(), ">".to_string()),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
err.help(&msg);
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract the span for the generic type `T` of `Option<T>` in a field definition
|
|
||||||
fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option<hir::HirId>) -> Option<Span> {
|
|
||||||
let node = tcx.hir().find(field_id?);
|
|
||||||
|
|
||||||
// Expect a field from our field_id
|
|
||||||
let Some(hir::Node::Field(field_def)) = node
|
|
||||||
else { bug!("Expected HirId corresponding to FieldDef, found: {:?}", node) };
|
|
||||||
|
|
||||||
// Match a type that is a simple QPath with no Self
|
|
||||||
let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = &field_def.ty.kind
|
|
||||||
else { return None };
|
|
||||||
|
|
||||||
// Check if the path we're checking resolves to Option
|
|
||||||
let hir::def::Res::Def(_, did) = path.res
|
|
||||||
else { return None };
|
|
||||||
|
|
||||||
// Bail if this path doesn't describe `::core::option::Option`
|
|
||||||
if !tcx.is_diagnostic_item(sym::Option, did) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match a single generic arg in the 0th path segment
|
|
||||||
let generic_arg = path.segments.last()?.args?.args.get(0)?;
|
|
||||||
|
|
||||||
// Take the span out of the type, if it's a type
|
|
||||||
if let hir::GenericArg::Type(generic_ty) = generic_arg { Some(generic_ty.span) } else { None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Summarizes information
|
/// Summarizes information
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ArgKind {
|
pub enum ArgKind {
|
||||||
|
|
|
@ -39,6 +39,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
implied_bounds::provide(providers);
|
implied_bounds::provide(providers);
|
||||||
layout::provide(providers);
|
layout::provide(providers);
|
||||||
needs_drop::provide(providers);
|
needs_drop::provide(providers);
|
||||||
|
representability::provide(providers);
|
||||||
ty::provide(providers);
|
ty::provide(providers);
|
||||||
instance::provide(providers);
|
instance::provide(providers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,386 +1,119 @@
|
||||||
//! Check whether a type is representable.
|
#![allow(rustc::untranslatable_diagnostic, rustc::diagnostic_outside_of_impl)]
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
|
||||||
use rustc_span::Span;
|
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
/// Describes whether a type is representable. For types that are not
|
use rustc_hir::def::DefKind;
|
||||||
/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
|
use rustc_index::bit_set::BitSet;
|
||||||
/// distinguish between types that are recursive with themselves and types that
|
use rustc_middle::ty::query::Providers;
|
||||||
/// contain a different recursive type. These cases can therefore be treated
|
use rustc_middle::ty::{self, Representability, Ty, TyCtxt};
|
||||||
/// differently when reporting errors.
|
use rustc_span::def_id::{DefId, LocalDefId};
|
||||||
///
|
|
||||||
/// The ordering of the cases is significant. They are sorted so that cmp::max
|
pub fn provide(providers: &mut Providers) {
|
||||||
/// will keep the "more erroneous" of two values.
|
*providers =
|
||||||
#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
|
Providers { representability, representability_adt_ty, params_in_repr, ..*providers };
|
||||||
pub enum Representability {
|
|
||||||
Representable,
|
|
||||||
ContainsRecursive,
|
|
||||||
/// Return a list of types that are included in themselves:
|
|
||||||
/// the spans where they are self-included, and (if found)
|
|
||||||
/// the HirId of the FieldDef that defines the self-inclusion.
|
|
||||||
SelfRecursive(Vec<(Span, Option<hir::HirId>)>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether a type is representable. This means it cannot contain unboxed
|
macro_rules! rtry {
|
||||||
/// structural recursion. This check is needed for structs and enums.
|
($e:expr) => {
|
||||||
pub fn ty_is_representable<'tcx>(
|
match $e {
|
||||||
tcx: TyCtxt<'tcx>,
|
e @ Representability::Infinite => return e,
|
||||||
ty: Ty<'tcx>,
|
Representability::Representable => {}
|
||||||
sp: Span,
|
|
||||||
field_id: Option<hir::HirId>,
|
|
||||||
) -> Representability {
|
|
||||||
debug!("is_type_representable: {:?}", ty);
|
|
||||||
// To avoid a stack overflow when checking an enum variant or struct that
|
|
||||||
// contains a different, structurally recursive type, maintain a stack of
|
|
||||||
// seen types and check recursion for each of them (issues #3008, #3779,
|
|
||||||
// #74224, #84611). `shadow_seen` contains the full stack and `seen` only
|
|
||||||
// the one for the current type (e.g. if we have structs A and B, B contains
|
|
||||||
// a field of type A, and we're currently looking at B, then `seen` will be
|
|
||||||
// cleared when recursing to check A, but `shadow_seen` won't, so that we
|
|
||||||
// can catch cases of mutual recursion where A also contains B).
|
|
||||||
let mut seen: Vec<Ty<'_>> = Vec::new();
|
|
||||||
let mut shadow_seen: Vec<ty::AdtDef<'tcx>> = Vec::new();
|
|
||||||
let mut representable_cache = FxHashMap::default();
|
|
||||||
let mut force_result = false;
|
|
||||||
let r = is_type_structurally_recursive(
|
|
||||||
tcx,
|
|
||||||
&mut seen,
|
|
||||||
&mut shadow_seen,
|
|
||||||
&mut representable_cache,
|
|
||||||
ty,
|
|
||||||
sp,
|
|
||||||
field_id,
|
|
||||||
&mut force_result,
|
|
||||||
);
|
|
||||||
debug!("is_type_representable: {:?} is {:?}", ty, r);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate until something non-representable is found
|
|
||||||
fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representability {
|
|
||||||
iter.fold(Representability::Representable, |r1, r2| match (r1, r2) {
|
|
||||||
(Representability::SelfRecursive(v1), Representability::SelfRecursive(v2)) => {
|
|
||||||
Representability::SelfRecursive(v1.into_iter().chain(v2).collect())
|
|
||||||
}
|
}
|
||||||
(r1, r2) => cmp::max(r1, r2),
|
};
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn are_inner_types_recursive<'tcx>(
|
fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability {
|
||||||
tcx: TyCtxt<'tcx>,
|
match tcx.def_kind(def_id) {
|
||||||
seen: &mut Vec<Ty<'tcx>>,
|
DefKind::Struct | DefKind::Union | DefKind::Enum => {
|
||||||
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
let adt_def = tcx.adt_def(def_id);
|
||||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
for variant in adt_def.variants() {
|
||||||
ty: Ty<'tcx>,
|
for field in variant.fields.iter() {
|
||||||
sp: Span,
|
rtry!(tcx.representability(field.did.expect_local()));
|
||||||
field_id: Option<hir::HirId>,
|
|
||||||
force_result: &mut bool,
|
|
||||||
) -> Representability {
|
|
||||||
debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
|
|
||||||
match ty.kind() {
|
|
||||||
ty::Tuple(fields) => {
|
|
||||||
// Find non representable
|
|
||||||
fold_repr(fields.iter().map(|ty| {
|
|
||||||
is_type_structurally_recursive(
|
|
||||||
tcx,
|
|
||||||
seen,
|
|
||||||
shadow_seen,
|
|
||||||
representable_cache,
|
|
||||||
ty,
|
|
||||||
sp,
|
|
||||||
field_id,
|
|
||||||
force_result,
|
|
||||||
)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
// Fixed-length vectors.
|
|
||||||
// FIXME(#11924) Behavior undecided for zero-length vectors.
|
|
||||||
ty::Array(ty, _) => is_type_structurally_recursive(
|
|
||||||
tcx,
|
|
||||||
seen,
|
|
||||||
shadow_seen,
|
|
||||||
representable_cache,
|
|
||||||
*ty,
|
|
||||||
sp,
|
|
||||||
field_id,
|
|
||||||
force_result,
|
|
||||||
),
|
|
||||||
ty::Adt(def, substs) => {
|
|
||||||
// Find non representable fields with their spans
|
|
||||||
fold_repr(def.all_fields().map(|field| {
|
|
||||||
let ty = field.ty(tcx, substs);
|
|
||||||
let (sp, field_id) = match field
|
|
||||||
.did
|
|
||||||
.as_local()
|
|
||||||
.map(|id| tcx.hir().local_def_id_to_hir_id(id))
|
|
||||||
.and_then(|id| tcx.hir().find(id))
|
|
||||||
{
|
|
||||||
Some(hir::Node::Field(field)) => (field.ty.span, Some(field.hir_id)),
|
|
||||||
_ => (sp, field_id),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut result = None;
|
|
||||||
|
|
||||||
// First, we check whether the field type per se is representable.
|
|
||||||
// This catches cases as in #74224 and #84611. There is a special
|
|
||||||
// case related to mutual recursion, though; consider this example:
|
|
||||||
//
|
|
||||||
// struct A<T> {
|
|
||||||
// z: T,
|
|
||||||
// x: B<T>,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// struct B<T> {
|
|
||||||
// y: A<T>
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Here, without the following special case, both A and B are
|
|
||||||
// ContainsRecursive, which is a problem because we only report
|
|
||||||
// errors for SelfRecursive. We fix this by detecting this special
|
|
||||||
// case (shadow_seen.first() is the type we are originally
|
|
||||||
// interested in, and if we ever encounter the same AdtDef again,
|
|
||||||
// we know that it must be SelfRecursive) and "forcibly" returning
|
|
||||||
// SelfRecursive (by setting force_result, which tells the calling
|
|
||||||
// invocations of are_inner_types_representable to forward the
|
|
||||||
// result without adjusting).
|
|
||||||
if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
|
|
||||||
*force_result = true;
|
|
||||||
result = Some(Representability::SelfRecursive(vec![(sp, field_id)]));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if result == None {
|
Representability::Representable
|
||||||
result = Some(Representability::Representable);
|
|
||||||
|
|
||||||
// Now, we check whether the field types per se are representable, e.g.
|
|
||||||
// for struct Foo { x: Option<Foo> }, we first check whether Option<_>
|
|
||||||
// by itself is representable (which it is), and the nesting of Foo
|
|
||||||
// will be detected later. This is necessary for #74224 and #84611.
|
|
||||||
|
|
||||||
// If we have encountered an ADT definition that we have not seen
|
|
||||||
// before (no need to check them twice), recurse to see whether that
|
|
||||||
// definition is SelfRecursive. If so, we must be ContainsRecursive.
|
|
||||||
if shadow_seen.len() > 1
|
|
||||||
&& !shadow_seen
|
|
||||||
.iter()
|
|
||||||
.take(shadow_seen.len() - 1)
|
|
||||||
.any(|seen_def| seen_def == def)
|
|
||||||
{
|
|
||||||
let adt_def_id = def.did();
|
|
||||||
let raw_adt_ty = tcx.type_of(adt_def_id);
|
|
||||||
debug!("are_inner_types_recursive: checking nested type: {:?}", raw_adt_ty);
|
|
||||||
|
|
||||||
// Check independently whether the ADT is SelfRecursive. If so,
|
|
||||||
// we must be ContainsRecursive (except for the special case
|
|
||||||
// mentioned above).
|
|
||||||
let mut nested_seen: Vec<Ty<'_>> = vec![];
|
|
||||||
result = Some(
|
|
||||||
match is_type_structurally_recursive(
|
|
||||||
tcx,
|
|
||||||
&mut nested_seen,
|
|
||||||
shadow_seen,
|
|
||||||
representable_cache,
|
|
||||||
raw_adt_ty,
|
|
||||||
sp,
|
|
||||||
field_id,
|
|
||||||
force_result,
|
|
||||||
) {
|
|
||||||
Representability::SelfRecursive(_) => {
|
|
||||||
if *force_result {
|
|
||||||
Representability::SelfRecursive(vec![(sp, field_id)])
|
|
||||||
} else {
|
|
||||||
Representability::ContainsRecursive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x => x,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only enter the following block if the type looks representable
|
|
||||||
// so far. This is necessary for cases such as this one (#74224):
|
|
||||||
//
|
|
||||||
// struct A<T> {
|
|
||||||
// x: T,
|
|
||||||
// y: A<A<T>>,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// struct B {
|
|
||||||
// z: A<usize>
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// When checking B, we recurse into A and check field y of type
|
|
||||||
// A<A<usize>>. We haven't seen this exact type before, so we recurse
|
|
||||||
// into A<A<usize>>, which contains, A<A<A<usize>>>, and so forth,
|
|
||||||
// ad infinitum. We can prevent this from happening by first checking
|
|
||||||
// A separately (the code above) and only checking for nested Bs if
|
|
||||||
// A actually looks representable (which it wouldn't in this example).
|
|
||||||
if result == Some(Representability::Representable) {
|
|
||||||
// Now, even if the type is representable (e.g. Option<_>),
|
|
||||||
// it might still contribute to a recursive type, e.g.:
|
|
||||||
// struct Foo { x: Option<Option<Foo>> }
|
|
||||||
// These cases are handled by passing the full `seen`
|
|
||||||
// stack to is_type_structurally_recursive (instead of the
|
|
||||||
// empty `nested_seen` above):
|
|
||||||
result = Some(
|
|
||||||
match is_type_structurally_recursive(
|
|
||||||
tcx,
|
|
||||||
seen,
|
|
||||||
shadow_seen,
|
|
||||||
representable_cache,
|
|
||||||
ty,
|
|
||||||
sp,
|
|
||||||
field_id,
|
|
||||||
force_result,
|
|
||||||
) {
|
|
||||||
Representability::SelfRecursive(_) => {
|
|
||||||
Representability::SelfRecursive(vec![(sp, field_id)])
|
|
||||||
}
|
|
||||||
x => x,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.unwrap()
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
ty::Closure(..) => {
|
DefKind::Field => representability_ty(tcx, tcx.type_of(def_id)),
|
||||||
// this check is run on type definitions, so we don't expect
|
def_kind => bug!("unexpected {def_kind:?}"),
|
||||||
// to see closure types
|
}
|
||||||
bug!("requires check invoked on inapplicable type: {:?}", ty)
|
}
|
||||||
|
|
||||||
|
fn representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability {
|
||||||
|
match *ty.kind() {
|
||||||
|
ty::Adt(..) => tcx.representability_adt_ty(ty),
|
||||||
|
// FIXME(#11924) allow zero-length arrays?
|
||||||
|
ty::Array(ty, _) => representability_ty(tcx, ty),
|
||||||
|
ty::Tuple(tys) => {
|
||||||
|
for ty in tys {
|
||||||
|
rtry!(representability_ty(tcx, ty));
|
||||||
|
}
|
||||||
|
Representability::Representable
|
||||||
}
|
}
|
||||||
_ => Representability::Representable,
|
_ => Representability::Representable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn same_adt<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
|
/*
|
||||||
|
The reason for this being a separate query is very subtle:
|
||||||
|
Consider this infinitely sized struct: `struct Foo(Box<Foo>, Bar<Foo>)`:
|
||||||
|
When calling representability(Foo), a query cycle will occur:
|
||||||
|
representability(Foo)
|
||||||
|
-> representability_adt_ty(Bar<Foo>)
|
||||||
|
-> representability(Foo)
|
||||||
|
For the diagnostic output (in `Value::from_cycle_error`), we want to detect that
|
||||||
|
the `Foo` in the *second* field of the struct is culpable. This requires
|
||||||
|
traversing the HIR of the struct and calling `params_in_repr(Bar)`. But we can't
|
||||||
|
call params_in_repr for a given type unless it is known to be representable.
|
||||||
|
params_in_repr will cycle/panic on infinitely sized types. Looking at the query
|
||||||
|
cycle above, we know that `Bar` is representable because
|
||||||
|
representability_adt_ty(Bar<..>) is in the cycle and representability(Bar) is
|
||||||
|
*not* in the cycle.
|
||||||
|
*/
|
||||||
|
fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability {
|
||||||
|
let ty::Adt(adt, substs) = ty.kind() else { bug!("expected adt") };
|
||||||
|
if let Some(def_id) = adt.did().as_local() {
|
||||||
|
rtry!(tcx.representability(def_id));
|
||||||
|
}
|
||||||
|
// At this point, we know that the item of the ADT type is representable;
|
||||||
|
// but the type parameters may cause a cycle with an upstream type
|
||||||
|
let params_in_repr = tcx.params_in_repr(adt.did());
|
||||||
|
for (i, subst) in substs.iter().enumerate() {
|
||||||
|
if let ty::GenericArgKind::Type(ty) = subst.unpack() {
|
||||||
|
if params_in_repr.contains(i as u32) {
|
||||||
|
rtry!(representability_ty(tcx, ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Representability::Representable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn params_in_repr(tcx: TyCtxt<'_>, def_id: DefId) -> BitSet<u32> {
|
||||||
|
let adt_def = tcx.adt_def(def_id);
|
||||||
|
let generics = tcx.generics_of(def_id);
|
||||||
|
let mut params_in_repr = BitSet::new_empty(generics.params.len());
|
||||||
|
for variant in adt_def.variants() {
|
||||||
|
for field in variant.fields.iter() {
|
||||||
|
params_in_repr_ty(tcx, tcx.type_of(field.did), &mut params_in_repr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params_in_repr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn params_in_repr_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, params_in_repr: &mut BitSet<u32>) {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Adt(ty_def, _) => ty_def == def,
|
ty::Adt(adt, substs) => {
|
||||||
_ => false,
|
let inner_params_in_repr = tcx.params_in_repr(adt.did());
|
||||||
}
|
for (i, subst) in substs.iter().enumerate() {
|
||||||
}
|
if let ty::GenericArgKind::Type(ty) = subst.unpack() {
|
||||||
|
if inner_params_in_repr.contains(i as u32) {
|
||||||
// Does the type `ty` directly (without indirection through a pointer)
|
params_in_repr_ty(tcx, ty, params_in_repr);
|
||||||
// contain any types on stack `seen`?
|
|
||||||
fn is_type_structurally_recursive<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
seen: &mut Vec<Ty<'tcx>>,
|
|
||||||
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
|
||||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
sp: Span,
|
|
||||||
field_id: Option<hir::HirId>,
|
|
||||||
force_result: &mut bool,
|
|
||||||
) -> Representability {
|
|
||||||
debug!("is_type_structurally_recursive: {:?} {:?} {:?}", ty, sp, field_id);
|
|
||||||
if let Some(representability) = representable_cache.get(&ty) {
|
|
||||||
debug!(
|
|
||||||
"is_type_structurally_recursive: {:?} {:?} {:?} - (cached) {:?}",
|
|
||||||
ty, sp, field_id, representability
|
|
||||||
);
|
|
||||||
return representability.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
let representability = is_type_structurally_recursive_inner(
|
|
||||||
tcx,
|
|
||||||
seen,
|
|
||||||
shadow_seen,
|
|
||||||
representable_cache,
|
|
||||||
ty,
|
|
||||||
sp,
|
|
||||||
field_id,
|
|
||||||
force_result,
|
|
||||||
);
|
|
||||||
|
|
||||||
representable_cache.insert(ty, representability.clone());
|
|
||||||
representability
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_type_structurally_recursive_inner<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
seen: &mut Vec<Ty<'tcx>>,
|
|
||||||
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
|
||||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
sp: Span,
|
|
||||||
field_id: Option<hir::HirId>,
|
|
||||||
force_result: &mut bool,
|
|
||||||
) -> Representability {
|
|
||||||
match ty.kind() {
|
|
||||||
ty::Adt(def, _) => {
|
|
||||||
{
|
|
||||||
debug!("is_type_structurally_recursive_inner: adt: {:?}, seen: {:?}", ty, seen);
|
|
||||||
|
|
||||||
// Iterate through stack of previously seen types.
|
|
||||||
let mut iter = seen.iter();
|
|
||||||
|
|
||||||
// The first item in `seen` is the type we are actually curious about.
|
|
||||||
// We want to return SelfRecursive if this type contains itself.
|
|
||||||
// It is important that we DON'T take generic parameters into account
|
|
||||||
// for this check, so that Bar<T> in this example counts as SelfRecursive:
|
|
||||||
//
|
|
||||||
// struct Foo;
|
|
||||||
// struct Bar<T> { x: Bar<Foo> }
|
|
||||||
|
|
||||||
if let Some(&seen_adt) = iter.next() {
|
|
||||||
if same_adt(seen_adt, *def) {
|
|
||||||
debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
|
|
||||||
return Representability::SelfRecursive(vec![(sp, field_id)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We also need to know whether the first item contains other types
|
|
||||||
// that are structurally recursive. If we don't catch this case, we
|
|
||||||
// will recurse infinitely for some inputs.
|
|
||||||
//
|
|
||||||
// It is important that we DO take generic parameters into account
|
|
||||||
// here, because nesting e.g. Options is allowed (as long as the
|
|
||||||
// definition of Option doesn't itself include an Option field, which
|
|
||||||
// would be a case of SelfRecursive above). The following, too, counts
|
|
||||||
// as SelfRecursive:
|
|
||||||
//
|
|
||||||
// struct Foo { Option<Option<Foo>> }
|
|
||||||
|
|
||||||
for &seen_adt in iter {
|
|
||||||
if ty == seen_adt {
|
|
||||||
debug!("ContainsRecursive: {:?} contains {:?}", seen_adt, ty);
|
|
||||||
return Representability::ContainsRecursive;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For structs and enums, track all previously seen types by pushing them
|
|
||||||
// onto the 'seen' stack.
|
|
||||||
seen.push(ty);
|
|
||||||
shadow_seen.push(*def);
|
|
||||||
let out = are_inner_types_recursive(
|
|
||||||
tcx,
|
|
||||||
seen,
|
|
||||||
shadow_seen,
|
|
||||||
representable_cache,
|
|
||||||
ty,
|
|
||||||
sp,
|
|
||||||
field_id,
|
|
||||||
force_result,
|
|
||||||
);
|
|
||||||
shadow_seen.pop();
|
|
||||||
seen.pop();
|
|
||||||
out
|
|
||||||
}
|
}
|
||||||
_ => {
|
ty::Array(ty, _) => params_in_repr_ty(tcx, ty, params_in_repr),
|
||||||
// No need to push in other cases.
|
ty::Tuple(tys) => tys.iter().for_each(|ty| params_in_repr_ty(tcx, ty, params_in_repr)),
|
||||||
are_inner_types_recursive(
|
ty::Param(param) => {
|
||||||
tcx,
|
params_in_repr.insert(param.index);
|
||||||
seen,
|
|
||||||
shadow_seen,
|
|
||||||
representable_cache,
|
|
||||||
ty,
|
|
||||||
sp,
|
|
||||||
field_id,
|
|
||||||
force_result,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// revisions: rpass cfail
|
// revisions: rpass cfail
|
||||||
|
|
||||||
enum A {
|
enum A {
|
||||||
//[cfail]~^ ERROR 3:1: 3:7: recursive type `A` has infinite size [E0072]
|
//[cfail]~^ ERROR 3:1: 3:7: recursive types `A` and `C` have infinite size [E0072]
|
||||||
B(C),
|
B(C),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,5 @@ struct C(Box<A>);
|
||||||
|
|
||||||
#[cfg(cfail)]
|
#[cfg(cfail)]
|
||||||
struct C(A);
|
struct C(A);
|
||||||
//[cfail]~^ ERROR 12:1: 12:9: recursive type `C` has infinite size [E0072]
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `DEF_ID` has infinite size
|
||||||
--> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5
|
--> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5
|
||||||
|
|
|
|
||||||
LL | enum E {
|
LL | enum E {
|
||||||
| ^^^^^^ recursive type has infinite size
|
| ^^^^^^
|
||||||
LL |
|
LL |
|
||||||
LL | This(E),
|
LL | This(E),
|
||||||
| - recursive without indirection
|
| - recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `DEF_ID` representable
|
help: insert some indirection (e.g., a `DEF_ID`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | This(Box<E>),
|
LL | This(Box<E>),
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `f::E` has infinite size
|
||||||
--> $DIR/infinite-recursive-type-impl-trait.rs:2:5
|
--> $DIR/infinite-recursive-type-impl-trait.rs:2:5
|
||||||
|
|
|
|
||||||
LL | enum E {
|
LL | enum E {
|
||||||
| ^^^^^^ recursive type has infinite size
|
| ^^^^^^
|
||||||
LL |
|
LL |
|
||||||
LL | V(E),
|
LL | V(E),
|
||||||
| - recursive without indirection
|
| - recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `f::E` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | V(Box<E>),
|
LL | V(Box<E>),
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `E` has infinite size
|
||||||
--> $DIR/infinite-recursive-type.rs:1:1
|
--> $DIR/infinite-recursive-type.rs:1:1
|
||||||
|
|
|
|
||||||
LL | enum E {
|
LL | enum E {
|
||||||
| ^^^^^^ recursive type has infinite size
|
| ^^^^^^
|
||||||
LL |
|
LL |
|
||||||
LL | V(E),
|
LL | V(E),
|
||||||
| - recursive without indirection
|
| - recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | V(Box<E>),
|
LL | V(Box<E>),
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -6,4 +6,11 @@ fn foo() -> Take {
|
||||||
Take(loop {})
|
Take(loop {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mutually infinite structs
|
||||||
|
struct Foo { //~ ERROR has infinite size
|
||||||
|
x: Bar<Foo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar<T>([T; 1]);
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -3,14 +3,25 @@ error[E0072]: recursive type `Take` has infinite size
|
||||||
|
|
|
|
||||||
LL | struct Take(Take);
|
LL | struct Take(Take);
|
||||||
| ^^^^^^^^^^^ ---- recursive without indirection
|
| ^^^^^^^^^^^ ---- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Take` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | struct Take(Box<Take>);
|
LL | struct Take(Box<Take>);
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0072]: recursive type `Foo` has infinite size
|
||||||
|
--> $DIR/infinite-struct.rs:10:1
|
||||||
|
|
|
||||||
|
LL | struct Foo {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
LL | x: Bar<Foo>,
|
||||||
|
| --- recursive without indirection
|
||||||
|
|
|
||||||
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
||||||
|
LL | x: Bar<Box<Foo>>,
|
||||||
|
| ++++ +
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0072`.
|
For more information about this error, try `rustc --explain E0072`.
|
||||||
|
|
|
@ -3,10 +3,8 @@ error[E0072]: recursive type `MList` has infinite size
|
||||||
|
|
|
|
||||||
LL | enum MList { Cons(isize, MList), Nil }
|
LL | enum MList { Cons(isize, MList), Nil }
|
||||||
| ^^^^^^^^^^ ----- recursive without indirection
|
| ^^^^^^^^^^ ----- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `MList` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | enum MList { Cons(isize, Box<MList>), Nil }
|
LL | enum MList { Cons(isize, Box<MList>), Nil }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/issue-17431-1.rs:1:1
|
--> $DIR/issue-17431-1.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct Foo { foo: Option<Option<Foo>> }
|
LL | struct Foo { foo: Option<Option<Foo>> }
|
||||||
| ^^^^^^^^^^ ------------------- recursive without indirection
|
| ^^^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | struct Foo { foo: Option<Box<Option<Foo>>> }
|
LL | struct Foo { foo: Option<Option<Box<Foo>>> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
struct Baz { q: Option<Foo> }
|
struct Baz { q: Option<Foo> }
|
||||||
//~^ ERROR recursive type `Baz` has infinite size
|
//~^ ERROR recursive types `Baz` and `Foo` have infinite size
|
||||||
|
|
||||||
struct Foo { q: Option<Baz> }
|
struct Foo { q: Option<Baz> }
|
||||||
//~^ ERROR recursive type `Foo` has infinite size
|
|
||||||
|
|
||||||
impl Foo { fn bar(&self) {} }
|
impl Foo { fn bar(&self) {} }
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,20 @@
|
||||||
error[E0072]: recursive type `Baz` has infinite size
|
error[E0072]: recursive types `Baz` and `Foo` have infinite size
|
||||||
--> $DIR/issue-17431-2.rs:1:1
|
--> $DIR/issue-17431-2.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct Baz { q: Option<Foo> }
|
LL | struct Baz { q: Option<Foo> }
|
||||||
| ^^^^^^^^^^ ----------- recursive without indirection
|
| ^^^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
...
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
|
||||||
|
|
|
||||||
LL | struct Baz { q: Option<Box<Foo>> }
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error[E0072]: recursive type `Foo` has infinite size
|
|
||||||
--> $DIR/issue-17431-2.rs:4:1
|
|
||||||
|
|
|
||||||
LL | struct Foo { q: Option<Baz> }
|
LL | struct Foo { q: Option<Baz> }
|
||||||
| ^^^^^^^^^^ ----------- recursive without indirection
|
| ^^^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
||||||
|
LL ~ struct Baz { q: Option<Box<Foo>> }
|
||||||
|
LL |
|
||||||
|
LL |
|
||||||
|
LL ~ struct Foo { q: Option<Box<Baz>> }
|
||||||
|
|
|
|
||||||
LL | struct Foo { q: Option<Box<Baz>> }
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0072`.
|
For more information about this error, try `rustc --explain E0072`.
|
||||||
|
|
|
@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/issue-17431-3.rs:3:1
|
--> $DIR/issue-17431-3.rs:3:1
|
||||||
|
|
|
|
||||||
LL | struct Foo { foo: Mutex<Option<Foo>> }
|
LL | struct Foo { foo: Mutex<Option<Foo>> }
|
||||||
| ^^^^^^^^^^ ------------------ recursive without indirection
|
| ^^^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | struct Foo { foo: Box<Mutex<Option<Foo>>> }
|
LL | struct Foo { foo: Mutex<Option<Box<Foo>>> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/issue-17431-4.rs:3:1
|
--> $DIR/issue-17431-4.rs:3:1
|
||||||
|
|
|
|
||||||
LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T> }
|
LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T> }
|
||||||
| ^^^^^^^^^^^^^ ---------------------- recursive without indirection
|
| ^^^^^^^^^^^^^ ------ recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | struct Foo<T> { foo: Option<Box<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
|
LL | struct Foo<T> { foo: Option<Option<Box<Foo<T>>>>, marker: marker::PhantomData<T> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,8 @@ error[E0072]: recursive type `Bar` has infinite size
|
||||||
|
|
|
|
||||||
LL | struct Bar<T> { x: Bar<Foo> , marker: marker::PhantomData<T> }
|
LL | struct Bar<T> { x: Bar<Foo> , marker: marker::PhantomData<T> }
|
||||||
| ^^^^^^^^^^^^^ -------- recursive without indirection
|
| ^^^^^^^^^^^^^ -------- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | struct Bar<T> { x: Box<Bar<Foo>> , marker: marker::PhantomData<T> }
|
LL | struct Bar<T> { x: Box<Bar<Foo>> , marker: marker::PhantomData<T> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/issue-17431-6.rs:3:1
|
--> $DIR/issue-17431-6.rs:3:1
|
||||||
|
|
|
|
||||||
LL | enum Foo { X(Mutex<Option<Foo>>) }
|
LL | enum Foo { X(Mutex<Option<Foo>>) }
|
||||||
| ^^^^^^^^ ------------------ recursive without indirection
|
| ^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | enum Foo { X(Box<Mutex<Option<Foo>>>) }
|
LL | enum Foo { X(Mutex<Option<Box<Foo>>>) }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/issue-17431-7.rs:1:1
|
--> $DIR/issue-17431-7.rs:1:1
|
||||||
|
|
|
|
||||||
LL | enum Foo { Voo(Option<Option<Foo>>) }
|
LL | enum Foo { Voo(Option<Option<Foo>>) }
|
||||||
| ^^^^^^^^ ------------------- recursive without indirection
|
| ^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | enum Foo { Voo(Option<Box<Option<Foo>>>) }
|
LL | enum Foo { Voo(Option<Option<Box<Foo>>>) }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,8 @@ error[E0072]: recursive type `Pong` has infinite size
|
||||||
|
|
|
|
||||||
LL | pub struct Pong(SendPacket<Ping>);
|
LL | pub struct Pong(SendPacket<Ping>);
|
||||||
| ^^^^^^^^^^^^^^^ ---------------- recursive without indirection
|
| ^^^^^^^^^^^^^^^ ---------------- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Pong` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | pub struct Pong(Box<SendPacket<Ping>>);
|
LL | pub struct Pong(Box<SendPacket<Ping>>);
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `Bar` has infinite size
|
||||||
--> $DIR/issue-3008-1.rs:5:1
|
--> $DIR/issue-3008-1.rs:5:1
|
||||||
|
|
|
|
||||||
LL | enum Bar {
|
LL | enum Bar {
|
||||||
| ^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^
|
||||||
...
|
...
|
||||||
LL | BarSome(Bar)
|
LL | BarSome(Bar)
|
||||||
| --- recursive without indirection
|
| --- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | BarSome(Box<Bar>)
|
LL | BarSome(Box<Bar>)
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -3,10 +3,8 @@ error[E0072]: recursive type `Bar` has infinite size
|
||||||
|
|
|
|
||||||
LL | struct Bar { x: Bar }
|
LL | struct Bar { x: Bar }
|
||||||
| ^^^^^^^^^^ --- recursive without indirection
|
| ^^^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | struct Bar { x: Box<Bar> }
|
LL | struct Bar { x: Box<Bar> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -3,10 +3,8 @@ error[E0072]: recursive type `E2` has infinite size
|
||||||
|
|
|
|
||||||
LL | enum E2<T> { V2(E2<E1>, marker::PhantomData<T>), }
|
LL | enum E2<T> { V2(E2<E1>, marker::PhantomData<T>), }
|
||||||
| ^^^^^^^^^^ ------ recursive without indirection
|
| ^^^^^^^^^^ ------ recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E2` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | enum E2<T> { V2(Box<E2<E1>>, marker::PhantomData<T>), }
|
LL | enum E2<T> { V2(Box<E2<E1>>, marker::PhantomData<T>), }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -2,16 +2,14 @@ error[E0072]: recursive type `Expr` has infinite size
|
||||||
--> $DIR/issue-32326.rs:5:1
|
--> $DIR/issue-32326.rs:5:1
|
||||||
|
|
|
|
||||||
LL | enum Expr {
|
LL | enum Expr {
|
||||||
| ^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^
|
||||||
LL | Plus(Expr, Expr),
|
LL | Plus(Expr, Expr),
|
||||||
| ---- ---- recursive without indirection
|
| ---- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive without indirection
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Expr` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | Plus(Box<Expr>, Box<Expr>),
|
LL | Plus(Box<Expr>, Expr),
|
||||||
| ++++ + ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `S` has infinite size
|
||||||
--> $DIR/issue-3779.rs:1:1
|
--> $DIR/issue-3779.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct S {
|
LL | struct S {
|
||||||
| ^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^
|
||||||
LL |
|
LL |
|
||||||
LL | element: Option<S>
|
LL | element: Option<S>
|
||||||
| --------- recursive without indirection
|
| - recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | element: Option<Box<S>>
|
LL | element: Option<Box<S>>
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -4,7 +4,7 @@ extern crate issue_57271_lib;
|
||||||
|
|
||||||
use issue_57271_lib::BaseType;
|
use issue_57271_lib::BaseType;
|
||||||
|
|
||||||
pub enum ObjectType { //~ ERROR recursive type `ObjectType` has infinite size
|
pub enum ObjectType { //~ ERROR recursive types `ObjectType` and `TypeSignature` have infinite size
|
||||||
Class(ClassTypeSignature),
|
Class(ClassTypeSignature),
|
||||||
Array(TypeSignature),
|
Array(TypeSignature),
|
||||||
TypeVariable(()),
|
TypeVariable(()),
|
||||||
|
@ -16,7 +16,7 @@ pub struct ClassTypeSignature {
|
||||||
pub inner: (),
|
pub inner: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TypeSignature { //~ ERROR recursive type `TypeSignature` has infinite size
|
pub enum TypeSignature {
|
||||||
Base(BaseType),
|
Base(BaseType),
|
||||||
Object(ObjectType),
|
Object(ObjectType),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,27 @@
|
||||||
error[E0072]: recursive type `ObjectType` has infinite size
|
error[E0072]: recursive types `ObjectType` and `TypeSignature` have infinite size
|
||||||
--> $DIR/issue-57271.rs:7:1
|
--> $DIR/issue-57271.rs:7:1
|
||||||
|
|
|
|
||||||
LL | pub enum ObjectType {
|
LL | pub enum ObjectType {
|
||||||
| ^^^^^^^^^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
LL | Class(ClassTypeSignature),
|
LL | Class(ClassTypeSignature),
|
||||||
LL | Array(TypeSignature),
|
LL | Array(TypeSignature),
|
||||||
| ------------- recursive without indirection
|
| ------------- recursive without indirection
|
||||||
|
|
...
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ObjectType` representable
|
|
||||||
|
|
|
||||||
LL | Array(Box<TypeSignature>),
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error[E0072]: recursive type `TypeSignature` has infinite size
|
|
||||||
--> $DIR/issue-57271.rs:19:1
|
|
||||||
|
|
|
||||||
LL | pub enum TypeSignature {
|
LL | pub enum TypeSignature {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
LL | Base(BaseType),
|
LL | Base(BaseType),
|
||||||
LL | Object(ObjectType),
|
LL | Object(ObjectType),
|
||||||
| ---------- recursive without indirection
|
| ---------- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `TypeSignature` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
||||||
|
LL ~ Array(Box<TypeSignature>),
|
||||||
|
LL | TypeVariable(()),
|
||||||
|
...
|
||||||
|
LL | Base(BaseType),
|
||||||
|
LL ~ Object(Box<ObjectType>),
|
||||||
|
|
|
|
||||||
LL | Object(Box<ObjectType>),
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0072`.
|
For more information about this error, try `rustc --explain E0072`.
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `ElemDerived` has infinite size
|
||||||
--> $DIR/issue-72554.rs:4:1
|
--> $DIR/issue-72554.rs:4:1
|
||||||
|
|
|
|
||||||
LL | pub enum ElemDerived {
|
LL | pub enum ElemDerived {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
...
|
...
|
||||||
LL | A(ElemDerived)
|
LL | A(ElemDerived)
|
||||||
| ----------- recursive without indirection
|
| ----------- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ElemDerived` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | A(Box<ElemDerived>)
|
LL | A(Box<ElemDerived>)
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -19,10 +19,8 @@ error[E0072]: recursive type `Foo` has infinite size
|
||||||
|
|
|
|
||||||
LL | struct Foo<Self>(Self);
|
LL | struct Foo<Self>(Self);
|
||||||
| ^^^^^^^^^^^^^^^^ ---- recursive without indirection
|
| ^^^^^^^^^^^^^^^^ ---- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | struct Foo<Self>(Box<Self>);
|
LL | struct Foo<Self>(Box<Self>);
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -3,10 +3,8 @@ error[E0072]: recursive type `List` has infinite size
|
||||||
|
|
|
|
||||||
LL | enum List<T> { Cons(T, List<T>), Nil }
|
LL | enum List<T> { Cons(T, List<T>), Nil }
|
||||||
| ^^^^^^^^^^^^ ------- recursive without indirection
|
| ^^^^^^^^^^^^ ------- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `List` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | enum List<T> { Cons(T, Box<List<T>>), Nil }
|
LL | enum List<T> { Cons(T, Box<List<T>>), Nil }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
// Test the error message resulting from a cycle in solving `Foo:
|
|
||||||
// Sized`. The specifics of the message will of course but the main
|
|
||||||
// thing we want to preserve is that:
|
|
||||||
//
|
|
||||||
// 1. the message should appear attached to one of the structs
|
|
||||||
// defined in this file;
|
|
||||||
// 2. it should elaborate the steps that led to the cycle.
|
|
||||||
|
|
||||||
struct Baz { q: Option<Foo> }
|
struct Baz { q: Option<Foo> }
|
||||||
//~^ ERROR recursive type `Baz` has infinite size
|
//~^ ERROR recursive types `Baz` and `Foo` have infinite size
|
||||||
struct Foo { q: Option<Baz> }
|
struct Foo { q: Option<Baz> }
|
||||||
//~^ ERROR recursive type `Foo` has infinite size
|
|
||||||
|
|
||||||
impl Foo { fn bar(&self) {} }
|
impl Foo { fn bar(&self) {} }
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,19 @@
|
||||||
error[E0072]: recursive type `Baz` has infinite size
|
error[E0072]: recursive types `Baz` and `Foo` have infinite size
|
||||||
--> $DIR/sized-cycle-note.rs:9:1
|
--> $DIR/sized-cycle-note.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct Baz { q: Option<Foo> }
|
LL | struct Baz { q: Option<Foo> }
|
||||||
| ^^^^^^^^^^ ----------- recursive without indirection
|
| ^^^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
LL |
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
|
||||||
|
|
|
||||||
LL | struct Baz { q: Option<Box<Foo>> }
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error[E0072]: recursive type `Foo` has infinite size
|
|
||||||
--> $DIR/sized-cycle-note.rs:11:1
|
|
||||||
|
|
|
||||||
LL | struct Foo { q: Option<Baz> }
|
LL | struct Foo { q: Option<Baz> }
|
||||||
| ^^^^^^^^^^ ----------- recursive without indirection
|
| ^^^^^^^^^^ --- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
||||||
|
LL ~ struct Baz { q: Option<Box<Foo>> }
|
||||||
|
LL |
|
||||||
|
LL ~ struct Foo { q: Option<Box<Baz>> }
|
||||||
|
|
|
|
||||||
LL | struct Foo { q: Option<Box<Baz>> }
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0072`.
|
For more information about this error, try `rustc --explain E0072`.
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `ListNode` has infinite size
|
||||||
--> $DIR/E0072.rs:1:1
|
--> $DIR/E0072.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct ListNode {
|
LL | struct ListNode {
|
||||||
| ^^^^^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^^^^^
|
||||||
LL | head: u8,
|
LL | head: u8,
|
||||||
LL | tail: Option<ListNode>,
|
LL | tail: Option<ListNode>,
|
||||||
| ---------------- recursive without indirection
|
| -------- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | tail: Option<Box<ListNode>>,
|
LL | tail: Option<Box<ListNode>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -3,12 +3,12 @@ error[E0072]: recursive type `ListNode` has infinite size
|
||||||
|
|
|
|
||||||
LL | / struct
|
LL | / struct
|
||||||
LL | | ListNode
|
LL | | ListNode
|
||||||
| |________^ recursive type has infinite size
|
| |________^
|
||||||
...
|
...
|
||||||
LL | tail: Option<ListNode>,
|
LL | tail: Option<ListNode>,
|
||||||
| ---------------- recursive without indirection
|
| -------- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | tail: Option<Box<ListNode>>,
|
LL | tail: Option<Box<ListNode>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
struct Foo<'a> { //~ ERROR recursive type
|
struct Foo<'a> { //~ ERROR recursive types `Foo` and `Bar` have infinite size
|
||||||
bar: Bar<'a>,
|
bar: Bar<'a>,
|
||||||
b: Rc<Bar<'a>>,
|
b: Rc<Bar<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Bar<'a> { //~ ERROR recursive type
|
struct Bar<'a> {
|
||||||
y: (Foo<'a>, Foo<'a>),
|
y: (Foo<'a>, Foo<'a>),
|
||||||
z: Option<Bar<'a>>,
|
z: Option<Bar<'a>>,
|
||||||
a: &'a Foo<'a>,
|
a: &'a Foo<'a>,
|
||||||
|
|
|
@ -1,35 +1,27 @@
|
||||||
error[E0072]: recursive type `Foo` has infinite size
|
error[E0072]: recursive types `Foo` and `Bar` have infinite size
|
||||||
--> $DIR/recursive-type-field.rs:3:1
|
--> $DIR/recursive-type-field.rs:3:1
|
||||||
|
|
|
|
||||||
LL | struct Foo<'a> {
|
LL | struct Foo<'a> {
|
||||||
| ^^^^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^^^^
|
||||||
LL | bar: Bar<'a>,
|
LL | bar: Bar<'a>,
|
||||||
| ------- recursive without indirection
|
| ------- recursive without indirection
|
||||||
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
|
||||||
|
|
|
||||||
LL | bar: Box<Bar<'a>>,
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error[E0072]: recursive type `Bar` has infinite size
|
|
||||||
--> $DIR/recursive-type-field.rs:8:1
|
|
||||||
|
|
|
||||||
LL | struct Bar<'a> {
|
|
||||||
| ^^^^^^^^^^^^^^ recursive type has infinite size
|
|
||||||
LL | y: (Foo<'a>, Foo<'a>),
|
|
||||||
| ------------------ recursive without indirection
|
|
||||||
LL | z: Option<Bar<'a>>,
|
|
||||||
| --------------- recursive without indirection
|
|
||||||
...
|
...
|
||||||
LL | d: [Bar<'a>; 1],
|
LL | struct Bar<'a> {
|
||||||
| ------------ recursive without indirection
|
| ^^^^^^^^^^^^^^
|
||||||
LL | e: Foo<'a>,
|
LL | y: (Foo<'a>, Foo<'a>),
|
||||||
| ------- recursive without indirection
|
| ------- ------- recursive without indirection
|
||||||
LL | x: Bar<'a>,
|
| |
|
||||||
| ------- recursive without indirection
|
| recursive without indirection
|
||||||
|
|
|
||||||
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
||||||
|
LL ~ bar: Box<Bar<'a>>,
|
||||||
|
LL | b: Rc<Bar<'a>>,
|
||||||
|
...
|
||||||
|
LL | struct Bar<'a> {
|
||||||
|
LL ~ y: (Box<Foo<'a>>, Box<Foo<'a>>),
|
||||||
|
|
|
|
||||||
= help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0072`.
|
For more information about this error, try `rustc --explain E0072`.
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `A` has infinite size
|
||||||
--> $DIR/issue-74224.rs:1:1
|
--> $DIR/issue-74224.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct A<T> {
|
LL | struct A<T> {
|
||||||
| ^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^
|
||||||
...
|
...
|
||||||
LL | y: A<A<T>>,
|
LL | y: A<A<T>>,
|
||||||
| ------- recursive without indirection
|
| ------- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `A` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | y: Box<A<A<T>>>,
|
LL | y: Box<A<A<T>>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/issue-84611.rs:1:1
|
--> $DIR/issue-84611.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct Foo<T> {
|
LL | struct Foo<T> {
|
||||||
| ^^^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^^^
|
||||||
LL |
|
LL |
|
||||||
LL | x: Foo<[T; 1]>,
|
LL | x: Foo<[T; 1]>,
|
||||||
| ----------- recursive without indirection
|
| ----------- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | x: Box<Foo<[T; 1]>>,
|
LL | x: Box<Foo<[T; 1]>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
struct A<T> {
|
struct A<T> {
|
||||||
//~^ ERROR recursive type `A` has infinite size
|
//~^ ERROR recursive types `A` and `B` have infinite size
|
||||||
x: T,
|
x: T,
|
||||||
y: B<T>,
|
y: B<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct B<T> {
|
struct B<T> {
|
||||||
//~^ ERROR recursive type `B` has infinite size
|
|
||||||
z: A<T>
|
z: A<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
struct C<T> {
|
struct C<T> {
|
||||||
//~^ ERROR recursive type `C` has infinite size
|
//~^ ERROR recursive types `C` and `D` have infinite size
|
||||||
x: T,
|
x: T,
|
||||||
y: Option<Option<D<T>>>,
|
y: Option<Option<D<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct D<T> {
|
struct D<T> {
|
||||||
//~^ ERROR recursive type `D` has infinite size
|
|
||||||
z: Option<Option<C<T>>>,
|
z: Option<Option<C<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,59 +1,49 @@
|
||||||
error[E0072]: recursive type `A` has infinite size
|
error[E0072]: recursive types `A` and `B` have infinite size
|
||||||
--> $DIR/mutual-struct-recursion.rs:1:1
|
--> $DIR/mutual-struct-recursion.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct A<T> {
|
LL | struct A<T> {
|
||||||
| ^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^
|
||||||
...
|
...
|
||||||
LL | y: B<T>,
|
LL | y: B<T>,
|
||||||
| ---- recursive without indirection
|
| ---- recursive without indirection
|
||||||
|
|
...
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `A` representable
|
|
||||||
|
|
|
||||||
LL | y: Box<B<T>>,
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error[E0072]: recursive type `B` has infinite size
|
|
||||||
--> $DIR/mutual-struct-recursion.rs:7:1
|
|
||||||
|
|
|
||||||
LL | struct B<T> {
|
LL | struct B<T> {
|
||||||
| ^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^
|
||||||
LL |
|
|
||||||
LL | z: A<T>
|
LL | z: A<T>
|
||||||
| ---- recursive without indirection
|
| ---- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `B` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
||||||
|
LL ~ y: Box<B<T>>,
|
||||||
|
LL | }
|
||||||
|
LL |
|
||||||
|
LL | struct B<T> {
|
||||||
|
LL ~ z: Box<A<T>>
|
||||||
|
|
|
|
||||||
LL | z: Box<A<T>>
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error[E0072]: recursive type `C` has infinite size
|
error[E0072]: recursive types `C` and `D` have infinite size
|
||||||
--> $DIR/mutual-struct-recursion.rs:12:1
|
--> $DIR/mutual-struct-recursion.rs:11:1
|
||||||
|
|
|
|
||||||
LL | struct C<T> {
|
LL | struct C<T> {
|
||||||
| ^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^
|
||||||
...
|
...
|
||||||
LL | y: Option<Option<D<T>>>,
|
LL | y: Option<Option<D<T>>>,
|
||||||
| -------------------- recursive without indirection
|
| ---- recursive without indirection
|
||||||
|
|
...
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable
|
|
||||||
|
|
|
||||||
LL | y: Option<Box<Option<D<T>>>>,
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error[E0072]: recursive type `D` has infinite size
|
|
||||||
--> $DIR/mutual-struct-recursion.rs:18:1
|
|
||||||
|
|
|
||||||
LL | struct D<T> {
|
LL | struct D<T> {
|
||||||
| ^^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^^
|
||||||
LL |
|
|
||||||
LL | z: Option<Option<C<T>>>,
|
LL | z: Option<Option<C<T>>>,
|
||||||
| -------------------- recursive without indirection
|
| ---- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
||||||
|
LL ~ y: Option<Option<Box<D<T>>>>,
|
||||||
|
LL | }
|
||||||
|
LL |
|
||||||
|
LL | struct D<T> {
|
||||||
|
LL ~ z: Option<Option<Box<C<T>>>>,
|
||||||
|
|
|
|
||||||
LL | z: Option<Box<Option<C<T>>>>,
|
|
||||||
| ++++ +
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0072`.
|
For more information about this error, try `rustc --explain E0072`.
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/type-recursive-box-shadowed.rs:7:1
|
--> $DIR/type-recursive-box-shadowed.rs:7:1
|
||||||
|
|
|
|
||||||
LL | struct Foo {
|
LL | struct Foo {
|
||||||
| ^^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^^
|
||||||
LL |
|
LL |
|
||||||
LL | inner: Foo,
|
LL | inner: Foo,
|
||||||
| --- recursive without indirection
|
| --- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | inner: Box<Foo>,
|
LL | inner: Box<Foo>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
|
@ -2,12 +2,12 @@ error[E0072]: recursive type `T1` has infinite size
|
||||||
--> $DIR/type-recursive.rs:1:1
|
--> $DIR/type-recursive.rs:1:1
|
||||||
|
|
|
|
||||||
LL | struct T1 {
|
LL | struct T1 {
|
||||||
| ^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^
|
||||||
LL | foo: isize,
|
LL | foo: isize,
|
||||||
LL | foolish: T1,
|
LL | foolish: T1,
|
||||||
| -- recursive without indirection
|
| -- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T1` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | foolish: Box<T1>,
|
LL | foolish: Box<T1>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
@ -16,11 +16,11 @@ error[E0072]: recursive type `T2` has infinite size
|
||||||
--> $DIR/type-recursive.rs:6:1
|
--> $DIR/type-recursive.rs:6:1
|
||||||
|
|
|
|
||||||
LL | struct T2 {
|
LL | struct T2 {
|
||||||
| ^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^
|
||||||
LL | inner: Option<T2>,
|
LL | inner: Option<T2>,
|
||||||
| ---------- recursive without indirection
|
| -- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T2` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | inner: Option<Box<T2>>,
|
LL | inner: Option<Box<T2>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
@ -29,11 +29,11 @@ error[E0072]: recursive type `T3` has infinite size
|
||||||
--> $DIR/type-recursive.rs:12:1
|
--> $DIR/type-recursive.rs:12:1
|
||||||
|
|
|
|
||||||
LL | struct T3 {
|
LL | struct T3 {
|
||||||
| ^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^
|
||||||
LL | inner: OptionT3,
|
LL | inner: OptionT3,
|
||||||
| -------- recursive without indirection
|
| -------- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T3` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | inner: Box<OptionT3>,
|
LL | inner: Box<OptionT3>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
@ -42,11 +42,9 @@ error[E0072]: recursive type `T4` has infinite size
|
||||||
--> $DIR/type-recursive.rs:16:1
|
--> $DIR/type-recursive.rs:16:1
|
||||||
|
|
|
|
||||||
LL | struct T4(Option<T4>);
|
LL | struct T4(Option<T4>);
|
||||||
| ^^^^^^^^^ ---------- recursive without indirection
|
| ^^^^^^^^^ -- recursive without indirection
|
||||||
| |
|
|
||||||
| recursive type has infinite size
|
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T4` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | struct T4(Option<Box<T4>>);
|
LL | struct T4(Option<Box<T4>>);
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
@ -55,11 +53,11 @@ error[E0072]: recursive type `T5` has infinite size
|
||||||
--> $DIR/type-recursive.rs:18:1
|
--> $DIR/type-recursive.rs:18:1
|
||||||
|
|
|
|
||||||
LL | enum T5 {
|
LL | enum T5 {
|
||||||
| ^^^^^^^ recursive type has infinite size
|
| ^^^^^^^
|
||||||
LL | Variant(Option<T5>),
|
LL | Variant(Option<T5>),
|
||||||
| ---------- recursive without indirection
|
| -- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T5` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | Variant(Option<Box<T5>>),
|
LL | Variant(Option<Box<T5>>),
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
@ -68,11 +66,11 @@ error[E0072]: recursive type `T6` has infinite size
|
||||||
--> $DIR/type-recursive.rs:22:1
|
--> $DIR/type-recursive.rs:22:1
|
||||||
|
|
|
|
||||||
LL | enum T6 {
|
LL | enum T6 {
|
||||||
| ^^^^^^^ recursive type has infinite size
|
| ^^^^^^^
|
||||||
LL | Variant{ field: Option<T6> },
|
LL | Variant{ field: Option<T6> },
|
||||||
| ---------- recursive without indirection
|
| -- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T6` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | Variant{ field: Option<Box<T6>> },
|
LL | Variant{ field: Option<Box<T6>> },
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
@ -81,14 +79,14 @@ error[E0072]: recursive type `T7` has infinite size
|
||||||
--> $DIR/type-recursive.rs:26:1
|
--> $DIR/type-recursive.rs:26:1
|
||||||
|
|
|
|
||||||
LL | struct T7 {
|
LL | struct T7 {
|
||||||
| ^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^
|
||||||
LL | foo: std::cell::Cell<Option<T7>>,
|
LL | foo: std::cell::Cell<Option<T7>>,
|
||||||
| --------------------------- recursive without indirection
|
| -- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T7` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | foo: Box<std::cell::Cell<Option<T7>>>,
|
LL | foo: std::cell::Cell<Option<Box<T7>>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,15 @@ error[E0072]: recursive type `U` has infinite size
|
||||||
--> $DIR/union-nonrepresentable.rs:1:1
|
--> $DIR/union-nonrepresentable.rs:1:1
|
||||||
|
|
|
|
||||||
LL | union U {
|
LL | union U {
|
||||||
| ^^^^^^^ recursive type has infinite size
|
| ^^^^^^^
|
||||||
LL | a: u8,
|
LL | a: u8,
|
||||||
LL | b: std::mem::ManuallyDrop<U>,
|
LL | b: std::mem::ManuallyDrop<U>,
|
||||||
| ------------------------- recursive without indirection
|
| - recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `U` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
|
|
|
|
||||||
LL | b: Box<std::mem::ManuallyDrop<U>>,
|
LL | b: std::mem::ManuallyDrop<Box<U>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue