diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 5248cb7f30e97..25e6036e85ab4 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -248,9 +248,12 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } ty::Predicate::ObjectSafe(trait_def_id) => { + let violations = object_safety_violations( + infcx.tcx, trait_def_id); report_object_safety_error(infcx.tcx, obligation.cause.span, trait_def_id, + violations, is_warning); note_obligation_cause(infcx, obligation); } @@ -286,7 +289,9 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } TraitNotObjectSafe(did) => { - report_object_safety_error(infcx.tcx, obligation.cause.span, did, is_warning); + let violations = object_safety_violations(infcx.tcx, did); + report_object_safety_error(infcx.tcx, obligation.cause.span, did, + violations, is_warning); note_obligation_cause(infcx, obligation); } } @@ -295,6 +300,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, trait_def_id: DefId, + violations: Vec, is_warning: bool) { span_err_or_warn!( @@ -302,7 +308,7 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, "the trait `{}` cannot be made into an object", tcx.item_path_str(trait_def_id)); - for violation in object_safety_violations(tcx, trait_def_id) { + for violation in violations { match violation { ObjectSafetyViolation::SizedSelf => { tcx.sess.fileline_note( diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index b0d4d92e8e1b2..5dc6f9454a881 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -37,6 +37,7 @@ pub use self::project::MismatchedProjectionTypes; pub use self::project::normalize; pub use self::project::Normalized; pub use self::object_safety::is_object_safe; +pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::object_safety_violations; pub use self::object_safety::ObjectSafetyViolation; pub use self::object_safety::MethodViolationCode; diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index 3a2602cd5b448..1762233b0449a 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -76,6 +76,27 @@ pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>, result } +/// Returns the object safety violations that affect +/// astconv - currently, Self in supertraits. This is needed +/// because `object_safety_violations` can't be used during +/// type collection. +pub fn astconv_object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_def_id: DefId) + -> Vec> +{ + let mut violations = vec![]; + + if supertraits_reference_self(tcx, trait_def_id) { + violations.push(ObjectSafetyViolation::SupertraitSelf); + } + + debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", + trait_def_id, + violations); + + violations +} + pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>, trait_def_id: DefId) -> Vec> @@ -118,9 +139,9 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>, violations } -fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_def_id: DefId) - -> bool +pub fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_def_id: DefId) + -> bool { let trait_def = tcx.lookup_trait_def(trait_def_id); let trait_ref = trait_def.trait_ref.clone(); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5be450ea27832..7b2bbbcc4a92a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -393,7 +393,7 @@ fn create_substs_for_ast_path<'tcx>( let tcx = this.tcx(); debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \ - types_provided={:?}, region_substs={:?}", + types_provided={:?}, region_substs={:?})", decl_generics, self_ty, types_provided, region_substs); @@ -474,6 +474,9 @@ fn create_substs_for_ast_path<'tcx>( } } + debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", + decl_generics, self_ty, substs); + substs } @@ -741,6 +744,7 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>( poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { + debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment); // The trait reference introduces a binding level here, so // we need to shift the `rscope`. It'd be nice if we could // do away with this rscope stuff and work this knowledge @@ -774,6 +778,8 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>( poly_projections.extend(converted_bindings); } + debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}", + trait_segment, poly_projections, poly_trait_ref); poly_trait_ref } @@ -1103,7 +1109,18 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>, object.principal_trait_ref_with_self_ty(tcx, tcx.types.err); // ensure the super predicates and stop if we encountered an error - if this.ensure_super_predicates(span, object.principal_def_id()).is_err() { + if this.ensure_super_predicates(span, principal.def_id()).is_err() { + return tcx.types.err; + } + + // check that there are no gross object safety violations, + // most importantly, that the supertraits don't contain Self, + // to avoid ICE-s. + let object_safety_violations = + traits::astconv_object_safety_violations(tcx, principal.def_id()); + if !object_safety_violations.is_empty() { + traits::report_object_safety_error( + tcx, span, principal.def_id(), object_safety_violations, false); return tcx.types.err; } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 3b08140612f25..30cb89cf0fde6 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3355,5 +3355,5 @@ register_diagnostics! { E0399, // trait items need to be implemented because the associated // type `{}` was overridden E0436, // functional record update requires a struct - E0513, // no type for local variable .. + E0513 // no type for local variable .. } diff --git a/src/test/compile-fail/issue-28576.rs b/src/test/compile-fail/issue-28576.rs new file mode 100644 index 0000000000000..bd7186708a6c2 --- /dev/null +++ b/src/test/compile-fail/issue-28576.rs @@ -0,0 +1,22 @@ +// 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. + +pub trait Foo { + type Assoc; +} + +pub trait Bar: Foo { + fn new(&self, b: & + Bar //~ ERROR the trait `Bar` cannot be made into an object + + ); +} + +fn main() {} diff --git a/src/test/compile-fail/object-safety-issue-22040.rs b/src/test/compile-fail/object-safety-issue-22040.rs index de419a259a24c..12407f06ca06c 100644 --- a/src/test/compile-fail/object-safety-issue-22040.rs +++ b/src/test/compile-fail/object-safety-issue-22040.rs @@ -20,12 +20,12 @@ trait Expr: Debug + PartialEq { #[derive(Debug)] struct SExpr<'x> { elements: Vec>, + //~^ ERROR E0038 } impl<'x> PartialEq for SExpr<'x> { fn eq(&self, other:&SExpr<'x>) -> bool { println!("L1: {} L2: {}", self.elements.len(), other.elements.len()); - //~^ ERROR E0038 let result = self.elements.len() == other.elements.len(); println!("Got compare {}", result); @@ -44,8 +44,8 @@ impl <'x> Expr for SExpr<'x> { } fn main() { - let a: Box = Box::new(SExpr::new()); //~ ERROR E0038 - let b: Box = Box::new(SExpr::new()); //~ ERROR E0038 + let a: Box = Box::new(SExpr::new()); + let b: Box = Box::new(SExpr::new()); // assert_eq!(a , b); } diff --git a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs index ba82635a4016e..0a79ec30e4b94 100644 --- a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs +++ b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs @@ -23,9 +23,9 @@ fn make_bar>(t: &T) -> &Bar { } fn make_baz(t: &T) -> &Baz { + //~^ ERROR E0038 + //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing t - //~^ ERROR E0038 - //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing } fn main() {