]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_builtin_macros/src/concat_bytes.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_builtin_macros / src / concat_bytes.rs
CommitLineData
a2a8927a
XL
1use rustc_ast as ast;
2use rustc_ast::{ptr::P, tokenstream::TokenStream};
a2a8927a
XL
3use rustc_errors::Applicability;
4use rustc_expand::base::{self, DummyResult};
487cf647
FG
5use rustc_session::errors::report_lit_error;
6use rustc_span::Span;
a2a8927a
XL
7
8/// Emits errors for literal expressions that are invalid inside and outside of an array.
487cf647
FG
9fn invalid_type_err(
10 cx: &mut base::ExtCtxt<'_>,
11 token_lit: ast::token::Lit,
12 span: Span,
13 is_nested: bool,
14) {
15 match ast::LitKind::from_token_lit(token_lit) {
16 Ok(ast::LitKind::Char(_)) => {
17 let mut err = cx.struct_span_err(span, "cannot concatenate character literals");
18 if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
a2a8927a 19 err.span_suggestion(
487cf647 20 span,
a2a8927a
XL
21 "try using a byte character",
22 format!("b{}", snippet),
23 Applicability::MachineApplicable,
24 )
25 .emit();
26 }
27 }
487cf647
FG
28 Ok(ast::LitKind::Str(_, _)) => {
29 let mut err = cx.struct_span_err(span, "cannot concatenate string literals");
a2a8927a
XL
30 // suggestion would be invalid if we are nested
31 if !is_nested {
487cf647 32 if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
a2a8927a 33 err.span_suggestion(
487cf647 34 span,
a2a8927a
XL
35 "try using a byte string",
36 format!("b{}", snippet),
37 Applicability::MachineApplicable,
38 );
39 }
40 }
41 err.emit();
42 }
487cf647
FG
43 Ok(ast::LitKind::Float(_, _)) => {
44 cx.span_err(span, "cannot concatenate float literals");
a2a8927a 45 }
487cf647
FG
46 Ok(ast::LitKind::Bool(_)) => {
47 cx.span_err(span, "cannot concatenate boolean literals");
a2a8927a 48 }
487cf647
FG
49 Ok(ast::LitKind::Err) => {}
50 Ok(ast::LitKind::Int(_, _)) if !is_nested => {
51 let mut err = cx.struct_span_err(span, "cannot concatenate numeric literals");
52 if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
a2a8927a 53 err.span_suggestion(
487cf647 54 span,
a2a8927a
XL
55 "try wrapping the number in an array",
56 format!("[{}]", snippet),
57 Applicability::MachineApplicable,
58 );
59 }
60 err.emit();
61 }
487cf647 62 Ok(ast::LitKind::Int(
a2a8927a
XL
63 val,
64 ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
487cf647 65 )) => {
a2a8927a 66 assert!(val > u8::MAX.into()); // must be an error
487cf647
FG
67 cx.span_err(span, "numeric literal is out of bounds");
68 }
69 Ok(ast::LitKind::Int(_, _)) => {
70 cx.span_err(span, "numeric literal is not a `u8`");
a2a8927a 71 }
9c376795 72 Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
487cf647
FG
73 Err(err) => {
74 report_lit_error(&cx.sess.parse_sess, err, token_lit, span);
a2a8927a 75 }
a2a8927a
XL
76 }
77}
78
79fn handle_array_element(
80 cx: &mut base::ExtCtxt<'_>,
81 has_errors: &mut bool,
82 missing_literals: &mut Vec<rustc_span::Span>,
83 expr: &P<rustc_ast::Expr>,
84) -> Option<u8> {
85 match expr.kind {
86 ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
87 if !*has_errors {
88 cx.span_err(expr.span, "cannot concatenate doubly nested array");
89 }
90 *has_errors = true;
91 None
92 }
487cf647
FG
93 ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
94 Ok(ast::LitKind::Int(
a2a8927a
XL
95 val,
96 ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
487cf647 97 )) if val <= u8::MAX.into() => Some(val as u8),
a2a8927a 98
487cf647 99 Ok(ast::LitKind::Byte(val)) => Some(val),
9c376795 100 Ok(ast::LitKind::ByteStr(..)) => {
a2a8927a
XL
101 if !*has_errors {
102 cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
103 .note("byte strings are treated as arrays of bytes")
104 .help("try flattening the array")
105 .emit();
106 }
107 *has_errors = true;
108 None
109 }
110 _ => {
111 if !*has_errors {
487cf647 112 invalid_type_err(cx, token_lit, expr.span, true);
a2a8927a
XL
113 }
114 *has_errors = true;
115 None
116 }
117 },
487cf647
FG
118 ast::ExprKind::IncludedBytes(..) => {
119 if !*has_errors {
120 cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
121 .note("byte strings are treated as arrays of bytes")
122 .help("try flattening the array")
123 .emit();
124 }
125 *has_errors = true;
126 None
127 }
a2a8927a
XL
128 _ => {
129 missing_literals.push(expr.span);
130 None
131 }
132 }
133}
134
135pub fn expand_concat_bytes(
136 cx: &mut base::ExtCtxt<'_>,
137 sp: rustc_span::Span,
138 tts: TokenStream,
139) -> Box<dyn base::MacResult + 'static> {
9c376795 140 let Some(es) = base::get_exprs_from_tts(cx, tts) else {
5e7ed085 141 return DummyResult::any(sp);
a2a8927a
XL
142 };
143 let mut accumulator = Vec::new();
144 let mut missing_literals = vec![];
145 let mut has_errors = false;
146 for e in es {
487cf647
FG
147 match &e.kind {
148 ast::ExprKind::Array(exprs) => {
a2a8927a
XL
149 for expr in exprs {
150 if let Some(elem) =
151 handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
152 {
153 accumulator.push(elem);
154 }
155 }
156 }
487cf647
FG
157 ast::ExprKind::Repeat(expr, count) => {
158 if let ast::ExprKind::Lit(token_lit) = count.value.kind
159 && let Ok(ast::LitKind::Int(count_val, _)) =
160 ast::LitKind::from_token_lit(token_lit)
a2a8927a
XL
161 {
162 if let Some(elem) =
163 handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
164 {
165 for _ in 0..count_val {
166 accumulator.push(elem);
167 }
168 }
169 } else {
170 cx.span_err(count.value.span, "repeat count is not a positive number");
171 }
172 }
487cf647
FG
173 &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
174 Ok(ast::LitKind::Byte(val)) => {
a2a8927a
XL
175 accumulator.push(val);
176 }
9c376795 177 Ok(ast::LitKind::ByteStr(ref bytes, _)) => {
a2a8927a
XL
178 accumulator.extend_from_slice(&bytes);
179 }
180 _ => {
181 if !has_errors {
487cf647 182 invalid_type_err(cx, token_lit, e.span, false);
a2a8927a
XL
183 }
184 has_errors = true;
185 }
186 },
487cf647
FG
187 ast::ExprKind::IncludedBytes(bytes) => {
188 accumulator.extend_from_slice(bytes);
189 }
a2a8927a
XL
190 ast::ExprKind::Err => {
191 has_errors = true;
192 }
193 _ => {
194 missing_literals.push(e.span);
195 }
196 }
197 }
198 if !missing_literals.is_empty() {
9c376795 199 let mut err = cx.struct_span_err(missing_literals, "expected a byte literal");
a2a8927a
XL
200 err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`");
201 err.emit();
202 return base::MacEager::expr(DummyResult::raw_expr(sp, true));
203 } else if has_errors {
204 return base::MacEager::expr(DummyResult::raw_expr(sp, true));
205 }
206 let sp = cx.with_def_site_ctxt(sp);
f2b60f7d 207 base::MacEager::expr(cx.expr_byte_str(sp, accumulator))
a2a8927a 208}