diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 71732261efc..4d0f965a4da 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1449,44 +1449,73 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ), _ => (": val", "literal", Applicability::HasPlaceholders, None), }; - let field_ids = self.r.field_def_ids(def_id); - let (fields, applicability) = match field_ids { - Some(field_ids) => { - let fields = field_ids.iter().map(|&id| self.r.tcx.item_name(id)); - let fields = if let Some(old_fields) = old_fields { - fields - .enumerate() - .map(|(idx, new)| (new, old_fields.get(idx))) - .map(|(new, old)| { - let new = new.to_ident_string(); - if let Some(Some(old)) = old - && new != *old - { - format!("{new}: {old}") - } else { - new - } - }) - .collect::>() - } else { - fields.map(|f| format!("{f}{tail}")).collect::>() - }; - - (fields.join(", "), applicability) + let fields = match def_id.as_local() { + Some(def_id) => { + self.r.struct_constructors.get(&def_id).cloned().map(|(_, _, f)| f) } - None => ("/* fields */".to_string(), Applicability::HasPlaceholders), + None => Some( + self.r + .tcx + .associated_item_def_ids(def_id) + .iter() + .map(|field_id| self.r.tcx.visibility(field_id)) + .collect(), + ), }; - let pad = match field_ids { - Some(field_ids) if field_ids.is_empty() => "", - _ => " ", - }; - err.span_suggestion( - span, - format!("use struct {descr} syntax instead"), - format!("{path_str} {{{pad}{fields}{pad}}}"), - applicability, - ); + + let hidden_fields = fields.map_or(false, |fields| { + fields + .iter() + .filter(|vis| { + !self.r.is_accessible_from(**vis, self.parent_scope.module) + }) + .next() + .is_some() + }); + + if !hidden_fields { + // If the fields of the type are private, we shouldn't be suggesting using + // the struct literal syntax at all, as that will cause a subsequent error. + let field_ids = self.r.field_def_ids(def_id); + let (fields, applicability) = match field_ids { + Some(field_ids) => { + let fields = field_ids.iter().map(|&id| self.r.tcx.item_name(id)); + + let fields = if let Some(old_fields) = old_fields { + fields + .enumerate() + .map(|(idx, new)| (new, old_fields.get(idx))) + .map(|(new, old)| { + let new = new.to_ident_string(); + if let Some(Some(old)) = old + && new != *old + { + format!("{new}: {old}") + } else { + new + } + }) + .collect::>() + } else { + fields.map(|f| format!("{f}{tail}")).collect::>() + }; + + (fields.join(", "), applicability) + } + None => ("/* fields */".to_string(), Applicability::HasPlaceholders), + }; + let pad = match field_ids { + Some(field_ids) if field_ids.is_empty() => "", + _ => " ", + }; + err.span_suggestion( + span, + format!("use struct {descr} syntax instead"), + format!("{path_str} {{{pad}{fields}{pad}}}"), + applicability, + ); + } } _ => { err.span_label(span, fallback_label.to_string()); diff --git a/tests/ui/xcrate/xcrate-unit-struct.stderr b/tests/ui/xcrate/xcrate-unit-struct.stderr index c6402e929be..7365170b69e 100644 --- a/tests/ui/xcrate/xcrate-unit-struct.stderr +++ b/tests/ui/xcrate/xcrate-unit-struct.stderr @@ -13,7 +13,7 @@ error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithPrivFi --> $DIR/xcrate-unit-struct.rs:11:13 | LL | let _ = xcrate_unit_struct::StructWithPrivFields; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `xcrate_unit_struct::StructWithPrivFields { foo: val }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ::: $DIR/auxiliary/xcrate_unit_struct.rs:25:1 |