@@ -26,10 +26,10 @@ use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructEx
26
26
use rustc_ast as ast;
27
27
use rustc_data_structures:: fx:: FxHashMap ;
28
28
use 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
+ } ;
33
33
use rustc_hir as hir;
34
34
use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
35
35
use rustc_hir:: def_id:: DefId ;
@@ -1701,12 +1701,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1701
1701
} ;
1702
1702
self . typeck_results . borrow_mut ( ) . fru_field_types_mut ( ) . insert ( expr_id, fru_tys) ;
1703
1703
} 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 ( ) ;
1707
1712
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 ) ;
1710
1715
} else {
1711
1716
self . report_missing_fields (
1712
1717
adt_ty,
@@ -1830,21 +1835,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1830
1835
/// Report an error for a struct field expression when there are invisible fields.
1831
1836
///
1832
1837
/// ```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
1834
1839
/// --> src/main.rs:8:5
1835
1840
/// |
1836
1841
/// 8 | foo::Foo {};
1837
1842
/// | ^^^^^^^^
1838
1843
///
1839
1844
/// error: aborting due to previous error
1840
1845
/// ```
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 (
1843
1854
span,
1844
1855
& 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" ,
1846
1857
) ,
1847
1858
) ;
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 ( ) ;
1848
1894
}
1849
1895
1850
1896
fn report_unknown_field (
0 commit comments