Detect cycles and specialize error reporting for Sized. It is important

to get the `Sized` error usable, since that hits new users
frequently. Further work is needed for the error reporting for non-Sized
cycle cases; those currently just fallback to the old path. Also adjust tests.
This commit is contained in:
Niko Matsakis 2016-01-08 21:41:37 -05:00
parent 4bbe532737
commit 3046ac217f
40 changed files with 291 additions and 92 deletions

View File

@ -712,6 +712,43 @@ There's no easy fix for this, generally code will need to be refactored so that
you no longer need to derive from `Super<Self>`.
"####,
E0072: r##"
When defining a recursive struct or enum, any use of the type being defined
from inside the definition must occur behind a pointer (like `Box` or `&`).
This is because structs and enums must have a well-defined size, and without
the pointer the size of the type would need to be unbounded.
Consider the following erroneous definition of a type for a list of bytes:
```
// error, invalid recursive struct type
struct ListNode {
head: u8,
tail: Option<ListNode>,
}
```
This type cannot have a well-defined size, because it needs to be arbitrarily
large (since we would be able to nest `ListNode`s to any depth). Specifically,
```plain
size of `ListNode` = 1 byte for `head`
+ 1 byte for the discriminant of the `Option`
+ size of `ListNode`
```
One way to fix this is by wrapping `ListNode` in a `Box`, like so:
```
struct ListNode {
head: u8,
tail: Option<Box<ListNode>>,
}
```
This works because `Box` is a pointer, so its size is well-known.
"##,
E0109: r##"
You tried to give a type parameter to a type which doesn't need it. Erroneous
code example:

View File

@ -182,7 +182,8 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
/// if the program type checks or not -- and they are unusual
/// occurrences in any case.
pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &Obligation<'tcx, T>)
obligation: &Obligation<'tcx, T>,
suggest_increasing_limit: bool)
-> !
where T: fmt::Display + TypeFoldable<'tcx>
{
@ -192,7 +193,9 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
"overflow evaluating the requirement `{}`",
predicate);
suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span);
if suggest_increasing_limit {
suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span);
}
note_obligation_cause(infcx, &mut err, obligation);
@ -201,6 +204,141 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
unreachable!();
}
/// Reports that a cycle was detected which led to overflow and halts
/// compilation. This is equivalent to `report_overflow_error` except
/// that we can give a more helpful error message (and, in particular,
/// we do not suggest increasing the overflow limit, which is not
/// going to help).
pub fn report_overflow_error_cycle<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
cycle: &Vec<PredicateObligation<'tcx>>)
-> !
{
assert!(cycle.len() > 1);
debug!("report_overflow_error_cycle(cycle length = {})", cycle.len());
let cycle = infcx.resolve_type_vars_if_possible(cycle);
debug!("report_overflow_error_cycle: cycle={:?}", cycle);
assert_eq!(&cycle[0].predicate, &cycle.last().unwrap().predicate);
try_report_overflow_error_type_of_infinite_size(infcx, &cycle);
report_overflow_error(infcx, &cycle[0], false);
}
/// If a cycle results from evaluated whether something is Sized, that
/// is a particular special case that always results from a struct or
/// enum definition that lacks indirection (e.g., `struct Foo { x: Foo
/// }`). We wish to report a targeted error for this case.
pub fn try_report_overflow_error_type_of_infinite_size<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
cycle: &[PredicateObligation<'tcx>])
{
let sized_trait = match infcx.tcx.lang_items.sized_trait() {
Some(v) => v,
None => return,
};
let top_is_sized = {
match cycle[0].predicate {
ty::Predicate::Trait(ref data) => data.def_id() == sized_trait,
_ => false,
}
};
if !top_is_sized {
return;
}
// The only way to have a type of infinite size is to have,
// somewhere, a struct/enum type involved. Identify all such types
// and report the cycle to the user.
let struct_enum_tys: Vec<_> =
cycle.iter()
.flat_map(|obligation| match obligation.predicate {
ty::Predicate::Trait(ref data) => {
assert_eq!(data.def_id(), sized_trait);
let self_ty = data.skip_binder().trait_ref.self_ty(); // (*)
// (*) ok to skip binder because this is just
// error reporting and regions don't really
// matter
match self_ty.sty {
ty::TyEnum(..) | ty::TyStruct(..) => Some(self_ty),
_ => None,
}
}
_ => {
infcx.tcx.sess.span_bug(obligation.cause.span,
&format!("Sized cycle involving non-trait-ref: {:?}",
obligation.predicate));
}
})
.collect();
assert!(!struct_enum_tys.is_empty());
// This is a bit tricky. We want to pick a "main type" in the
// listing that is local to the current crate, so we can give a
// good span to the user. But it might not be the first one in our
// cycle list. So find the first one that is local and then
// rotate.
let (main_index, main_def_id) =
struct_enum_tys.iter()
.enumerate()
.filter_map(|(index, ty)| match ty.sty {
ty::TyEnum(adt_def, _) | ty::TyStruct(adt_def, _) if adt_def.did.is_local() =>
Some((index, adt_def.did)),
_ =>
None,
})
.next()
.unwrap(); // should always be SOME local type involved!
// Rotate so that the "main" type is at index 0.
let struct_enum_tys: Vec<_> =
struct_enum_tys.iter()
.cloned()
.skip(main_index)
.chain(struct_enum_tys.iter().cloned().take(main_index))
.collect();
let tcx = infcx.tcx;
let mut err = recursive_type_with_infinite_size_error(tcx, main_def_id);
let len = struct_enum_tys.len();
if len > 2 {
let span = tcx.map.span_if_local(main_def_id).unwrap();
err.fileline_note(span,
&format!("type `{}` is embedded within `{}`...",
struct_enum_tys[0],
struct_enum_tys[1]));
for &next_ty in &struct_enum_tys[1..len-1] {
err.fileline_note(span,
&format!("...which in turn is embedded within `{}`...", next_ty));
}
err.fileline_note(span,
&format!("...which in turn is embedded within `{}`, \
completing the cycle.",
struct_enum_tys[len-1]));
}
err.emit();
infcx.tcx.sess.abort_if_errors();
unreachable!();
}
pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &ty::ctxt<'tcx>,
type_def_id: DefId)
-> DiagnosticBuilder<'tcx>
{
assert!(type_def_id.is_local());
let span = tcx.map.span_if_local(type_def_id).unwrap();
let mut err = struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size",
tcx.item_path_str(type_def_id));
err.fileline_help(span, &format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
at some point to make `{}` representable",
tcx.item_path_str(type_def_id)));
err
}
pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>)

