@@ -26,10 +26,10 @@ use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructEx
2626use rustc_ast as ast;
2727use rustc_data_structures:: fx:: FxHashMap ;
2828use rustc_data_structures:: stack:: ensure_sufficient_stack;
29- use rustc_errors:: Diagnostic ;
30- use rustc_errors :: EmissionGuarantee ;
31- use rustc_errors :: ErrorGuaranteed ;
32- use rustc_errors :: { pluralize , struct_span_err , Applicability , DiagnosticBuilder , DiagnosticId } ;
29+ use rustc_errors:: {
30+ pluralize , struct_span_err , Applicability , Diagnostic , DiagnosticBuilder , DiagnosticId ,
31+ EmissionGuarantee , ErrorGuaranteed ,
32+ } ;
3333use rustc_hir as hir;
3434use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
3535use rustc_hir:: def_id:: DefId ;
@@ -1701,12 +1701,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17011701 } ;
17021702 self . typeck_results . borrow_mut ( ) . fru_field_types_mut ( ) . insert ( expr_id, fru_tys) ;
17031703 } else if adt_kind != AdtKind :: Union && !remaining_fields. is_empty ( ) {
1704- let inaccessible_remaining_fields = remaining_fields. iter ( ) . any ( |( _, ( _, field) ) | {
1705- !field. vis . is_accessible_from ( tcx. parent_module ( expr_id) . to_def_id ( ) , tcx)
1706- } ) ;
1704+ debug ! ( ?remaining_fields) ;
1705+ let private_fields: Vec < & ty:: FieldDef > = variant
1706+ . fields
1707+ . iter ( )
1708+ . filter ( |field| {
1709+ !field. vis . is_accessible_from ( tcx. parent_module ( expr_id) . to_def_id ( ) , tcx)
1710+ } )
1711+ . collect ( ) ;
17071712
1708- if inaccessible_remaining_fields {
1709- self . report_inaccessible_fields ( adt_ty, span) ;
1713+ if !private_fields . is_empty ( ) {
1714+ self . report_private_fields ( adt_ty, span, private_fields , ast_fields ) ;
17101715 } else {
17111716 self . report_missing_fields (
17121717 adt_ty,
@@ -1830,21 +1835,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18301835 /// Report an error for a struct field expression when there are invisible fields.
18311836 ///
18321837 /// ```text
1833- /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
1838+ /// error: cannot construct `Foo` with struct literal syntax due to private fields
18341839 /// --> src/main.rs:8:5
18351840 /// |
18361841 /// 8 | foo::Foo {};
18371842 /// | ^^^^^^^^
18381843 ///
18391844 /// error: aborting due to previous error
18401845 /// ```
1841- fn report_inaccessible_fields ( & self , adt_ty : Ty < ' tcx > , span : Span ) {
1842- self . tcx . sess . span_err (
1846+ fn report_private_fields (
1847+ & self ,
1848+ adt_ty : Ty < ' tcx > ,
1849+ span : Span ,
1850+ private_fields : Vec < & ty:: FieldDef > ,
1851+ used_fields : & ' tcx [ hir:: ExprField < ' tcx > ] ,
1852+ ) {
1853+ let mut err = self . tcx . sess . struct_span_err (
18431854 span,
18441855 & format ! (
1845- "cannot construct `{adt_ty}` with struct literal syntax due to inaccessible fields" ,
1856+ "cannot construct `{adt_ty}` with struct literal syntax due to private fields" ,
18461857 ) ,
18471858 ) ;
1859+ let ( used_private_fields, remaining_private_fields) : (
1860+ Vec < ( Symbol , Span , bool ) > ,
1861+ Vec < ( Symbol , Span , bool ) > ,
1862+ ) = private_fields
1863+ . iter ( )
1864+ . map ( |field| {
1865+ match used_fields. iter ( ) . find ( |used_field| field. name == used_field. ident . name ) {
1866+ Some ( used_field) => ( field. name , used_field. span , true ) ,
1867+ None => ( field. name , self . tcx . def_span ( field. did ) , false ) ,
1868+ }
1869+ } )
1870+ . partition ( |field| field. 2 ) ;
1871+ err. span_labels ( used_private_fields. iter ( ) . map ( |( _, span, _) | * span) , "private field" ) ;
1872+ if !remaining_private_fields. is_empty ( ) {
1873+ let remaining_private_fields_len = remaining_private_fields. len ( ) ;
1874+ let names = match & remaining_private_fields
1875+ . iter ( )
1876+ . map ( |( name, _, _) | name. to_string ( ) )
1877+ . collect :: < Vec < _ > > ( ) [ ..]
1878+ {
1879+ _ if remaining_private_fields_len > 6 => String :: new ( ) ,
1880+ [ name] => format ! ( "`{name}` " ) ,
1881+ [ names @ .., last] => {
1882+ let names = names. iter ( ) . map ( |name| format ! ( "`{name}`" ) ) . collect :: < Vec < _ > > ( ) ;
1883+ format ! ( "{} and `{last}` " , names. join( ", " ) )
1884+ }
1885+ [ ] => unreachable ! ( ) ,
1886+ } ;
1887+ err. note ( format ! (
1888+ "... and other private field{s} {names}that {were} not provided" ,
1889+ s = pluralize!( remaining_private_fields_len) ,
1890+ were = pluralize!( "was" , remaining_private_fields_len) ,
1891+ ) ) ;
1892+ }
1893+ err. emit ( ) ;
18481894 }
18491895
18501896 fn report_unknown_field (
0 commit comments