@@ -229,6 +229,13 @@ fn def_id_visibility<'tcx>(
229
229
let vis = match tcx. hir ( ) . get ( hir_id) {
230
230
Node :: Item ( item) => & item. vis ,
231
231
Node :: ForeignItem ( foreign_item) => & foreign_item. vis ,
232
+ Node :: MacroDef ( macro_def) => {
233
+ if attr:: contains_name ( & macro_def. attrs , sym:: macro_export) {
234
+ return ( ty:: Visibility :: Public , macro_def. span , "public" ) ;
235
+ } else {
236
+ & macro_def. vis
237
+ }
238
+ } ,
232
239
Node :: TraitItem ( ..) | Node :: Variant ( ..) => {
233
240
return def_id_visibility ( tcx, tcx. hir ( ) . get_parent_did ( hir_id) ) ;
234
241
}
@@ -433,11 +440,24 @@ impl VisibilityLike for Option<AccessLevel> {
433
440
struct EmbargoVisitor < ' tcx > {
434
441
tcx : TyCtxt < ' tcx > ,
435
442
436
- // Accessibility levels for reachable nodes.
443
+ /// Accessibility levels for reachable nodes.
437
444
access_levels : AccessLevels ,
438
- // Previous accessibility level; `None` means unreachable.
445
+ /// A set of pairs corresponding to modules, where the first module is
446
+ /// reachable via a macro that's defined in the second module. This cannot
447
+ /// be represented as reachable because it can't handle the following case:
448
+ ///
449
+ /// pub mod n { // Should be `Public`
450
+ /// pub(crate) mod p { // Should *not* be accessible
451
+ /// pub fn f() -> i32 { 12 } // Must be `Reachable`
452
+ /// }
453
+ /// }
454
+ /// pub macro m() {
455
+ /// n::p::f()
456
+ /// }
457
+ macro_reachable : FxHashSet < ( hir:: HirId , DefId ) > ,
458
+ /// Previous accessibility level; `None` means unreachable.
439
459
prev_level : Option < AccessLevel > ,
440
- // Has something changed in the level map?
460
+ /// Has something changed in the level map?
441
461
changed : bool ,
442
462
}
443
463
@@ -452,7 +472,7 @@ impl EmbargoVisitor<'tcx> {
452
472
self . access_levels . map . get ( & id) . cloned ( )
453
473
}
454
474
455
- // Updates node level and returns the updated level.
475
+ /// Updates node level and returns the updated level.
456
476
fn update ( & mut self , id : hir:: HirId , level : Option < AccessLevel > ) -> Option < AccessLevel > {
457
477
let old_level = self . get ( id) ;
458
478
// Accessibility levels can only grow.
@@ -477,6 +497,127 @@ impl EmbargoVisitor<'tcx> {
477
497
}
478
498
}
479
499
500
+ /// Updates the item as being reachable through a macro defined in the given
501
+ /// module. Returns `true` if the level has changed.
502
+ fn update_macro_reachable ( & mut self , reachable_mod : hir:: HirId , defining_mod : DefId ) -> bool {
503
+ if self . macro_reachable . insert ( ( reachable_mod, defining_mod) ) {
504
+ self . update_macro_reachable_mod ( reachable_mod, defining_mod) ;
505
+ true
506
+ } else {
507
+ false
508
+ }
509
+ }
510
+
511
+ fn update_macro_reachable_mod (
512
+ & mut self ,
513
+ reachable_mod : hir:: HirId ,
514
+ defining_mod : DefId ,
515
+ ) {
516
+ let module_def_id = self . tcx . hir ( ) . local_def_id ( reachable_mod) ;
517
+ let module = self . tcx . hir ( ) . get_module ( module_def_id) . 0 ;
518
+ for item_id in & module. item_ids {
519
+ let hir_id = item_id. id ;
520
+ let item_def_id = self . tcx . hir ( ) . local_def_id ( hir_id) ;
521
+ if let Some ( def_kind) = self . tcx . def_kind ( item_def_id) {
522
+ let item = self . tcx . hir ( ) . expect_item ( hir_id) ;
523
+ let vis = ty:: Visibility :: from_hir ( & item. vis , hir_id, self . tcx ) ;
524
+ self . update_macro_reachable_def ( hir_id, def_kind, vis, defining_mod) ;
525
+ }
526
+ }
527
+
528
+ if let Some ( exports) = self . tcx . module_exports ( module_def_id) {
529
+ for export in exports {
530
+ if export. vis . is_accessible_from ( defining_mod, self . tcx ) {
531
+ if let Res :: Def ( def_kind, def_id) = export. res {
532
+ let vis = def_id_visibility ( self . tcx , def_id) . 0 ;
533
+ if let Some ( hir_id) = self . tcx . hir ( ) . as_local_hir_id ( def_id) {
534
+ self . update_macro_reachable_def (
535
+ hir_id,
536
+ def_kind,
537
+ vis,
538
+ defining_mod,
539
+ ) ;
540
+ }
541
+ }
542
+ }
543
+ }
544
+ }
545
+ }
546
+
547
+ fn update_macro_reachable_def (
548
+ & mut self ,
549
+ hir_id : hir:: HirId ,
550
+ def_kind : DefKind ,
551
+ vis : ty:: Visibility ,
552
+ module : DefId ,
553
+ ) {
554
+ let level = Some ( AccessLevel :: Reachable ) ;
555
+ if let ty:: Visibility :: Public = vis {
556
+ self . update ( hir_id, level) ;
557
+ }
558
+ match def_kind {
559
+ // No type privacy, so can be directly marked as reachable.
560
+ DefKind :: Const
561
+ | DefKind :: Macro ( _)
562
+ | DefKind :: Static
563
+ | DefKind :: TraitAlias
564
+ | DefKind :: TyAlias => {
565
+ if vis. is_accessible_from ( module, self . tcx ) {
566
+ self . update ( hir_id, level) ;
567
+ }
568
+ } ,
569
+
570
+ // We can't use a module name as the final segment of a path, except
571
+ // in use statements. Since re-export checking doesn't consider
572
+ // hygiene these don't need to be marked reachable. The contents of
573
+ // the module, however may be reachable.
574
+ DefKind :: Mod => {
575
+ if vis. is_accessible_from ( module, self . tcx ) {
576
+ self . update_macro_reachable ( hir_id, module) ;
577
+ }
578
+ }
579
+
580
+ DefKind :: Struct | DefKind :: Union => {
581
+ // While structs and unions have type privacy, their fields do
582
+ // not.
583
+ if let ty:: Visibility :: Public = vis {
584
+ let item = self . tcx . hir ( ) . expect_item ( hir_id) ;
585
+ if let hir:: ItemKind :: Struct ( ref struct_def, _)
586
+ | hir:: ItemKind :: Union ( ref struct_def, _) = item. node
587
+ {
588
+ for field in struct_def. fields ( ) {
589
+ let field_vis = ty:: Visibility :: from_hir (
590
+ & field. vis ,
591
+ field. hir_id ,
592
+ self . tcx ,
593
+ ) ;
594
+ if field_vis. is_accessible_from ( module, self . tcx ) {
595
+ self . reach ( field. hir_id , level) . ty ( ) ;
596
+ }
597
+ }
598
+ } else {
599
+ bug ! ( "item {:?} with DefKind {:?}" , item, def_kind) ;
600
+ }
601
+ }
602
+ }
603
+
604
+ // These have type privacy, so are not reachable unless they're
605
+ // public
606
+ DefKind :: AssocConst
607
+ | DefKind :: AssocTy
608
+ | DefKind :: AssocOpaqueTy
609
+ | DefKind :: ConstParam
610
+ | DefKind :: Ctor ( _, _)
611
+ | DefKind :: Enum
612
+ | DefKind :: ForeignTy
613
+ | DefKind :: Fn
614
+ | DefKind :: OpaqueTy
615
+ | DefKind :: Method
616
+ | DefKind :: Trait
617
+ | DefKind :: TyParam
618
+ | DefKind :: Variant => ( ) ,
619
+ }
620
+ }
480
621
481
622
/// Given the path segments of a `ItemKind::Use`, then we need
482
623
/// to update the visibility of the intermediate use so that it isn't linted
@@ -746,40 +887,21 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
746
887
return
747
888
}
748
889
749
- let module_did = ty:: DefIdTree :: parent (
890
+ let macro_module_def_id = ty:: DefIdTree :: parent (
750
891
self . tcx ,
751
892
self . tcx . hir ( ) . local_def_id ( md. hir_id )
752
893
) . unwrap ( ) ;
753
- let mut module_id = self . tcx . hir ( ) . as_local_hir_id ( module_did ) . unwrap ( ) ;
894
+ let mut module_id = self . tcx . hir ( ) . as_local_hir_id ( macro_module_def_id ) . unwrap ( ) ;
754
895
let level = if md. vis . node . is_pub ( ) { self . get ( module_id) } else { None } ;
755
- let level = self . update ( md. hir_id , level) ;
756
- if level . is_none ( ) {
896
+ let new_level = self . update ( md. hir_id , level) ;
897
+ if new_level . is_none ( ) {
757
898
return
758
899
}
759
900
760
901
loop {
761
- let module = if module_id == hir:: CRATE_HIR_ID {
762
- & self . tcx . hir ( ) . krate ( ) . module
763
- } else if let hir:: ItemKind :: Mod ( ref module) =
764
- self . tcx . hir ( ) . expect_item ( module_id) . node {
765
- module
766
- } else {
767
- unreachable ! ( )
768
- } ;
769
- for id in & module. item_ids {
770
- self . update ( id. id , level) ;
771
- }
772
- let def_id = self . tcx . hir ( ) . local_def_id ( module_id) ;
773
- if let Some ( exports) = self . tcx . module_exports ( def_id) {
774
- for export in exports. iter ( ) {
775
- if let Some ( hir_id) = self . tcx . hir ( ) . as_local_hir_id ( export. res . def_id ( ) ) {
776
- self . update ( hir_id, level) ;
777
- }
778
- }
779
- }
780
-
781
- if module_id == hir:: CRATE_HIR_ID {
782
- break
902
+ let changed_reachability = self . update_macro_reachable ( module_id, macro_module_def_id) ;
903
+ if changed_reachability || module_id == hir:: CRATE_HIR_ID {
904
+ break ;
783
905
}
784
906
module_id = self . tcx . hir ( ) . get_parent_node ( module_id) ;
785
907
}
@@ -826,7 +948,12 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
826
948
fn tcx ( & self ) -> TyCtxt < ' tcx > { self . ev . tcx }
827
949
fn visit_def_id ( & mut self , def_id : DefId , _kind : & str , _descr : & dyn fmt:: Display ) -> bool {
828
950
if let Some ( hir_id) = self . ev . tcx . hir ( ) . as_local_hir_id ( def_id) {
829
- self . ev . update ( hir_id, self . access_level ) ;
951
+ if let ( ( ty:: Visibility :: Public , ..) , _)
952
+ | ( _, Some ( AccessLevel :: ReachableFromImplTrait ) )
953
+ = ( def_id_visibility ( self . tcx ( ) , def_id) , self . access_level )
954
+ {
955
+ self . ev . update ( hir_id, self . access_level ) ;
956
+ }
830
957
}
831
958
false
832
959
}
@@ -1860,6 +1987,7 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, krate: CrateNum) -> &AccessLevels {
1860
1987
let mut visitor = EmbargoVisitor {
1861
1988
tcx,
1862
1989
access_levels : Default :: default ( ) ,
1990
+ macro_reachable : Default :: default ( ) ,
1863
1991
prev_level : Some ( AccessLevel :: Public ) ,
1864
1992
changed : false ,
1865
1993
} ;
0 commit comments