diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 9dd8a7050fd28..1f5a6d7914125 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -20,7 +20,7 @@ use syntax::ptr::P; use syntax::visit::{self, Visitor}; use syntax::{span_err, struct_span_err, walk_list}; use syntax_ext::proc_macro_decls::is_proc_macro_attr; -use syntax_pos::Span; +use syntax_pos::{Span, MultiSpan}; use errors::Applicability; use log::debug; @@ -679,6 +679,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { "unions cannot have zero fields"); } } + ItemKind::Existential(ref bounds, _) => { + if !bounds.iter() + .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { + let msp = MultiSpan::from_spans(bounds.iter() + .map(|bound| bound.span()).collect()); + self.err_handler().span_err(msp, "at least one trait must be specified"); + } + } _ => {} } diff --git a/src/test/run-pass/existential_type.rs b/src/test/run-pass/existential_type.rs index dfb195ec83062..b36435cf113f1 100644 --- a/src/test/run-pass/existential_type.rs +++ b/src/test/run-pass/existential_type.rs @@ -68,14 +68,14 @@ fn my_other_iter(u: U) -> MyOtherIter { } trait Trait {} -existential type GenericBound<'a, T: Trait>: 'a; +existential type GenericBound<'a, T: Trait>: Sized + 'a; fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> { t } mod pass_through { - pub existential type Passthrough: 'static; + pub existential type Passthrough: Sized + 'static; fn define_passthrough(t: T) -> Passthrough { t diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.rs b/src/test/ui/existential_types/existential-types-with-no-traits.rs new file mode 100644 index 0000000000000..46339c73b1f1d --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-no-traits.rs @@ -0,0 +1,14 @@ +#![feature(existential_type)] + +existential type Foo: 'static; +//~^ ERROR: at least one trait must be specified + +fn foo() -> Foo { + "foo" +} + +fn bar() -> impl 'static { //~ ERROR: at least one trait must be specified + "foo" +} + +fn main() {} diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.stderr b/src/test/ui/existential_types/existential-types-with-no-traits.stderr new file mode 100644 index 0000000000000..4b2fbc79d3bc2 --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-no-traits.stderr @@ -0,0 +1,14 @@ +error: at least one trait must be specified + --> $DIR/existential-types-with-no-traits.rs:3:23 + | +LL | existential type Foo: 'static; + | ^^^^^^^ + +error: at least one trait must be specified + --> $DIR/existential-types-with-no-traits.rs:10:13 + | +LL | fn bar() -> impl 'static { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/existential_types/generic_nondefining_use.rs b/src/test/ui/existential_types/generic_nondefining_use.rs index 75af5d9570ff2..ffc965aca47c9 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.rs +++ b/src/test/ui/existential_types/generic_nondefining_use.rs @@ -4,6 +4,8 @@ fn main() {} existential type Cmp: 'static; //~^ ERROR could not find defining uses +//~^^ ERROR: at least one trait must be specified + // not a defining use, because it doesn't define *all* possible generics fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define diff --git a/src/test/ui/existential_types/generic_nondefining_use.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr index ef579260f061c..d205d44c68c71 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,5 +1,11 @@ +error: at least one trait must be specified + --> $DIR/generic_nondefining_use.rs:5:26 + | +LL | existential type Cmp: 'static; + | ^^^^^^^ + error: defining existential type use does not fully define existential type - --> $DIR/generic_nondefining_use.rs:9:1 + --> $DIR/generic_nondefining_use.rs:11:1 | LL | / fn cmp() -> Cmp { LL | | 5u32 @@ -12,5 +18,5 @@ error: could not find defining uses LL | existential type Cmp: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/existential_types/generic_not_used.rs b/src/test/ui/existential_types/generic_not_used.rs index bfe7b8c4a1d53..054e6f5f2ade9 100644 --- a/src/test/ui/existential_types/generic_not_used.rs +++ b/src/test/ui/existential_types/generic_not_used.rs @@ -3,6 +3,7 @@ fn main() {} existential type WrongGeneric: 'static; +//~^ ERROR: at least one trait must be specified fn wrong_generic(_: U, v: V) -> WrongGeneric { //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list diff --git a/src/test/ui/existential_types/generic_not_used.stderr b/src/test/ui/existential_types/generic_not_used.stderr index 1ae4ab65929f0..d243233992b02 100644 --- a/src/test/ui/existential_types/generic_not_used.stderr +++ b/src/test/ui/existential_types/generic_not_used.stderr @@ -1,5 +1,11 @@ +error: at least one trait must be specified + --> $DIR/generic_not_used.rs:5:44 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^ + error: type parameter `V` is part of concrete type but not used in parameter list for existential type - --> $DIR/generic_not_used.rs:7:73 + --> $DIR/generic_not_used.rs:8:73 | LL | fn wrong_generic(_: U, v: V) -> WrongGeneric { | _________________________________________________________________________^ @@ -8,5 +14,5 @@ LL | | v LL | | } | |_^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs index 02bb151ccb618..d9eedd6dca7c1 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs @@ -8,6 +8,7 @@ fn main() { existential type WrongGeneric: 'static; //~^ ERROR the parameter type `T` may not live long enough +//~^^ ERROR: at least one trait must be specified fn wrong_generic(t: T) -> WrongGeneric { t diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr index 002acc41553b6..2f76eea4460bd 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr @@ -1,3 +1,9 @@ +error: at least one trait must be specified + --> $DIR/generic_type_does_not_live_long_enough.rs:9:35 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^ + error[E0308]: mismatched types --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 | @@ -22,7 +28,7 @@ note: ...so that the type `T` will meet its required lifetime bounds LL | existential type WrongGeneric: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0310. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/existential_types/generic_underconstrained.rs b/src/test/ui/existential_types/generic_underconstrained.rs index 967faca067c1e..cc0db893c6aa7 100644 --- a/src/test/ui/existential_types/generic_underconstrained.rs +++ b/src/test/ui/existential_types/generic_underconstrained.rs @@ -4,6 +4,7 @@ fn main() {} trait Trait {} existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` +//~^ ERROR: at least one trait must be specified // no `Trait` bound fn underconstrain(_: T) -> Underconstrained { diff --git a/src/test/ui/existential_types/generic_underconstrained.stderr b/src/test/ui/existential_types/generic_underconstrained.stderr index 8551a939e8ed8..35083a53eb343 100644 --- a/src/test/ui/existential_types/generic_underconstrained.stderr +++ b/src/test/ui/existential_types/generic_underconstrained.stderr @@ -1,3 +1,9 @@ +error: at least one trait must be specified + --> $DIR/generic_underconstrained.rs:6:46 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^ + error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/generic_underconstrained.rs:6:1 | @@ -7,6 +13,6 @@ LL | existential type Underconstrained: 'static; = help: consider adding a `where T: Trait` bound = note: the return type of a function must have a statically known size -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/generic_underconstrained2.rs b/src/test/ui/existential_types/generic_underconstrained2.rs index 98d9da832cfd3..c6263eacd53e3 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.rs +++ b/src/test/ui/existential_types/generic_underconstrained2.rs @@ -4,6 +4,7 @@ fn main() {} existential type Underconstrained: 'static; //~^ ERROR `U` doesn't implement `std::fmt::Debug` +//~^^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained(_: U) -> Underconstrained { @@ -12,6 +13,7 @@ fn underconstrained(_: U) -> Underconstrained { existential type Underconstrained2: 'static; //~^ ERROR `V` doesn't implement `std::fmt::Debug` +//~^^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained2(_: U, _: V) -> Underconstrained2 { diff --git a/src/test/ui/existential_types/generic_underconstrained2.stderr b/src/test/ui/existential_types/generic_underconstrained2.stderr index c7b6d6ade557c..6ff783f33b96f 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.stderr +++ b/src/test/ui/existential_types/generic_underconstrained2.stderr @@ -1,3 +1,15 @@ +error: at least one trait must be specified + --> $DIR/generic_underconstrained2.rs:5:56 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^ + +error: at least one trait must be specified + --> $DIR/generic_underconstrained2.rs:14:57 + | +LL | existential type Underconstrained2: 'static; + | ^^^^^^^ + error[E0277]: `U` doesn't implement `std::fmt::Debug` --> $DIR/generic_underconstrained2.rs:5:1 | @@ -9,7 +21,7 @@ LL | existential type Underconstrained: 'static; = note: the return type of a function must have a statically known size error[E0277]: `V` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:13:1 + --> $DIR/generic_underconstrained2.rs:14:1 | LL | existential type Underconstrained2: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` @@ -18,6 +30,6 @@ LL | existential type Underconstrained2: 'static; = help: consider adding a `where V: std::fmt::Debug` bound = note: the return type of a function must have a statically known size -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/unused_generic_param.rs b/src/test/ui/existential_types/unused_generic_param.rs index 7af6508788129..5455b39f4cbe2 100644 --- a/src/test/ui/existential_types/unused_generic_param.rs +++ b/src/test/ui/existential_types/unused_generic_param.rs @@ -1,18 +1,17 @@ -// compile-pass #![feature(existential_type)] fn main() { } -// test that unused generic parameters are ok existential type PartiallyDefined: 'static; +//~^ ERROR: at least one trait must be specified fn partially_defined(_: T) -> PartiallyDefined { 4u32 } -// test that unused generic parameters are ok existential type PartiallyDefined2: 'static; +//~^ ERROR: at least one trait must be specified fn partially_defined2(_: T) -> PartiallyDefined2 { 4u32 diff --git a/src/test/ui/existential_types/unused_generic_param.stderr b/src/test/ui/existential_types/unused_generic_param.stderr new file mode 100644 index 0000000000000..9d628d069d36c --- /dev/null +++ b/src/test/ui/existential_types/unused_generic_param.stderr @@ -0,0 +1,14 @@ +error: at least one trait must be specified + --> $DIR/unused_generic_param.rs:6:39 + | +LL | existential type PartiallyDefined: 'static; + | ^^^^^^^ + +error: at least one trait must be specified + --> $DIR/unused_generic_param.rs:13:40 + | +LL | existential type PartiallyDefined2: 'static; + | ^^^^^^^ + +error: aborting due to 2 previous errors +