diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6b6a688bf1d18..6b7934731099a 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -251,6 +251,76 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { }); } + fn check_auto_trait(&mut self, + trait_def_id: DefId, + items: &[hir::TraitItem], + span: Span) + { + // We want to ensure: + // + // 1) that there are no items contained within + // the trait defintion + // + // 2) that the definition doesn't violate the no-super trait rule + // for auto traits. + // + // 3) that the trait definition does not have any type parameters + + let predicates = self.tcx().lookup_predicates(trait_def_id); + + // We must exclude the Self : Trait predicate contained by all + // traits. + let has_predicates = + predicates.predicates.iter().any(|predicate| { + match predicate { + &ty::Predicate::Trait(ref poly_trait_ref) => { + let self_ty = poly_trait_ref.0.self_ty(); + !(self_ty.is_self() && poly_trait_ref.def_id() == trait_def_id) + }, + _ => true, + } + }); + + let trait_def = self.tcx().lookup_trait_def(trait_def_id); + + let has_ty_params = + trait_def.generics + .types + .len() > 1; + + // We use an if-else here, since the generics will also trigger + // an extraneous error message when we find predicates like + // `T : Sized` for a trait like: `trait Magic`. + // + // We also put the check on the number of items here, + // as it seems confusing to report an error about + // extraneous predicates created by things like + // an associated type inside the trait. + let mut err = None; + if !items.is_empty() { + error_380(self.ccx, span); + } else if has_ty_params { + err = Some(struct_span_err!(self.tcx().sess, span, E0566, + "traits with auto impls (`e.g. impl \ + Trait for ..`) can not have type parameters")); + } else if has_predicates { + err = Some(struct_span_err!(self.tcx().sess, span, E0565, + "traits with auto impls (`e.g. impl \ + Trait for ..`) cannot have predicates")); + } + + // Finally if either of the above conditions apply we should add a note + // indicating that this error is the result of a recent soundness fix. + match err { + None => {}, + Some(mut e) => { + e.note("the new auto trait rules are the result of a \ + recent soundness fix; see #29859 for more details"); + e.emit(); + } + } + } + fn check_trait(&mut self, item: &hir::Item, items: &[hir::TraitItem]) @@ -258,9 +328,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let trait_def_id = self.tcx().map.local_def_id(item.id); if self.tcx().trait_has_default_impl(trait_def_id) { - if !items.is_empty() { - error_380(self.ccx, item.span); - } + self.check_auto_trait(trait_def_id, items, item.span); } self.for_item(item).with_fcx(|fcx, this| { @@ -618,7 +686,7 @@ fn error_192(ccx: &CrateCtxt, span: Span) { fn error_380(ccx: &CrateCtxt, span: Span) { span_err!(ccx.tcx.sess, span, E0380, - "traits with default impls (`e.g. unsafe impl \ + "traits with default impls (`e.g. impl \ Trait for ..`) must have no methods or associated items") } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 8bb5efdcad2c3..a188cebde6cc7 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4079,4 +4079,6 @@ register_diagnostics! { E0563, // cannot determine a type for this `impl Trait`: {} E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` + E0565, // auto-traits can not have predicates, + E0566, // auto traits can not have type parameters } diff --git a/src/test/compile-fail/issue-23080-2.rs b/src/test/compile-fail/issue-23080-2.rs index b77230a8b340d..9d20c17674bc3 100644 --- a/src/test/compile-fail/issue-23080-2.rs +++ b/src/test/compile-fail/issue-23080-2.rs @@ -13,7 +13,7 @@ #![feature(optin_builtin_traits)] unsafe trait Trait { -//~^ error: traits with default impls (`e.g. unsafe impl Trait for ..`) must have no methods or associated items +//~^ ERROR E0380 type Output; } diff --git a/src/test/compile-fail/issue-23080.rs b/src/test/compile-fail/issue-23080.rs index 99373a69697ae..2e8cba87be515 100644 --- a/src/test/compile-fail/issue-23080.rs +++ b/src/test/compile-fail/issue-23080.rs @@ -13,7 +13,7 @@ #![feature(optin_builtin_traits)] unsafe trait Trait { -//~^ error: traits with default impls (`e.g. unsafe impl Trait for ..`) must have no methods or associated items +//~^ ERROR E0380 fn method(&self) { println!("Hello"); } diff --git a/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs b/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs deleted file mode 100644 index cdf4b405fd83e..0000000000000 --- a/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 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 for a potential corner case in current impl where you have an -// auto trait (Magic1) that depends on a normal trait (Magic2) which -// in turn depends on the auto trait (Magic1). This was incorrectly -// being considered coinductive, but because of the normal trait -// interfering, it should not be. - -#![feature(optin_builtin_traits)] - -trait Magic1: Magic2 { } -impl Magic1 for .. {} - -trait Magic2 { } -impl Magic2 for T { } - -fn is_magic1() { } - -#[derive(Debug)] -struct NoClone; - -fn main() { - is_magic1::(); //~ ERROR E0275 -} diff --git a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs index ec8db996600d1..168148b92fe44 100644 --- a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs +++ b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs @@ -14,7 +14,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} +trait Magic: Copy {} //~ ERROR E0565 impl Magic for .. {} fn copy(x: T) -> (T, T) { (x, x) } @@ -23,6 +23,6 @@ fn copy(x: T) -> (T, T) { (x, x) } struct NoClone; fn main() { - let (a, b) = copy(NoClone); //~ ERROR E0277 + let (a, b) = copy(NoClone); println!("{:?} {:?}", a, b); } diff --git a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs similarity index 58% rename from src/test/compile-fail/typeck-default-trait-impl-superregion.rs rename to src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs index aa918119fbcee..333cb569ee895 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,20 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - #![feature(optin_builtin_traits)] -trait MyTrait : 'static {} - -impl MyTrait for .. {} +trait Magic : Sized where Option : Magic {} //~ ERROR E0565 +impl Magic for .. {} +impl Magic for T {} -fn foo() { } +fn copy(x: T) -> (T, T) { (x, x) } -fn bar<'a>() { - foo::<&'a ()>(); //~ ERROR does not fulfill the required lifetime -} +#[derive(Debug)] +struct NoClone; fn main() { + let (a, b) = copy(NoClone); + println!("{:?} {:?}", a, b); } diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs new file mode 100644 index 0000000000000..713f26f82079e --- /dev/null +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs @@ -0,0 +1,49 @@ +// Copyright 2016 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. + +// This test is for #29859, we need to ensure auto traits, +// (also known previously as default traits), do not have +// supertraits. Since the compiler synthesizes these +// instances on demand, we are essentially enabling +// users to write axioms if we view trait selection, +// as a proof system. +// +// For example the below test allows us to add the rule: +// forall (T : Type), T : Copy +// +// Providing a copy instance for *any* type, which +// is most definitely unsound. Imagine copying a +// type that contains a mutable reference, enabling +// mutable aliasing. +// +// You can imagine an even more dangerous test, +// which currently compiles on nightly. +// +// fn main() { +// let mut i = 10; +// let (a, b) = copy(&mut i); +// println!("{:?} {:?}", a, b); +// } + +#![feature(optin_builtin_traits)] + +trait Magic: Copy {} //~ ERROR E0565 +impl Magic for .. {} +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); + println!("{:?} {:?}", a, b); +} diff --git a/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs new file mode 100644 index 0000000000000..f2841a413db9e --- /dev/null +++ b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs @@ -0,0 +1,14 @@ +// Copyright 2016 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. + +#![feature(optin_builtin_traits)] + +trait Magic {} //~ ERROR E0566 +impl Magic for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs b/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs deleted file mode 100644 index 0b071a9acd092..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015 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 that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait : NotImplemented {} - -impl MyTrait for .. {} - -fn foo() { bar::() } - -fn bar() { } - -fn main() { - foo::(); //~ ERROR `i32: NotImplemented` is not satisfied - bar::(); //~ ERROR `i64: NotImplemented` is not satisfied -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs deleted file mode 100644 index 3085f45a83dd1..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015 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. - -// ignore-tidy-linelength - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait: Sized - where Option : NotImplemented -{} - -impl NotImplemented for i32 {} - -impl MyTrait for .. {} - -fn bar() { } - -fn test() { - bar::>(); - //~^ ERROR `std::option::Option: NotImplemented` is not satisfied -} - -fn main() { -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs deleted file mode 100644 index 47e87c09d12b1..0000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015 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. - -// ignore-tidy-linelength - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait: Sized - where Option : NotImplemented -{} - -impl NotImplemented for i32 {} - -impl MyTrait for .. {} - -fn foo() { - //~^ ERROR `std::option::Option: NotImplemented` is not satisfied - // This should probably typecheck. This is #20671. -} - -fn bar() { } - -fn main() { -} diff --git a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs index c2ff7a0054f19..52bd386ba595b 100644 --- a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs +++ b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs @@ -14,7 +14,7 @@ pub mod bar { use std::marker; - pub trait Bar: 'static {} + pub trait Bar {} impl Bar for .. {}