Skip to content

Commit 9ce9567

Browse files
committed
Auto merge of #14837 - Veykril:rustc-lexer, r=Veykril
Support c string literals
2 parents 034d7c8 + 3e528b8 commit 9ce9567

File tree

24 files changed

+381
-162
lines changed

24 files changed

+381
-162
lines changed

crates/hir-def/src/body/pretty.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ impl<'a> Printer<'a> {
611611
match literal {
612612
Literal::String(it) => w!(self, "{:?}", it),
613613
Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
614+
Literal::CString(it) => w!(self, "\"{}\\0\"", it),
614615
Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
615616
Literal::Bool(it) => w!(self, "{}", it),
616617
Literal::Int(i, suffix) => {

crates/hir-def/src/hir.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl fmt::Display for FloatTypeWrapper {
8585
pub enum Literal {
8686
String(Box<str>),
8787
ByteString(Box<[u8]>),
88+
CString(Box<str>),
8889
Char(char),
8990
Bool(bool),
9091
Int(i128, Option<BuiltinInt>),
@@ -135,6 +136,10 @@ impl From<ast::LiteralKind> for Literal {
135136
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
136137
Literal::String(text)
137138
}
139+
LiteralKind::CString(s) => {
140+
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
141+
Literal::CString(text)
142+
}
138143
LiteralKind::Byte(b) => {
139144
Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8))
140145
}

crates/hir-def/src/lang_item.rs

Lines changed: 142 additions & 128 deletions
Large diffs are not rendered by default.

crates/hir-ty/src/consteval/tests.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,6 +1883,38 @@ fn byte_string() {
18831883
);
18841884
}
18851885

1886+
#[test]
1887+
fn c_string() {
1888+
check_number(
1889+
r#"
1890+
//- minicore: index, slice
1891+
#[lang = "CStr"]
1892+
pub struct CStr {
1893+
inner: [u8]
1894+
}
1895+
const GOAL: u8 = {
1896+
let a = c"hello";
1897+
a.inner[0]
1898+
};
1899+
"#,
1900+
104,
1901+
);
1902+
check_number(
1903+
r#"
1904+
//- minicore: index, slice
1905+
#[lang = "CStr"]
1906+
pub struct CStr {
1907+
inner: [u8]
1908+
}
1909+
const GOAL: u8 = {
1910+
let a = c"hello";
1911+
a.inner[6]
1912+
};
1913+
"#,
1914+
0,
1915+
);
1916+
}
1917+
18861918
#[test]
18871919
fn consts() {
18881920
check_number(

crates/hir-ty/src/infer/expr.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use hir_def::{
1313
hir::{
1414
ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
1515
},
16-
lang_item::LangItem,
16+
lang_item::{LangItem, LangItemTarget},
1717
path::{GenericArg, GenericArgs},
1818
BlockId, ConstParamId, FieldId, ItemContainerId, Lookup,
1919
};
@@ -832,6 +832,20 @@ impl<'a> InferenceContext<'a> {
832832
let array_type = TyKind::Array(byte_type, len).intern(Interner);
833833
TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner)
834834
}
835+
Literal::CString(..) => TyKind::Ref(
836+
Mutability::Not,
837+
static_lifetime(),
838+
self.resolve_lang_item(LangItem::CStr)
839+
.and_then(LangItemTarget::as_struct)
840+
.map_or_else(
841+
|| self.err_ty(),
842+
|strukt| {
843+
TyKind::Adt(AdtId(strukt.into()), Substitution::empty(Interner))
844+
.intern(Interner)
845+
},
846+
),
847+
)
848+
.intern(Interner),
835849
Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner),
836850
Literal::Int(_v, ty) => match ty {
837851
Some(int_ty) => {

crates/hir-ty/src/infer/pat.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,9 +428,10 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
428428
// FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
429429
Pat::Path(..) => true,
430430
Pat::ConstBlock(..) => true,
431-
Pat::Lit(expr) => {
432-
!matches!(body[*expr], Expr::Literal(Literal::String(..) | Literal::ByteString(..)))
433-
}
431+
Pat::Lit(expr) => !matches!(
432+
body[*expr],
433+
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
434+
),
434435
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
435436
}
436437
}

crates/hir-ty/src/mir/lower.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,15 +1133,26 @@ impl<'ctx> MirLowerCtx<'ctx> {
11331133
let bytes = match l {
11341134
hir_def::hir::Literal::String(b) => {
11351135
let b = b.as_bytes();
1136-
let mut data = vec![];
1136+
let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
11371137
data.extend(0usize.to_le_bytes());
11381138
data.extend(b.len().to_le_bytes());
11391139
let mut mm = MemoryMap::default();
11401140
mm.insert(0, b.to_vec());
11411141
return Ok(Operand::from_concrete_const(data, mm, ty));
11421142
}
1143+
hir_def::hir::Literal::CString(b) => {
1144+
let b = b.as_bytes();
1145+
let bytes = b.iter().copied().chain(iter::once(0)).collect::<Vec<_>>();
1146+
1147+
let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
1148+
data.extend(0usize.to_le_bytes());
1149+
data.extend(bytes.len().to_le_bytes());
1150+
let mut mm = MemoryMap::default();
1151+
mm.insert(0, bytes);
1152+
return Ok(Operand::from_concrete_const(data, mm, ty));
1153+
}
11431154
hir_def::hir::Literal::ByteString(b) => {
1144-
let mut data = vec![];
1155+
let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
11451156
data.extend(0usize.to_le_bytes());
11461157
data.extend(b.len().to_le_bytes());
11471158
let mut mm = MemoryMap::default();

crates/hir-ty/src/tests/simple.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3572,3 +3572,18 @@ fn main() {
35723572
"#,
35733573
);
35743574
}
3575+
3576+
#[test]
3577+
fn cstring_literals() {
3578+
check_types(
3579+
r#"
3580+
#[lang = "CStr"]
3581+
pub struct CStr;
3582+
3583+
fn main() {
3584+
c"ello";
3585+
//^^^^^^^ &CStr
3586+
}
3587+
"#,
3588+
);
3589+
}

crates/ide-assists/src/handlers/raw_string.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{utils::required_hashes, AssistContext, AssistId, AssistKind, Assists
2020
// }
2121
// ```
2222
pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
23+
// FIXME: This should support byte and c strings as well.
2324
let token = ctx.find_token_at_offset::<ast::String>()?;
2425
if token.is_raw() {
2526
return None;

crates/ide/src/extend_selection.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn try_extend_selection(
3939
) -> Option<TextRange> {
4040
let range = frange.range;
4141

42-
let string_kinds = [COMMENT, STRING, BYTE_STRING];
42+
let string_kinds = [COMMENT, STRING, BYTE_STRING, C_STRING];
4343
let list_kinds = [
4444
RECORD_PAT_FIELD_LIST,
4545
MATCH_ARM_LIST,

0 commit comments

Comments
 (0)