From ff940db666daeae83c6c71685901c6c14df17018 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 15 Aug 2022 14:11:11 -0500 Subject: [PATCH] Rewrite representability --- Cargo.lock | 1 - compiler/rustc_hir_analysis/Cargo.toml | 1 - .../rustc_hir_analysis/src/check/check.rs | 28 +- compiler/rustc_hir_analysis/src/check/mod.rs | 1 - compiler/rustc_lint_defs/src/lib.rs | 3 + .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 4 + compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- compiler/rustc_middle/src/arena.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 26 + compiler/rustc_middle/src/ty/adt.rs | 7 + compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_middle/src/values.rs | 170 ++++++- compiler/rustc_query_impl/src/keys.rs | 10 + compiler/rustc_query_impl/src/plumbing.rs | 8 +- compiler/rustc_query_system/src/query/job.rs | 6 +- compiler/rustc_query_system/src/query/mod.rs | 9 +- .../rustc_query_system/src/query/plumbing.rs | 11 +- compiler/rustc_query_system/src/values.rs | 5 +- .../src/traits/error_reporting/mod.rs | 76 --- compiler/rustc_ty_utils/src/lib.rs | 1 + .../rustc_ty_utils/src/representability.rs | 451 ++++-------------- src/test/incremental/issue-61323.rs | 3 +- ...te-recursive-type-impl-trait-return.stderr | 4 +- .../infinite-recursive-type-impl-trait.stderr | 4 +- .../rustdoc-ui/infinite-recursive-type.stderr | 4 +- src/test/ui/infinite/infinite-struct.rs | 7 + src/test/ui/infinite/infinite-struct.stderr | 19 +- .../infinite-tag-type-recursion.stderr | 4 +- src/test/ui/issues/issue-17431-1.stderr | 10 +- src/test/ui/issues/issue-17431-2.rs | 3 +- src/test/ui/issues/issue-17431-2.stderr | 31 +- src/test/ui/issues/issue-17431-3.stderr | 10 +- src/test/ui/issues/issue-17431-4.stderr | 10 +- src/test/ui/issues/issue-17431-5.stderr | 4 +- src/test/ui/issues/issue-17431-6.stderr | 10 +- src/test/ui/issues/issue-17431-7.stderr | 10 +- src/test/ui/issues/issue-2718-a.stderr | 4 +- src/test/ui/issues/issue-3008-1.stderr | 4 +- src/test/ui/issues/issue-3008-2.stderr | 4 +- src/test/ui/issues/issue-3008-3.stderr | 4 +- src/test/ui/issues/issue-32326.stderr | 12 +- src/test/ui/issues/issue-3779.stderr | 6 +- src/test/ui/issues/issue-57271.rs | 4 +- src/test/ui/issues/issue-57271.stderr | 28 +- src/test/ui/issues/issue-72554.stderr | 4 +- .../keyword/keyword-self-as-type-param.stderr | 4 +- src/test/ui/recursion/recursive-enum.stderr | 4 +- src/test/ui/sized-cycle-note.rs | 11 +- src/test/ui/sized-cycle-note.stderr | 32 +- src/test/ui/span/E0072.stderr | 6 +- src/test/ui/span/multiline-span-E0072.stderr | 6 +- src/test/ui/span/recursive-type-field.rs | 4 +- src/test/ui/span/recursive-type-field.stderr | 38 +- .../struct-rec/issue-74224.stderr | 4 +- .../struct-rec/issue-84611.stderr | 4 +- .../struct-rec/mutual-struct-recursion.rs | 6 +- .../struct-rec/mutual-struct-recursion.stderr | 62 +-- .../type/type-recursive-box-shadowed.stderr | 4 +- src/test/ui/type/type-recursive.stderr | 42 +- .../ui/union/union-nonrepresentable.stderr | 10 +- 61 files changed, 529 insertions(+), 736 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 027121774d4ec..3b8d0d87f2a9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3552,7 +3552,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_ty_utils", "rustc_type_ir", "smallvec", "tracing", diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index dd26b3da7bcf6..0761d8cdbd8f6 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -26,7 +26,6 @@ rustc_span = { path = "../rustc_span" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_ty_utils = { path = "../rustc_ty_utils" } rustc_lint = { path = "../rustc_lint" } rustc_serialize = { path = "../rustc_serialize" } rustc_type_ir = { path = "../rustc_type_ir" } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a2636f23a4f25..1ef5cd9d1a2a6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -31,7 +31,6 @@ use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCtxt}; -use rustc_ty_utils::representability::{self, Representability}; use std::ops::ControlFlow; @@ -381,7 +380,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated - check_representable(tcx, span, def_id); + let _ = tcx.representability(def_id); if def.repr().simd() { 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 span = tcx.def_span(def_id); 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_union_fields(tcx, span, def_id); 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) { let t = tcx.type_of(def_id); 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); - check_representable(tcx, sp, def_id); + let _ = tcx.representability(def_id); check_transparent(tcx, sp, def); } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 04e8c9c22d159..331bd7e26c858 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -123,7 +123,6 @@ use rustc_span::{self, BytePos, Span, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; 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 std::cell::RefCell; use std::num::NonZeroU32; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index cbe7afc8e5558..aa54b3d8ac2bc 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -25,6 +25,9 @@ macro_rules! pluralize { ($x:expr) => { if $x != 1 { "s" } else { "" } }; + ("has", $x:expr) => { + if $x == 1 { "has" } else { "have" } + }; ("is", $x:expr) => { if $x == 1 { "is" } else { "are" } }; diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 466da175810d5..c4dff8b3f48ed 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -210,6 +210,7 @@ provide! { tcx, def_id, other, cdata, lookup_const_stability => { table } lookup_default_body_stability => { table } lookup_deprecation_entry => { table } + params_in_repr => { table } unused_generic_params => { table } opt_def_kind => { table_direct } impl_parent => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1a7a3c65c3b3f..3fc10197b9129 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1156,6 +1156,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::Trait | DefKind::TraitAlias = def_kind { 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) && let Ok(table) = self.tcx.collect_trait_impl_trait_tys(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 6d7345570af85..a509ecdf7591b 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -13,7 +13,8 @@ use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; 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::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; @@ -383,6 +384,7 @@ define_tables! { inherent_impls: Table>, expn_that_defined: Table>, unused_generic_params: Table>>, + params_in_repr: Table>>, repr_options: Table>, // `def_keys` and `def_path_hashes` represent a lazy version of a // `DefPathTable`. This allows us to avoid deserializing an entire diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 6bdf5a023b6c3..d2847e4bc12a7 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -103,6 +103,7 @@ macro_rules! arena_types { [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, [decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap>, + [] bit_set_u32: rustc_index::bit_set::BitSet, ]); ) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 334eb953cbcb4..a175b1eb46733 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -301,6 +301,32 @@ rustc_queries! { 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 { + 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`. query thir_body(key: ty::WithOptConstParam) -> Result<(&'tcx Steal>, thir::ExprId), ErrorGuaranteed> diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 3c485e2640970..80bbc8e630e02 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -566,3 +566,10 @@ impl<'tcx> AdtDef<'tcx> { ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0) } } + +#[derive(Clone, Copy, Debug)] +#[derive(HashStable)] +pub enum Representability { + Representable, + Infinite, +} diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 0257ca7b29c71..f289f2265a287 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -82,6 +82,7 @@ trivially_parameterized_over_tcx! { rustc_hir::def::DefKind, rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, + rustc_index::bit_set::BitSet, rustc_index::bit_set::FiniteBitSet, rustc_session::cstore::ForeignModule, rustc_session::cstore::LinkagePreference, diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 7fbe9ae2a8418..bb89959b29ded 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -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_span::def_id::LocalDefId; +use rustc_span::Span; + +use std::fmt::Write; impl<'tcx> Value> 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>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { std::mem::transmute::, Ty<'_>>(tcx.ty_error()) } @@ -10,7 +20,7 @@ impl<'tcx> Value> for Ty<'_> { } impl<'tcx> Value> 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>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { @@ -22,7 +32,7 @@ impl<'tcx> Value> for ty::SymbolName<'_> { } impl<'tcx> Value> 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>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { @@ -34,7 +44,7 @@ impl<'tcx> Value> for AdtSizedConstraint<'_> { } impl<'tcx> Value> 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(); // FIXME(compiler-errors): It would be nice if we could get the // query key, so we could at least generate a fn signature that @@ -52,3 +62,153 @@ impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { unsafe { std::mem::transmute::, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) } } } + +impl<'tcx> Value> 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, +) { + 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, + seen_representable: &FxHashSet, +) { + 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)) + } + _ => {} + } +} diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index cdbf734cdbe18..8be2e2be86b58 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -27,6 +27,10 @@ pub trait Key { fn key_as_def_id(&self) -> Option { None } + + fn ty_adt_id(&self) -> Option { + None + } } impl Key for () { @@ -407,6 +411,12 @@ impl<'tcx> Key for Ty<'tcx> { fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } + fn ty_adt_id(&self) -> Option { + match self.kind() { + ty::Adt(adt, _) => Some(adt.did()), + _ => None, + } + } } impl<'tcx> Key for TyAndLayout<'tcx> { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 2b3850bc0dfb5..aaeaa3bd51d63 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -318,13 +318,12 @@ pub(crate) fn create_query_frame< } else { Some(key.default_span(*tcx)) }; + let def_id = key.key_as_def_id(); let def_kind = if kind == dep_graph::DepKind::opt_def_kind { // Try to avoid infinite recursion. None } else { - key.key_as_def_id() - .and_then(|def_id| def_id.as_local()) - .and_then(|def_id| tcx.opt_def_kind(def_id)) + def_id.and_then(|def_id| def_id.as_local()).and_then(|def_id| tcx.opt_def_kind(def_id)) }; let hash = || { tcx.with_stable_hashing_context(|mut hcx| { @@ -334,8 +333,9 @@ pub(crate) fn create_query_frame< hasher.finish::() }) }; + 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) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 64aba4703ca3a..ed65393f57e4d 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -551,7 +551,7 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) { #[cold] pub(crate) fn report_cycle<'a>( sess: &'a Session, - CycleError { usage, cycle: stack }: CycleError, + CycleError { usage, cycle: stack }: &CycleError, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { assert!(!stack.is_empty()); @@ -569,10 +569,10 @@ pub(crate) fn report_cycle<'a>( } let mut cycle_usage = None; - if let Some((span, query)) = usage { + if let Some((span, ref query)) = *usage { cycle_usage = Some(crate::error::CycleUsage { span: query.default_span(span), - usage: query.description, + usage: query.description.to_string(), }); } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 7a96c53b60481..118703fc0d48c 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -18,6 +18,7 @@ use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; use rustc_data_structures::sync::Lock; use rustc_errors::Diagnostic; use rustc_hir::def::DefKind; +use rustc_span::def_id::DefId; use rustc_span::Span; use thin_vec::ThinVec; @@ -29,7 +30,9 @@ pub struct QueryStackFrame { pub name: &'static str, pub description: String, span: Option, - def_kind: Option, + pub def_id: Option, + pub def_kind: Option, + pub ty_adt_id: Option, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. #[cfg(parallel_compiler)] @@ -42,14 +45,18 @@ impl QueryStackFrame { name: &'static str, description: String, span: Option, + def_id: Option, def_kind: Option, + ty_adt_id: Option, _hash: impl FnOnce() -> u64, ) -> Self { Self { name, description, span, + def_id, def_kind, + ty_adt_id, #[cfg(parallel_compiler)] hash: _hash(), } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 8179a674afaec..15b89daa6db11 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -119,7 +119,7 @@ where #[inline(never)] fn mk_cycle( tcx: CTX, - error: CycleError, + cycle_error: CycleError, handler: HandleCycleError, cache: &dyn crate::query::QueryStorage, ) -> R @@ -128,13 +128,14 @@ where V: std::fmt::Debug + Value, R: Clone, { - let error = report_cycle(tcx.dep_context().sess(), error); - let value = handle_cycle_error(*tcx.dep_context(), error, handler); + let error = report_cycle(tcx.dep_context().sess(), &cycle_error); + let value = handle_cycle_error(*tcx.dep_context(), &cycle_error, error, handler); cache.store_nocache(value) } fn handle_cycle_error( tcx: CTX, + cycle_error: &CycleError, mut error: DiagnosticBuilder<'_, ErrorGuaranteed>, handler: HandleCycleError, ) -> V @@ -146,7 +147,7 @@ where match handler { Error => { error.emit(); - Value::from_cycle_error(tcx) + Value::from_cycle_error(tcx, &cycle_error.cycle) } Fatal => { error.emit(); @@ -155,7 +156,7 @@ where } DelayBug => { error.delay_as_bug(); - Value::from_cycle_error(tcx) + Value::from_cycle_error(tcx, &cycle_error.cycle) } } } diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs index aeef66f86dacc..67fbf14e61299 100644 --- a/compiler/rustc_query_system/src/values.rs +++ b/compiler/rustc_query_system/src/values.rs @@ -1,11 +1,12 @@ use crate::dep_graph::DepContext; +use crate::query::QueryInfo; pub trait Value: Sized { - fn from_cycle_error(tcx: CTX) -> Self; + fn from_cycle_error(tcx: CTX, cycle: &[QueryInfo]) -> Self; } impl Value for T { - default fn from_cycle_error(tcx: CTX) -> T { + default fn from_cycle_error(tcx: CTX, _: &[QueryInfo]) -> T { tcx.sess().abort_if_errors(); // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's // non-trivial to define it earlier. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6dcf9c4d26174..8afe20bf2298f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -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)>, -) { - 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` in a field definition -fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option) -> Option { - 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 #[derive(Clone)] pub enum ArgKind { diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 0ddc154fbebbf..cce5a79ddc855 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -39,6 +39,7 @@ pub fn provide(providers: &mut Providers) { implied_bounds::provide(providers); layout::provide(providers); needs_drop::provide(providers); + representability::provide(providers); ty::provide(providers); instance::provide(providers); } diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index eded7891682ea..7f48fb804178d 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -1,386 +1,119 @@ -//! Check whether a type is representable. -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; +#![allow(rustc::untranslatable_diagnostic, rustc::diagnostic_outside_of_impl)] -/// Describes whether a type is representable. For types that are not -/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to -/// distinguish between types that are recursive with themselves and types that -/// contain a different recursive type. These cases can therefore be treated -/// differently when reporting errors. -/// -/// The ordering of the cases is significant. They are sorted so that cmp::max -/// will keep the "more erroneous" of two values. -#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] -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)>), -} +use rustc_hir::def::DefKind; +use rustc_index::bit_set::BitSet; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; +use rustc_span::def_id::{DefId, LocalDefId}; -/// Check whether a type is representable. This means it cannot contain unboxed -/// structural recursion. This check is needed for structs and enums. -pub fn ty_is_representable<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - sp: Span, - field_id: Option, -) -> 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> = Vec::new(); - let mut shadow_seen: Vec> = 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 +pub fn provide(providers: &mut Providers) { + *providers = + Providers { representability, representability_adt_ty, params_in_repr, ..*providers }; } -// Iterate until something non-representable is found -fn fold_repr>(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()) +macro_rules! rtry { + ($e:expr) => { + match $e { + e @ Representability::Infinite => return e, + Representability::Representable => {} } - (r1, r2) => cmp::max(r1, r2), - }) + }; } -fn are_inner_types_recursive<'tcx>( - tcx: TyCtxt<'tcx>, - seen: &mut Vec>, - shadow_seen: &mut Vec>, - representable_cache: &mut FxHashMap, Representability>, - ty: Ty<'tcx>, - sp: Span, - field_id: Option, - 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 { - // z: T, - // x: B, - // } - // - // struct B { - // y: A - // } - // - // 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 { - result = Some(Representability::Representable); - - // Now, we check whether the field types per se are representable, e.g. - // for struct Foo { x: Option }, 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> = 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 { - // x: T, - // y: A>, - // } - // - // struct B { - // z: A - // } - // - // When checking B, we recurse into A and check field y of type - // A>. We haven't seen this exact type before, so we recurse - // into A>, which contains, A>>, 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> } - // 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, - }, - ); - } +fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability { + match tcx.def_kind(def_id) { + DefKind::Struct | DefKind::Union | DefKind::Enum => { + let adt_def = tcx.adt_def(def_id); + for variant in adt_def.variants() { + for field in variant.fields.iter() { + rtry!(tcx.representability(field.did.expect_local())); } - - result.unwrap() - })) - } - ty::Closure(..) => { - // this check is run on type definitions, so we don't expect - // to see closure types - bug!("requires check invoked on inapplicable type: {:?}", ty) + } + Representability::Representable } - _ => Representability::Representable, + DefKind::Field => representability_ty(tcx, tcx.type_of(def_id)), + def_kind => bug!("unexpected {def_kind:?}"), } } -fn same_adt<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { +fn representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { match *ty.kind() { - ty::Adt(ty_def, _) => ty_def == def, - _ => false, + 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, } } -// Does the type `ty` directly (without indirection through a pointer) -// contain any types on stack `seen`? -fn is_type_structurally_recursive<'tcx>( - tcx: TyCtxt<'tcx>, - seen: &mut Vec>, - shadow_seen: &mut Vec>, - representable_cache: &mut FxHashMap, Representability>, - ty: Ty<'tcx>, - sp: Span, - field_id: Option, - 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(); +/* +The reason for this being a separate query is very subtle: +Consider this infinitely sized struct: `struct Foo(Box, Bar)`: +When calling representability(Foo), a query cycle will occur: + representability(Foo) + -> representability_adt_ty(Bar) + -> 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)); } - - 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 + // 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 is_type_structurally_recursive_inner<'tcx>( - tcx: TyCtxt<'tcx>, - seen: &mut Vec>, - shadow_seen: &mut Vec>, - representable_cache: &mut FxHashMap, Representability>, - ty: Ty<'tcx>, - sp: Span, - field_id: Option, - 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 in this example counts as SelfRecursive: - // - // struct Foo; - // struct Bar { x: Bar } - - 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> } +fn params_in_repr(tcx: TyCtxt<'_>, def_id: DefId) -> BitSet { + 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 +} - for &seen_adt in iter { - if ty == seen_adt { - debug!("ContainsRecursive: {:?} contains {:?}", seen_adt, ty); - return Representability::ContainsRecursive; +fn params_in_repr_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, params_in_repr: &mut BitSet) { + match *ty.kind() { + ty::Adt(adt, substs) => { + 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) { + params_in_repr_ty(tcx, ty, params_in_repr); } } } - - // 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 } - _ => { - // No need to push in other cases. - are_inner_types_recursive( - tcx, - seen, - shadow_seen, - representable_cache, - ty, - sp, - field_id, - force_result, - ) + ty::Array(ty, _) => params_in_repr_ty(tcx, ty, params_in_repr), + ty::Tuple(tys) => tys.iter().for_each(|ty| params_in_repr_ty(tcx, ty, params_in_repr)), + ty::Param(param) => { + params_in_repr.insert(param.index); } + _ => {} } } diff --git a/src/test/incremental/issue-61323.rs b/src/test/incremental/issue-61323.rs index 97cbfe408f261..7ce47947cbb0c 100644 --- a/src/test/incremental/issue-61323.rs +++ b/src/test/incremental/issue-61323.rs @@ -1,7 +1,7 @@ // revisions: rpass cfail 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), } @@ -10,6 +10,5 @@ struct C(Box); #[cfg(cfail)] struct C(A); -//[cfail]~^ ERROR 12:1: 12:9: recursive type `C` has infinite size [E0072] fn main() {} diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr index aa39d26feed1e..e6ab67d59ce58 100644 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `DEF_ID` has infinite size --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5 | LL | enum E { - | ^^^^^^ recursive type has infinite size + | ^^^^^^ LL | LL | This(E), | - 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), | ++++ + diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr index 009bedec5ed6a..165ff67837244 100644 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `f::E` has infinite size --> $DIR/infinite-recursive-type-impl-trait.rs:2:5 | LL | enum E { - | ^^^^^^ recursive type has infinite size + | ^^^^^^ LL | LL | V(E), | - 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), | ++++ + diff --git a/src/test/rustdoc-ui/infinite-recursive-type.stderr b/src/test/rustdoc-ui/infinite-recursive-type.stderr index b33aba446223c..9e2c3ff164209 100644 --- a/src/test/rustdoc-ui/infinite-recursive-type.stderr +++ b/src/test/rustdoc-ui/infinite-recursive-type.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `E` has infinite size --> $DIR/infinite-recursive-type.rs:1:1 | LL | enum E { - | ^^^^^^ recursive type has infinite size + | ^^^^^^ LL | LL | V(E), | - 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), | ++++ + diff --git a/src/test/ui/infinite/infinite-struct.rs b/src/test/ui/infinite/infinite-struct.rs index 74185dc597b52..f08e10f6bdbc0 100644 --- a/src/test/ui/infinite/infinite-struct.rs +++ b/src/test/ui/infinite/infinite-struct.rs @@ -6,4 +6,11 @@ fn foo() -> Take { Take(loop {}) } +// mutually infinite structs +struct Foo { //~ ERROR has infinite size + x: Bar, +} + +struct Bar([T; 1]); + fn main() {} diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr index 5a6d13786d197..b6c72b1de4695 100644 --- a/src/test/ui/infinite/infinite-struct.stderr +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -3,14 +3,25 @@ error[E0072]: recursive type `Take` has infinite size | LL | struct Take(Take); | ^^^^^^^^^^^ ---- 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); | ++++ + -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, + | --- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | x: Bar>, + | ++++ + + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index d2dad4b9178d9..513bbfc1b8cf1 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -3,10 +3,8 @@ error[E0072]: recursive type `MList` has infinite size | LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ ----- 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), Nil } | ++++ + diff --git a/src/test/ui/issues/issue-17431-1.stderr b/src/test/ui/issues/issue-17431-1.stderr index db32eb952ba79..e3af8976cee91 100644 --- a/src/test/ui/issues/issue-17431-1.stderr +++ b/src/test/ui/issues/issue-17431-1.stderr @@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-1.rs:1:1 | LL | struct Foo { foo: Option> } - | ^^^^^^^^^^ ------------------- recursive without indirection - | | - | recursive type has infinite size + | ^^^^^^^^^^ --- 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 | struct Foo { foo: Option>> } - | ++++ + +LL | struct Foo { foo: Option>> } + | ++++ + error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-2.rs b/src/test/ui/issues/issue-17431-2.rs index 9ed97f63177f0..f7b9c6a55ddf7 100644 --- a/src/test/ui/issues/issue-17431-2.rs +++ b/src/test/ui/issues/issue-17431-2.rs @@ -1,8 +1,7 @@ struct Baz { q: Option } -//~^ ERROR recursive type `Baz` has infinite size +//~^ ERROR recursive types `Baz` and `Foo` have infinite size struct Foo { q: Option } -//~^ ERROR recursive type `Foo` has infinite size impl Foo { fn bar(&self) {} } diff --git a/src/test/ui/issues/issue-17431-2.stderr b/src/test/ui/issues/issue-17431-2.stderr index d23fd1474ac12..39a99ec1ef739 100644 --- a/src/test/ui/issues/issue-17431-2.stderr +++ b/src/test/ui/issues/issue-17431-2.stderr @@ -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 | LL | struct Baz { q: Option } - | ^^^^^^^^^^ ----------- 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> } - | ++++ + - -error[E0072]: recursive type `Foo` has infinite size - --> $DIR/issue-17431-2.rs:4:1 - | + | ^^^^^^^^^^ --- recursive without indirection +... LL | struct Foo { q: Option } - | ^^^^^^^^^^ ----------- recursive without indirection - | | - | recursive type has infinite size + | ^^^^^^^^^^ --- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable +LL ~ struct Baz { q: Option> } +LL | +LL | +LL ~ struct Foo { q: Option> } | -LL | struct Foo { q: Option> } - | ++++ + -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/issues/issue-17431-3.stderr b/src/test/ui/issues/issue-17431-3.stderr index 0dde6f382c34a..394134c78556b 100644 --- a/src/test/ui/issues/issue-17431-3.stderr +++ b/src/test/ui/issues/issue-17431-3.stderr @@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-3.rs:3:1 | LL | struct Foo { foo: Mutex> } - | ^^^^^^^^^^ ------------------ recursive without indirection - | | - | recursive type has infinite size + | ^^^^^^^^^^ --- 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 | struct Foo { foo: Box>> } - | ++++ + +LL | struct Foo { foo: Mutex>> } + | ++++ + error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-4.stderr b/src/test/ui/issues/issue-17431-4.stderr index ddf669b8fd1cb..3d141e44babf4 100644 --- a/src/test/ui/issues/issue-17431-4.stderr +++ b/src/test/ui/issues/issue-17431-4.stderr @@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-4.rs:3:1 | LL | struct Foo { foo: Option>>, marker: marker::PhantomData } - | ^^^^^^^^^^^^^ ---------------------- recursive without indirection - | | - | recursive type has infinite size + | ^^^^^^^^^^^^^ ------ 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 | struct Foo { foo: Option>>>, marker: marker::PhantomData } - | ++++ + +LL | struct Foo { foo: Option>>>, marker: marker::PhantomData } + | ++++ + error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-5.stderr b/src/test/ui/issues/issue-17431-5.stderr index a379598c2657c..44a90a6fe3898 100644 --- a/src/test/ui/issues/issue-17431-5.stderr +++ b/src/test/ui/issues/issue-17431-5.stderr @@ -3,10 +3,8 @@ error[E0072]: recursive type `Bar` has infinite size | LL | struct Bar { x: Bar , marker: marker::PhantomData } | ^^^^^^^^^^^^^ -------- 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> , marker: marker::PhantomData } | ++++ + diff --git a/src/test/ui/issues/issue-17431-6.stderr b/src/test/ui/issues/issue-17431-6.stderr index fcac420b23845..e0a8225507e5a 100644 --- a/src/test/ui/issues/issue-17431-6.stderr +++ b/src/test/ui/issues/issue-17431-6.stderr @@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-6.rs:3:1 | LL | enum Foo { X(Mutex>) } - | ^^^^^^^^ ------------------ recursive without indirection - | | - | recursive type has infinite size + | ^^^^^^^^ --- 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 | enum Foo { X(Box>>) } - | ++++ + +LL | enum Foo { X(Mutex>>) } + | ++++ + error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-7.stderr b/src/test/ui/issues/issue-17431-7.stderr index 6f8a7e3867b09..ecf072b8e8aea 100644 --- a/src/test/ui/issues/issue-17431-7.stderr +++ b/src/test/ui/issues/issue-17431-7.stderr @@ -2,14 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-7.rs:1:1 | LL | enum Foo { Voo(Option>) } - | ^^^^^^^^ ------------------- recursive without indirection - | | - | recursive type has infinite size + | ^^^^^^^^ --- 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 | enum Foo { Voo(Option>>) } - | ++++ + +LL | enum Foo { Voo(Option>>) } + | ++++ + error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/issues/issue-2718-a.stderr index c6e703f4876f8..7ea620f386a20 100644 --- a/src/test/ui/issues/issue-2718-a.stderr +++ b/src/test/ui/issues/issue-2718-a.stderr @@ -3,10 +3,8 @@ error[E0072]: recursive type `Pong` has infinite size | LL | pub struct Pong(SendPacket); | ^^^^^^^^^^^^^^^ ---------------- 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>); | ++++ + diff --git a/src/test/ui/issues/issue-3008-1.stderr b/src/test/ui/issues/issue-3008-1.stderr index e49d8e6aa0d8e..be25b9091d589 100644 --- a/src/test/ui/issues/issue-3008-1.stderr +++ b/src/test/ui/issues/issue-3008-1.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `Bar` has infinite size --> $DIR/issue-3008-1.rs:5:1 | LL | enum Bar { - | ^^^^^^^^ recursive type has infinite size + | ^^^^^^^^ ... LL | BarSome(Bar) | --- 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) | ++++ + diff --git a/src/test/ui/issues/issue-3008-2.stderr b/src/test/ui/issues/issue-3008-2.stderr index b3ce6e42096bb..858a8fd6af808 100644 --- a/src/test/ui/issues/issue-3008-2.stderr +++ b/src/test/ui/issues/issue-3008-2.stderr @@ -3,10 +3,8 @@ error[E0072]: recursive type `Bar` has infinite size | LL | struct Bar { x: Bar } | ^^^^^^^^^^ --- 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 } | ++++ + diff --git a/src/test/ui/issues/issue-3008-3.stderr b/src/test/ui/issues/issue-3008-3.stderr index c1c043e217b4e..a1a81e2936775 100644 --- a/src/test/ui/issues/issue-3008-3.stderr +++ b/src/test/ui/issues/issue-3008-3.stderr @@ -3,10 +3,8 @@ error[E0072]: recursive type `E2` has infinite size | LL | enum E2 { V2(E2, marker::PhantomData), } | ^^^^^^^^^^ ------ 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 { V2(Box>, marker::PhantomData), } | ++++ + diff --git a/src/test/ui/issues/issue-32326.stderr b/src/test/ui/issues/issue-32326.stderr index cea765850564f..dc51198d98ce8 100644 --- a/src/test/ui/issues/issue-32326.stderr +++ b/src/test/ui/issues/issue-32326.stderr @@ -2,16 +2,14 @@ error[E0072]: recursive type `Expr` has infinite size --> $DIR/issue-32326.rs:5:1 | LL | enum Expr { - | ^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^ 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, Box), - | ++++ + ++++ + +LL | Plus(Box, Expr), + | ++++ + error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3779.stderr b/src/test/ui/issues/issue-3779.stderr index e853d0f8c8932..a0dbcc920fa3d 100644 --- a/src/test/ui/issues/issue-3779.stderr +++ b/src/test/ui/issues/issue-3779.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `S` has infinite size --> $DIR/issue-3779.rs:1:1 | LL | struct S { - | ^^^^^^^^ recursive type has infinite size + | ^^^^^^^^ LL | LL | element: Option - | --------- 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> | ++++ + diff --git a/src/test/ui/issues/issue-57271.rs b/src/test/ui/issues/issue-57271.rs index 9940fecbeed53..f74222e3e51db 100644 --- a/src/test/ui/issues/issue-57271.rs +++ b/src/test/ui/issues/issue-57271.rs @@ -4,7 +4,7 @@ extern crate issue_57271_lib; 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), Array(TypeSignature), TypeVariable(()), @@ -16,7 +16,7 @@ pub struct ClassTypeSignature { pub inner: (), } -pub enum TypeSignature { //~ ERROR recursive type `TypeSignature` has infinite size +pub enum TypeSignature { Base(BaseType), Object(ObjectType), } diff --git a/src/test/ui/issues/issue-57271.stderr b/src/test/ui/issues/issue-57271.stderr index 8250096656ab2..391e69c91fb0f 100644 --- a/src/test/ui/issues/issue-57271.stderr +++ b/src/test/ui/issues/issue-57271.stderr @@ -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 | LL | pub enum ObjectType { - | ^^^^^^^^^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^^^^^^^^^ LL | Class(ClassTypeSignature), LL | Array(TypeSignature), | ------------- recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ObjectType` representable - | -LL | Array(Box), - | ++++ + - -error[E0072]: recursive type `TypeSignature` has infinite size - --> $DIR/issue-57271.rs:19:1 - | +... LL | pub enum TypeSignature { - | ^^^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^^^^^^^^^^^^ LL | Base(BaseType), LL | Object(ObjectType), | ---------- 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), +LL | TypeVariable(()), + ... +LL | Base(BaseType), +LL ~ Object(Box), | -LL | Object(Box), - | ++++ + -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr index 3e5adcae133ca..bc85cd7b18d55 100644 --- a/src/test/ui/issues/issue-72554.stderr +++ b/src/test/ui/issues/issue-72554.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `ElemDerived` has infinite size --> $DIR/issue-72554.rs:4:1 | LL | pub enum ElemDerived { - | ^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^^^^^^^^^^ ... LL | A(ElemDerived) | ----------- 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) | ++++ + diff --git a/src/test/ui/keyword/keyword-self-as-type-param.stderr b/src/test/ui/keyword/keyword-self-as-type-param.stderr index 419652e13492f..5aef94754869f 100644 --- a/src/test/ui/keyword/keyword-self-as-type-param.stderr +++ b/src/test/ui/keyword/keyword-self-as-type-param.stderr @@ -19,10 +19,8 @@ error[E0072]: recursive type `Foo` has infinite size | LL | struct Foo(Self); | ^^^^^^^^^^^^^^^^ ---- 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(Box); | ++++ + diff --git a/src/test/ui/recursion/recursive-enum.stderr b/src/test/ui/recursion/recursive-enum.stderr index f5d25c5641dd1..d662d1022038d 100644 --- a/src/test/ui/recursion/recursive-enum.stderr +++ b/src/test/ui/recursion/recursive-enum.stderr @@ -3,10 +3,8 @@ error[E0072]: recursive type `List` has infinite size | LL | enum List { Cons(T, List), Nil } | ^^^^^^^^^^^^ ------- 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 { Cons(T, Box>), Nil } | ++++ + diff --git a/src/test/ui/sized-cycle-note.rs b/src/test/ui/sized-cycle-note.rs index ca8be5692ba97..766a5fa0de3dc 100644 --- a/src/test/ui/sized-cycle-note.rs +++ b/src/test/ui/sized-cycle-note.rs @@ -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 } -//~^ ERROR recursive type `Baz` has infinite size +//~^ ERROR recursive types `Baz` and `Foo` have infinite size struct Foo { q: Option } -//~^ ERROR recursive type `Foo` has infinite size impl Foo { fn bar(&self) {} } diff --git a/src/test/ui/sized-cycle-note.stderr b/src/test/ui/sized-cycle-note.stderr index 536510814c57c..06c87b61f41f6 100644 --- a/src/test/ui/sized-cycle-note.stderr +++ b/src/test/ui/sized-cycle-note.stderr @@ -1,29 +1,19 @@ -error[E0072]: recursive type `Baz` has infinite size - --> $DIR/sized-cycle-note.rs:9:1 +error[E0072]: recursive types `Baz` and `Foo` have infinite size + --> $DIR/sized-cycle-note.rs:1:1 | LL | struct Baz { q: Option } - | ^^^^^^^^^^ ----------- 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> } - | ++++ + - -error[E0072]: recursive type `Foo` has infinite size - --> $DIR/sized-cycle-note.rs:11:1 - | + | ^^^^^^^^^^ --- recursive without indirection +LL | LL | struct Foo { q: Option } - | ^^^^^^^^^^ ----------- recursive without indirection - | | - | recursive type has infinite size + | ^^^^^^^^^^ --- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable +LL ~ struct Baz { q: Option> } +LL | +LL ~ struct Foo { q: Option> } | -LL | struct Foo { q: Option> } - | ++++ + -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr index 882ed577cf366..20f2e0df05efe 100644 --- a/src/test/ui/span/E0072.stderr +++ b/src/test/ui/span/E0072.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `ListNode` has infinite size --> $DIR/E0072.rs:1:1 | LL | struct ListNode { - | ^^^^^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^^^^^ LL | head: u8, LL | tail: Option, - | ---------------- 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>, | ++++ + diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index 79b13f45fd8ee..fc2f6e6622c2a 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -3,12 +3,12 @@ error[E0072]: recursive type `ListNode` has infinite size | LL | / struct LL | | ListNode - | |________^ recursive type has infinite size + | |________^ ... LL | tail: Option, - | ---------------- 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>, | ++++ + diff --git a/src/test/ui/span/recursive-type-field.rs b/src/test/ui/span/recursive-type-field.rs index 58ea81b8395ee..bd4c435347cfc 100644 --- a/src/test/ui/span/recursive-type-field.rs +++ b/src/test/ui/span/recursive-type-field.rs @@ -1,11 +1,11 @@ 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>, b: Rc>, } -struct Bar<'a> { //~ ERROR recursive type +struct Bar<'a> { y: (Foo<'a>, Foo<'a>), z: Option>, a: &'a Foo<'a>, diff --git a/src/test/ui/span/recursive-type-field.stderr b/src/test/ui/span/recursive-type-field.stderr index 08e97e750c31a..10af4c36ba4b4 100644 --- a/src/test/ui/span/recursive-type-field.stderr +++ b/src/test/ui/span/recursive-type-field.stderr @@ -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 | LL | struct Foo<'a> { - | ^^^^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^^^^ LL | bar: Bar<'a>, | ------- recursive without indirection +... +LL | struct Bar<'a> { + | ^^^^^^^^^^^^^^ +LL | y: (Foo<'a>, Foo<'a>), + | ------- ------- recursive without indirection + | | + | recursive without indirection | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable - | -LL | bar: Box>, - | ++++ + - -error[E0072]: recursive type `Bar` has infinite size - --> $DIR/recursive-type-field.rs:8:1 +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | +LL ~ bar: Box>, +LL | b: Rc>, + ... LL | struct Bar<'a> { - | ^^^^^^^^^^^^^^ recursive type has infinite size -LL | y: (Foo<'a>, Foo<'a>), - | ------------------ recursive without indirection -LL | z: Option>, - | --------------- recursive without indirection -... -LL | d: [Bar<'a>; 1], - | ------------ recursive without indirection -LL | e: Foo<'a>, - | ------- recursive without indirection -LL | x: Bar<'a>, - | ------- recursive without indirection +LL ~ y: (Box>, Box>), | - = 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`. diff --git a/src/test/ui/structs-enums/struct-rec/issue-74224.stderr b/src/test/ui/structs-enums/struct-rec/issue-74224.stderr index 6199178467fcf..f1d50bc8af5ac 100644 --- a/src/test/ui/structs-enums/struct-rec/issue-74224.stderr +++ b/src/test/ui/structs-enums/struct-rec/issue-74224.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `A` has infinite size --> $DIR/issue-74224.rs:1:1 | LL | struct A { - | ^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^ ... LL | y: A>, | ------- 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>>, | ++++ + diff --git a/src/test/ui/structs-enums/struct-rec/issue-84611.stderr b/src/test/ui/structs-enums/struct-rec/issue-84611.stderr index 2e99435e033d5..536f54e3e9611 100644 --- a/src/test/ui/structs-enums/struct-rec/issue-84611.stderr +++ b/src/test/ui/structs-enums/struct-rec/issue-84611.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-84611.rs:1:1 | LL | struct Foo { - | ^^^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^^^ LL | LL | x: Foo<[T; 1]>, | ----------- 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>, | ++++ + diff --git a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs index cca97f43effc3..3bfce8b4f9656 100644 --- a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs +++ b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs @@ -1,22 +1,20 @@ struct A { -//~^ ERROR recursive type `A` has infinite size +//~^ ERROR recursive types `A` and `B` have infinite size x: T, y: B, } struct B { -//~^ ERROR recursive type `B` has infinite size z: A } struct C { -//~^ ERROR recursive type `C` has infinite size +//~^ ERROR recursive types `C` and `D` have infinite size x: T, y: Option>>, } struct D { -//~^ ERROR recursive type `D` has infinite size z: Option>>, } diff --git a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr index 80a494f3f65eb..881bc2819369b 100644 --- a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr +++ b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr @@ -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 | LL | struct A { - | ^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^ ... LL | y: B, | ---- recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `A` representable - | -LL | y: Box>, - | ++++ + - -error[E0072]: recursive type `B` has infinite size - --> $DIR/mutual-struct-recursion.rs:7:1 - | +... LL | struct B { - | ^^^^^^^^^^^ recursive type has infinite size -LL | + | ^^^^^^^^^^^ LL | z: A | ---- 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>, +LL | } +LL | +LL | struct B { +LL ~ z: Box> | -LL | z: Box> - | ++++ + -error[E0072]: recursive type `C` has infinite size - --> $DIR/mutual-struct-recursion.rs:12:1 +error[E0072]: recursive types `C` and `D` have infinite size + --> $DIR/mutual-struct-recursion.rs:11:1 | LL | struct C { - | ^^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^^ ... LL | y: Option>>, - | -------------------- recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable - | -LL | y: Option>>>, - | ++++ + - -error[E0072]: recursive type `D` has infinite size - --> $DIR/mutual-struct-recursion.rs:18:1 - | + | ---- recursive without indirection +... LL | struct D { - | ^^^^^^^^^^^ recursive type has infinite size -LL | + | ^^^^^^^^^^^ LL | z: Option>>, - | -------------------- recursive without indirection + | ---- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable +LL ~ y: Option>>>, +LL | } +LL | +LL | struct D { +LL ~ z: Option>>>, | -LL | z: Option>>>, - | ++++ + -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/type/type-recursive-box-shadowed.stderr b/src/test/ui/type/type-recursive-box-shadowed.stderr index c22d848f3797e..cb0e982877cf7 100644 --- a/src/test/ui/type/type-recursive-box-shadowed.stderr +++ b/src/test/ui/type/type-recursive-box-shadowed.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/type-recursive-box-shadowed.rs:7:1 | LL | struct Foo { - | ^^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^^ LL | LL | inner: Foo, | --- 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, | ++++ + diff --git a/src/test/ui/type/type-recursive.stderr b/src/test/ui/type/type-recursive.stderr index 3202710286e1a..9a4d798f61e01 100644 --- a/src/test/ui/type/type-recursive.stderr +++ b/src/test/ui/type/type-recursive.stderr @@ -2,12 +2,12 @@ error[E0072]: recursive type `T1` has infinite size --> $DIR/type-recursive.rs:1:1 | LL | struct T1 { - | ^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^ LL | foo: isize, LL | foolish: T1, | -- 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, | ++++ + @@ -16,11 +16,11 @@ error[E0072]: recursive type `T2` has infinite size --> $DIR/type-recursive.rs:6:1 | LL | struct T2 { - | ^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^ LL | inner: Option, - | ---------- 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>, | ++++ + @@ -29,11 +29,11 @@ error[E0072]: recursive type `T3` has infinite size --> $DIR/type-recursive.rs:12:1 | LL | struct T3 { - | ^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^ LL | inner: OptionT3, | -------- 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, | ++++ + @@ -42,11 +42,9 @@ error[E0072]: recursive type `T4` has infinite size --> $DIR/type-recursive.rs:16:1 | LL | struct T4(Option); - | ^^^^^^^^^ ---------- recursive without indirection - | | - | recursive type has infinite size + | ^^^^^^^^^ -- recursive without indirection | -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>); | ++++ + @@ -55,11 +53,11 @@ error[E0072]: recursive type `T5` has infinite size --> $DIR/type-recursive.rs:18:1 | LL | enum T5 { - | ^^^^^^^ recursive type has infinite size + | ^^^^^^^ LL | Variant(Option), - | ---------- 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>), | ++++ + @@ -68,11 +66,11 @@ error[E0072]: recursive type `T6` has infinite size --> $DIR/type-recursive.rs:22:1 | LL | enum T6 { - | ^^^^^^^ recursive type has infinite size + | ^^^^^^^ LL | Variant{ field: Option }, - | ---------- 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> }, | ++++ + @@ -81,14 +79,14 @@ error[E0072]: recursive type `T7` has infinite size --> $DIR/type-recursive.rs:26:1 | LL | struct T7 { - | ^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^ LL | foo: std::cell::Cell>, - | --------------------------- 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>>, - | ++++ + +LL | foo: std::cell::Cell>>, + | ++++ + error: aborting due to 7 previous errors diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index 9804b1418b208..c266d2e9e138b 100644 --- a/src/test/ui/union/union-nonrepresentable.stderr +++ b/src/test/ui/union/union-nonrepresentable.stderr @@ -2,15 +2,15 @@ error[E0072]: recursive type `U` has infinite size --> $DIR/union-nonrepresentable.rs:1:1 | LL | union U { - | ^^^^^^^ recursive type has infinite size + | ^^^^^^^ LL | a: u8, LL | b: std::mem::ManuallyDrop, - | ------------------------- 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>, - | ++++ + +LL | b: std::mem::ManuallyDrop>, + | ++++ + error: aborting due to previous error