1414
1515use std:: mem:: replace;
1616
17+ use metadata:: csearch;
1718use middle:: lint;
1819use middle:: resolve;
1920use middle:: ty;
@@ -358,6 +359,12 @@ enum PrivacyResult {
358359 DisallowedBy ( ast:: NodeId ) ,
359360}
360361
362+ enum FieldName {
363+ UnnamedField ( uint ) , // index
364+ // FIXME #6993: change type (and name) from Ident to Name
365+ NamedField ( ast:: Ident ) ,
366+ }
367+
361368impl < ' a > PrivacyVisitor < ' a > {
362369 // used when debugging
363370 fn nodestr ( & self , id : ast:: NodeId ) -> ~str {
@@ -560,18 +567,23 @@ impl<'a> PrivacyVisitor<'a> {
560567 }
561568
562569 // Checks that a field is in scope.
563- // FIXME #6993: change type (and name) from Ident to Name
564- fn check_field ( & mut self , span : Span , id : ast:: DefId , ident : ast:: Ident ) {
565- for field in ty:: lookup_struct_fields ( self . tcx , id) . iter ( ) {
566- if field. name != ident. name { continue ; }
567- if field. vis == ast:: Public { break }
568- if !is_local ( field. id ) ||
569- !self . private_accessible ( field. id . node ) {
570- self . tcx . sess . span_err ( span,
571- format ! ( "field `{}` is private" ,
572- token:: get_ident( ident) ) )
570+ fn check_field ( & mut self , span : Span , id : ast:: DefId ,
571+ name : FieldName ) {
572+ let fields = ty:: lookup_struct_fields ( self . tcx , id) ;
573+ let field = match name {
574+ NamedField ( ident) => {
575+ fields. iter ( ) . find ( |f| f. name == ident. name ) . unwrap ( )
573576 }
574- break ;
577+ UnnamedField ( idx) => fields. get ( idx)
578+ } ;
579+ if field. vis == ast:: Public { return }
580+ if !is_local ( field. id ) || !self . private_accessible ( field. id . node ) {
581+ let msg = match name {
582+ NamedField ( name) => format ! ( "field `{}` is private" ,
583+ token:: get_ident( name) ) ,
584+ UnnamedField ( idx) => format ! ( "field \\ #{} is private" , idx + 1 ) ,
585+ } ;
586+ self . tcx . sess . span_err ( span, msg) ;
575587 }
576588 }
577589
@@ -634,10 +646,11 @@ impl<'a> PrivacyVisitor<'a> {
634646 _ => { } ,
635647 }
636648 }
637- // If an import is not used in either namespace, we still want to check
638- // that it could be legal. Therefore we check in both namespaces and only
639- // report an error if both would be illegal. We only report one error,
640- // even if it is illegal to import from both namespaces.
649+ // If an import is not used in either namespace, we still
650+ // want to check that it could be legal. Therefore we check
651+ // in both namespaces and only report an error if both would
652+ // be illegal. We only report one error, even if it is
653+ // illegal to import from both namespaces.
641654 match ( value_priv, check_value, type_priv, check_type) {
642655 ( Some ( p) , resolve:: Unused , None , _) |
643656 ( None , _, Some ( p) , resolve:: Unused ) => {
@@ -701,7 +714,8 @@ impl<'a> PrivacyVisitor<'a> {
701714 // is whether the trait itself is accessible or not.
702715 MethodParam ( MethodParam { trait_id : trait_id, .. } ) |
703716 MethodObject ( MethodObject { trait_id : trait_id, .. } ) => {
704- self . report_error ( self . ensure_public ( span, trait_id, None , "source trait" ) ) ;
717+ self . report_error ( self . ensure_public ( span, trait_id, None ,
718+ "source trait" ) ) ;
705719 }
706720 }
707721 }
@@ -726,7 +740,7 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
726740 match ty:: get ( ty:: expr_ty_adjusted ( self . tcx , base,
727741 & * self . method_map . borrow ( ) ) ) . sty {
728742 ty:: ty_struct( id, _) => {
729- self . check_field ( expr. span , id, ident) ;
743+ self . check_field ( expr. span , id, NamedField ( ident) ) ;
730744 }
731745 _ => { }
732746 }
@@ -749,15 +763,16 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
749763 match ty:: get ( ty:: expr_ty ( self . tcx , expr) ) . sty {
750764 ty:: ty_struct( id, _) => {
751765 for field in ( * fields) . iter ( ) {
752- self . check_field ( expr. span , id, field. ident . node ) ;
766+ self . check_field ( expr. span , id,
767+ NamedField ( field. ident . node ) ) ;
753768 }
754769 }
755770 ty:: ty_enum( _, _) => {
756771 match self . tcx . def_map . borrow ( ) . get_copy ( & expr. id ) {
757772 ast:: DefVariant ( _, variant_id, _) => {
758773 for field in fields. iter ( ) {
759774 self . check_field ( expr. span , variant_id,
760- field. ident . node ) ;
775+ NamedField ( field. ident . node ) ) ;
761776 }
762777 }
763778 _ => self . tcx . sess . span_bug ( expr. span ,
@@ -772,6 +787,46 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
772787 struct type?!") ,
773788 }
774789 }
790+ ast:: ExprPath ( ..) => {
791+ let guard = |did : ast:: DefId | {
792+ let fields = ty:: lookup_struct_fields ( self . tcx , did) ;
793+ let any_priv = fields. iter ( ) . any ( |f| {
794+ f. vis != ast:: Public && (
795+ !is_local ( f. id ) ||
796+ !self . private_accessible ( f. id . node ) )
797+ } ) ;
798+ if any_priv {
799+ self . tcx . sess . span_err ( expr. span ,
800+ "cannot invoke tuple struct constructor \
801+ with private fields") ;
802+ }
803+ } ;
804+ match self . tcx . def_map . borrow ( ) . find ( & expr. id ) {
805+ Some ( & ast:: DefStruct ( did) ) => {
806+ guard ( if is_local ( did) {
807+ local_def ( self . tcx . map . get_parent ( did. node ) )
808+ } else {
809+ // "tuple structs" with zero fields (such as
810+ // `pub struct Foo;`) don't have a ctor_id, hence
811+ // the unwrap_or to the same struct id.
812+ let maybe_did =
813+ csearch:: get_tuple_struct_definition_if_ctor (
814+ & self . tcx . sess . cstore , did) ;
815+ maybe_did. unwrap_or ( did)
816+ } )
817+ }
818+ // Tuple struct constructors across crates are identified as
819+ // DefFn types, so we explicitly handle that case here.
820+ Some ( & ast:: DefFn ( did, _) ) if !is_local ( did) => {
821+ match csearch:: get_tuple_struct_definition_if_ctor (
822+ & self . tcx . sess . cstore , did) {
823+ Some ( did) => guard ( did) ,
824+ None => { }
825+ }
826+ }
827+ _ => { }
828+ }
829+ }
775830 _ => { }
776831 }
777832
@@ -821,15 +876,16 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
821876 match ty:: get ( ty:: pat_ty ( self . tcx , pattern) ) . sty {
822877 ty:: ty_struct( id, _) => {
823878 for field in fields. iter ( ) {
824- self . check_field ( pattern. span , id, field. ident ) ;
879+ self . check_field ( pattern. span , id,
880+ NamedField ( field. ident ) ) ;
825881 }
826882 }
827883 ty:: ty_enum( _, _) => {
828884 match self . tcx . def_map . borrow ( ) . find ( & pattern. id ) {
829885 Some ( & ast:: DefVariant ( _, variant_id, _) ) => {
830886 for field in fields. iter ( ) {
831887 self . check_field ( pattern. span , variant_id,
832- field. ident ) ;
888+ NamedField ( field. ident ) ) ;
833889 }
834890 }
835891 _ => self . tcx . sess . span_bug ( pattern. span ,
@@ -844,6 +900,27 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
844900 struct type?!") ,
845901 }
846902 }
903+
904+ // Patterns which bind no fields are allowable (the path is check
905+ // elsewhere).
906+ ast:: PatEnum ( _, Some ( ref fields) ) => {
907+ match ty:: get ( ty:: pat_ty ( self . tcx , pattern) ) . sty {
908+ ty:: ty_struct( id, _) => {
909+ for ( i, field) in fields. iter ( ) . enumerate ( ) {
910+ match field. node {
911+ ast:: PatWild ( ..) => continue ,
912+ _ => { }
913+ }
914+ self . check_field ( field. span , id, UnnamedField ( i) ) ;
915+ }
916+ }
917+ ty:: ty_enum( ..) => {
918+ // enum fields have no privacy at this time
919+ }
920+ _ => { }
921+ }
922+
923+ }
847924 _ => { }
848925 }
849926
0 commit comments