@@ -13,42 +13,54 @@ use syntax::ext::base;
13
13
use syntax:: ext:: build:: AstBuilder ;
14
14
use syntax:: symbol:: Symbol ;
15
15
use syntax:: tokenstream;
16
- use syntax_pos;
16
+ use syntax_pos:: Span ;
17
17
18
18
use std:: string:: String ;
19
19
20
20
pub fn expand_syntax_ext (
21
21
cx : & mut base:: ExtCtxt ,
22
- sp : syntax_pos :: Span ,
22
+ sp : Span ,
23
23
tts : & [ tokenstream:: TokenTree ] ,
24
24
) -> Box < dyn base:: MacResult + ' static > {
25
25
let es = match base:: get_exprs_from_tts ( cx, sp, tts) {
26
26
Some ( e) => e,
27
27
None => return base:: DummyResult :: expr ( sp) ,
28
28
} ;
29
- let mut accumulator = String :: new ( ) ;
29
+ let mut string_accumulator = String :: new ( ) ;
30
+ let mut string_pos = vec ! [ ] ;
31
+ let mut b_accumulator: Vec < u8 > = vec ! [ ] ;
32
+ let mut b_pos: Vec < Span > = vec ! [ ] ;
30
33
let mut missing_literal = vec ! [ ] ;
31
34
for e in es {
32
35
match e. node {
33
36
ast:: ExprKind :: Lit ( ref lit) => match lit. node {
34
37
ast:: LitKind :: Str ( ref s, _)
35
38
| ast:: LitKind :: Float ( ref s, _)
36
39
| ast:: LitKind :: FloatUnsuffixed ( ref s) => {
37
- accumulator. push_str ( & s. as_str ( ) ) ;
40
+ string_accumulator. push_str ( & s. as_str ( ) ) ;
41
+ string_pos. push ( e. span ) ;
38
42
}
39
43
ast:: LitKind :: Char ( c) => {
40
- accumulator. push ( c) ;
44
+ string_accumulator. push ( c) ;
45
+ string_pos. push ( e. span ) ;
41
46
}
42
47
ast:: LitKind :: Int ( i, ast:: LitIntType :: Unsigned ( _) )
43
48
| ast:: LitKind :: Int ( i, ast:: LitIntType :: Signed ( _) )
44
49
| ast:: LitKind :: Int ( i, ast:: LitIntType :: Unsuffixed ) => {
45
- accumulator. push_str ( & i. to_string ( ) ) ;
50
+ string_accumulator. push_str ( & i. to_string ( ) ) ;
51
+ string_pos. push ( e. span ) ;
46
52
}
47
53
ast:: LitKind :: Bool ( b) => {
48
- accumulator. push_str ( & b. to_string ( ) ) ;
54
+ string_accumulator. push_str ( & b. to_string ( ) ) ;
55
+ string_pos. push ( e. span ) ;
49
56
}
50
- ast:: LitKind :: Byte ( ..) | ast:: LitKind :: ByteStr ( ..) => {
51
- cx. span_err ( e. span , "cannot concatenate a byte string literal" ) ;
57
+ ast:: LitKind :: Byte ( byte) => {
58
+ b_accumulator. push ( byte) ;
59
+ b_pos. push ( e. span ) ;
60
+ }
61
+ ast:: LitKind :: ByteStr ( ref b_str) => {
62
+ b_accumulator. extend ( b_str. iter ( ) ) ;
63
+ b_pos. push ( e. span ) ;
52
64
}
53
65
} ,
54
66
_ => {
@@ -61,6 +73,36 @@ pub fn expand_syntax_ext(
61
73
err. note ( "only literals (like `\" foo\" `, `42` and `3.14`) can be passed to `concat!()`" ) ;
62
74
err. emit ( ) ;
63
75
}
76
+ // Do not allow mixing "" and b""
77
+ if string_accumulator. len ( ) > 0 && b_accumulator. len ( ) > 0 {
78
+ let mut err = cx. struct_span_err (
79
+ b_pos. clone ( ) ,
80
+ "cannot concatenate a byte string literal with string literals" ,
81
+ ) ;
82
+ for pos in & b_pos {
83
+ err. span_label ( * pos, "byte string literal" ) ;
84
+ }
85
+ for pos in & string_pos {
86
+ err. span_label ( * pos, "string literal" ) ;
87
+
88
+ }
89
+ err. help ( "do not mix byte string literals and string literals" ) ;
90
+ err. multipart_suggestion (
91
+ "you can use byte string literals" ,
92
+ string_pos
93
+ . iter ( )
94
+ . map ( |pos| ( pos. shrink_to_lo ( ) , "b" . to_string ( ) ) )
95
+ . collect ( ) ,
96
+ ) ;
97
+ err. emit ( ) ;
98
+ }
64
99
let sp = sp. apply_mark ( cx. current_expansion . mark ) ;
65
- base:: MacEager :: expr ( cx. expr_str ( sp, Symbol :: intern ( & accumulator) ) )
100
+ if b_accumulator. len ( ) > 0 {
101
+ base:: MacEager :: expr ( cx. expr_lit (
102
+ sp,
103
+ ast:: LitKind :: new_byte_str ( b_accumulator) ,
104
+ ) )
105
+ } else {
106
+ base:: MacEager :: expr ( cx. expr_str ( sp, Symbol :: intern ( & string_accumulator) ) )
107
+ }
66
108
}
0 commit comments