@@ -15,7 +15,7 @@ use syntax::ext::build::AstBuilder;
15
15
use syntax:: parse:: token;
16
16
use syntax:: print:: pprust;
17
17
use syntax:: tokenstream:: { TokenStream , TokenTree } ;
18
- use syntax_pos:: Span ;
18
+ use syntax_pos:: { Span , DUMMY_SP } ;
19
19
20
20
pub fn expand_assert < ' cx > (
21
21
cx : & ' cx mut ExtCtxt ,
@@ -41,10 +41,18 @@ pub fn expand_assert<'cx>(
41
41
tts : if let Some ( ts) = custom_msg_args {
42
42
ts. into ( )
43
43
} else {
44
- let panic_str = format ! ( "assertion failed: {}" , pprust:: expr_to_string( & cond_expr) ) ;
45
- TokenStream :: from ( token:: Literal (
46
- token:: Lit :: Str_ ( Name :: intern ( & panic_str) ) ,
47
- None ,
44
+ // `expr_to_string` escapes the string literals with `.escape_default()`
45
+ // which escapes all non-ASCII characters with `\u`.
46
+ let escaped_expr = escape_format_string ( & unescape_printable_unicode (
47
+ & pprust:: expr_to_string ( & cond_expr) ,
48
+ ) ) ;
49
+
50
+ TokenStream :: from ( TokenTree :: Token (
51
+ DUMMY_SP ,
52
+ token:: Literal (
53
+ token:: Lit :: Str_ ( Name :: intern ( & format ! ( "assertion failed: {}" , escaped_expr) ) ) ,
54
+ None ,
55
+ ) ,
48
56
) ) . into ( )
49
57
} ,
50
58
} ;
@@ -62,3 +70,53 @@ pub fn expand_assert<'cx>(
62
70
) ;
63
71
MacEager :: expr ( if_expr)
64
72
}
73
+
74
+ /// Escapes a string for use as a formatting string.
75
+ fn escape_format_string ( s : & str ) -> String {
76
+ let mut res = String :: with_capacity ( s. len ( ) ) ;
77
+ for c in s. chars ( ) {
78
+ res. extend ( c. escape_debug ( ) ) ;
79
+ match c {
80
+ '{' | '}' => res. push ( c) ,
81
+ _ => { }
82
+ }
83
+ }
84
+ res
85
+ }
86
+
87
+ #[ test]
88
+ fn test_escape_format_string ( ) {
89
+ assert ! ( escape_format_string( r"foo{}\" ) == r"foo{{}}\\" ) ;
90
+ }
91
+
92
+ /// Unescapes the escaped unicodes (`\u{...}`) that are printable.
93
+ fn unescape_printable_unicode ( mut s : & str ) -> String {
94
+ use std:: { char, u32} ;
95
+
96
+ let mut res = String :: with_capacity ( s. len ( ) ) ;
97
+
98
+ loop {
99
+ if let Some ( start) = s. find ( r"\u{" ) {
100
+ res. push_str ( & s[ 0 ..start] ) ;
101
+ s = & s[ start..] ;
102
+ s. find ( '}' )
103
+ . and_then ( |end| {
104
+ let v = u32:: from_str_radix ( & s[ 3 ..end] , 16 ) . ok ( ) ?;
105
+ let c = char:: from_u32 ( v) ?;
106
+ // Escape unprintable characters.
107
+ res. extend ( c. escape_debug ( ) ) ;
108
+ s = & s[ end + 1 ..] ;
109
+ Some ( ( ) )
110
+ } )
111
+ . expect ( "lexer should have rejected invalid escape sequences" ) ;
112
+ } else {
113
+ res. push_str ( s) ;
114
+ return res;
115
+ }
116
+ }
117
+ }
118
+
119
+ #[ test]
120
+ fn test_unescape_printable_unicode ( ) {
121
+ assert ! ( unescape_printable_unicode( r"\u{2603}\n\u{0}" ) == r"☃\n\u{0}" ) ;
122
+ }
0 commit comments