rustc_builtin_macros/
concat.rs
1use rustc_ast::tokenstream::TokenStream;
2use rustc_ast::{ExprKind, LitKind, UnOp};
3use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
4use rustc_session::errors::report_lit_error;
5use rustc_span::Symbol;
6
7use crate::errors;
8use crate::util::get_exprs_from_tts;
9
10pub(crate) fn expand_concat(
11 cx: &mut ExtCtxt<'_>,
12 sp: rustc_span::Span,
13 tts: TokenStream,
14) -> MacroExpanderResult<'static> {
15 let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
16 return ExpandResult::Retry(());
17 };
18 let es = match mac {
19 Ok(es) => es,
20 Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
21 };
22 let mut accumulator = String::new();
23 let mut missing_literal = vec![];
24 let mut guar = None;
25 for e in es {
26 match e.kind {
27 ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) {
28 Ok(LitKind::Str(s, _) | LitKind::Float(s, _)) => {
29 accumulator.push_str(s.as_str());
30 }
31 Ok(LitKind::Char(c)) => {
32 accumulator.push(c);
33 }
34 Ok(LitKind::Int(i, _)) => {
35 accumulator.push_str(&i.to_string());
36 }
37 Ok(LitKind::Bool(b)) => {
38 accumulator.push_str(&b.to_string());
39 }
40 Ok(LitKind::CStr(..)) => {
41 guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span }));
42 }
43 Ok(LitKind::Byte(..) | LitKind::ByteStr(..)) => {
44 guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }));
45 }
46 Ok(LitKind::Err(guarantee)) => {
47 guar = Some(guarantee);
48 }
49 Err(err) => {
50 guar = Some(report_lit_error(&cx.sess.psess, err, token_lit, e.span));
51 }
52 },
53 ExprKind::Unary(UnOp::Neg, ref expr) if let ExprKind::Lit(token_lit) = expr.kind => {
55 match LitKind::from_token_lit(token_lit) {
56 Ok(LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
57 Ok(LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),
58 Err(err) => {
59 guar = Some(report_lit_error(&cx.sess.psess, err, token_lit, e.span));
60 }
61 _ => missing_literal.push(e.span),
62 }
63 }
64 ExprKind::IncludedBytes(..) => {
65 cx.dcx().emit_err(errors::ConcatBytestr { span: e.span });
66 }
67 ExprKind::Err(guarantee) => {
68 guar = Some(guarantee);
69 }
70 ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"),
71 _ => {
72 missing_literal.push(e.span);
73 }
74 }
75 }
76
77 ExpandResult::Ready(if !missing_literal.is_empty() {
78 let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
79 DummyResult::any(sp, guar)
80 } else if let Some(guar) = guar {
81 DummyResult::any(sp, guar)
82 } else {
83 let sp = cx.with_def_site_ctxt(sp);
84 MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
85 })
86}