Skip to content

Commit 0dbd6e9

Browse files
committed
Improve some codes according to the reviews
- improve diagnostics of field uniqueness check and representation check - simplify the implementation of field uniqueness check - remove some useless codes and improvement neatness
1 parent 2b04ca9 commit 0dbd6e9

File tree

9 files changed

+655
-121
lines changed

9 files changed

+655
-121
lines changed

compiler/rustc_hir_analysis/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ hir_analysis_field_already_declared_current_nested =
136136
.nested_field_decl_note = field `{$field_name}` declared here
137137
.previous_decl_label = `{$field_name}` first declared here
138138
139+
hir_analysis_field_already_declared_nested_help =
140+
fields from the type of this unnamed field are considered fields of the outer type
141+
139142
hir_analysis_field_already_declared_previous_nested =
140143
field `{$field_name}` is already declared
141144
.label = field already declared
@@ -445,10 +448,12 @@ hir_analysis_unnamed_fields_repr_field_missing_repr_c =
445448
named type of unnamed field must have `#[repr(C)]` representation
446449
.label = unnamed field defined here
447450
.field_ty_label = `{$field_ty}` defined here
451+
.suggestion = add `#[repr(C)]` to this {$field_adt_kind}
448452
449453
hir_analysis_unnamed_fields_repr_missing_repr_c =
450454
{$adt_kind} with unnamed fields must have `#[repr(C)]` representation
451455
.label = {$adt_kind} `{$adt_name}` defined here
456+
.suggestion = add `#[repr(C)]` to this {$adt_kind}
452457
453458
hir_analysis_unrecognized_atomic_operation =
454459
unrecognized atomic operation function: `{$op}`

compiler/rustc_hir_analysis/src/check/check.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
122122
adt_kind,
123123
adt_name,
124124
unnamed_fields,
125+
sugg_span: span.shrink_to_lo(),
125126
});
126127
}
127128
}
@@ -131,10 +132,13 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
131132
&& !adt.is_anonymous()
132133
&& !adt.repr().c()
133134
{
135+
let field_ty_span = tcx.def_span(adt.did());
134136
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
135137
span: tcx.def_span(field.did),
136-
field_ty_span: tcx.def_span(adt.did()),
138+
field_ty_span,
137139
field_ty,
140+
field_adt_kind: adt.descr(),
141+
sugg_span: field_ty_span.shrink_to_lo(),
138142
});
139143
}
140144
}

compiler/rustc_hir_analysis/src/collect.rs

+126-106
Original file line numberDiff line numberDiff line change
@@ -791,12 +791,30 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
791791
}
792792
}
793793

794+
fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
795+
tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
796+
if field.is_unnamed() {
797+
let field_ty = tcx.type_of(field.did).instantiate_identity();
798+
let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
799+
tcx.find_field((adt_def.did(), ident)).map(|_| idx)
800+
} else {
801+
(field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
802+
}
803+
})
804+
}
805+
794806
#[derive(Clone, Copy)]
795807
struct NestedSpan {
796808
span: Span,
797809
nested_field_span: Span,
798810
}
799811

812+
impl NestedSpan {
813+
fn to_field_already_declared_nested_help(&self) -> errors::FieldAlreadyDeclaredNestedHelp {
814+
errors::FieldAlreadyDeclaredNestedHelp { span: self.span }
815+
}
816+
}
817+
800818
#[derive(Clone, Copy)]
801819
enum FieldDeclSpan {
802820
NotNested(Span),
@@ -815,87 +833,131 @@ impl From<NestedSpan> for FieldDeclSpan {
815833
}
816834
}
817835

