]> git.lizzy.rs Git - rust.git/commitdiff
rustc: don't reveal specializable polymorphic projections.
authorEduard Burtescu <edy.burt@gmail.com>
Fri, 1 Jul 2016 16:32:53 +0000 (19:32 +0300)
committerEduard Burtescu <edy.burt@gmail.com>
Fri, 12 Aug 2016 03:43:34 +0000 (06:43 +0300)
src/librustc/traits/project.rs
src/test/compile-fail/transmute-different-sizes.rs

index b43074a68b16838ed8f4649aa0467024e44e4087..b93693cd756ce7f2337c3649d089e4181107a566 100644 (file)
@@ -93,7 +93,7 @@ pub enum Reveal {
     /// }
     NotSpecializable,
 
-    /// At trans time, all projections will succeed.
+    /// At trans time, all monomorphic projections will succeed.
     All,
 }
 
@@ -878,7 +878,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
 
                 candidate_set.vec.push(ProjectionTyCandidate::Select);
             }
-            super::VtableImpl(ref impl_data) if selcx.projection_mode() != Reveal::All => {
+            super::VtableImpl(ref impl_data) => {
                 // We have to be careful when projecting out of an
                 // impl because of specialization. If we are not in
                 // trans (i.e., projection mode is not "any"), and the
@@ -902,37 +902,43 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                                                  impl_data.impl_def_id,
                                                  obligation.predicate.item_name);
                 let new_candidate = if let Some(node_item) = opt_node_item {
-                    if node_item.node.is_from_trait() {
-                        if node_item.item.ty.is_some() {
-                            // The impl inherited a `type Foo =
-                            // Bar` given in the trait, which is
-                            // implicitly default. No candidate.
-                            None
-                        } else {
-                            // The impl did not specify `type` and neither
-                            // did the trait:
-                            //
-                            // ```rust
-                            // trait Foo { type T; }
-                            // impl Foo for Bar { }
-                            // ```
-                            //
-                            // This is an error, but it will be
-                            // reported in `check_impl_items_against_trait`.
-                            // We accept it here but will flag it as
-                            // an error when we confirm the candidate
-                            // (which will ultimately lead to `normalize_to_error`
-                            // being invoked).
+                    let is_default = if node_item.node.is_from_trait() {
+                        // If true, the impl inherited a `type Foo = Bar`
+                        // given in the trait, which is implicitly default.
+                        // Otherwise, the impl did not specify `type` and
+                        // neither did the trait:
+                        //
+                        // ```rust
+                        // trait Foo { type T; }
+                        // impl Foo for Bar { }
+                        // ```
+                        //
+                        // This is an error, but it will be
+                        // reported in `check_impl_items_against_trait`.
+                        // We accept it here but will flag it as
+                        // an error when we confirm the candidate
+                        // (which will ultimately lead to `normalize_to_error`
+                        // being invoked).
+                        node_item.item.ty.is_some()
+                    } else {
+                        node_item.item.defaultness.is_default()
+                    };
+
+                    // Only reveal a specializable default if we're past type-checking
+                    // and the obligations is monomorphic, otherwise passes such as
+                    // transmute checking and polymorphic MIR optimizations could
+                    // get a result which isn't correct for all monomorphizations.
+                    if !is_default {
+                        Some(ProjectionTyCandidate::Select)
+                    } else if selcx.projection_mode() == Reveal::All {
+                        assert!(!poly_trait_ref.needs_infer());
+                        if !poly_trait_ref.needs_subst() {
                             Some(ProjectionTyCandidate::Select)
+                        } else {
+                            None
                         }
-                    } else if node_item.item.defaultness.is_default() {
-                        // The impl specified `default type Foo =
-                        // Bar`. No candidate.
-                        None
                     } else {
-                        // The impl specified `type Foo = Bar`
-                        // with no default. Add a candidate.
-                        Some(ProjectionTyCandidate::Select)
+                        None
                     }
                 } else {
                     // This is saying that neither the trait nor
@@ -982,11 +988,6 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                 };
                 candidate_set.vec.extend(new_candidate);
             }
-            super::VtableImpl(_) => {
-                // In trans mode, we can just project out of impls, no prob.
-                assert!(selcx.projection_mode() == Reveal::All);
-                candidate_set.vec.push(ProjectionTyCandidate::Select);
-            }
             super::VtableParam(..) => {
                 // This case tell us nothing about the value of an
                 // associated type. Consider:
index df87a7bbdc9c223eb877f372d3987a14f9ab5dee..5fab271efce64cb72905e943b8b029531b75dff3 100644 (file)
@@ -11,6 +11,7 @@
 // Tests that `transmute` cannot be called on types of different size.
 
 #![allow(warnings)]
+#![feature(specialization)]
 
 use std::mem::transmute;
 
@@ -24,4 +25,15 @@ unsafe fn g<T>(x: &T) {
     //~^ ERROR transmute called with differently sized types
 }
 
+trait Specializable { type Output; }
+
+impl<T> Specializable for T {
+    default type Output = u16;
+}
+
+unsafe fn specializable<T>(x: u16) -> <T as Specializable>::Output {
+    transmute(x)
+    //~^ ERROR transmute called with differently sized types
+}
+
 fn main() {}