diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 8ea79406531d..e470fe689b91 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 2debbb1ee4e3..80d666a0aba1 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 686682142052..5389ba49c577 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 e666b1ea6bc2..f44a000ac1ba 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 9a16c9db6daf..a37569614028 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 065d7e7e81f2..07686f509c1b 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 a3bd7787db77..1f4612f53913 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 70a91af6c479..673334bd2251 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 638b9615ea33..fd23cdccd572 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,