818-
/// Check the uniqueness of fields across adt where there are
819-
/// nested fields imported from an unnamed field.
820-
fn check_field_uniqueness_in_nested_adt(
821-
tcx: TyCtxt<'_>,
822-
adt_def: ty::AdtDef<'_>,
823-
check: &mut impl FnMut(Ident, /* nested_field_span */ Span),
824-
) {
825-
for field in adt_def.all_fields() {
826-
if field.is_unnamed() {
827-
// Here we don't care about the generic parameters, so `instantiate_identity` is enough.
828-
match tcx.type_of(field.did).instantiate_identity().kind() {
829-
ty::Adt(adt_def, _) => {
830-
check_field_uniqueness_in_nested_adt(tcx, *adt_def, &mut *check);
836+
struct FieldUniquenessCheckContext<'tcx> {
837+
tcx: TyCtxt<'tcx>,
838+
seen_fields: FxHashMap<Ident, FieldDeclSpan>,
839+
}
840+
841+
impl<'tcx> FieldUniquenessCheckContext<'tcx> {
842+
fn new(tcx: TyCtxt<'tcx>) -> Self {
843+
Self { tcx, seen_fields: FxHashMap::default() }
844+
}
845+
846+
/// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before.
847+
fn check_field_decl(&mut self, ident: Ident, field_decl: FieldDeclSpan) {
848+
use FieldDeclSpan::*;
849+
let field_name = ident.name;
850+
let ident = ident.normalize_to_macros_2_0();
851+
match (field_decl, self.seen_fields.get(&ident).copied()) {
852+
(NotNested(span), Some(NotNested(prev_span))) => {
853+
self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
854+
field_name,
855+
span,
856+
prev_span,
857+
});
858+
}
859+
(NotNested(span), Some(Nested(prev))) => {
860+
self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
861+
field_name,
862+
span,
863+
prev_span: prev.span,
864+
prev_nested_field_span: prev.nested_field_span,
865+
prev_help: prev.to_field_already_declared_nested_help(),
866+
});
867+
}
868+
(
869+
Nested(current @ NestedSpan { span, nested_field_span, .. }),
870+
Some(NotNested(prev_span)),
871+
) => {
872+
self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
873+
field_name,
874+
span,
875+
nested_field_span,
876+
help: current.to_field_already_declared_nested_help(),
877+
prev_span,
878+
});
879+
}
880+
(Nested(current @ NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
881+
self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
882+
field_name,
883+
span,
884+
nested_field_span,
885+
help: current.to_field_already_declared_nested_help(),
886+
prev_span: prev.span,
887+
prev_nested_field_span: prev.nested_field_span,
888+
prev_help: prev.to_field_already_declared_nested_help(),
889+
});
890+
}
891+
(field_decl, None) => {
892+
self.seen_fields.insert(ident, field_decl);
893+
}
894+
}
895+
}
896+
897+
/// Check the uniqueness of fields across adt where there are
898+
/// nested fields imported from an unnamed field.
899+
fn check_field_in_nested_adt(&mut self, adt_def: ty::AdtDef<'_>, unnamed_field_span: Span) {
900+
for field in adt_def.all_fields() {
901+
if field.is_unnamed() {
902+
// Here we don't care about the generic parameters, so `instantiate_identity` is enough.
903+
match self.tcx.type_of(field.did).instantiate_identity().kind() {
904+
ty::Adt(adt_def, _) => {
905+
self.check_field_in_nested_adt(*adt_def, unnamed_field_span);
906+
}
907+
ty_kind => span_bug!(
908+
self.tcx.def_span(field.did),
909+
"Unexpected TyKind in FieldUniquenessCheckContext::check_field_in_nested_adt(): {ty_kind:?}"
910+
),
831911
}
832-
ty_kind => bug!(
833-
"Unexpected ty kind in check_field_uniqueness_in_nested_adt(): {ty_kind:?}"
834-
),
912+
} else {
913+
self.check_field_decl(
914+
field.ident(self.tcx),
915+
NestedSpan {
916+
span: unnamed_field_span,
917+
nested_field_span: self.tcx.def_span(field.did),
918+
}
919+
.into(),
920+
);
835921
}
836-
} else {
837-
check(field.ident(tcx), tcx.def_span(field.did));
838922
}
839923
}
840-
}
841924

