]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_builtin_macros/src/concat_bytes.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_builtin_macros / src / concat_bytes.rs
1 use rustc_ast as ast;
2 use rustc_ast::{ptr::P, tokenstream::TokenStream};
3 use rustc_expand::base::{self, DummyResult};
4 use rustc_session::errors::report_lit_error;
5 use rustc_span::Span;
6
7 use crate::errors;
8
9 /// Emits errors for literal expressions that are invalid inside and outside of an array.
10 fn invalid_type_err(
11 cx: &mut base::ExtCtxt<'_>,
12 token_lit: ast::token::Lit,
13 span: Span,
14 is_nested: bool,
15 ) {
16 use errors::{
17 ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob,
18 };
19 let snippet = cx.sess.source_map().span_to_snippet(span).ok();
20 match ast::LitKind::from_token_lit(token_lit) {
21 Ok(ast::LitKind::CStr(_, _)) => {
22 // FIXME(c_str_literals): should concatenation of C string literals
23 // include the null bytes in the end?
24 cx.span_err(span, "cannot concatenate C string literals");
25 }
26 Ok(ast::LitKind::Char(_)) => {
27 let sugg =
28 snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
29 cx.sess.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg });
30 }
31 Ok(ast::LitKind::Str(_, _)) => {
32 // suggestion would be invalid if we are nested
33 let sugg = if !is_nested {
34 snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet })
35 } else {
36 None
37 };
38 cx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
39 }
40 Ok(ast::LitKind::Float(_, _)) => {
41 cx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None });
42 }
43 Ok(ast::LitKind::Bool(_)) => {
44 cx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None });
45 }
46 Ok(ast::LitKind::Err) => {}
47 Ok(ast::LitKind::Int(_, _)) if !is_nested => {
48 let sugg =
49 snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet });
50 cx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg });
51 }
52 Ok(ast::LitKind::Int(
53 val,
54 ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
55 )) => {
56 assert!(val > u8::MAX.into()); // must be an error
57 cx.emit_err(ConcatBytesOob { span });
58 }
59 Ok(ast::LitKind::Int(_, _)) => {
60 cx.emit_err(ConcatBytesNonU8 { span });
61 }
62 Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
63 Err(err) => {
64 report_lit_error(&cx.sess.parse_sess, err, token_lit, span);
65 }
66 }
67 }
68
69 fn handle_array_element(
70 cx: &mut base::ExtCtxt<'_>,
71 has_errors: &mut bool,
72 missing_literals: &mut Vec<rustc_span::Span>,
73 expr: &P<rustc_ast::Expr>,
74 ) -> Option<u8> {
75 match expr.kind {
76 ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
77 if !*has_errors {
78 cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
79 }
80 *has_errors = true;
81 None
82 }
83 ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
84 Ok(ast::LitKind::Int(
85 val,
86 ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
87 )) if val <= u8::MAX.into() => Some(val as u8),
88
89 Ok(ast::LitKind::Byte(val)) => Some(val),
90 Ok(ast::LitKind::ByteStr(..)) => {
91 if !*has_errors {
92 cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true });
93 }
94 *has_errors = true;
95 None
96 }
97 _ => {
98 if !*has_errors {
99 invalid_type_err(cx, token_lit, expr.span, true);
100 }
101 *has_errors = true;
102 None
103 }
104 },
105 ast::ExprKind::IncludedBytes(..) => {
106 if !*has_errors {
107 cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
108 }
109 *has_errors = true;
110 None
111 }
112 _ => {
113 missing_literals.push(expr.span);
114 None
115 }
116 }
117 }
118
119 pub fn expand_concat_bytes(
120 cx: &mut base::ExtCtxt<'_>,
121 sp: rustc_span::Span,
122 tts: TokenStream,
123 ) -> Box<dyn base::MacResult + 'static> {
124 let Some(es) = base::get_exprs_from_tts(cx, tts) else {
125 return DummyResult::any(sp);
126 };
127 let mut accumulator = Vec::new();
128 let mut missing_literals = vec![];
129 let mut has_errors = false;
130 for e in es {
131 match &e.kind {
132 ast::ExprKind::Array(exprs) => {
133 for expr in exprs {
134 if let Some(elem) =
135 handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
136 {
137 accumulator.push(elem);
138 }
139 }
140 }
141 ast::ExprKind::Repeat(expr, count) => {
142 if let ast::ExprKind::Lit(token_lit) = count.value.kind
143 && let Ok(ast::LitKind::Int(count_val, _)) =
144 ast::LitKind::from_token_lit(token_lit)
145 {
146 if let Some(elem) =
147 handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
148 {
149 for _ in 0..count_val {
150 accumulator.push(elem);
151 }
152 }
153 } else {
154 cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span });
155 }
156 }
157 &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
158 Ok(ast::LitKind::Byte(val)) => {
159 accumulator.push(val);
160 }
161 Ok(ast::LitKind::ByteStr(ref bytes, _)) => {
162 accumulator.extend_from_slice(&bytes);
163 }
164 _ => {
165 if !has_errors {
166 invalid_type_err(cx, token_lit, e.span, false);
167 }
168 has_errors = true;
169 }
170 },
171 ast::ExprKind::IncludedBytes(bytes) => {
172 accumulator.extend_from_slice(bytes);
173 }
174 ast::ExprKind::Err => {
175 has_errors = true;
176 }
177 _ => {
178 missing_literals.push(e.span);
179 }
180 }
181 }
182 if !missing_literals.is_empty() {
183 cx.emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
184 return base::MacEager::expr(DummyResult::raw_expr(sp, true));
185 } else if has_errors {
186 return base::MacEager::expr(DummyResult::raw_expr(sp, true));
187 }
188 let sp = cx.with_def_site_ctxt(sp);
189 base::MacEager::expr(cx.expr_byte_str(sp, accumulator))
190 }