2 use rustc_ast::{ptr::P, tokenstream::TokenStream};
3 use rustc_errors::Applicability;
4 use rustc_expand::base::{self, DummyResult};
5 use rustc_session::errors::report_lit_error;
8 /// Emits errors for literal expressions that are invalid inside and outside of an array.
10 cx: &mut base::ExtCtxt<'_>,
11 token_lit: ast::token::Lit,
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) {
21 "try using a byte character",
22 format!("b{}", snippet),
23 Applicability::MachineApplicable,
28 Ok(ast::LitKind::Str(_, _)) => {
29 let mut err = cx.struct_span_err(span, "cannot concatenate string literals");
30 // suggestion would be invalid if we are nested
32 if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
35 "try using a byte string",
36 format!("b{}", snippet),
37 Applicability::MachineApplicable,
43 Ok(ast::LitKind::Float(_, _)) => {
44 cx.span_err(span, "cannot concatenate float literals");
46 Ok(ast::LitKind::Bool(_)) => {
47 cx.span_err(span, "cannot concatenate boolean literals");
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) {
55 "try wrapping the number in an array",
56 format!("[{}]", snippet),
57 Applicability::MachineApplicable,
64 ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
66 assert!(val > u8::MAX.into()); // must be an error
67 cx.span_err(span, "numeric literal is out of bounds");
69 Ok(ast::LitKind::Int(_, _)) => {
70 cx.span_err(span, "numeric literal is not a `u8`");
72 Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
74 report_lit_error(&cx.sess.parse_sess, err, token_lit, span);
79 fn 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>,
86 ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
88 cx.span_err(expr.span, "cannot concatenate doubly nested array");
93 ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
96 ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
97 )) if val <= u8::MAX.into() => Some(val as u8),
99 Ok(ast::LitKind::Byte(val)) => Some(val),
100 Ok(ast::LitKind::ByteStr(..)) => {
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")
112 invalid_type_err(cx, token_lit, expr.span, true);
118 ast::ExprKind::IncludedBytes(..) => {
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")
129 missing_literals.push(expr.span);
135 pub fn expand_concat_bytes(
136 cx: &mut base::ExtCtxt<'_>,
137 sp: rustc_span::Span,
139 ) -> Box<dyn base::MacResult + 'static> {
140 let Some(es) = base::get_exprs_from_tts(cx, tts) else {
141 return DummyResult::any(sp);
143 let mut accumulator = Vec::new();
144 let mut missing_literals = vec![];
145 let mut has_errors = false;
148 ast::ExprKind::Array(exprs) => {
151 handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
153 accumulator.push(elem);
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)
163 handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
165 for _ in 0..count_val {
166 accumulator.push(elem);
170 cx.span_err(count.value.span, "repeat count is not a positive number");
173 &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
174 Ok(ast::LitKind::Byte(val)) => {
175 accumulator.push(val);
177 Ok(ast::LitKind::ByteStr(ref bytes, _)) => {
178 accumulator.extend_from_slice(&bytes);
182 invalid_type_err(cx, token_lit, e.span, false);
187 ast::ExprKind::IncludedBytes(bytes) => {
188 accumulator.extend_from_slice(bytes);
190 ast::ExprKind::Err => {
194 missing_literals.push(e.span);
198 if !missing_literals.is_empty() {
199 let mut err = cx.struct_span_err(missing_literals, "expected a byte literal");
200 err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`");
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));
206 let sp = cx.with_def_site_ctxt(sp);
207 base::MacEager::expr(cx.expr_byte_str(sp, accumulator))