| // Test to ensure that trait bounds are properly |
| // checked on specializable associated types |
| |
| #![allow(incomplete_features)] |
| #![feature(specialization)] |
| |
| trait UncheckedCopy: Sized { |
| type Output: From<Self> + Copy + Into<Self>; |
| } |
| |
| impl<T> UncheckedCopy for T { |
| default type Output = Self; |
| //~^ ERROR: the trait bound `T: Copy` is not satisfied |
| } |
| |
| fn unchecked_copy<T: UncheckedCopy>(other: &T::Output) -> T { |
| (*other).into() |
| } |
| |
| fn bug(origin: String) { |
| // Turn the String into it's Output type... |
| // Which we can just do by `.into()`, the assoc type states `From<Self>`. |
| let origin_output = origin.into(); |
| |
| // Make a copy of String::Output, which is a String... |
| let mut copy: String = unchecked_copy::<String>(&origin_output); |
| |
| // Turn the Output type into a String again, |
| // Which we can just do by `.into()`, the assoc type states `Into<Self>`. |
| let mut origin: String = origin_output.into(); |
| |
| // assert both Strings use the same buffer. |
| assert_eq!(copy.as_ptr(), origin.as_ptr()); |
| |
| // Any use of the copy we made becomes invalid, |
| drop(origin); |
| |
| // OH NO! UB UB UB UB! |
| copy.push_str(" world!"); |
| println!("{}", copy); |
| } |
| |
| fn main() { |
| bug(String::from("hello")); |
| } |