Skip to content

Commit 044c99d

Browse files
committed
Improve diagnostics for concat_bytes! with C string literals
Use the same error as other invalid types for `concat_bytes!`, rather than using `ConcatCStrLit` from `concat!`. Also add more information with a note about why this doesn't work, and a suggestion to use a null-terminated byte string instead.
1 parent 342f07a commit 044c99d

File tree

5 files changed

+86
-43
lines changed

5 files changed

+86
-43
lines changed

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number
104104
builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals
105105
.byte_char = try using a byte character
106106
.byte_str = try using a byte string
107+
.c_str = try using a null-terminated byte string
108+
.c_str_note = concatenating C strings is ambiguous about including the '\0'
107109
.number_array = try wrapping the number in an array
108110
109111
builtin_macros_concat_bytes_missing_literal = expected a byte literal

compiler/rustc_builtin_macros/src/concat_bytes.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_ast::ptr::P;
22
use rustc_ast::tokenstream::TokenStream;
3-
use rustc_ast::{ExprKind, LitIntType, LitKind, UintTy, token};
3+
use rustc_ast::{ExprKind, LitIntType, LitKind, StrStyle, UintTy, token};
44
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
55
use rustc_session::errors::report_lit_error;
66
use rustc_span::{ErrorGuaranteed, Span};
@@ -21,15 +21,32 @@ fn invalid_type_err(
2121
let snippet = cx.sess.source_map().span_to_snippet(span).ok();
2222
let dcx = cx.dcx();
2323
match LitKind::from_token_lit(token_lit) {
24-
Ok(LitKind::CStr(_, _)) => {
24+
Ok(LitKind::CStr(_, style)) => {
2525
// Avoid ambiguity in handling of terminal `NUL` by refusing to
2626
// concatenate C string literals as bytes.
27-
dcx.emit_err(errors::ConcatCStrLit { span })
27+
let sugg = if let Some(mut as_bstr) = snippet
28+
&& style == StrStyle::Cooked
29+
&& as_bstr.starts_with('c')
30+
&& as_bstr.ends_with('"')
31+
{
32+
// Suggest`c"foo"` -> `b"foo\0"` if we can
33+
as_bstr.replace_range(0..1, "b");
34+
as_bstr.pop();
35+
as_bstr.push_str(r#"\0""#);
36+
Some(ConcatBytesInvalidSuggestion::CStrLit { span, as_bstr })
37+
} else {
38+
// No suggestion for a missing snippet, raw strings, or if for some reason we have
39+
// a span that doesn't match `c"foo"` (possible if a proc macro assigns a span
40+
// that doesn't actually point to a C string).
41+
None
42+
};
43+
// We can only provide a suggestion if we have a snip and it is not a raw string
44+
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "C string", sugg, cs_note: Some(()) })
2845
}
2946
Ok(LitKind::Char(_)) => {
3047
let sugg =
3148
snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
32-
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg })
49+
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg, cs_note: None })
3350
}
3451
Ok(LitKind::Str(_, _)) => {
3552
// suggestion would be invalid if we are nested
@@ -38,18 +55,21 @@ fn invalid_type_err(
3855
} else {
3956
None
4057
};
41-
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg })
58+
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg, cs_note: None })
4259
}
4360
Ok(LitKind::Float(_, _)) => {
44-
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None })
45-
}
46-
Ok(LitKind::Bool(_)) => {
47-
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None })
61+
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None, cs_note: None })
4862
}
63+
Ok(LitKind::Bool(_)) => dcx.emit_err(ConcatBytesInvalid {
64+
span,
65+
lit_kind: "boolean",
66+
sugg: None,
67+
cs_note: None,
68+
}),
4969
Ok(LitKind::Int(_, _)) if !is_nested => {
5070
let sugg =
5171
snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet });
52-
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg })
72+
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg, cs_note: None })
5373
}
5474
Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => {
5575
assert!(val.get() > u8::MAX.into()); // must be an error

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ pub(crate) struct ConcatBytesInvalid {
215215
pub(crate) lit_kind: &'static str,
216216
#[subdiagnostic]
217217
pub(crate) sugg: Option<ConcatBytesInvalidSuggestion>,
218+
#[note(builtin_macros_c_str_note)]
219+
pub(crate) cs_note: Option<()>,
218220
}
219221

220222
#[derive(Subdiagnostic)]
@@ -239,6 +241,13 @@ pub(crate) enum ConcatBytesInvalidSuggestion {
239241
span: Span,
240242
snippet: String,
241243
},
244+
#[note(builtin_macros_c_str_note)]
245+
#[suggestion(builtin_macros_c_str, code = "{as_bstr}", applicability = "machine-applicable")]
246+
CStrLit {
247+
#[primary_span]
248+
span: Span,
249+
as_bstr: String,
250+
},
242251
#[suggestion(
243252
builtin_macros_number_array,
244253
code = "[{snippet}]",

tests/ui/macros/concat-bytes-error.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ fn main() {
1515
//~^ SUGGESTION br"tnrsi"
1616
concat_bytes!(r#"tnrsi"#, r###"tnri"###); //~ ERROR cannot concatenate string literals
1717
//~^ SUGGESTION br#"tnrsi"#
18-
concat_bytes!(c"tnrsi", c"tnri"); //~ ERROR cannot concatenate a C string literal
19-
concat_bytes!(cr"tnrsi", cr"tnri"); //~ ERROR cannot concatenate a C string literal
20-
concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); //~ ERROR cannot concatenate a C string literal
18+
concat_bytes!(c"tnrsi", c"tnri"); //~ ERROR cannot concatenate C string literals
19+
//~^ SUGGESTION b"tnrsi\0"
20+
concat_bytes!(cr"tnrsi", cr"tnri"); //~ ERROR cannot concatenate C string literals
21+
concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); //~ ERROR cannot concatenate C string literals
2122

2223
// Other literals
2324
concat_bytes!(2.8); //~ ERROR cannot concatenate float literals

tests/ui/macros/concat-bytes-error.stderr

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,106 +32,117 @@ error: cannot concatenate string literals
3232
LL | concat_bytes!(r#"tnrsi"#, r###"tnri"###);
3333
| ^^^^^^^^^^ help: try using a byte string: `br#"tnrsi"#`
3434

35-
error: cannot concatenate a C string literal
35+
error: cannot concatenate C string literals
36+
--> $DIR/concat-bytes-error.rs:18:19
37+
|
38+
LL | concat_bytes!(c"tnrsi", c"tnri");
39+
| ^^^^^^^^ help: try using a null-terminated byte string: `b"tnrsi\0"`
40+
|
41+
note: concatenating C strings is ambiguous about including the '\0'
3642
--> $DIR/concat-bytes-error.rs:18:19
3743
|
3844
LL | concat_bytes!(c"tnrsi", c"tnri");
3945
| ^^^^^^^^
46+
= note: concatenating C strings is ambiguous about including the '\0'
4047

41-
error: cannot concatenate a C string literal
42-
--> $DIR/concat-bytes-error.rs:19:19
48+
error: cannot concatenate C string literals
49+
--> $DIR/concat-bytes-error.rs:20:19
4350
|
4451
LL | concat_bytes!(cr"tnrsi", cr"tnri");
4552
| ^^^^^^^^^
53+
|
54+
= note: concatenating C strings is ambiguous about including the '\0'
4655

47-
error: cannot concatenate a C string literal
48-
--> $DIR/concat-bytes-error.rs:20:19
56+
error: cannot concatenate C string literals
57+
--> $DIR/concat-bytes-error.rs:21:19
4958
|
5059
LL | concat_bytes!(cr#"tnrsi"#, cr###"tnri"###);
5160
| ^^^^^^^^^^^
61+
|
62+
= note: concatenating C strings is ambiguous about including the '\0'
5263

5364
error: cannot concatenate float literals
54-
--> $DIR/concat-bytes-error.rs:23:19
65+
--> $DIR/concat-bytes-error.rs:24:19
5566
|
5667
LL | concat_bytes!(2.8);
5768
| ^^^
5869

5970
error: cannot concatenate numeric literals
60-
--> $DIR/concat-bytes-error.rs:24:19
71+
--> $DIR/concat-bytes-error.rs:25:19
6172
|
6273
LL | concat_bytes!(300);
6374
| ^^^ help: try wrapping the number in an array: `[300]`
6475

6576
error: cannot concatenate character literals
66-
--> $DIR/concat-bytes-error.rs:26:19
77+
--> $DIR/concat-bytes-error.rs:27:19
6778
|
6879
LL | concat_bytes!('a');
6980
| ^^^ help: try using a byte character: `b'a'`
7081

7182
error: cannot concatenate boolean literals
72-
--> $DIR/concat-bytes-error.rs:28:19
83+
--> $DIR/concat-bytes-error.rs:29:19
7384
|
7485
LL | concat_bytes!(true, false);
7586
| ^^^^
7687

7788
error: cannot concatenate numeric literals
78-
--> $DIR/concat-bytes-error.rs:29:19
89+
--> $DIR/concat-bytes-error.rs:30:19
7990
|
8091
LL | concat_bytes!(42, b"va", b'l');
8192
| ^^ help: try wrapping the number in an array: `[42]`
8293

8394
error: cannot concatenate numeric literals
84-
--> $DIR/concat-bytes-error.rs:31:19
95+
--> $DIR/concat-bytes-error.rs:32:19
8596
|
8697
LL | concat_bytes!(42, b"va", b'l', [1, 2]);
8798
| ^^ help: try wrapping the number in an array: `[42]`
8899

89100
error: cannot concatenate string literals
90-
--> $DIR/concat-bytes-error.rs:36:9
101+
--> $DIR/concat-bytes-error.rs:37:9
91102
|
92103
LL | "hi",
93104
| ^^^^
94105

95106
error: cannot concatenate character literals
96-
--> $DIR/concat-bytes-error.rs:39:9
107+
--> $DIR/concat-bytes-error.rs:40:9
97108
|
98109
LL | 'a',
99110
| ^^^ help: try using a byte character: `b'a'`
100111

101112
error: cannot concatenate boolean literals
102-
--> $DIR/concat-bytes-error.rs:43:9
113+
--> $DIR/concat-bytes-error.rs:44:9
103114
|
104115
LL | true,
105116
| ^^^^
106117

107118
error: cannot concatenate boolean literals
108-
--> $DIR/concat-bytes-error.rs:46:9
119+
--> $DIR/concat-bytes-error.rs:47:9
109120
|
110121
LL | false,
111122
| ^^^^^
112123

113124
error: cannot concatenate float literals
114-
--> $DIR/concat-bytes-error.rs:49:9
125+
--> $DIR/concat-bytes-error.rs:50:9
115126
|
116127
LL | 2.6,
117128
| ^^^
118129

119130
error: numeric literal is out of bounds
120-
--> $DIR/concat-bytes-error.rs:52:9
131+
--> $DIR/concat-bytes-error.rs:53:9
121132
|
122133
LL | 265,
123134
| ^^^
124135

125136
error: expected a byte literal
126-
--> $DIR/concat-bytes-error.rs:55:9
137+
--> $DIR/concat-bytes-error.rs:56:9
127138
|
128139
LL | -33,
129140
| ^^^
130141
|
131142
= note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
132143

133144
error: cannot concatenate doubly nested array
134-
--> $DIR/concat-bytes-error.rs:58:9
145+
--> $DIR/concat-bytes-error.rs:59:9
135146
|
136147
LL | b"hi!",
137148
| ^^^^^^
@@ -140,69 +151,69 @@ LL | b"hi!",
140151
= help: try flattening the array
141152

142153
error: cannot concatenate doubly nested array
143-
--> $DIR/concat-bytes-error.rs:61:9
154+
--> $DIR/concat-bytes-error.rs:62:9
144155
|
145156
LL | [5, 6, 7],
146157
| ^^^^^^^^^
147158

148159
error: cannot concatenate numeric literals
149-
--> $DIR/concat-bytes-error.rs:63:19
160+
--> $DIR/concat-bytes-error.rs:64:19
150161
|
151162
LL | concat_bytes!(5u16);
152163
| ^^^^ help: try wrapping the number in an array: `[5u16]`
153164

154165
error: numeric literal is not a `u8`
155-
--> $DIR/concat-bytes-error.rs:65:20
166+
--> $DIR/concat-bytes-error.rs:66:20
156167
|
157168
LL | concat_bytes!([5u16]);
158169
| ^^^^
159170

160171
error: repeat count is not a positive number
161-
--> $DIR/concat-bytes-error.rs:66:23
172+
--> $DIR/concat-bytes-error.rs:67:23
162173
|
163174
LL | concat_bytes!([3; ()]);
164175
| ^^
165176

166177
error: repeat count is not a positive number
167-
--> $DIR/concat-bytes-error.rs:67:23
178+
--> $DIR/concat-bytes-error.rs:68:23
168179
|
169180
LL | concat_bytes!([3; -2]);
170181
| ^^
171182

172183
error: repeat count is not a positive number
173-
--> $DIR/concat-bytes-error.rs:68:25
184+
--> $DIR/concat-bytes-error.rs:69:25
174185
|
175186
LL | concat_bytes!([pie; -2]);
176187
| ^^
177188

178189
error: expected a byte literal
179-
--> $DIR/concat-bytes-error.rs:69:20
190+
--> $DIR/concat-bytes-error.rs:70:20
180191
|
181192
LL | concat_bytes!([pie; 2]);
182193
| ^^^
183194
|
184195
= note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
185196

186197
error: cannot concatenate float literals
187-
--> $DIR/concat-bytes-error.rs:70:20
198+
--> $DIR/concat-bytes-error.rs:71:20
188199
|
189200
LL | concat_bytes!([2.2; 0]);
190201
| ^^^
191202

192203
error: repeat count is not a positive number
193-
--> $DIR/concat-bytes-error.rs:71:25
204+
--> $DIR/concat-bytes-error.rs:72:25
194205
|
195206
LL | concat_bytes!([5.5; ()]);
196207
| ^^
197208

198209
error: cannot concatenate doubly nested array
199-
--> $DIR/concat-bytes-error.rs:72:20
210+
--> $DIR/concat-bytes-error.rs:73:20
200211
|
201212
LL | concat_bytes!([[1, 2, 3]; 3]);
202213
| ^^^^^^^^^
203214

204215
error: cannot concatenate doubly nested array
205-
--> $DIR/concat-bytes-error.rs:73:20
216+
--> $DIR/concat-bytes-error.rs:74:20
206217
|
207218
LL | concat_bytes!([[42; 2]; 3]);
208219
| ^^^^^^^

0 commit comments

Comments
 (0)