Skip to content

Commit 03360be

Browse files
committed
Auto merge of rust-lang#92066 - Smittyvb:concat_bytes-repeat, r=nagisa
Support [x; n] expressions in concat_bytes! Currently trying to use `concat_bytes!` with a repeating array value like `[42; 5]` results in an error: ``` error: expected a byte literal --> src/main.rs:3:27 | 3 | let x = concat_bytes!([3; 4]); | ^^^^^^ | = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` ``` This makes it so repeating array syntax can be used the same way normal arrays can be. The RFC doesn't explicitly mention repeat expressions, but it seems reasonable to allow them as well, since normal arrays are allowed. It is possible to make the compiler get stuck compiling forever with `concat_bytes!([3; 999999999])`, but I don't think that's much of an issue since you can do that already with `const X: [u8; 999999999] = [3; 999999999];`. Contributes to rust-lang#87555.
2 parents 82418f9 + 9702348 commit 03360be

File tree

4 files changed

+135
-42
lines changed

4 files changed

+135
-42
lines changed

compiler/rustc_builtin_macros/src/concat_bytes.rs

+65-40
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,52 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
7272
}
7373
}
7474

75+
fn handle_array_element(
76+
cx: &mut base::ExtCtxt<'_>,
77+
has_errors: &mut bool,
78+
missing_literals: &mut Vec<rustc_span::Span>,
79+
expr: &P<rustc_ast::Expr>,
80+
) -> Option<u8> {
81+
match expr.kind {
82+
ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
83+
if !*has_errors {
84+
cx.span_err(expr.span, "cannot concatenate doubly nested array");
85+
}
86+
*has_errors = true;
87+
None
88+
}
89+
ast::ExprKind::Lit(ref lit) => match lit.kind {
90+
ast::LitKind::Int(
91+
val,
92+
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
93+
) if val <= u8::MAX.into() => Some(val as u8),
94+
95+
ast::LitKind::Byte(val) => Some(val),
96+
ast::LitKind::ByteStr(_) => {
97+
if !*has_errors {
98+
cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
99+
.note("byte strings are treated as arrays of bytes")
100+
.help("try flattening the array")
101+
.emit();
102+
}
103+
*has_errors = true;
104+
None
105+
}
106+
_ => {
107+
if !*has_errors {
108+
invalid_type_err(cx, expr, true);
109+
}
110+
*has_errors = true;
111+
None
112+
}
113+
},
114+
_ => {
115+
missing_literals.push(expr.span);
116+
None
117+
}
118+
}
119+
}
120+
75121
pub fn expand_concat_bytes(
76122
cx: &mut base::ExtCtxt<'_>,
77123
sp: rustc_span::Span,
@@ -88,48 +134,27 @@ pub fn expand_concat_bytes(
88134
match e.kind {
89135
ast::ExprKind::Array(ref exprs) => {
90136
for expr in exprs {
91-
match expr.kind {
92-
ast::ExprKind::Array(_) => {
93-
if !has_errors {
94-
cx.span_err(expr.span, "cannot concatenate doubly nested array");
95-
}
96-
has_errors = true;
97-
}
98-
ast::ExprKind::Lit(ref lit) => match lit.kind {
99-
ast::LitKind::Int(
100-
val,
101-
ast::LitIntType::Unsuffixed
102-
| ast::LitIntType::Unsigned(ast::UintTy::U8),
103-
) if val <= u8::MAX.into() => {
104-
accumulator.push(val as u8);
105-
}
106-
107-
ast::LitKind::Byte(val) => {
108-
accumulator.push(val);
109-
}
110-
ast::LitKind::ByteStr(_) => {
111-
if !has_errors {
112-
cx.struct_span_err(
113-
expr.span,
114-
"cannot concatenate doubly nested array",
115-
)
116-
.note("byte strings are treated as arrays of bytes")
117-
.help("try flattening the array")
118-
.emit();
119-
}
120-
has_errors = true;
121-
}
122-
_ => {
123-
if !has_errors {
124-
invalid_type_err(cx, expr, true);
125-
}
126-
has_errors = true;
127-
}
128-
},
129-
_ => {
130-
missing_literals.push(expr.span);
137+
if let Some(elem) =
138+
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
139+
{
140+
accumulator.push(elem);
141+
}
142+
}
143+
}
144+
ast::ExprKind::Repeat(ref expr, ref count) => {
145+
if let ast::ExprKind::Lit(ast::Lit {
146+
kind: ast::LitKind::Int(count_val, _), ..
147+
}) = count.value.kind
148+
{
149+
if let Some(elem) =
150+
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
151+
{
152+
for _ in 0..count_val {
153+
accumulator.push(elem);
131154
}
132155
}
156+
} else {
157+
cx.span_err(count.value.span, "repeat count is not a positive number");
133158
}
134159
}
135160
ast::ExprKind::Lit(ref lit) => match lit.kind {

src/test/ui/macros/concat-bytes-error.rs

+8
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,12 @@ fn main() {
3939
]);
4040
concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals
4141
concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8`
42+
concat_bytes!([3; ()]); //~ ERROR repeat count is not a positive number
43+
concat_bytes!([3; -2]); //~ ERROR repeat count is not a positive number
44+
concat_bytes!([pie; -2]); //~ ERROR repeat count is not a positive number
45+
concat_bytes!([pie; 2]); //~ ERROR expected a byte literal
46+
concat_bytes!([2.2; 0]); //~ ERROR cannot concatenate float literals
47+
concat_bytes!([5.5; ()]); //~ ERROR repeat count is not a positive number
48+
concat_bytes!([[1, 2, 3]; 3]); //~ ERROR cannot concatenate doubly nested array
49+
concat_bytes!([[42; 2]; 3]); //~ ERROR cannot concatenate doubly nested array
4250
}