842-
/// Check the uniqueness of fields in a struct variant, and recursively
843-
/// check the nested fields if it is an unnamed field with type of an
844-
/// annoymous adt.
845-
fn check_field_uniqueness(
846-
tcx: TyCtxt<'_>,
847-
field: &hir::FieldDef<'_>,
848-
check: &mut impl FnMut(Ident, FieldDeclSpan),
849-
) {
850-
if field.ident.name == kw::Underscore {
851-
let ty_span = field.ty.span;
925+
/// Check the uniqueness of fields in a struct variant, and recursively
926+
/// check the nested fields if it is an unnamed field with type of an
927+
/// annoymous adt.
928+
fn check_field(&mut self, field: &hir::FieldDef<'_>) {
929+
if field.ident.name != kw::Underscore {
930+
self.check_field_decl(field.ident, field.span.into());
931+
return;
932+
}
852933
match &field.ty.kind {
853934
hir::TyKind::AnonAdt(item_id) => {
854-
match &tcx.hir_node(item_id.hir_id()).expect_item().kind {
935+
match &self.tcx.hir_node(item_id.hir_id()).expect_item().kind {
855936
hir::ItemKind::Struct(variant_data, ..)
856937
| hir::ItemKind::Union(variant_data, ..) => {
857-
variant_data
858-
.fields()
859-
.iter()
860-
.for_each(|f| check_field_uniqueness(tcx, f, &mut *check));
938+
variant_data.fields().iter().for_each(|f| self.check_field(f));
861939
}
862940
item_kind => span_bug!(
863-
ty_span,
864-
"Unexpected item kind in check_field_uniqueness(): {item_kind:?}"
941+
field.ty.span,
942+
"Unexpected ItemKind in FieldUniquenessCheckContext::check_field(): {item_kind:?}"
865943
),
866944
}
867945
}
868946
hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
869-
check_field_uniqueness_in_nested_adt(
870-
tcx,
871-
tcx.adt_def(res.def_id()),
872-
&mut |ident, nested_field_span| {
873-
check(ident, NestedSpan { span: field.span, nested_field_span }.into())
874-
},
875-
);
947+
self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
876948
}
877949
// Abort due to errors (there must be an error if an unnamed field
878950
// has any type kind other than an anonymous adt or a named adt)
879-
_ => {
880-
debug_assert!(tcx.dcx().has_errors().is_some());
881-
tcx.dcx().abort_if_errors()
951+
ty_kind => {
952+
self.tcx.dcx().span_delayed_bug(
953+
field.ty.span,
954+
format!("Unexpected TyKind in FieldUniquenessCheckContext::check_field(): {ty_kind:?}"),
955+
);
956+
// FIXME: errors during AST validation should abort the compilation before reaching here.
957+
self.tcx.dcx().abort_if_errors();
882958
}
883959
}
884-
return;
885960
}
886-
check(field.ident, field.span.into());
887-
}
888-
889-
fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
890-
tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
891-
if field.is_unnamed() {
892-
let field_ty = tcx.type_of(field.did).instantiate_identity();
893-
let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
894-
tcx.find_field((adt_def.did(), ident)).map(|_| idx)
895-
} else {
896-
(field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
897-
}
898-
})
899961
}
900962

