@@ -15,7 +15,7 @@ use syntax::ext::build::AstBuilder;
1515use syntax:: parse:: token;
1616use syntax:: print:: pprust;
1717use syntax:: tokenstream:: { TokenStream , TokenTree } ;
18- use syntax_pos:: Span ;
18+ use syntax_pos:: { Span , DUMMY_SP } ;
1919
2020pub fn expand_assert < ' cx > (
2121 cx : & ' cx mut ExtCtxt ,
@@ -41,10 +41,18 @@ pub fn expand_assert<'cx>(
4141 tts : if let Some ( ts) = custom_msg_args {
4242 ts. into ( )
4343 } 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+ ) ,
4856 ) ) . into ( )
4957 } ,
5058 } ;
@@ -62,3 +70,53 @@ pub fn expand_assert<'cx>(
6270 ) ;
6371 MacEager :: expr ( if_expr)
6472}
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