| 
2 | 2 | 
  | 
3 | 3 | use crate::ast::{self, LitKind, MetaItemLit, StrStyle};  | 
4 | 4 | use crate::token::{self, Token};  | 
5 |  | -use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};  | 
 | 5 | +use rustc_lexer::unescape::{  | 
 | 6 | +    byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit,  | 
 | 7 | +    Mode,  | 
 | 8 | +};  | 
6 | 9 | use rustc_span::symbol::{kw, sym, Symbol};  | 
7 | 10 | use rustc_span::Span;  | 
 | 11 | +use std::ops::Range;  | 
8 | 12 | use std::{ascii, fmt, str};  | 
9 | 13 | 
 
  | 
10 | 14 | // Escapes a string, represented as a symbol. Reuses the original symbol,  | 
@@ -35,6 +39,7 @@ pub enum LitError {  | 
35 | 39 |     InvalidFloatSuffix,  | 
36 | 40 |     NonDecimalFloat(u32),  | 
37 | 41 |     IntTooLarge(u32),  | 
 | 42 | +    NulInCStr(Range<usize>),  | 
38 | 43 | }  | 
39 | 44 | 
 
  | 
40 | 45 | impl LitKind {  | 
@@ -158,6 +163,52 @@ impl LitKind {  | 
158 | 163 | 
 
  | 
159 | 164 |                 LitKind::ByteStr(bytes.into(), StrStyle::Raw(n))  | 
160 | 165 |             }  | 
 | 166 | +            token::CStr => {  | 
 | 167 | +                let s = symbol.as_str();  | 
 | 168 | +                let mut buf = Vec::with_capacity(s.len());  | 
 | 169 | +                let mut error = Ok(());  | 
 | 170 | +                unescape_c_string(s, Mode::CStr, &mut |span, c| match c {  | 
 | 171 | +                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {  | 
 | 172 | +                        error = Err(LitError::NulInCStr(span));  | 
 | 173 | +                    }  | 
 | 174 | +                    Ok(CStrUnit::Byte(b)) => buf.push(b),  | 
 | 175 | +                    Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),  | 
 | 176 | +                    Ok(CStrUnit::Char(c)) => {  | 
 | 177 | +                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())  | 
 | 178 | +                    }  | 
 | 179 | +                    Err(err) => {  | 
 | 180 | +                        if err.is_fatal() {  | 
 | 181 | +                            error = Err(LitError::LexerError);  | 
 | 182 | +                        }  | 
 | 183 | +                    }  | 
 | 184 | +                });  | 
 | 185 | +                error?;  | 
 | 186 | +                buf.push(0);  | 
 | 187 | +                LitKind::CStr(buf.into(), StrStyle::Cooked)  | 
 | 188 | +            }  | 
 | 189 | +            token::CStrRaw(n) => {  | 
 | 190 | +                let s = symbol.as_str();  | 
 | 191 | +                let mut buf = Vec::with_capacity(s.len());  | 
 | 192 | +                let mut error = Ok(());  | 
 | 193 | +                unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {  | 
 | 194 | +                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {  | 
 | 195 | +                        error = Err(LitError::NulInCStr(span));  | 
 | 196 | +                    }  | 
 | 197 | +                    Ok(CStrUnit::Byte(b)) => buf.push(b),  | 
 | 198 | +                    Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),  | 
 | 199 | +                    Ok(CStrUnit::Char(c)) => {  | 
 | 200 | +                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())  | 
 | 201 | +                    }  | 
 | 202 | +                    Err(err) => {  | 
 | 203 | +                        if err.is_fatal() {  | 
 | 204 | +                            error = Err(LitError::LexerError);  | 
 | 205 | +                        }  | 
 | 206 | +                    }  | 
 | 207 | +                });  | 
 | 208 | +                error?;  | 
 | 209 | +                buf.push(0);  | 
 | 210 | +                LitKind::CStr(buf.into(), StrStyle::Raw(n))  | 
 | 211 | +            }  | 
161 | 212 |             token::Err => LitKind::Err,  | 
162 | 213 |         })  | 
163 | 214 |     }  | 
@@ -191,6 +242,14 @@ impl fmt::Display for LitKind {  | 
191 | 242 |                     string = symbol  | 
192 | 243 |                 )?;  | 
193 | 244 |             }  | 
 | 245 | +            LitKind::CStr(ref bytes, StrStyle::Cooked) => {  | 
 | 246 | +                write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))?  | 
 | 247 | +            }  | 
 | 248 | +            LitKind::CStr(ref bytes, StrStyle::Raw(n)) => {  | 
 | 249 | +                // This can only be valid UTF-8.  | 
 | 250 | +                let symbol = str::from_utf8(bytes).unwrap();  | 
 | 251 | +                write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?;  | 
 | 252 | +            }  | 
194 | 253 |             LitKind::Int(n, ty) => {  | 
195 | 254 |                 write!(f, "{n}")?;  | 
196 | 255 |                 match ty {  | 
@@ -237,6 +296,8 @@ impl MetaItemLit {  | 
237 | 296 |             LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),  | 
238 | 297 |             LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,  | 
239 | 298 |             LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),  | 
 | 299 | +            LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr,  | 
 | 300 | +            LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n),  | 
240 | 301 |             LitKind::Byte(_) => token::Byte,  | 
241 | 302 |             LitKind::Char(_) => token::Char,  | 
242 | 303 |             LitKind::Int(..) => token::Integer,  | 
 | 
0 commit comments