src/test/ui/macros/concat-bytes-error.stderr

+51-1
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,55 @@ error: numeric literal is not a `u8`
127127
LL | concat_bytes!([5u16]);
128128
| ^^^^
129129

130-
error: aborting due to 20 previous errors
130+
error: repeat count is not a positive number
131+
--> $DIR/concat-bytes-error.rs:42:23
132+
|
133+
LL | concat_bytes!([3; ()]);
134+
| ^^
135+
136+
error: repeat count is not a positive number
137+
--> $DIR/concat-bytes-error.rs:43:23
138+
|
139+
LL | concat_bytes!([3; -2]);
140+
| ^^
141+
142+
error: repeat count is not a positive number
143+
--> $DIR/concat-bytes-error.rs:44:25
144+
|
145+
LL | concat_bytes!([pie; -2]);
146+
| ^^
147+
148+
error: expected a byte literal
149+
--> $DIR/concat-bytes-error.rs:45:20
150+
|
151+
LL | concat_bytes!([pie; 2]);
152+
| ^^^
153+
|
154+
= note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
155+
156+
error: cannot concatenate float literals
157+
--> $DIR/concat-bytes-error.rs:46:20
158+
|
159+
LL | concat_bytes!([2.2; 0]);
160+
| ^^^
161+
162+
error: repeat count is not a positive number
163+
--> $DIR/concat-bytes-error.rs:47:25
164+
|
165+
LL | concat_bytes!([5.5; ()]);
166+
| ^^
167+
168+
error: cannot concatenate doubly nested array
169+
--> $DIR/concat-bytes-error.rs:48:20
170+
|
171+
LL | concat_bytes!([[1, 2, 3]; 3]);
172+
| ^^^^^^^^^
173+
174+
error: cannot concatenate doubly nested array
175+
--> $DIR/concat-bytes-error.rs:49:20
176+
|
177+
LL | concat_bytes!([[42; 2]; 3]);
178+
| ^^^^^^^
179+
180+
error: aborting due to 28 previous errors
131181

src/test/ui/macros/concat-bytes.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,15 @@
33

44
fn main() {
55
assert_eq!(concat_bytes!(), &[]);
6-
assert_eq!(concat_bytes!(b'A', b"BC", [68, b'E', 70]), b"ABCDEF");
6+
assert_eq!(
7+
concat_bytes!(b'A', b"BC", [68, b'E', 70], [b'G'; 1], [72; 2], [73u8; 3], [65; 0]),
8+
b"ABCDEFGHHIII",
9+
);
10+
assert_eq!(
11+
concat_bytes!(
12+
concat_bytes!(b"AB", b"CD"),
13+
concat_bytes!(b"EF", b"GH"),
14+
),
15+
b"ABCDEFGH",
16+
);
717
}

0 commit comments

Comments
 (0)