summaryrefslogtreecommitdiff
path: root/compiler/rustc_ast/src/util/literal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_ast/src/util/literal.rs')
-rw-r--r--compiler/rustc_ast/src/util/literal.rs63
1 files changed, 62 insertions, 1 deletions
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 74b842ac96e..15a54fe13d0 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -2,9 +2,13 @@
use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
use crate::token::{self, Token};
-use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
+use rustc_lexer::unescape::{
+ byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit,
+ Mode,
+};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
+use std::ops::Range;
use std::{ascii, fmt, str};
// Escapes a string, represented as a symbol. Reuses the original symbol,
@@ -35,6 +39,7 @@ pub enum LitError {
InvalidFloatSuffix,
NonDecimalFloat(u32),
IntTooLarge(u32),
+ NulInCStr(Range<usize>),
}
impl LitKind {
@@ -158,6 +163,52 @@ impl LitKind {
LitKind::ByteStr(bytes.into(), StrStyle::Raw(n))
}
+ token::CStr => {
+ let s = symbol.as_str();
+ let mut buf = Vec::with_capacity(s.len());
+ let mut error = Ok(());
+ unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
+ Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+ error = Err(LitError::NulInCStr(span));
+ }
+ Ok(CStrUnit::Byte(b)) => buf.push(b),
+ Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+ Ok(CStrUnit::Char(c)) => {
+ buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+ }
+ Err(err) => {
+ if err.is_fatal() {
+ error = Err(LitError::LexerError);
+ }
+ }
+ });
+ error?;
+ buf.push(0);
+ LitKind::CStr(buf.into(), StrStyle::Cooked)
+ }
+ token::CStrRaw(n) => {
+ let s = symbol.as_str();
+ let mut buf = Vec::with_capacity(s.len());
+ let mut error = Ok(());
+ unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
+ Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+ error = Err(LitError::NulInCStr(span));
+ }
+ Ok(CStrUnit::Byte(b)) => buf.push(b),
+ Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+ Ok(CStrUnit::Char(c)) => {
+ buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+ }
+ Err(err) => {
+ if err.is_fatal() {
+ error = Err(LitError::LexerError);
+ }
+ }
+ });
+ error?;
+ buf.push(0);
+ LitKind::CStr(buf.into(), StrStyle::Raw(n))
+ }
token::Err => LitKind::Err,
})
}
@@ -191,6 +242,14 @@ impl fmt::Display for LitKind {
string = symbol
)?;
}
+ LitKind::CStr(ref bytes, StrStyle::Cooked) => {
+ write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))?
+ }
+ LitKind::CStr(ref bytes, StrStyle::Raw(n)) => {
+ // This can only be valid UTF-8.
+ let symbol = str::from_utf8(bytes).unwrap();
+ write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?;
+ }
LitKind::Int(n, ty) => {
write!(f, "{n}")?;
match ty {
@@ -237,6 +296,8 @@ impl MetaItemLit {
LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),
LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,
LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),
+ LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr,
+ LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n),
LitKind::Byte(_) => token::Byte,
LitKind::Char(_) => token::Char,
LitKind::Int(..) => token::Integer,