Skip to content

Rollup of 5 pull requests #95526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 31, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -253,8 +253,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let constraint_sets: Vec<_> = unnormalized_input_output_tys
.flat_map(|ty| {
debug!("build: input_or_output={:?}", ty);
// We add implied bounds from both the unnormalized and normalized ty
// See issue #87748
// We only add implied bounds for the normalized type as the unnormalized
// type may not actually get checked by the caller.
//
// Can otherwise be unsound, see #91068.
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
4 changes: 3 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
@@ -1899,7 +1899,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ObligationCause::new(
span,
self.tcx().hir().local_def_id_to_hir_id(def_id),
traits::ObligationCauseCode::RepeatVec(is_const_fn),
traits::ObligationCauseCode::RepeatElementCopy {
is_const_fn,
},
),
self.param_env,
ty::Binder::dummy(ty::TraitRef::new(
1 change: 0 additions & 1 deletion compiler/rustc_infer/src/infer/at.rs
Original file line number Diff line number Diff line change
@@ -65,7 +65,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Self {
tcx: self.tcx.clone(),
defining_use_anchor: self.defining_use_anchor.clone(),
reveal_defining_opaque_types: self.reveal_defining_opaque_types.clone(),
in_progress_typeck_results: self.in_progress_typeck_results.clone(),
inner: self.inner.clone(),
skip_leak_check: self.skip_leak_check.clone(),
27 changes: 2 additions & 25 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
@@ -290,10 +290,6 @@ pub struct InferCtxt<'a, 'tcx> {
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
pub defining_use_anchor: Option<LocalDefId>,

/// Used by WF-checking to not have to figure out hidden types itself, but
/// to just invoke type_of to get the already computed hidden type from typeck.
pub reveal_defining_opaque_types: bool,

/// During type-checking/inference of a body, `in_progress_typeck_results`
/// contains a reference to the typeck results being built up, which are
/// used for reading closure kinds/signatures as they are inferred,
@@ -569,7 +565,6 @@ pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
defining_use_anchor: Option<LocalDefId>,
reveal_defining_opaque_types: bool,
}

pub trait TyCtxtInferExt<'tcx> {
@@ -578,12 +573,7 @@ pub trait TyCtxtInferExt<'tcx> {

impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
InferCtxtBuilder {
tcx: self,
defining_use_anchor: None,
fresh_typeck_results: None,
reveal_defining_opaque_types: false,
}
InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
}
}

@@ -607,13 +597,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
self
}

/// WF-checking doesn't need to recompute opaque types and can instead use
/// the type_of query to get them from typeck.
pub fn reveal_defining_opaque_types(mut self) -> Self {
self.reveal_defining_opaque_types = true;
self
}

/// Given a canonical value `C` as a starting point, create an
/// inference context that contains each of the bound values
/// within instantiated as a fresh variable. The `f` closure is
@@ -638,17 +621,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
}

pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
let InferCtxtBuilder {
tcx,
defining_use_anchor,
reveal_defining_opaque_types,
ref fresh_typeck_results,
} = *self;
let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
let in_progress_typeck_results = fresh_typeck_results.as_ref();
f(InferCtxt {
tcx,
defining_use_anchor,
reveal_defining_opaque_types,
in_progress_typeck_results,
inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None),
11 changes: 6 additions & 5 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -236,11 +236,12 @@ pub enum ObligationCauseCode<'tcx> {
SizedBoxType,
/// Inline asm operand type must be `Sized`.
InlineAsmSized,
/// `[T, ..n]` implies that `T` must be `Copy`.
/// If the function in the array repeat expression is a `const fn`,
/// display a help message suggesting to move the function call to a
/// new `const` item while saying that `T` doesn't implement `Copy`.
RepeatVec(bool),
/// `[expr; N]` requires `type_of(expr): Copy`.
RepeatElementCopy {
/// If element is a `const fn` we display a help message suggesting to move the
/// function call to a new `const` item while saying that `T` doesn't implement `Copy`.
is_const_fn: bool,
},

/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
FieldSized {
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
@@ -198,7 +198,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let kind = match pat.kind {
hir::PatKind::Wild => PatKind::Wild,

hir::PatKind::Lit(ref value) => self.lower_lit(value),
hir::PatKind::Lit(value) => self.lower_lit(value),

hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
59 changes: 48 additions & 11 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
@@ -2285,10 +2285,10 @@ impl<'v> Visitor<'v> for FindTypeParam {
}
}

pub fn recursive_type_with_infinite_size_error(
tcx: TyCtxt<'_>,
pub fn recursive_type_with_infinite_size_error<'tcx>(
tcx: TyCtxt<'tcx>,
type_def_id: DefId,
spans: Vec<Span>,
spans: Vec<(Span, Option<hir::HirId>)>,
) {
assert!(type_def_id.is_local());
let span = tcx.hir().span_if_local(type_def_id).unwrap();
@@ -2297,24 +2297,33 @@ pub fn recursive_type_with_infinite_size_error(
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 {
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
.iter()
.flat_map(|&span| {
[
(span.shrink_to_lo(), "Box<".to_string()),
(span.shrink_to_hi(), ">".to_string()),
]
.into_iter()
.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,
@@ -2325,6 +2334,34 @@ pub fn recursive_type_with_infinite_size_error(
err.emit();
}

/// Extract the span for the generic type `T` of `Option<T>` in a field definition
fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option<hir::HirId>) -> Option<Span> {
let node = tcx.hir().find(field_id?);

// Expect a field from our field_id
let Some(hir::Node::Field(field_def)) = node
else { bug!("Expected HirId corresponding to FieldDef, found: {:?}", node) };

// Match a type that is a simple QPath with no Self
let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = &field_def.ty.kind
else { return None };

// Check if the path we're checking resolves to Option
let hir::def::Res::Def(_, did) = path.res
else { return None };

// Bail if this path doesn't describe `::core::option::Option`
if !tcx.is_diagnostic_item(sym::Option, did) {
return None;
}

// Match a single generic arg in the 0th path segment
let generic_arg = path.segments.last()?.args?.args.get(0)?;

// Take the span out of the type, if it's a type
if let hir::GenericArg::Type(generic_ty) = generic_arg { Some(generic_ty.span) } else { None }
}

/// Summarizes information
#[derive(Clone)]
pub enum ArgKind {
Original file line number Diff line number Diff line change
@@ -1988,7 +1988,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
ObligationCauseCode::Coercion { source: _, target } => {
err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
}
ObligationCauseCode::RepeatVec(is_const_fn) => {
ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
err.note(
"the `Copy` trait is required because the repeated element will be copied",
);
70 changes: 47 additions & 23 deletions compiler/rustc_ty_utils/src/representability.rs
Original file line number Diff line number Diff line change
@@ -17,12 +17,20 @@ use std::cmp;
pub enum Representability {
Representable,
ContainsRecursive,
SelfRecursive(Vec<Span>),
/// Return a list of types that are included in themselves:
/// the spans where they are self-included, and (if found)
/// the HirId of the FieldDef that defines the self-inclusion.
SelfRecursive(Vec<(Span, Option<hir::HirId>)>),
}

/// Check whether a type is representable. This means it cannot contain unboxed
/// structural recursion. This check is needed for structs and enums.
pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> Representability {
pub fn ty_is_representable<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
sp: Span,
field_id: Option<hir::HirId>,
) -> Representability {
debug!("is_type_representable: {:?}", ty);
// To avoid a stack overflow when checking an enum variant or struct that
// contains a different, structurally recursive type, maintain a stack of
@@ -38,11 +46,12 @@ pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> R
let mut force_result = false;
let r = is_type_structurally_recursive(
tcx,
sp,
&mut seen,
&mut shadow_seen,
&mut representable_cache,
ty,
sp,
field_id,
&mut force_result,
);
debug!("is_type_representable: {:?} is {:?}", ty, r);
@@ -61,11 +70,12 @@ fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representabilit

fn are_inner_types_recursive<'tcx>(
tcx: TyCtxt<'tcx>,
sp: Span,
seen: &mut Vec<Ty<'tcx>>,
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
ty: Ty<'tcx>,
sp: Span,
field_id: Option<hir::HirId>,
force_result: &mut bool,
) -> Representability {
debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
@@ -75,11 +85,12 @@ fn are_inner_types_recursive<'tcx>(
fold_repr(fields.iter().map(|ty| {
is_type_structurally_recursive(
tcx,
sp,
seen,
shadow_seen,
representable_cache,
ty,
sp,
field_id,
force_result,
)
}))
@@ -88,20 +99,26 @@ fn are_inner_types_recursive<'tcx>(
// FIXME(#11924) Behavior undecided for zero-length vectors.
ty::Array(ty, _) => is_type_structurally_recursive(
tcx,
sp,
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 span = match field.did.as_local().and_then(|id| tcx.hir().find_by_def_id(id)) {
Some(hir::Node::Field(field)) => field.ty.span,
_ => sp,
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;
@@ -130,7 +147,7 @@ fn are_inner_types_recursive<'tcx>(
// result without adjusting).
if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
*force_result = true;
result = Some(Representability::SelfRecursive(vec![span]));
result = Some(Representability::SelfRecursive(vec![(sp, field_id)]));
}

if result == None {
@@ -161,16 +178,17 @@ fn are_inner_types_recursive<'tcx>(
result = Some(
match is_type_structurally_recursive(
tcx,
span,
&mut nested_seen,
shadow_seen,
representable_cache,
raw_adt_ty,
sp,
field_id,
force_result,
) {
Representability::SelfRecursive(_) => {
if *force_result {
Representability::SelfRecursive(vec![span])
Representability::SelfRecursive(vec![(sp, field_id)])
} else {
Representability::ContainsRecursive
}
@@ -208,15 +226,16 @@ fn are_inner_types_recursive<'tcx>(
result = Some(
match is_type_structurally_recursive(
tcx,
span,
seen,
shadow_seen,
representable_cache,
ty,
sp,
field_id,
force_result,
) {
Representability::SelfRecursive(_) => {
Representability::SelfRecursive(vec![span])
Representability::SelfRecursive(vec![(sp, field_id)])
}
x => x,
},
@@ -247,29 +266,31 @@ fn same_adt<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
// contain any types on stack `seen`?
fn is_type_structurally_recursive<'tcx>(
tcx: TyCtxt<'tcx>,
sp: Span,
seen: &mut Vec<Ty<'tcx>>,
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
ty: Ty<'tcx>,
sp: Span,
field_id: Option<hir::HirId>,
force_result: &mut bool,
) -> Representability {
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
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, representability
"is_type_structurally_recursive: {:?} {:?} {:?} - (cached) {:?}",
ty, sp, field_id, representability
);
return representability.clone();
}

let representability = is_type_structurally_recursive_inner(
tcx,
sp,
seen,
shadow_seen,
representable_cache,
ty,
sp,
field_id,
force_result,
);

@@ -279,11 +300,12 @@ fn is_type_structurally_recursive<'tcx>(

fn is_type_structurally_recursive_inner<'tcx>(
tcx: TyCtxt<'tcx>,
sp: Span,
seen: &mut Vec<Ty<'tcx>>,
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
ty: Ty<'tcx>,
sp: Span,
field_id: Option<hir::HirId>,
force_result: &mut bool,
) -> Representability {
match ty.kind() {
@@ -305,7 +327,7 @@ fn is_type_structurally_recursive_inner<'tcx>(
if let Some(&seen_adt) = iter.next() {
if same_adt(seen_adt, *def) {
debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
return Representability::SelfRecursive(vec![sp]);
return Representability::SelfRecursive(vec![(sp, field_id)]);
}
}

@@ -335,11 +357,12 @@ fn is_type_structurally_recursive_inner<'tcx>(
shadow_seen.push(*def);
let out = are_inner_types_recursive(
tcx,
sp,
seen,
shadow_seen,
representable_cache,
ty,
sp,
field_id,
force_result,
);
shadow_seen.pop();
@@ -350,11 +373,12 @@ fn is_type_structurally_recursive_inner<'tcx>(
// No need to push in other cases.
are_inner_types_recursive(
tcx,
sp,
seen,
shadow_seen,
representable_cache,
ty,
sp,
field_id,
force_result,
)
}
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
@@ -1045,7 +1045,7 @@ pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalD
// 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) {
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;
7 changes: 0 additions & 7 deletions compiler/rustc_typeck/src/check/inherited.rs
Original file line number Diff line number Diff line change
@@ -95,13 +95,6 @@ impl<'tcx> InheritedBuilder<'tcx> {
let def_id = self.def_id;
self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
}

/// WF-checking doesn't need to recompute opaque types and can instead use
/// the type_of query to get them from typeck.
pub fn reveal_defining_opaque_types(mut self) -> Self {
self.infcx = self.infcx.reveal_defining_opaque_types();
self
}
}

impl<'a, 'tcx> Inherited<'a, 'tcx> {
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -968,7 +968,7 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<

fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
CheckWfFcxBuilder {
inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(),
inherited: Inherited::build(tcx, def_id),
id: hir::HirId::make_owner(def_id),
span,
param_env: tcx.param_env(def_id),
8 changes: 4 additions & 4 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
@@ -84,7 +84,7 @@
//! have to change, and is it worse or better now? Would any patterns become truly inexpressible?
//! Could we carve out special exceptions for those patterns? Should we?
//!
//! A secondary goal of this project is to see if we can disamiguate the many functions of
//! A secondary goal of this project is to see if we can disambiguate the many functions of
//! pointer<->integer casts enough for the definition of `usize` to be loosened so that it
//! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue
//! to conflate these notions). This would potentially make it possible to more efficiently
@@ -163,7 +163,7 @@
//! of pointers and `usize` (and `isize`), and defining a pointer to semantically contain the
//! following information:
//!
//! * The **address-space** it is part of (i.e. "data" vs "code" in WASM).
//! * The **address-space** it is part of (e.g. "data" vs "code" in WASM).
//! * The **address** it points to, which can be represented by a `usize`.
//! * The **provenance** it has, defining the memory it has permission to access.
//!
@@ -246,7 +246,7 @@
//! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers,
//! we would like to know why, and what needs to be done to fix it.)
//!
//! Something more complicated and just generally *evil* like a XOR-List requires more significant
//! Something more complicated and just generally *evil* like an XOR-List requires more significant
//! changes like allocating all nodes in a pre-allocated Vec or Arena and using a pointer
//! to the whole allocation to reconstitute the XORed addresses.
//!
@@ -257,7 +257,7 @@
//! special attention at all, because they're generally accessing memory outside the scope of
//! "the abstract machine", or already using "I know what I'm doing" annotations like "volatile".
//!
//! Under [Strict Provenance] is is Undefined Behaviour to:
//! Under [Strict Provenance] it is Undefined Behaviour to:
//!
//! * Access memory through a pointer that does not have provenance over that memory.
//!
7 changes: 4 additions & 3 deletions library/core/src/sync/atomic.rs
Original file line number Diff line number Diff line change
@@ -65,9 +65,10 @@
//! For reference, the `std` library requires `AtomicBool`s and pointer-sized atomics, although
//! `core` does not.
//!
//! Currently you'll need to use `#[cfg(target_arch)]` primarily to
//! conditionally compile in code with atomics. There is an unstable
//! `#[cfg(target_has_atomic)]` as well which may be stabilized in the future.
//! The `#[cfg(target_has_atomic)]` attribute can be used to conditionally
//! compile based on the target's supported bit widths. It is a key-value
//! option set for each supported size, with values "8", "16", "32", "64",
//! "128", and "ptr" for pointer-sized atomics.
//!
//! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm
//!
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-17431-1.stderr
Original file line number Diff line number Diff line change
@@ -8,8 +8,8 @@ LL | struct Foo { foo: Option<Option<Foo>> }
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | struct Foo { foo: Box<Option<Option<Foo>>> }
| ++++ +
LL | struct Foo { foo: Option<Box<Option<Foo>>> }
| ++++ +

error: aborting due to previous error

8 changes: 4 additions & 4 deletions src/test/ui/issues/issue-17431-2.stderr
Original file line number Diff line number Diff line change
@@ -8,8 +8,8 @@ LL | struct Baz { q: Option<Foo> }
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
LL | struct Baz { q: Box<Option<Foo>> }
| ++++ +
LL | struct Baz { q: Option<Box<Foo>> }
| ++++ +

error[E0072]: recursive type `Foo` has infinite size
--> $DIR/issue-17431-2.rs:4:1
@@ -21,8 +21,8 @@ LL | struct Foo { q: Option<Baz> }
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | struct Foo { q: Box<Option<Baz>> }
| ++++ +
LL | struct Foo { q: Option<Box<Baz>> }
| ++++ +

error: aborting due to 2 previous errors

4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-17431-4.stderr
Original file line number Diff line number Diff line change
@@ -8,8 +8,8 @@ LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T>
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | struct Foo<T> { foo: Box<Option<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
| ++++ +
LL | struct Foo<T> { foo: Option<Box<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
| ++++ +

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-17431-7.stderr
Original file line number Diff line number Diff line change
@@ -8,8 +8,8 @@ LL | enum Foo { Voo(Option<Option<Foo>>) }
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | enum Foo { Voo(Box<Option<Option<Foo>>>) }
| ++++ +
LL | enum Foo { Voo(Option<Box<Option<Foo>>>) }
| ++++ +

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-3779.stderr
Original file line number Diff line number Diff line change
@@ -9,8 +9,8 @@ LL | element: Option<S>
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable
|
LL | element: Box<Option<S>>
| ++++ +
LL | element: Option<Box<S>>
| ++++ +

error: aborting due to previous error

8 changes: 4 additions & 4 deletions src/test/ui/sized-cycle-note.stderr
Original file line number Diff line number Diff line change
@@ -8,8 +8,8 @@ LL | struct Baz { q: Option<Foo> }
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
LL | struct Baz { q: Box<Option<Foo>> }
| ++++ +
LL | struct Baz { q: Option<Box<Foo>> }
| ++++ +

error[E0072]: recursive type `Foo` has infinite size
--> $DIR/sized-cycle-note.rs:11:1
@@ -21,8 +21,8 @@ LL | struct Foo { q: Option<Baz> }
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | struct Foo { q: Box<Option<Baz>> }
| ++++ +
LL | struct Foo { q: Option<Box<Baz>> }
| ++++ +

error: aborting due to 2 previous errors

4 changes: 2 additions & 2 deletions src/test/ui/span/E0072.stderr
Original file line number Diff line number Diff line change
@@ -9,8 +9,8 @@ LL | tail: Option<ListNode>,
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
|
LL | tail: Box<Option<ListNode>>,
| ++++ +
LL | tail: Option<Box<ListNode>>,
| ++++ +

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/span/multiline-span-E0072.stderr
Original file line number Diff line number Diff line change
@@ -12,8 +12,8 @@ LL | | }
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
|
LL | tail: Box<Option<ListNode>>,
| ++++ +
LL | tail: Option<Box<ListNode>>,
| ++++ +

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -37,8 +37,8 @@ LL | y: Option<Option<D<T>>>,
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable
|
LL | y: Box<Option<Option<D<T>>>>,
| ++++ +
LL | y: Option<Box<Option<D<T>>>>,
| ++++ +

error[E0072]: recursive type `D` has infinite size
--> $DIR/mutual-struct-recursion.rs:18:1
@@ -51,8 +51,8 @@ LL | z: Option<Option<C<T>>>,
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable
|
LL | z: Box<Option<Option<C<T>>>>,
| ++++ +
LL | z: Option<Box<Option<C<T>>>>,
| ++++ +

error: aborting due to 4 previous errors

12 changes: 12 additions & 0 deletions src/test/ui/type/type-recursive-box-shadowed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//FIXME(compiler-errors): This fixup should suggest the full box path, not just `Box`

struct Box<T> {
t: T,
}

struct Foo {
//~^ ERROR recursive type `Foo` has infinite size
inner: Foo,
}

fn main() {}
17 changes: 17 additions & 0 deletions src/test/ui/type/type-recursive-box-shadowed.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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
|
LL | inner: Box<Foo>,
| ++++ +

error: aborting due to previous error

For more information about this error, try `rustc --explain E0072`.
26 changes: 25 additions & 1 deletion src/test/ui/type/type-recursive.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
struct T1 { //~ ERROR E0072
foo: isize,
foolish: T1
foolish: T1,
}

struct T2 { //~ ERROR E0072
inner: Option<T2>,
}

type OptionT3 = Option<T3>;

struct T3 { //~ ERROR E0072
inner: OptionT3,
}

struct T4(Option<T4>); //~ ERROR E0072

enum T5 { //~ ERROR E0072
Variant(Option<T5>),
}

enum T6 { //~ ERROR E0072
Variant{ field: Option<T6> },
}

struct T7 { //~ ERROR E0072
foo: std::cell::Cell<Option<T7>>,
}

fn main() { }
85 changes: 82 additions & 3 deletions src/test/ui/type/type-recursive.stderr
Original file line number Diff line number Diff line change
@@ -4,14 +4,93 @@ error[E0072]: recursive type `T1` has infinite size
LL | struct T1 {
| ^^^^^^^^^ recursive type has infinite size
LL | foo: isize,
LL | foolish: T1
LL | foolish: T1,
| -- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T1` representable
|
LL | foolish: Box<T1>
LL | foolish: Box<T1>,
| ++++ +

error: aborting due to previous error
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<T2>,
| ---------- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T2` representable
|
LL | inner: Option<Box<T2>>,
| ++++ +

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
|
LL | inner: Box<OptionT3>,
| ++++ +

error[E0072]: recursive type `T4` has infinite size
--> $DIR/type-recursive.rs:16:1
|
LL | struct T4(Option<T4>);
| ^^^^^^^^^^----------^^
| | |
| | recursive without indirection
| recursive type has infinite size
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T4` representable
|
LL | struct T4(Option<Box<T4>>);
| ++++ +

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<T5>),
| ---------- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T5` representable
|
LL | Variant(Option<Box<T5>>),
| ++++ +

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<T6> },
| ---------- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T6` representable
|
LL | Variant{ field: Option<Box<T6>> },
| ++++ +

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<Option<T7>>,
| --------------------------- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T7` representable
|
LL | foo: Box<std::cell::Cell<Option<T7>>>,
| ++++ +

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0072`.