901963
fn convert_variant(
@@ -909,58 +971,16 @@ fn convert_variant(
909971
is_anonymous: bool,
910972
) -> ty::VariantDef {
911973
let mut has_unnamed_fields = false;
912-
let mut seen_fields: FxHashMap<Ident, FieldDeclSpan> = Default::default();
974+
let mut field_uniqueness_check_ctx = FieldUniquenessCheckContext::new(tcx);
913975
let fields = def
914976
.fields()
915977
.iter()
916978
.inspect(|f| {
917979
has_unnamed_fields |= f.ident.name == kw::Underscore;
980+
// We only check named ADT here because anonymous ADTs are checked inside
981+
// the nammed ADT in which they are defined.
918982
if !is_anonymous {
919-
check_field_uniqueness(tcx, f, &mut |ident, field_decl| {
920-
use FieldDeclSpan::*;
921-
let field_name = ident.name;
922-
let ident = ident.normalize_to_macros_2_0();
923-
match (field_decl, seen_fields.get(&ident).copied()) {
924-
(NotNested(span), Some(NotNested(prev_span))) => {
925-
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
926-
field_name,
927-
span,
928-
prev_span,
929-
});
930-
}
931-
(NotNested(span), Some(Nested(prev))) => {
932-
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
933-
field_name,
934-
span,
935-
prev_span: prev.span,
936-
prev_nested_field_span: prev.nested_field_span,
937-
});
938-
}
939-
(
940-
Nested(NestedSpan { span, nested_field_span }),
941-
Some(NotNested(prev_span)),
942-
) => {
943-
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
944-
field_name,
945-
span,
946-
nested_field_span,
947-
prev_span,
948-
});
949-
}
950-
(Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
951-
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
952-
field_name,
953-
span,
954-
nested_field_span,
955-
prev_span: prev.span,
956-
prev_nested_field_span: prev.nested_field_span,
957-
});
958-
}
959-
(field_decl, None) => {
960-
seen_fields.insert(ident, field_decl);
961-
}
962-
}
963-
});
983+
field_uniqueness_check_ctx.check_field(f);
964984
}
965985
})
966986
.map(|f| ty::FieldDef {

compiler/rustc_hir_analysis/src/errors.rs

+20
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ pub enum FieldAlreadyDeclared {
193193
span: Span,
194194
#[note(hir_analysis_nested_field_decl_note)]
195195
nested_field_span: Span,
196+
#[subdiagnostic]
197+
help: FieldAlreadyDeclaredNestedHelp,
196198
#[label(hir_analysis_previous_decl_label)]
197199
prev_span: Span,
198200
},
@@ -206,6 +208,8 @@ pub enum FieldAlreadyDeclared {
206208
prev_span: Span,
207209
#[note(hir_analysis_previous_nested_field_decl_note)]
208210
prev_nested_field_span: Span,
211+
#[subdiagnostic]
212+
prev_help: FieldAlreadyDeclaredNestedHelp,
209213
},
210214
#[diag(hir_analysis_field_already_declared_both_nested)]
211215
BothNested {
@@ -215,13 +219,24 @@ pub enum FieldAlreadyDeclared {
215219
span: Span,
216220
#[note(hir_analysis_nested_field_decl_note)]
217221
nested_field_span: Span,
222+
#[subdiagnostic]
223+
help: FieldAlreadyDeclaredNestedHelp,
218224
#[label(hir_analysis_previous_decl_label)]
219225
prev_span: Span,
220226
#[note(hir_analysis_previous_nested_field_decl_note)]
221227
prev_nested_field_span: Span,
228+
#[subdiagnostic]
229+
prev_help: FieldAlreadyDeclaredNestedHelp,
222230
},
223231
}
224232

233+
#[derive(Subdiagnostic)]
234+
#[help(hir_analysis_field_already_declared_nested_help)]
235+
pub struct FieldAlreadyDeclaredNestedHelp {
236+
#[primary_span]
237+
pub span: Span,
238+
}
239+
225240
#[derive(Diagnostic)]
226241
#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = E0184)]
227242
pub struct CopyImplOnTypeWithDtor {
@@ -1583,6 +1598,8 @@ pub enum UnnamedFieldsRepr<'a> {
15831598
adt_name: Symbol,
15841599
#[subdiagnostic]
15851600
unnamed_fields: Vec<UnnamedFieldsReprFieldDefined>,
1601+
#[suggestion(code = "#[repr(C)]\n")]
1602+
sugg_span: Span,
15861603
},
15871604
#[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)]
15881605
FieldMissingReprC {
@@ -1592,6 +1609,9 @@ pub enum UnnamedFieldsRepr<'a> {
15921609
#[label(hir_analysis_field_ty_label)]
15931610
field_ty_span: Span,
15941611
field_ty: Ty<'a>,
1612+
field_adt_kind: &'static str,
1613+
#[suggestion(code = "#[repr(C)]\n")]
1614+
sugg_span: Span,
15951615
},
15961616
}
15971617

0 commit comments

Comments
 (0)