diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index ed951015a4f19..76e0c6231344a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -997,6 +997,7 @@ fn check_type_defn<'tcx>( item: &hir::Item<'tcx>, all_sized: bool, ) -> Result<(), ErrorGuaranteed> { + // Check for a cycle let _ = tcx.representability(item.owner_id.def_id); let adt_def = tcx.adt_def(item.owner_id); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 15addd2407857..5fb3877a05235 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -903,7 +903,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { solve::provide(&mut providers.queries); rustc_passes::provide(&mut providers.queries); rustc_traits::provide(&mut providers.queries); - rustc_ty_utils::provide(&mut providers.queries); + rustc_ty_utils::provide(providers); rustc_metadata::provide(providers); rustc_lint::provide(&mut providers.queries); rustc_symbol_mangling::provide(&mut providers.queries); @@ -981,6 +981,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( rustc_query_impl::query_system( providers.queries, providers.extern_queries, + providers.query_cycle_handlers, query_result_on_disk_cache, incremental, ), diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 3a3a2743ec4f8..e1c62cff17fa3 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -592,11 +592,9 @@ rustc_queries! { separate_provide_extern } - /// Checks whether a type is representable or infinitely sized - query representability(key: LocalDefId) -> rustc_middle::ty::Representability { + /// Checks whether a type is representable or infinitely sized, emits a cycle error if it's not. + query representability(key: LocalDefId) { desc { "checking if `{}` is representable", tcx.def_path_str(key) } - // 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 @@ -604,15 +602,16 @@ rustc_queries! { } /// An implementation detail for the `representability` query - query representability_adt_ty(key: Ty<'tcx>) -> rustc_middle::ty::Representability { + query representability_adt_ty(key: Ty<'tcx>) { desc { "checking if `{}` is representable", key } - cycle_delay_bug anon } /// Set of param indexes for type params that are in the type's representation + /// + /// An implementation detail for the `representability` query query params_in_repr(key: DefId) -> &'tcx rustc_index::bit_set::DenseBitSet { - desc { "finding type parameters in the representation" } + desc { "finding type parameters in the representation of `{}`", tcx.def_path_str(key) } arena_cache no_hash separate_provide_extern diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 4d4833b4943e4..c3db895f58782 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -396,7 +396,6 @@ impl_erasable_for_simple_types! { rustc_middle::ty::Destructor, rustc_middle::ty::fast_reject::SimplifiedType, rustc_middle::ty::ImplPolarity, - rustc_middle::ty::Representability, rustc_middle::ty::UnusedGenericParams, rustc_middle::ty::util::AlwaysRequiresDrop, rustc_middle::ty::Visibility, diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 506d7616cbfc9..aed09b910625c 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -15,7 +15,8 @@ use crate::dep_graph; use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; use crate::queries::{ - ExternProviders, PerQueryVTables, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates, + CycleHandlers, ExternProviders, PerQueryVTables, Providers, QueryArenas, QueryCaches, + QueryEngine, QueryStates, }; use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra}; @@ -146,6 +147,7 @@ pub struct QuerySystemFns { pub engine: QueryEngine, pub local_providers: Providers, pub extern_providers: ExternProviders, + pub cycle_handlers: CycleHandlers, pub encode_query_results: for<'tcx> fn( tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'_, 'tcx>, @@ -565,6 +567,18 @@ macro_rules! define_callbacks { fn clone(&self) -> Self { *self } } + #[derive(Default)] + pub struct CycleHandlers { + $( + pub $name: Option, &$crate::query::CycleError) -> Option>, + )* + } + + impl Copy for CycleHandlers {} + impl Clone for CycleHandlers { + fn clone(&self) -> Self { *self } + } + pub struct QueryEngine { $( pub $name: for<'tcx> fn( diff --git a/compiler/rustc_middle/src/query/stack.rs b/compiler/rustc_middle/src/query/stack.rs index fd80c7edd602d..8c1b002d2885b 100644 --- a/compiler/rustc_middle/src/query/stack.rs +++ b/compiler/rustc_middle/src/query/stack.rs @@ -5,10 +5,12 @@ use std::sync::Arc; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_hir::def::DefKind; -use rustc_span::Span; use rustc_span::def_id::DefId; +use rustc_span::{ErrorGuaranteed, Span}; use crate::dep_graph::DepKind; +use crate::query::CycleError; +use crate::ty::TyCtxt; /// Description of a frame in the query stack. /// @@ -20,7 +22,7 @@ pub struct QueryStackFrame { /// by calling `lift`. This is done so that collecting query does not need to invoke /// queries, instead `lift` will call queries in a more appropriate location. pub info: I, - + pub cycle_handler: Option, &CycleError) -> Option>, pub dep_kind: DepKind, pub def_id: Option, /// A def-id that is extracted from a `Ty` in a query key @@ -28,19 +30,10 @@ pub struct QueryStackFrame { } impl<'tcx> QueryStackFrame> { - #[inline] - pub fn new( - info: QueryStackDeferred<'tcx>, - dep_kind: DepKind, - def_id: Option, - def_id_for_ty_in_cycle: Option, - ) -> Self { - Self { info, def_id, dep_kind, def_id_for_ty_in_cycle } - } - pub fn lift(&self) -> QueryStackFrame { QueryStackFrame { info: self.info.extract(), + cycle_handler: self.cycle_handler, dep_kind: self.dep_kind, def_id: self.def_id, def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 020669588ac5c..065205054aad4 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -672,9 +672,3 @@ impl<'tcx> AdtDef<'tcx> { if self.is_struct() { tcx.adt_sizedness_constraint((self.did(), sizedness)) } else { None } } } - -#[derive(Clone, Copy, Debug, HashStable)] -pub enum Representability { - Representable, - Infinite(ErrorGuaranteed), -} diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 5c4c1733be29e..cd0ea4fa51472 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -61,9 +61,8 @@ pub(crate) fn provide(providers: &mut Providers) { /// requires calling [`InhabitedPredicate::instantiate`] fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { if let Some(def_id) = def_id.as_local() { - if matches!(tcx.representability(def_id), ty::Representability::Infinite(_)) { - return InhabitedPredicate::True; - } + // Check for a cycle + let _ = tcx.representability(def_id); } let adt = tcx.adt_def(def_id); InhabitedPredicate::any( diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs index 0bbe3856033b7..6544e85a6047f 100644 --- a/compiler/rustc_middle/src/util/mod.rs +++ b/compiler/rustc_middle/src/util/mod.rs @@ -4,5 +4,6 @@ pub mod bug; pub struct Providers { pub queries: crate::queries::Providers, pub extern_queries: crate::queries::ExternProviders, + pub query_cycle_handlers: crate::queries::CycleHandlers, pub hooks: crate::hooks::Providers, } diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 1f064599332c1..593033e697ebd 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -107,6 +107,15 @@ fn mk_cycle<'tcx, C: QueryCache, const FLAGS: QueryFlags>( tcx: TyCtxt<'tcx>, cycle_error: CycleError, ) -> C::Value { + // Check if any queries in the cycle can handle this cycle error + for query in &cycle_error.cycle { + if let Some(cycle_handler) = query.frame.cycle_handler + && let Some(guard) = cycle_handler(tcx, &cycle_error) + { + guard.raise_fatal(); + } + } + let error = report_cycle(tcx.sess, &cycle_error); handle_cycle_error(query, tcx, &cycle_error, error) } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 2804f5cfa055d..10781d400dd21 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -15,7 +15,7 @@ use std::marker::ConstParamTy; use rustc_data_structures::sync::AtomicU64; use rustc_middle::dep_graph::{self, DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::queries::{ - self, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, + self, CycleHandlers, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, }; use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; use rustc_middle::query::plumbing::{ @@ -239,6 +239,7 @@ trait QueryDispatcherUnerased<'tcx, C: QueryCache, const FLAGS: QueryFlags> { pub fn query_system<'tcx>( local_providers: Providers, extern_providers: ExternProviders, + cycle_decor_providers: CycleHandlers, on_disk_cache: Option, incremental: bool, ) -> QuerySystem<'tcx> { @@ -252,6 +253,7 @@ pub fn query_system<'tcx>( engine: engine(incremental), local_providers, extern_providers, + cycle_handlers: cycle_decor_providers, encode_query_results: encode_all_query_results, try_mark_green, }, diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index a9153cbc90df4..c7b56c7f96b69 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -18,13 +18,15 @@ use rustc_middle::query::on_disk_cache::{ }; use rustc_middle::query::plumbing::QueryVTable; use rustc_middle::query::{ - Key, QueryCache, QueryJobId, QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, + CycleError, Key, QueryCache, QueryJobId, QueryStackDeferred, QueryStackFrame, + QueryStackFrameExtra, }; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::print::with_reduced_queries; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; use rustc_serialize::{Decodable, Encodable}; +use rustc_span::ErrorGuaranteed; use rustc_span::def_id::LOCAL_CRATE; use crate::error::{QueryOverflow, QueryOverflowNote}; @@ -309,19 +311,24 @@ where pub(crate) fn create_deferred_query_stack_frame<'tcx, Cache>( tcx: TyCtxt<'tcx>, vtable: &'tcx QueryVTable<'tcx, Cache>, + cycle_handler: Option, &CycleError) -> Option>, key: Cache::Key, ) -> QueryStackFrame> where Cache: QueryCache, Cache::Key: Key + DynSend + DynSync, { - let kind = vtable.dep_kind; - let def_id: Option = key.key_as_def_id(); let def_id_for_ty_in_cycle: Option = key.def_id_for_ty_in_cycle(); let info = QueryStackDeferred::new((tcx, vtable, key), mk_query_stack_frame_extra); - QueryStackFrame::new(info, kind, def_id, def_id_for_ty_in_cycle) + QueryStackFrame { + info, + cycle_handler, + dep_kind: vtable.dep_kind, + def_id, + def_id_for_ty_in_cycle, + } } pub(crate) fn encode_query_results<'a, 'tcx, Q, C: QueryCache, const FLAGS: QueryFlags>( @@ -647,7 +654,8 @@ macro_rules! define_queries { ) -> Option<()> { let make_frame = |tcx: TyCtxt<'tcx>, key| { let vtable = &tcx.query_system.query_vtables.$name; - $crate::plumbing::create_deferred_query_stack_frame(tcx, vtable, key) + let cycle_decorator = tcx.query_system.fns.cycle_handlers.$name; + $crate::plumbing::create_deferred_query_stack_frame(tcx, vtable, cycle_decorator, key) }; // Call `gather_active_jobs_inner` to do the actual work. diff --git a/compiler/rustc_query_impl/src/values.rs b/compiler/rustc_query_impl/src/values.rs index 8f55e98df867e..373d4a9d31aea 100644 --- a/compiler/rustc_query_impl/src/values.rs +++ b/compiler/rustc_query_impl/src/values.rs @@ -1,18 +1,15 @@ use std::collections::VecDeque; -use std::fmt::Write; use std::ops::ControlFlow; -use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; -use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; +use rustc_errors::{MultiSpan, struct_span_code_err}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::DefKind; use rustc_middle::dep_graph::DepKind; use rustc_middle::query::CycleError; use rustc_middle::query::plumbing::CyclePlaceholder; -use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span}; use crate::job::report_cycle; @@ -97,42 +94,6 @@ impl<'tcx> Value<'tcx> for ty::Binder<'_, ty::FnSig<'_>> { } } -impl<'tcx> Value<'tcx> for Representability { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle_error: &CycleError, - _guar: ErrorGuaranteed, - ) -> Self { - let mut item_and_field_ids = Vec::new(); - let mut representable_ids = FxHashSet::default(); - for info in &cycle_error.cycle { - if info.frame.dep_kind == DepKind::representability - && let Some(field_id) = info.frame.def_id - && let Some(field_id) = field_id.as_local() - && let Some(DefKind::Field) = info.frame.info.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_error.cycle { - if info.frame.dep_kind == DepKind::representability_adt_ty - && let Some(def_id) = info.frame.def_id_for_ty_in_cycle - && let Some(def_id) = def_id.as_local() - && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) - { - representable_ids.insert(def_id); - } - } - let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids); - Representability::Infinite(guar) - } -} - impl<'tcx> Value<'tcx> for ty::EarlyBinder<'_, Ty<'_>> { fn from_cycle_error( tcx: TyCtxt<'tcx>, @@ -291,134 +252,3 @@ impl<'tcx, T> Value<'tcx> for Result> { Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle(guar)))) } } - -// item_and_field_ids should form a cycle where each field contains the -// type in the next element in the list -fn recursive_type_error( - tcx: TyCtxt<'_>, - mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>, - representable_ids: &FxHashSet, -) -> ErrorGuaranteed { - 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::Node::Field(field) = tcx.hir_node_by_def_id(field_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); - 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 - }; - struct_span_code_err!( - tcx.dcx(), - err_span, - E0072, - "recursive type{} {} {} infinite size", - pluralize!(cycle_len), - items_list, - pluralize!("has", cycle_len), - ) - .with_multipart_suggestion( - "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle", - suggestion, - Applicability::HasPlaceholders, - ) - .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 Res::Def(kind, def_id) = path.res - && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union) - { - let check_params = def_id.as_local().is_none_or(|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); - // the domain size check is needed because the HIR may not be well-formed at this point - for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size()) - { - if let hir::GenericArg::Type(ty) = arg - && params_in_repr.contains(i as u32) - { - find_item_ty_spans( - tcx, - ty.as_unambig_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_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 2e21efbde1ac5..60f8b1d0cdbec 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -13,7 +13,7 @@ #![feature(never_type)] // tidy-alphabetical-end -use rustc_middle::query::Providers; +use rustc_middle::util::Providers; mod abi; mod assoc; @@ -32,17 +32,17 @@ mod structural_match; mod ty; pub fn provide(providers: &mut Providers) { - abi::provide(providers); - assoc::provide(providers); - common_traits::provide(providers); - consts::provide(providers); - implied_bounds::provide(providers); - layout::provide(providers); - needs_drop::provide(providers); - opaque_types::provide(providers); + abi::provide(&mut providers.queries); + assoc::provide(&mut providers.queries); + common_traits::provide(&mut providers.queries); + consts::provide(&mut providers.queries); + implied_bounds::provide(&mut providers.queries); + layout::provide(&mut providers.queries); + needs_drop::provide(&mut providers.queries); + opaque_types::provide(&mut providers.queries); representability::provide(providers); - ty::provide(providers); - instance::provide(providers); - structural_match::provide(providers); - nested_bodies::provide(providers); + ty::provide(&mut providers.queries); + instance::provide(&mut providers.queries); + structural_match::provide(&mut providers.queries); + nested_bodies::provide(&mut providers.queries); } diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 33d334092ba9c..ca07d3750794b 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -1,51 +1,54 @@ -use rustc_hir::def::DefKind; +use std::fmt::Write; + +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{Applicability, E0072, MultiSpan, pluralize, struct_span_code_err}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; -use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; +use rustc_middle::dep_graph::DepKind; +use rustc_middle::query::CycleError; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::util::Providers; use rustc_span::def_id::LocalDefId; +use rustc_span::{ErrorGuaranteed, Span}; pub(crate) fn provide(providers: &mut Providers) { - *providers = - Providers { representability, representability_adt_ty, params_in_repr, ..*providers }; -} - -macro_rules! rtry { - ($e:expr) => { - match $e { - e @ Representability::Infinite(_) => return e, - Representability::Representable => {} - } + providers.queries = rustc_middle::query::Providers { + representability, + representability_adt_ty, + params_in_repr, + ..providers.queries }; + providers.query_cycle_handlers.representability = Some(representability_cycle_decor); + providers.query_cycle_handlers.representability_adt_ty = Some(representability_cycle_decor); } -fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability { +fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) { match tcx.def_kind(def_id) { DefKind::Struct | DefKind::Union | DefKind::Enum => { for variant in tcx.adt_def(def_id).variants() { for field in variant.fields.iter() { - rtry!(tcx.representability(field.did.expect_local())); + let _ = tcx.representability(field.did.expect_local()); } } - Representability::Representable } DefKind::Field => representability_ty(tcx, tcx.type_of(def_id).instantiate_identity()), def_kind => bug!("unexpected {def_kind:?}"), } } -fn representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { +fn representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { 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_ty(tcx, ty); } - Representability::Representable } - _ => Representability::Representable, + _ => (), } } @@ -65,10 +68,10 @@ 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 { +fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { let ty::Adt(adt, args) = ty.kind() else { bug!("expected adt") }; if let Some(def_id) = adt.did().as_local() { - rtry!(tcx.representability(def_id)); + let _ = 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 @@ -76,11 +79,10 @@ fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representab for (i, arg) in args.iter().enumerate() { if let ty::GenericArgKind::Type(ty) = arg.kind() { if params_in_repr.contains(i as u32) { - rtry!(representability_ty(tcx, ty)); + representability_ty(tcx, ty); } } } - Representability::Representable } fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DenseBitSet { @@ -119,3 +121,166 @@ fn params_in_repr_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, params_in_repr: &mut _ => {} } } + +fn representability_cycle_decor( + tcx: TyCtxt<'_>, + cycle_error: &CycleError, +) -> Option { + let mut item_and_field_ids = Vec::new(); + let mut representable_ids = FxHashSet::default(); + for info in &cycle_error.cycle { + if info.frame.dep_kind == DepKind::representability + && let Some(field_id) = info.frame.def_id + && let Some(field_id) = field_id.as_local() + && let Some(DefKind::Field) = info.frame.info.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_error.cycle { + if info.frame.dep_kind == DepKind::representability_adt_ty + && let Some(def_id) = info.frame.def_id_for_ty_in_cycle + && let Some(def_id) = def_id.as_local() + && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) + { + representable_ids.insert(def_id); + } + } + Some(recursive_type_error(tcx, item_and_field_ids, &representable_ids)) +} + +// item_and_field_ids should form a cycle where each field contains the +// type in the next element in the list +fn recursive_type_error( + tcx: TyCtxt<'_>, + mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>, + representable_ids: &FxHashSet, +) -> ErrorGuaranteed { + 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::Node::Field(field) = tcx.hir_node_by_def_id(field_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); + 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 + }; + struct_span_code_err!( + tcx.dcx(), + err_span, + E0072, + "recursive type{} {} {} infinite size", + pluralize!(cycle_len), + items_list, + pluralize!("has", cycle_len), + ) + .with_multipart_suggestion( + "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle", + suggestion, + Applicability::HasPlaceholders, + ) + .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 Res::Def(kind, def_id) = path.res + && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union) + { + let check_params = def_id.as_local().is_none_or(|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); + // the domain size check is needed because the HIR may not be well-formed at this point + for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size()) + { + if let hir::GenericArg::Type(ty) = arg + && params_in_repr.contains(i as u32) + { + find_item_ty_spans( + tcx, + ty.as_unambig_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_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index d6a29aba22b90..dcff643f83188 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -116,10 +116,9 @@ fn adt_sizedness_constraint<'tcx>( tcx: TyCtxt<'tcx>, (def_id, sizedness): (DefId, SizedTraitKind), ) -> Option>> { - if let Some(def_id) = def_id.as_local() - && let ty::Representability::Infinite(_) = tcx.representability(def_id) - { - return None; + if let Some(def_id) = def_id.as_local() { + // Check for a cycle + let _ = tcx.representability(def_id); } let def = tcx.adt_def(def_id); diff --git a/tests/ui/enum-discriminant/issue-72554.rs b/tests/ui/enum-discriminant/issue-72554.rs index 1fe9a5f4faa7d..99ec67255a90c 100644 --- a/tests/ui/enum-discriminant/issue-72554.rs +++ b/tests/ui/enum-discriminant/issue-72554.rs @@ -3,13 +3,11 @@ use std::collections::BTreeSet; #[derive(Hash)] pub enum ElemDerived { //~^ ERROR recursive type `ElemDerived` has infinite size - //~| ERROR cycle detected - A(ElemDerived) + A(ElemDerived), } - pub enum Elem { - Derived(ElemDerived) + Derived(ElemDerived), } pub struct Set(BTreeSet); diff --git a/tests/ui/enum-discriminant/issue-72554.stderr b/tests/ui/enum-discriminant/issue-72554.stderr index 648680c6031da..c3d2ebcc972fa 100644 --- a/tests/ui/enum-discriminant/issue-72554.stderr +++ b/tests/ui/enum-discriminant/issue-72554.stderr @@ -3,30 +3,15 @@ error[E0072]: recursive type `ElemDerived` has infinite size | LL | pub enum ElemDerived { | ^^^^^^^^^^^^^^^^^^^^ -... -LL | A(ElemDerived) +LL | +LL | A(ElemDerived), | ----------- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | -LL | A(Box) +LL | A(Box), | ++++ + -error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived` - --> $DIR/issue-72554.rs:4:1 - | -LL | pub enum ElemDerived { - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again -note: cycle used when computing drop-check constraints for `Elem` - --> $DIR/issue-72554.rs:11:1 - | -LL | pub enum Elem { - | ^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/infinite/infinite-struct.rs b/tests/ui/infinite/infinite-struct.rs index d784455824604..5a8be69ebea89 100644 --- a/tests/ui/infinite/infinite-struct.rs +++ b/tests/ui/infinite/infinite-struct.rs @@ -1,7 +1,5 @@ struct Take(Take); //~^ ERROR has infinite size -//~| ERROR cycle -//~| ERROR reached the recursion limit finding the struct tail for `Take` // check that we don't hang trying to find the tail of a recursive struct (#79437) fn foo() -> Take { @@ -9,7 +7,8 @@ fn foo() -> Take { } // mutually infinite structs -struct Foo { //~ ERROR has infinite size +struct Foo { + //~^ ERROR has infinite size x: Bar, } diff --git a/tests/ui/infinite/infinite-struct.stderr b/tests/ui/infinite/infinite-struct.stderr index 0d1ec4989aa53..1cd9b0a4ed16a 100644 --- a/tests/ui/infinite/infinite-struct.stderr +++ b/tests/ui/infinite/infinite-struct.stderr @@ -10,10 +10,11 @@ LL | struct Take(Box); | ++++ + error[E0072]: recursive type `Foo` has infinite size - --> $DIR/infinite-struct.rs:12:1 + --> $DIR/infinite-struct.rs:10:1 | LL | struct Foo { | ^^^^^^^^^^ +LL | LL | x: Bar, | --- recursive without indirection | @@ -22,25 +23,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | x: Bar>, | ++++ + -error: reached the recursion limit finding the struct tail for `Take` - --> $DIR/infinite-struct.rs:1:1 - | -LL | struct Take(Take); - | ^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` - -error[E0391]: cycle detected when computing when `Take` needs drop - --> $DIR/infinite-struct.rs:1:1 - | -LL | struct Take(Take); - | ^^^^^^^^^^^ - | - = note: ...which immediately requires computing when `Take` needs drop again - = note: cycle used when computing whether `Take` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/infinite/infinite-tag-type-recursion.rs b/tests/ui/infinite/infinite-tag-type-recursion.rs index 1b5cb55b4e4d1..9d2d8a411ca16 100644 --- a/tests/ui/infinite/infinite-tag-type-recursion.rs +++ b/tests/ui/infinite/infinite-tag-type-recursion.rs @@ -1,5 +1,9 @@ -enum MList { Cons(isize, MList), Nil } -//~^ ERROR recursive type `MList` has infinite size -//~| ERROR cycle +enum MList { + //~^ ERROR recursive type `MList` has infinite size + Cons(isize, MList), + Nil, +} -fn main() { let a = MList::Cons(10, MList::Cons(11, MList::Nil)); } +fn main() { + let a = MList::Cons(10, MList::Cons(11, MList::Nil)); +} diff --git a/tests/ui/infinite/infinite-tag-type-recursion.stderr b/tests/ui/infinite/infinite-tag-type-recursion.stderr index 8745224a45e13..4603b557159bb 100644 --- a/tests/ui/infinite/infinite-tag-type-recursion.stderr +++ b/tests/ui/infinite/infinite-tag-type-recursion.stderr @@ -1,25 +1,17 @@ error[E0072]: recursive type `MList` has infinite size --> $DIR/infinite-tag-type-recursion.rs:1:1 | -LL | enum MList { Cons(isize, MList), Nil } - | ^^^^^^^^^^ ----- recursive without indirection +LL | enum MList { + | ^^^^^^^^^^ +LL | +LL | Cons(isize, MList), + | ----- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | -LL | enum MList { Cons(isize, Box), Nil } - | ++++ + - -error[E0391]: cycle detected when computing when `MList` needs drop - --> $DIR/infinite-tag-type-recursion.rs:1:1 - | -LL | enum MList { Cons(isize, MList), Nil } - | ^^^^^^^^^^ - | - = note: ...which immediately requires computing when `MList` needs drop again - = note: cycle used when computing whether `MList` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +LL | Cons(isize, Box), + | ++++ + -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/query-system/query-cycle-printing-issue-151226.rs b/tests/ui/query-system/query-cycle-printing-issue-151226.rs index 9d0a20737c9fa..551321619ddd0 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151226.rs +++ b/tests/ui/query-system/query-cycle-printing-issue-151226.rs @@ -1,8 +1,6 @@ struct A(std::sync::OnceLock); //~^ ERROR recursive type `A` has infinite size -//~| ERROR cycle detected when computing layout of `A<()>` static B: A<()> = todo!(); -//~^ ERROR cycle occurred during layout computation fn main() {} diff --git a/tests/ui/query-system/query-cycle-printing-issue-151226.stderr b/tests/ui/query-system/query-cycle-printing-issue-151226.stderr index 7e574b5911a39..bb05cf5f915d7 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151226.stderr +++ b/tests/ui/query-system/query-cycle-printing-issue-151226.stderr @@ -9,28 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | struct A(Box>); | ++++ + -error[E0391]: cycle detected when computing layout of `A<()>` - | - = note: ...which requires computing layout of `std::sync::once_lock::OnceLock>`... - = note: ...which requires computing layout of `core::cell::UnsafeCell>>`... - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit>`... - = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop>`... - = note: ...which requires computing layout of `core::mem::maybe_dangling::MaybeDangling>`... - = note: ...which again requires computing layout of `A<()>`, completing the cycle -note: cycle used when checking that `B` is well-formed - --> $DIR/query-cycle-printing-issue-151226.rs:5:1 - | -LL | static B: A<()> = todo!(); - | ^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0080]: a cycle occurred during layout computation - --> $DIR/query-cycle-printing-issue-151226.rs:5:1 - | -LL | static B: A<()> = todo!(); - | ^^^^^^^^^^^^^^^ evaluation of `B` failed here - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0080, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs index a3b510848dcd3..ad1885d1ee3de 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs @@ -1,9 +1,12 @@ use std::cell::UnsafeCell; -enum Foo { X(UnsafeCell>) } -//~^ ERROR recursive type `Foo` has infinite size -//~| ERROR cycle detected +enum Foo { + //~^ ERROR recursive type `Foo` has infinite size + X(UnsafeCell>), +} -impl Foo { fn bar(self) {} } +impl Foo { + fn bar(self) {} +} fn main() {} diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr index b192593d266b7..b0f196713247d 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr @@ -1,25 +1,17 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-6.rs:3:1 | -LL | enum Foo { X(UnsafeCell>) } - | ^^^^^^^^ --- recursive without indirection +LL | enum Foo { + | ^^^^^^^^ +LL | +LL | X(UnsafeCell>), + | --- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | -LL | enum Foo { X(UnsafeCell>>) } - | ++++ + - -error[E0391]: cycle detected when computing when `Foo` needs drop - --> $DIR/issue-17431-6.rs:3:1 - | -LL | enum Foo { X(UnsafeCell>) } - | ^^^^^^^^ - | - = note: ...which immediately requires computing when `Foo` needs drop again - = note: cycle used when computing whether `Foo` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +LL | X(UnsafeCell>>), + | ++++ + -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/traits/issue-105231.rs b/tests/ui/traits/issue-105231.rs index 83c3158c106b6..9e47ded7c8c81 100644 --- a/tests/ui/traits/issue-105231.rs +++ b/tests/ui/traits/issue-105231.rs @@ -6,5 +6,4 @@ struct B(A>); trait Foo {} impl Foo for T where T: Send {} impl Foo for B {} -//~^ ERROR conflicting implementations of trait `Foo` for type `B` fn main() {} diff --git a/tests/ui/traits/issue-105231.stderr b/tests/ui/traits/issue-105231.stderr index b048548018a71..6732d4f5803c9 100644 --- a/tests/ui/traits/issue-105231.stderr +++ b/tests/ui/traits/issue-105231.stderr @@ -37,18 +37,6 @@ LL | struct B(A>); = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = note: all type parameters must be used in a non-recursive way in order to constrain their variance -error[E0119]: conflicting implementations of trait `Foo` for type `B` - --> $DIR/issue-105231.rs:8:1 - | -LL | impl Foo for T where T: Send {} - | ------------------------------- first implementation here -LL | impl Foo for B {} - | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `B` - | - = note: overflow evaluating the requirement `B: Send` - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_105231`) - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0072, E0119. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs index 8d291054365f9..d3a6ba94b68fb 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs @@ -1,4 +1,3 @@ -//~ ERROR: cycle detected //! Safe transmute did not handle cycle errors that could occur during //! layout computation. This test checks that we do not ICE in such //! situations (see #117491). diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index a96876a2c25a1..0b5689e1912f0 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -1,5 +1,5 @@ error[E0072]: recursive type `ExplicitlyPadded` has infinite size - --> $DIR/transmute_infinitely_recursive_type.rs:21:5 + --> $DIR/transmute_infinitely_recursive_type.rs:20:5 | LL | struct ExplicitlyPadded(ExplicitlyPadded); | ^^^^^^^^^^^^^^^^^^^^^^^ ---------------- recursive without indirection @@ -9,13 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | struct ExplicitlyPadded(Box); | ++++ + -error[E0391]: cycle detected when computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` - | - = note: ...which immediately requires computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` again - = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`.