Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #19388 from Veykril/push-oqysrnttwywu
feat: parse `unsafe` record fields
Lukas Wirth 2025-03-25
parent ed7e25a · parent 452e2ca · commit 749fde9
-rw-r--r--crates/hir-def/src/data/adt.rs6
-rw-r--r--crates/hir-def/src/item_tree.rs1
-rw-r--r--crates/hir-def/src/item_tree/lower.rs4
-rw-r--r--crates/hir-def/src/item_tree/pretty.rs14
-rw-r--r--crates/parser/src/grammar/items/adt.rs3
-rw-r--r--crates/parser/test_data/parser/inline/ok/record_field_list.rast14
-rw-r--r--crates/parser/test_data/parser/inline/ok/record_field_list.rs2
-rw-r--r--crates/syntax/rust.ungram2
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs2
9 files changed, 39 insertions, 9 deletions
diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs
index 8ea7940653..e470fe689b 100644
--- a/crates/hir-def/src/data/adt.rs
+++ b/crates/hir-def/src/data/adt.rs
@@ -171,6 +171,7 @@ pub struct FieldData {
pub name: Name,
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
+ pub is_unsafe: bool,
}
fn repr_from_value(
@@ -329,14 +330,14 @@ impl EnumVariantData {
impl VariantData {
pub fn fields(&self) -> &Arena<FieldData> {
const EMPTY: &Arena<FieldData> = &Arena::new();
- match &self {
+ match self {
VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
_ => EMPTY,
}
}
pub fn types_map(&self) -> &TypesMap {
- match &self {
+ match self {
VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => {
types_map
}
@@ -405,5 +406,6 @@ fn lower_field(
name: field.name.clone(),
type_ref: field.type_ref,
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
+ is_unsafe: field.is_unsafe,
}
}
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 2debbb1ee4..80d666a0ab 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -1032,6 +1032,7 @@ pub struct Field {
pub name: Name,
pub type_ref: TypeRefId,
pub visibility: RawVisibilityId,
+ pub is_unsafe: bool,
}
#[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index 6866821420..5389ba49c5 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -320,7 +320,7 @@ impl<'a> Ctx<'a> {
let visibility = self.lower_visibility(field);
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
- Field { name, type_ref, visibility }
+ Field { name, type_ref, visibility, is_unsafe: field.unsafe_token().is_some() }
}
fn lower_tuple_field(
@@ -332,7 +332,7 @@ impl<'a> Ctx<'a> {
let name = Name::new_tuple_field(idx);
let visibility = self.lower_visibility(field);
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
- Field { name, type_ref, visibility }
+ Field { name, type_ref, visibility, is_unsafe: false }
}
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs
index e666b1ea6b..f44a000ac1 100644
--- a/crates/hir-def/src/item_tree/pretty.rs
+++ b/crates/hir-def/src/item_tree/pretty.rs
@@ -135,12 +135,17 @@ impl Printer<'_> {
self.whitespace();
w!(self, "{{");
self.indented(|this| {
- for (idx, Field { name, type_ref, visibility }) in fields.iter().enumerate() {
+ for (idx, Field { name, type_ref, visibility, is_unsafe }) in
+ fields.iter().enumerate()
+ {
this.print_attrs_of(
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
"\n",
);
this.print_visibility(*visibility);
+ if *is_unsafe {
+ w!(this, "unsafe ");
+ }
w!(this, "{}: ", name.display(self.db.upcast(), edition));
this.print_type_ref(*type_ref, map);
wln!(this, ",");
@@ -151,12 +156,17 @@ impl Printer<'_> {
FieldsShape::Tuple => {
w!(self, "(");
self.indented(|this| {
- for (idx, Field { name, type_ref, visibility }) in fields.iter().enumerate() {
+ for (idx, Field { name, type_ref, visibility, is_unsafe }) in
+ fields.iter().enumerate()
+ {
this.print_attrs_of(
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
"\n",
);
this.print_visibility(*visibility);
+ if *is_unsafe {
+ w!(this, "unsafe ");
+ }
w!(this, "{}: ", name.display(self.db.upcast(), edition));
this.print_type_ref(*type_ref, map);
wln!(this, ",");
diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs
index 9a16c9db6d..a375696140 100644
--- a/crates/parser/src/grammar/items/adt.rs
+++ b/crates/parser/src/grammar/items/adt.rs
@@ -107,7 +107,7 @@ pub(crate) fn variant_list(p: &mut Parser<'_>) {
}
// test record_field_list
-// struct S { a: i32, b: f32 }
+// struct S { a: i32, b: f32, unsafe c: u8 }
pub(crate) fn record_field_list(p: &mut Parser<'_>) {
assert!(p.at(T!['{']));
let m = p.start();
@@ -131,6 +131,7 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
// struct S { #[attr] f: f32 }
attributes::outer_attrs(p);
opt_visibility(p, false);
+ p.eat(T![unsafe]);
if p.at(IDENT) {
name(p);
p.expect(T![:]);
diff --git a/crates/parser/test_data/parser/inline/ok/record_field_list.rast b/crates/parser/test_data/parser/inline/ok/record_field_list.rast
index 065d7e7e81..07686f509c 100644
--- a/crates/parser/test_data/parser/inline/ok/record_field_list.rast
+++ b/crates/parser/test_data/parser/inline/ok/record_field_list.rast
@@ -30,6 +30,20 @@ SOURCE_FILE
PATH_SEGMENT
NAME_REF
IDENT "f32"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_FIELD
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/record_field_list.rs b/crates/parser/test_data/parser/inline/ok/record_field_list.rs
index a3bd7787db..1f4612f539 100644
--- a/crates/parser/test_data/parser/inline/ok/record_field_list.rs
+++ b/crates/parser/test_data/parser/inline/ok/record_field_list.rs
@@ -1 +1 @@
-struct S { a: i32, b: f32 }
+struct S { a: i32, b: f32, unsafe c: u8 }
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 70a91af6c4..673334bd22 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -240,7 +240,7 @@ RecordFieldList =
'{' fields:(RecordField (',' RecordField)* ','?)? '}'
RecordField =
- Attr* Visibility?
+ Attr* Visibility? 'unsafe'?
Name ':' Type ('=' Expr)?
TupleFieldList =
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 638b9615ea..fd23cdccd5 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1337,6 +1337,8 @@ impl RecordField {
pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
#[inline]
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+ #[inline]
+ pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
}
pub struct RecordFieldList {
pub(crate) syntax: SyntaxNode,