about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <arielb1@mail.tau.ac.il>2015-09-24 18:27:29 +0300
committerAriel Ben-Yehuda <arielb1@mail.tau.ac.il>2015-09-24 18:27:29 +0300
commit77e8f33c3d7950e4fae8477e0420024a51488c91 (patch)
tree7a9d9a28e7cc79f82ded3108c0b971bd56e043d2
parent8fe79bdfdacb2f5914971bd1a0b63b9577afbf6a (diff)
downloadrust-77e8f33c3d7950e4fae8477e0420024a51488c91.tar.gz
rust-77e8f33c3d7950e4fae8477e0420024a51488c91.zip
early-prohibit objects with Self-containing supertraits
Fixes #28576
-rw-r--r--src/librustc/middle/traits/error_reporting.rs10
-rw-r--r--src/librustc/middle/traits/mod.rs1
-rw-r--r--src/librustc/middle/traits/object_safety.rs27
-rw-r--r--src/librustc_typeck/astconv.rs21
-rw-r--r--src/librustc_typeck/diagnostics.rs2
-rw-r--r--src/test/compile-fail/issue-28576.rs22
-rw-r--r--src/test/compile-fail/object-safety-issue-22040.rs6
-rw-r--r--src/test/compile-fail/object-safety-supertrait-mentions-Self.rs4
8 files changed, 80 insertions, 13 deletions
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index 5248cb7f30e..25e6036e85a 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<ObjectSafetyViolation>,
                                         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 b0d4d92e8e1..5dc6f9454a8 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 3a2602cd5b4..1762233b044 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<ObjectSafetyViolation<'tcx>>
+{
+    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<ObjectSafetyViolation<'tcx>>
@@ -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 5be450ea278..7b2bbbcc4a9 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::PolyProjectionPredicate<'tcx>>)
     -> 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 3b08140612f..30cb89cf0fd 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 00000000000..bd7186708a6
--- /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 <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.
+
+pub trait Foo<RHS=Self> {
+    type Assoc;
+}
+
+pub trait Bar: Foo<Assoc=()> {
+    fn new(&self, b: &
+           Bar //~ ERROR the trait `Bar` cannot be made into an object
+              <Assoc=()>
+    );
+}
+
+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 de419a259a2..12407f06ca0 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<Box<Expr+ 'x>>,
+    //~^ 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<Expr> = Box::new(SExpr::new()); //~ ERROR E0038
-    let b: Box<Expr> = Box::new(SExpr::new()); //~ ERROR E0038
+    let a: Box<Expr> = Box::new(SExpr::new());
+    let b: Box<Expr> = 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 ba82635a401..0a79ec30e4b 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:Bar<u32>>(t: &T) -> &Bar<u32> {
 }
 
 fn make_baz<T: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() {