@@ -95,8 +95,8 @@ pub enum UnwindResult {
9595 /// The task is ending successfully
9696 Success ,
9797
98- /// The Task is failing with reason `UnwindReason `
99- Failure ( UnwindReason ) ,
98+ /// The Task is failing with reason `UnwindMessage `
99+ Failure ( UnwindMessage ) ,
100100}
101101
102102impl UnwindResult {
@@ -121,20 +121,25 @@ impl UnwindResult {
121121
122122/// Represents the cause of a task failure
123123#[ deriving( ToStr ) ]
124- pub enum UnwindReason {
125- /// Failed with a string message
126- UnwindReasonStr ( SendStr ) ,
124+ pub enum UnwindMessage {
125+ // FIXME: #9913 - This variant is not neccessary once Any works properly
126+ /// Failed with a static string message
127+ UnwindMessageStrStatic ( & ' static str ) ,
128+
129+ // FIXME: #9913 - This variant is not neccessary once Any works properly
130+ /// Failed with a owned string message
131+ UnwindMessageStrOwned ( ~str ) ,
127132
128133 /// Failed with an `~Any`
129- UnwindReasonAny ( ~Any ) ,
134+ UnwindMessageAny ( ~Any ) ,
130135
131136 /// Failed because of linked failure
132- UnwindReasonLinked
137+ UnwindMessageLinked
133138}
134139
135140pub struct Unwinder {
136141 unwinding : bool ,
137- cause : Option < UnwindReason >
142+ cause : Option < UnwindMessage >
138143}
139144
140145impl Unwinder {
@@ -527,7 +532,7 @@ impl Unwinder {
527532 }
528533 }
529534
530- pub fn begin_unwind ( & mut self , cause : UnwindReason ) -> ! {
535+ pub fn begin_unwind ( & mut self , cause : UnwindMessage ) -> ! {
531536 #[ fixed_stack_segment] ; #[ inline( never) ] ;
532537
533538 self . unwinding = true ;
@@ -622,7 +627,7 @@ pub extern "C" fn rust_stack_exhausted() {
622627/// This is the entry point of unwinding for things like lang items and such.
623628/// The arguments are normally generated by the compiler, and need to
624629/// have static lifetimes.
625- pub fn begin_unwind ( msg : * c_char , file : * c_char , line : size_t ) -> ! {
630+ pub fn begin_unwind_raw ( msg : * c_char , file : * c_char , line : size_t ) -> ! {
626631 use c_str:: CString ;
627632 use cast:: transmute;
628633
@@ -638,11 +643,33 @@ pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! {
638643 let msg = static_char_ptr ( msg) ;
639644 let file = static_char_ptr ( file) ;
640645
641- begin_unwind_reason ( UnwindReasonStr ( msg. into_send_str ( ) ) , file, line as uint )
646+ begin_unwind ( msg, file, line as uint )
642647}
643648
644649/// This is the entry point of unwinding for fail!() and assert!().
645- pub fn begin_unwind_reason ( reason : UnwindReason , file : & ' static str , line : uint ) -> ! {
650+ pub fn begin_unwind < M : Any + Send > ( msg : M , file : & ' static str , line : uint ) -> ! {
651+ // Wrap the fail message in a `Any` box for uniform representation.
652+ let any = ~msg as ~Any ;
653+
654+ // FIXME: #9913 - This can be changed to be internal to begin_unwind_internal
655+ // once Any works properly.
656+ // As a workaround, string types need to be special cased right now
657+ // because `Any` does not support dynamically querying whether the
658+ // type implements a trait yet, so without requiring that every `Any`
659+ // also implements `ToStr` there is no way to get a failure message
660+ // out of it again during unwinding.
661+ let msg = if any. is :: < & ' static str > ( ) {
662+ UnwindMessageStrStatic ( * any. move :: < & ' static str > ( ) . unwrap ( ) )
663+ } else if any. is :: < ~str > ( ) {
664+ UnwindMessageStrOwned ( * any. move :: < ~str > ( ) . unwrap ( ) )
665+ } else {
666+ UnwindMessageAny ( any)
667+ } ;
668+
669+ begin_unwind_internal ( msg, file, line)
670+ }
671+
672+ fn begin_unwind_internal ( msg : UnwindMessage , file : & ' static str , line : uint ) -> ! {
646673 use rt:: in_green_task_context;
647674 use rt:: task:: Task ;
648675 use rt:: local:: Local ;
@@ -656,15 +683,16 @@ pub fn begin_unwind_reason(reason: UnwindReason, file: &'static str, line: uint)
656683 let task: * mut Task ;
657684
658685 {
659- let msg = match reason {
660- UnwindReasonStr ( ref s) => s. as_slice ( ) ,
661- UnwindReasonAny ( _) => "~Any" ,
662- UnwindReasonLinked => "linked failure" ,
686+ let msg_s = match msg {
687+ UnwindMessageAny ( _) => "~Any" ,
688+ UnwindMessageLinked => "linked failure" ,
689+ UnwindMessageStrOwned ( ref s) => s. as_slice ( ) ,
690+ UnwindMessageStrStatic ( ref s) => s. as_slice ( ) ,
663691 } ;
664692
665693 if !in_green_task_context ( ) {
666694 rterrln ! ( "failed in non-task context at '{}', {}:{}" ,
667- msg , file, line) ;
695+ msg_s , file, line) ;
668696 intrinsics:: abort ( ) ;
669697 }
670698
@@ -679,19 +707,20 @@ pub fn begin_unwind_reason(reason: UnwindReason, file: &'static str, line: uint)
679707 // due to mismanagment of its own kill flag, so calling our own
680708 // logger in its current state is a bit of a problem.
681709
682- rterrln ! ( "task '{}' failed at '{}', {}:{}" , n, msg , file, line) ;
710+ rterrln ! ( "task '{}' failed at '{}', {}:{}" , n, msg_s , file, line) ;
683711
684712 if ( * task) . unwinder . unwinding {
685713 rtabort ! ( "unwinding again" ) ;
686714 }
687715 }
688716
689- ( * task) . unwinder . begin_unwind ( reason ) ;
717+ ( * task) . unwinder . begin_unwind ( msg ) ;
690718 }
691719}
692720
693721#[ cfg( test) ]
694722mod test {
723+ use super :: * ;
695724 use rt:: test:: * ;
696725
697726 #[ test]
@@ -804,4 +833,8 @@ mod test {
804833 a.next = Some(b);
805834 }
806835 }
836+
837+ #[test]
838+ #[should_fail]
839+ fn test_begin_unwind() { begin_unwind(" cause" , file!( ) , line!( ) ) }
807840}
0 commit comments