View File

@ -11,10 +11,10 @@
use middle::infer::InferCtxt;
use middle::ty::{self, Ty, TypeFoldable};
use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
use std::iter;
use syntax::ast;
use util::common::ErrorReported;
use util::nodemap::{FnvHashSet, NodeMap};
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
use super::CodeAmbiguity;
use super::CodeProjectionError;
@ -25,6 +25,7 @@ use super::FulfillmentErrorCode;
use super::ObligationCause;
use super::PredicateObligation;
use super::project;
use super::report_overflow_error_cycle;
use super::select::SelectionContext;
use super::Unimplemented;
use super::util::predicate_for_builtin_bound;
@ -357,6 +358,17 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
}
let obligation = &pending_obligation.obligation;
// If we exceed the recursion limit, take a moment to look for a
// cycle so we can give a better error report from here, where we
// have more context.
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
if obligation.recursion_depth >= recursion_limit {
if let Some(cycle) = scan_for_cycle(obligation, &backtrace) {
report_overflow_error_cycle(selcx.infcx(), &cycle);
}
}
match obligation.predicate {
ty::Predicate::Trait(ref data) => {
if coinductive_match(selcx, obligation, data, &backtrace) {
@ -488,11 +500,15 @@ fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
-> bool
{
if selcx.tcx().trait_has_default_impl(top_data.def_id()) {
debug!("coinductive_match: top_data={:?}", top_data);
for bt_obligation in backtrace.clone() {
debug!("coinductive_match: bt_obligation={:?}", bt_obligation);
// *Everything* in the backtrace must be a defaulted trait.
match bt_obligation.obligation.predicate {
ty::Predicate::Trait(ref data) => {
if !selcx.tcx().trait_has_default_impl(data.def_id()) {
debug!("coinductive_match: trait does not have default impl");
break;
}
}
@ -501,7 +517,7 @@ fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
// And we must find a recursive match.
if bt_obligation.obligation.predicate == top_obligation.predicate {
debug!("process_predicate: found a match in the backtrace");
debug!("coinductive_match: found a match in the backtrace");
return true;
}
}
@ -510,6 +526,27 @@ fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
false
}
fn scan_for_cycle<'a,'tcx>(top_obligation: &PredicateObligation<'tcx>,
backtrace: &Backtrace<PendingPredicateObligation<'tcx>>)
-> Option<Vec<PredicateObligation<'tcx>>>
{
let mut map = FnvHashMap();
let all_obligations =
|| iter::once(top_obligation)
.chain(backtrace.clone()
.map(|p| &p.obligation));
for (index, bt_obligation) in all_obligations().enumerate() {
if let Some(&start) = map.get(&bt_obligation.predicate) {
// Found a cycle starting at position `start` and running
// until the current position (`index`).
return Some(all_obligations().skip(start).take(index - start + 1).cloned().collect());
} else {
map.insert(bt_obligation.predicate.clone(), index);
}
}
None
}
fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
r_b: ty::Region,
cause: ObligationCause<'tcx>,

View File

@ -28,8 +28,10 @@ use syntax::ast;
use syntax::codemap::{Span, DUMMY_SP};
pub use self::error_reporting::TraitErrorKey;
pub use self::error_reporting::recursive_type_with_infinite_size_error;
pub use self::error_reporting::report_fulfillment_errors;
pub use self::error_reporting::report_overflow_error;
pub use self::error_reporting::report_overflow_error_cycle;
pub use self::error_reporting::report_selection_error;
pub use self::error_reporting::report_object_safety_error;
pub use self::coherence::orphan_check;

View File

@ -479,7 +479,7 @@ fn project_type<'cx,'tcx>(
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
if obligation.recursion_depth >= recursion_limit {
debug!("project: overflow!");
report_overflow_error(selcx.infcx(), &obligation);
report_overflow_error(selcx.infcx(), &obligation, true);
}
let obligation_trait_ref =

View File

@ -711,7 +711,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// not update) the cache.
let recursion_limit = self.infcx.tcx.sess.recursion_limit.get();
if stack.obligation.recursion_depth >= recursion_limit {
report_overflow_error(self.infcx(), &stack.obligation);
report_overflow_error(self.infcx(), &stack.obligation, true);
}
// Check the cache. Note that we skolemize the trait-ref
@ -2124,6 +2124,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested: ty::Binder<Vec<Ty<'tcx>>>)
-> VtableBuiltinData<PredicateObligation<'tcx>>
{
debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})",
obligation, bound, nested);
let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) {
Ok(def_id) => def_id,
Err(_) => {

View File

@ -4132,7 +4132,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
pub fn check_representable(tcx: &ty::ctxt,
sp: Span,
item_id: ast::NodeId,
designation: &str) -> bool {
_designation: &str) -> bool {
let rty = tcx.node_id_to_type(item_id);
// Check that it is possible to represent this type. This call identifies
@ -4142,9 +4142,7 @@ pub fn check_representable(tcx: &ty::ctxt,
// caught by case 1.
match rty.is_representable(tcx, sp) {
Representability::SelfRecursive => {
struct_span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation)
.fileline_help(sp, "wrap the inner value in a box to make it representable")
.emit();
traits::recursive_type_with_infinite_size_error(tcx, tcx.map.local_def_id(item_id)).emit();
return false
}
Representability::Representable | Representability::ContainsRecursive => (),

View File

@ -869,43 +869,6 @@ fn main() {
```
"##,
E0072: r##"
When defining a recursive struct or enum, any use of the type being defined
from inside the definition must occur behind a pointer (like `Box` or `&`).
This is because structs and enums must have a well-defined size, and without
the pointer the size of the type would need to be unbounded.
Consider the following erroneous definition of a type for a list of bytes:
```
// error, invalid recursive struct type
struct ListNode {
head: u8,
tail: Option<ListNode>,
}
```
This type cannot have a well-defined size, because it needs to be arbitrarily
large (since we would be able to nest `ListNode`s to any depth). Specifically,
```plain
size of `ListNode` = 1 byte for `head`
+ 1 byte for the discriminant of the `Option`
+ size of `ListNode`
```
One way to fix this is by wrapping `ListNode` in a `Box`, like so:
```
struct ListNode {
head: u8,
tail: Option<Box<ListNode>>,
}
```
This works because `Box` is a pointer, so its size is well-known.
"##,
E0073: r##"
You cannot define a struct (or enum) `Foo` that requires an instance of `Foo`
in order to make a new `Foo` value. This is because there would be no way a

View File

@ -13,5 +13,6 @@ trait Trait {}
pub fn main() {
let x: Vec<Trait + Sized> = Vec::new();
//~^ ERROR the trait `core::marker::Sized` is not implemented
//~^^ ERROR the trait `core::marker::Sized` is not implemented
//~| ERROR the trait `core::marker::Sized` is not implemented
//~| ERROR the trait `core::marker::Sized` is not implemented
}

View File

@ -8,9 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: invalid recursive enum type
enum mlist { cons(isize, mlist), nil, }
//~^ ERROR recursive type `mlist` has infinite size
fn main() { let a = mlist::cons(10, mlist::cons(11, mlist::nil)); }

View File

@ -9,7 +9,7 @@
// except according to those terms.
struct Foo { foo: Option<Option<Foo>> }
//~^ ERROR invalid recursive struct type
//~^ ERROR recursive type `Foo` has infinite size
impl Foo { fn bar(&self) {} }

View File

@ -9,10 +9,9 @@
// except according to those terms.
struct Baz { q: Option<Foo> }
//~^ ERROR invalid recursive struct type
struct Foo { q: Option<Baz> }
//~^ ERROR invalid recursive struct type
//~^ ERROR recursive type `Foo` has infinite size
impl Foo { fn bar(&self) {} }

View File

@ -11,7 +11,7 @@
use std::sync::Mutex;
struct Foo { foo: Mutex<Option<Foo>> }
//~^ ERROR invalid recursive struct type
//~^ ERROR recursive type `Foo` has infinite size
impl Foo { fn bar(&self) {} }

View File

@ -11,7 +11,7 @@
use std::marker;
struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T> }
//~^ ERROR invalid recursive struct type
//~^ ERROR recursive type `Foo` has infinite size
impl<T> Foo<T> { fn bar(&self) {} }

View File

@ -11,8 +11,9 @@
use std::marker;
struct Foo { foo: Bar<Foo> }
struct Bar<T> { x: Bar<Foo> , marker: marker::PhantomData<T> }
//~^ ERROR invalid recursive struct type
//~^ ERROR recursive type `Bar` has infinite size
impl Foo { fn foo(&self) {} }

View File

@ -11,7 +11,7 @@
use std::sync::Mutex;
enum Foo { X(Mutex<Option<Foo>>) }
//~^ ERROR invalid recursive enum type
//~^ ERROR recursive type `Foo` has infinite size
impl Foo { fn bar(self) {} }

View File

@ -9,7 +9,7 @@
// except according to those terms.
enum Foo { Voo(Option<Option<Foo>>) }
//~^ ERROR invalid recursive enum type
//~^ ERROR recursive type `Foo` has infinite size
impl Foo { fn bar(&self) {} }

View File

@ -9,7 +9,7 @@
// except according to those terms.
fn main() {
for (ref i,) in [].iter() { //~ ERROR: type mismatch resolving
for (ref i,) in [].iter() { //~ ERROR mismatched types
i.clone();
//~^ ERROR: the type of this value must be known in this context
}

View File

@ -40,6 +40,7 @@ impl<'a> Publisher<'a> for MyStruct<'a> {
//~^^ ERROR cannot infer
//~| ERROR cannot infer
//~| ERROR cannot infer
//~| ERROR cannot infer
//
// The fact that `Publisher` is using an implicit lifetime is
// what was causing the debruijn accounting to be off, so

View File

@ -8,11 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: overflow representing the type `S`
trait Mirror { type It; }
impl<T> Mirror for T { type It = Self; }
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
struct S(Option<<S as Mirror>::It>);
//~^ ERROR recursive type `S` has infinite size
fn main() {
let _s = S(None);

View File

@ -16,7 +16,7 @@ mod pingpong {
use send_packet;
pub type ping = send_packet<pong>;
pub struct pong(send_packet<ping>);
//~^ ERROR invalid recursive struct type
//~^ ERROR recursive type `pingpong::pong` has infinite size
}
fn main() {}

View File

@ -10,7 +10,7 @@
enum foo { foo_(bar) }
enum bar { bar_none, bar_some(bar) }
//~^ ERROR invalid recursive enum type
//~^ ERROR recursive type `bar` has infinite size
fn main() {
}

View File

@ -12,7 +12,7 @@
enum foo { foo_(bar) }
struct bar { x: bar }
//~^ ERROR invalid recursive struct type
//~^ ERROR E0072
fn main() {
}

View File

@ -12,7 +12,7 @@ use std::marker;
enum E1 { V1(E2<E1>), }
enum E2<T> { V2(E2<E1>, marker::PhantomData<T>), }
//~^ ERROR invalid recursive enum type
//~^ ERROR recursive type `E2` has infinite size
impl E1 { fn foo(&self) {} }

View File

@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct S {
//~^ ERROR invalid recursive struct type
struct S { //~ ERROR E0072
element: Option<S>
}

View File

@ -17,6 +17,5 @@ use std::cell::RefCell;
static boxed: Box<RefCell<isize>> = box RefCell::new(0);
//~^ ERROR allocations are not allowed in statics
//~| ERROR the trait `core::marker::Sync` is not implemented for the type
//~| ERROR the trait `core::marker::Sync` is not implemented for the type
fn main() { }

View File

@ -27,14 +27,12 @@ fn f<T>(val: T) {
let t: S<T> = S(marker::PhantomData);
let a = &t as &Gettable<T>;
//~^ ERROR the trait `core::marker::Send` is not implemented
//~^^ ERROR the trait `core::marker::Copy` is not implemented
}
fn g<T>(val: T) {
let t: S<T> = S(marker::PhantomData);
let a: &Gettable<T> = &t;
//~^ ERROR the trait `core::marker::Send` is not implemented
//~^^ ERROR the trait `core::marker::Copy` is not implemented
}
fn foo<'a>() {

View File

@ -13,8 +13,8 @@
extern crate libc;
trait Mirror { type It; }
impl<T> Mirror for T { type It = Self; }
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
#[repr(C)]
pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
#[repr(C)]

View File

@ -16,5 +16,4 @@ fn main() {
let x = RefCell::new(0);
f(x);
//~^ ERROR `core::marker::Sync` is not implemented
//~^^ ERROR `core::marker::Sync` is not implemented
}

View File

@ -18,7 +18,6 @@ use std::cell::RefCell;
fn assert<T: RecoverSafe + ?Sized>() {}
fn main() {
assert::<Rc<RefCell<i32>>>(); //~ ERROR: is not implemented
//~^ ERROR: is not implemented
assert::<Rc<RefCell<i32>>>(); //~ ERROR E0277
}

View File

@ -19,5 +19,4 @@ fn assert<T: RecoverSafe + ?Sized>() {}
fn main() {
assert::<Arc<RefCell<i32>>>(); //~ ERROR: is not implemented
//~^ ERROR: is not implemented
}

View File

@ -17,6 +17,5 @@ use std::cell::RefCell;
fn assert<T: RecoverSafe + ?Sized>() {}
fn main() {
assert::<&RefCell<i32>>(); //~ ERROR: is not implemented
//~^ ERROR is not implemented
assert::<&RefCell<i32>>(); //~ ERROR E0277
}

View File

@ -17,7 +17,6 @@ use std::cell::RefCell;
fn assert<T: RecoverSafe + ?Sized>() {}
fn main() {
assert::<*mut RefCell<i32>>(); //~ ERROR: is not implemented
//~^ ERROR is not implemented
assert::<*mut RefCell<i32>>(); //~ ERROR E0277
}

View File

@ -28,6 +28,7 @@ fn make_bar<T:Bar>(t: &T) -> &Bar {
}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
//~^ ERROR E0038
t as &Bar
}

View File

@ -17,12 +17,11 @@ pub fn main() {
// Bool => does not implement iterator.
for i in false..true {}
//~^ ERROR the trait
//~^^ ERROR the trait
//~^^^ ERROR the trait
//~^ ERROR E0277
// Unsized type.
let arr: &[_] = &[1, 2, 3];
let range = *arr..;
//~^ ERROR the trait `core::marker::Sized` is not implemented
//~| ERROR the trait `core::marker::Sized` is not implemented
}

View File

@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: invalid recursive enum type
enum list<T> { cons(T, list<T>), nil }
//~^ ERROR recursive type `list` has infinite size
fn main() {}

View File

@ -0,0 +1,31 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test the error message resulting from a cycle in solving `Foo:
// Sized`. The specifics of the message will of course but the main
// thing we want to preserve is that:
//
// 1. the message should appear attached to one of the structs
// defined in this file;
// 2. it should elaborate the steps that led to the cycle.
struct Baz { q: Option<Foo> }
struct Foo { q: Option<Baz> }
//~^ ERROR recursive type `Foo` has infinite size
//~| type `Foo` is embedded within `core::option::Option<Foo>`...
//~| ...which in turn is embedded within `core::option::Option<Foo>`...
//~| ...which in turn is embedded within `Baz`...
//~| ...which in turn is embedded within `core::option::Option<Baz>`...
//~| ...which in turn is embedded within `Foo`, completing the cycle.
impl Foo { fn bar(&self) {} }
fn main() {}

View File

@ -22,6 +22,6 @@ fn main() {
x: 3
};
let baz: Foo<usize> = panic!();
let baz: Foo<usize> = loop { };
//~^ ERROR not implemented
}

View File

@ -21,5 +21,7 @@ fn main() {
(box 10 as Box<bar>).dup();
//~^ ERROR E0038
//~| ERROR E0038
//~| ERROR E0038
//~| ERROR E0038
//~| ERROR E0277
}

View File

@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:invalid recursive struct type
struct t1 {
struct t1 { //~ ERROR E0072
foo: isize,
foolish: t1
}