2 use rustc_ast
::{ptr::P, tokenstream::TokenStream}
;
3 use rustc_expand
::base
::{self, DummyResult}
;
4 use rustc_session
::errors
::report_lit_error
;
9 /// Emits errors for literal expressions that are invalid inside and outside of an array.
11 cx
: &mut base
::ExtCtxt
<'_
>,
12 token_lit
: ast
::token
::Lit
,
17 ConcatBytesInvalid
, ConcatBytesInvalidSuggestion
, ConcatBytesNonU8
, ConcatBytesOob
,
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");
26 Ok(ast
::LitKind
::Char(_
)) => {
28 snippet
.map(|snippet
| ConcatBytesInvalidSuggestion
::CharLit { span, snippet }
);
29 cx
.sess
.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }
);
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 }
)
38 cx
.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }
);
40 Ok(ast
::LitKind
::Float(_
, _
)) => {
41 cx
.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }
);
43 Ok(ast
::LitKind
::Bool(_
)) => {
44 cx
.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }
);
46 Ok(ast
::LitKind
::Err
) => {}
47 Ok(ast
::LitKind
::Int(_
, _
)) if !is_nested
=> {
49 snippet
.map(|snippet
| ConcatBytesInvalidSuggestion
::IntLit { span: span, snippet }
);
50 cx
.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }
);
54 ast
::LitIntType
::Unsuffixed
| ast
::LitIntType
::Unsigned(ast
::UintTy
::U8
),
56 assert
!(val
> u8::MAX
.into()); // must be an error
57 cx
.emit_err(ConcatBytesOob { span }
);
59 Ok(ast
::LitKind
::Int(_
, _
)) => {
60 cx
.emit_err(ConcatBytesNonU8 { span }
);
62 Ok(ast
::LitKind
::ByteStr(..) | ast
::LitKind
::Byte(_
)) => unreachable
!(),
64 report_lit_error(&cx
.sess
.parse_sess
, err
, token_lit
, span
);
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
>,
76 ast
::ExprKind
::Array(_
) | ast
::ExprKind
::Repeat(_
, _
) => {
78 cx
.emit_err(errors
::ConcatBytesArray { span: expr.span, bytestr: false }
);
83 ast
::ExprKind
::Lit(token_lit
) => match ast
::LitKind
::from_token_lit(token_lit
) {
86 ast
::LitIntType
::Unsuffixed
| ast
::LitIntType
::Unsigned(ast
::UintTy
::U8
),
87 )) if val
<= u8::MAX
.into() => Some(val
as u8),
89 Ok(ast
::LitKind
::Byte(val
)) => Some(val
),
90 Ok(ast
::LitKind
::ByteStr(..)) => {
92 cx
.emit_err(errors
::ConcatBytesArray { span: expr.span, bytestr: true }
);
99 invalid_type_err(cx
, token_lit
, expr
.span
, true);
105 ast
::ExprKind
::IncludedBytes(..) => {
107 cx
.emit_err(errors
::ConcatBytesArray { span: expr.span, bytestr: false }
);
113 missing_literals
.push(expr
.span
);
119 pub fn expand_concat_bytes(
120 cx
: &mut base
::ExtCtxt
<'_
>,
121 sp
: rustc_span
::Span
,
123 ) -> Box
<dyn base
::MacResult
+ '
static> {
124 let Some(es
) = base
::get_exprs_from_tts(cx
, tts
) else {
125 return DummyResult
::any(sp
);
127 let mut accumulator
= Vec
::new();
128 let mut missing_literals
= vec
![];
129 let mut has_errors
= false;
132 ast
::ExprKind
::Array(exprs
) => {
135 handle_array_element(cx
, &mut has_errors
, &mut missing_literals
, expr
)
137 accumulator
.push(elem
);
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
)
147 handle_array_element(cx
, &mut has_errors
, &mut missing_literals
, expr
)
149 for _
in 0..count_val
{
150 accumulator
.push(elem
);
154 cx
.emit_err(errors
::ConcatBytesBadRepeat {span: count.value.span }
);
157 &ast
::ExprKind
::Lit(token_lit
) => match ast
::LitKind
::from_token_lit(token_lit
) {
158 Ok(ast
::LitKind
::Byte(val
)) => {
159 accumulator
.push(val
);
161 Ok(ast
::LitKind
::ByteStr(ref bytes
, _
)) => {
162 accumulator
.extend_from_slice(&bytes
);
166 invalid_type_err(cx
, token_lit
, e
.span
, false);
171 ast
::ExprKind
::IncludedBytes(bytes
) => {
172 accumulator
.extend_from_slice(bytes
);
174 ast
::ExprKind
::Err
=> {
178 missing_literals
.push(e
.span
);
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));
188 let sp
= cx
.with_def_site_ctxt(sp
);
189 base
::MacEager
::expr(cx
.expr_byte_str(sp
, accumulator
))