diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 3aabe4b4931..2a2936e7363 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -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`. "####, +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, +} +``` + +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>, +} +``` + +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: diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 883c5e7bb40..ef97c4c8a12 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -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>) + -> ! +{ + 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>) diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 0e1c9c3843b..2fdf93e6e35 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -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>) + -> Option>> +{ + 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>, diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 4a92a8a9d58..8fecffcea9f 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -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; diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index e9d7b330d07..c363425db85 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -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 = diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f6d0da904a4..75992b6849b 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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>>) -> VtableBuiltinData> { + 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(_) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e9184a12d72..eafa1e4304d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 => (), diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 5f2582a548b..55a1021f0fb 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -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, -} -``` - -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>, -} -``` - -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 diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index 8c13ff70515..bfe9d740339 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -13,5 +13,6 @@ trait Trait {} pub fn main() { let x: Vec = 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 } diff --git a/src/test/compile-fail/infinite-tag-type-recursion.rs b/src/test/compile-fail/infinite-tag-type-recursion.rs index 7dbf75feda0..c9a7f731aea 100644 --- a/src/test/compile-fail/infinite-tag-type-recursion.rs +++ b/src/test/compile-fail/infinite-tag-type-recursion.rs @@ -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)); } diff --git a/src/test/compile-fail/issue-17431-1.rs b/src/test/compile-fail/issue-17431-1.rs index bd3f2835058..260cc366fae 100644 --- a/src/test/compile-fail/issue-17431-1.rs +++ b/src/test/compile-fail/issue-17431-1.rs @@ -9,7 +9,7 @@ // except according to those terms. struct Foo { foo: Option> } -//~^ ERROR invalid recursive struct type +//~^ ERROR recursive type `Foo` has infinite size impl Foo { fn bar(&self) {} } diff --git a/src/test/compile-fail/issue-17431-2.rs b/src/test/compile-fail/issue-17431-2.rs index 4e1c0d6571d..edbc8c82432 100644 --- a/src/test/compile-fail/issue-17431-2.rs +++ b/src/test/compile-fail/issue-17431-2.rs @@ -9,10 +9,9 @@ // except according to those terms. struct Baz { q: Option } -//~^ ERROR invalid recursive struct type struct Foo { q: Option } -//~^ ERROR invalid recursive struct type +//~^ ERROR recursive type `Foo` has infinite size impl Foo { fn bar(&self) {} } diff --git a/src/test/compile-fail/issue-17431-3.rs b/src/test/compile-fail/issue-17431-3.rs index 07c5f106456..9ba085591f0 100644 --- a/src/test/compile-fail/issue-17431-3.rs +++ b/src/test/compile-fail/issue-17431-3.rs @@ -11,7 +11,7 @@ use std::sync::Mutex; struct Foo { foo: Mutex> } -//~^ ERROR invalid recursive struct type +//~^ ERROR recursive type `Foo` has infinite size impl Foo { fn bar(&self) {} } diff --git a/src/test/compile-fail/issue-17431-4.rs b/src/test/compile-fail/issue-17431-4.rs index 74952d9ca2b..665c3cf8fe6 100644 --- a/src/test/compile-fail/issue-17431-4.rs +++ b/src/test/compile-fail/issue-17431-4.rs @@ -11,7 +11,7 @@ use std::marker; struct Foo { foo: Option>>, marker: marker::PhantomData } -//~^ ERROR invalid recursive struct type +//~^ ERROR recursive type `Foo` has infinite size impl Foo { fn bar(&self) {} } diff --git a/src/test/compile-fail/issue-17431-5.rs b/src/test/compile-fail/issue-17431-5.rs index 157b5ed434e..85ed4d5d634 100644 --- a/src/test/compile-fail/issue-17431-5.rs +++ b/src/test/compile-fail/issue-17431-5.rs @@ -11,8 +11,9 @@ use std::marker; struct Foo { foo: Bar } + struct Bar { x: Bar , marker: marker::PhantomData } -//~^ ERROR invalid recursive struct type +//~^ ERROR recursive type `Bar` has infinite size impl Foo { fn foo(&self) {} } diff --git a/src/test/compile-fail/issue-17431-6.rs b/src/test/compile-fail/issue-17431-6.rs index b2037378d37..4c1e82c3d6a 100644 --- a/src/test/compile-fail/issue-17431-6.rs +++ b/src/test/compile-fail/issue-17431-6.rs @@ -11,7 +11,7 @@ use std::sync::Mutex; enum Foo { X(Mutex>) } -//~^ ERROR invalid recursive enum type +//~^ ERROR recursive type `Foo` has infinite size impl Foo { fn bar(self) {} } diff --git a/src/test/compile-fail/issue-17431-7.rs b/src/test/compile-fail/issue-17431-7.rs index 9ad81e030aa..71b85da29fc 100644 --- a/src/test/compile-fail/issue-17431-7.rs +++ b/src/test/compile-fail/issue-17431-7.rs @@ -9,7 +9,7 @@ // except according to those terms. enum Foo { Voo(Option>) } -//~^ ERROR invalid recursive enum type +//~^ ERROR recursive type `Foo` has infinite size impl Foo { fn bar(&self) {} } diff --git a/src/test/compile-fail/issue-20261.rs b/src/test/compile-fail/issue-20261.rs index 42fd856ad87..09044b5b505 100644 --- a/src/test/compile-fail/issue-20261.rs +++ b/src/test/compile-fail/issue-20261.rs @@ -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 } diff --git a/src/test/compile-fail/issue-20831-debruijn.rs b/src/test/compile-fail/issue-20831-debruijn.rs index 3f96a9c3422..48ea344c7c2 100644 --- a/src/test/compile-fail/issue-20831-debruijn.rs +++ b/src/test/compile-fail/issue-20831-debruijn.rs @@ -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 diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs index 8b02e8e7046..28080ae09e5 100644 --- a/src/test/compile-fail/issue-26548.rs +++ b/src/test/compile-fail/issue-26548.rs @@ -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 Mirror for T { type It = Self; } +trait Mirror { type It: ?Sized; } +impl Mirror for T { type It = Self; } struct S(Option<::It>); +//~^ ERROR recursive type `S` has infinite size fn main() { let _s = S(None); diff --git a/src/test/compile-fail/issue-2718-a.rs b/src/test/compile-fail/issue-2718-a.rs index 37daf76c0b9..6de28cbbf35 100644 --- a/src/test/compile-fail/issue-2718-a.rs +++ b/src/test/compile-fail/issue-2718-a.rs @@ -16,7 +16,7 @@ mod pingpong { use send_packet; pub type ping = send_packet; pub struct pong(send_packet); - //~^ ERROR invalid recursive struct type + //~^ ERROR recursive type `pingpong::pong` has infinite size } fn main() {} diff --git a/src/test/compile-fail/issue-3008-1.rs b/src/test/compile-fail/issue-3008-1.rs index eb684208326..d3c15763eb0 100644 --- a/src/test/compile-fail/issue-3008-1.rs +++ b/src/test/compile-fail/issue-3008-1.rs @@ -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() { } diff --git a/src/test/compile-fail/issue-3008-2.rs b/src/test/compile-fail/issue-3008-2.rs index f934e0771c2..e6cc29634a1 100644 --- a/src/test/compile-fail/issue-3008-2.rs +++ b/src/test/compile-fail/issue-3008-2.rs @@ -12,7 +12,7 @@ enum foo { foo_(bar) } struct bar { x: bar } -//~^ ERROR invalid recursive struct type +//~^ ERROR E0072 fn main() { } diff --git a/src/test/compile-fail/issue-3008-3.rs b/src/test/compile-fail/issue-3008-3.rs index f8756b83f23..66bfab003e9 100644 --- a/src/test/compile-fail/issue-3008-3.rs +++ b/src/test/compile-fail/issue-3008-3.rs @@ -12,7 +12,7 @@ use std::marker; enum E1 { V1(E2), } enum E2 { V2(E2, marker::PhantomData), } -//~^ ERROR invalid recursive enum type +//~^ ERROR recursive type `E2` has infinite size impl E1 { fn foo(&self) {} } diff --git a/src/test/compile-fail/issue-3779.rs b/src/test/compile-fail/issue-3779.rs index 66d8fb40cd1..d96b1a1cbe3 100644 --- a/src/test/compile-fail/issue-3779.rs +++ b/src/test/compile-fail/issue-3779.rs @@ -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 } diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index 7d0a9007829..87b7b73d57d 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -17,6 +17,5 @@ use std::cell::RefCell; static boxed: Box> = 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() { } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index 3474a73b31f..aec40c1a73a 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -27,14 +27,12 @@ fn f(val: T) { let t: S = S(marker::PhantomData); let a = &t as &Gettable; //~^ ERROR the trait `core::marker::Send` is not implemented - //~^^ ERROR the trait `core::marker::Copy` is not implemented } fn g(val: T) { let t: S = S(marker::PhantomData); let a: &Gettable = &t; //~^ ERROR the trait `core::marker::Send` is not implemented - //~^^ ERROR the trait `core::marker::Copy` is not implemented } fn foo<'a>() { diff --git a/src/test/compile-fail/lint-ctypes.rs b/src/test/compile-fail/lint-ctypes.rs index 5c49098d870..731c1edbfc0 100644 --- a/src/test/compile-fail/lint-ctypes.rs +++ b/src/test/compile-fail/lint-ctypes.rs @@ -13,8 +13,8 @@ extern crate libc; -trait Mirror { type It; } -impl Mirror for T { type It = Self; } +trait Mirror { type It: ?Sized; } +impl Mirror for T { type It = Self; } #[repr(C)] pub struct StructWithProjection(*mut ::It); #[repr(C)] diff --git a/src/test/compile-fail/mut-not-freeze.rs b/src/test/compile-fail/mut-not-freeze.rs index 2269c58c97d..db19132b2c4 100644 --- a/src/test/compile-fail/mut-not-freeze.rs +++ b/src/test/compile-fail/mut-not-freeze.rs @@ -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 } diff --git a/src/test/compile-fail/not-panic-safe-2.rs b/src/test/compile-fail/not-panic-safe-2.rs index 47a65505d8a..922d70b8013 100644 --- a/src/test/compile-fail/not-panic-safe-2.rs +++ b/src/test/compile-fail/not-panic-safe-2.rs @@ -18,7 +18,6 @@ use std::cell::RefCell; fn assert() {} fn main() { - assert::>>(); //~ ERROR: is not implemented - //~^ ERROR: is not implemented + assert::>>(); //~ ERROR E0277 } diff --git a/src/test/compile-fail/not-panic-safe-3.rs b/src/test/compile-fail/not-panic-safe-3.rs index a0c7865eeb0..50a69543f7d 100644 --- a/src/test/compile-fail/not-panic-safe-3.rs +++ b/src/test/compile-fail/not-panic-safe-3.rs @@ -19,5 +19,4 @@ fn assert() {} fn main() { assert::>>(); //~ ERROR: is not implemented - //~^ ERROR: is not implemented } diff --git a/src/test/compile-fail/not-panic-safe-4.rs b/src/test/compile-fail/not-panic-safe-4.rs index 9e716131525..c50e4b9d87e 100644 --- a/src/test/compile-fail/not-panic-safe-4.rs +++ b/src/test/compile-fail/not-panic-safe-4.rs @@ -17,6 +17,5 @@ use std::cell::RefCell; fn assert() {} fn main() { - assert::<&RefCell>(); //~ ERROR: is not implemented - //~^ ERROR is not implemented + assert::<&RefCell>(); //~ ERROR E0277 } diff --git a/src/test/compile-fail/not-panic-safe-6.rs b/src/test/compile-fail/not-panic-safe-6.rs index 90c730d3758..0fc912dc95f 100644 --- a/src/test/compile-fail/not-panic-safe-6.rs +++ b/src/test/compile-fail/not-panic-safe-6.rs @@ -17,7 +17,6 @@ use std::cell::RefCell; fn assert() {} fn main() { - assert::<*mut RefCell>(); //~ ERROR: is not implemented - //~^ ERROR is not implemented + assert::<*mut RefCell>(); //~ ERROR E0277 } diff --git a/src/test/compile-fail/object-safety-generics.rs b/src/test/compile-fail/object-safety-generics.rs index 341736f7ab5..8e3161ef884 100644 --- a/src/test/compile-fail/object-safety-generics.rs +++ b/src/test/compile-fail/object-safety-generics.rs @@ -28,6 +28,7 @@ fn make_bar(t: &T) -> &Bar { } fn make_bar_explicit(t: &T) -> &Bar { + //~^ ERROR E0038 t as &Bar } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 826e4283ef8..b839902c683 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -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 } diff --git a/src/test/compile-fail/recursive-enum.rs b/src/test/compile-fail/recursive-enum.rs index 33dcbdf74d2..555755cdb96 100644 --- a/src/test/compile-fail/recursive-enum.rs +++ b/src/test/compile-fail/recursive-enum.rs @@ -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 { cons(T, list), nil } +//~^ ERROR recursive type `list` has infinite size fn main() {} diff --git a/src/test/compile-fail/sized-cycle-note.rs b/src/test/compile-fail/sized-cycle-note.rs new file mode 100644 index 00000000000..bb1ab2eafb3 --- /dev/null +++ b/src/test/compile-fail/sized-cycle-note.rs @@ -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 or the MIT license +// , 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 } + +struct Foo { q: Option } +//~^ ERROR recursive type `Foo` has infinite size +//~| type `Foo` is embedded within `core::option::Option`... +//~| ...which in turn is embedded within `core::option::Option`... +//~| ...which in turn is embedded within `Baz`... +//~| ...which in turn is embedded within `core::option::Option`... +//~| ...which in turn is embedded within `Foo`, completing the cycle. + +impl Foo { fn bar(&self) {} } + +fn main() {} diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs index d39b7e15edc..520691fbecc 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs @@ -22,6 +22,6 @@ fn main() { x: 3 }; - let baz: Foo = panic!(); + let baz: Foo = loop { }; //~^ ERROR not implemented } diff --git a/src/test/compile-fail/trait-test-2.rs b/src/test/compile-fail/trait-test-2.rs index 2d4df77f960..0cfcf6bb3f9 100644 --- a/src/test/compile-fail/trait-test-2.rs +++ b/src/test/compile-fail/trait-test-2.rs @@ -21,5 +21,7 @@ fn main() { (box 10 as Box).dup(); //~^ ERROR E0038 //~| ERROR E0038 + //~| ERROR E0038 + //~| ERROR E0038 //~| ERROR E0277 } diff --git a/src/test/compile-fail/type-recursive.rs b/src/test/compile-fail/type-recursive.rs index 3b08d900733..4bb739800df 100644 --- a/src/test/compile-fail/type-recursive.rs +++ b/src/test/compile-fail/type-recursive.rs @@ -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 }