@@ -9,7 +9,9 @@ use rustc_attr_parsing::AttributeParser;
99use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
1010use rustc_data_structures:: intern:: Interned ;
1111use rustc_errors:: codes:: * ;
12- use rustc_errors:: { Applicability , Diagnostic , MultiSpan , pluralize, struct_span_code_err} ;
12+ use rustc_errors:: {
13+ Applicability , BufferedEarlyLint , Diagnostic , MultiSpan , pluralize, struct_span_code_err,
14+ } ;
1315use rustc_hir:: Attribute ;
1416use rustc_hir:: attrs:: AttributeKind ;
1517use rustc_hir:: attrs:: diagnostic:: { CustomDiagnostic , Directive , FormatArgs } ;
@@ -19,6 +21,7 @@ use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport};
1921use rustc_middle:: span_bug;
2022use rustc_middle:: ty:: { TyCtxt , Visibility } ;
2123use rustc_session:: errors:: feature_err;
24+ use rustc_session:: lint:: LintId ;
2225use rustc_session:: lint:: builtin:: {
2326 AMBIGUOUS_GLOB_REEXPORTS , EXPORTED_PRIVATE_DEPENDENCIES , HIDDEN_GLOB_REEXPORTS ,
2427 PUB_USE_OF_PRIVATE_EXTERN_CRATE , REDUNDANT_IMPORTS , UNUSED_IMPORTS ,
@@ -273,6 +276,8 @@ impl<'ra> ImportData<'ra> {
273276 vis : self . vis ,
274277 nearest_parent_mod : self . parent_scope . module . nearest_parent_mod ( ) . expect_local ( ) ,
275278 is_single : matches ! ( self . kind, ImportKind :: Single { .. } ) ,
279+ priv_macro_use : matches ! ( self . kind, ImportKind :: MacroUse { warn_private: true } ) ,
280+ span : self . span ,
276281 }
277282 }
278283}
@@ -381,22 +386,31 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
381386 ) -> Visibility {
382387 assert ! ( import. vis. is_accessible_from( import. nearest_parent_mod, self . tcx) ) ;
383388 let decl_vis = if min { decl. min_vis ( ) } else { decl. vis ( ) } ;
384- if decl_vis. partial_cmp ( import. vis , self . tcx ) == Some ( Ordering :: Less )
389+ let ord = decl_vis. partial_cmp ( import. vis , self . tcx ) ;
390+ let extern_crate_hack = pub_use_of_private_extern_crate_hack ( import, decl) . is_some ( ) ;
391+ if ord == Some ( Ordering :: Less )
385392 && decl_vis. is_accessible_from ( import. nearest_parent_mod , self . tcx )
386- && pub_use_of_private_extern_crate_hack ( import , decl ) . is_none ( )
393+ && !extern_crate_hack
387394 {
388395 // Imported declaration is less visible than the import, but is still visible
389396 // from the current module, use the declaration's visibility.
390397 decl_vis. expect_local ( )
391398 } else {
392399 // Good case - imported declaration is more visible than the import, or the same,
393400 // use the import's visibility.
401+ //
394402 // Bad case - imported declaration is too private for the current module.
395403 // It doesn't matter what visibility we choose here (except in the `PRIVATE_MACRO_USE`
396- // and `PUB_USE_OF_PRIVATE_EXTERN_CRATE` cases), because either some error will be
397- // reported, or the import declaration will be thrown away (unfortunately cannot use
398- // delayed bug here for this reason).
404+ // and `PUB_USE_OF_PRIVATE_EXTERN_CRATE` cases), because an error will be reported.
399405 // Use import visibility to keep the all declaration visibilities in a module ordered.
406+ if !min
407+ && matches ! ( ord, None | Some ( Ordering :: Less ) )
408+ && !extern_crate_hack
409+ && !import. priv_macro_use
410+ {
411+ let msg = format ! ( "cannot extend visibility from {decl_vis:?} to {:?}" , import. vis) ;
412+ self . dcx ( ) . span_delayed_bug ( import. span , msg) ;
413+ }
400414 import. vis
401415 }
402416 }
@@ -784,6 +798,29 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
784798 let resolution = resolution. borrow ( ) ;
785799 let Some ( binding) = resolution. best_decl ( ) else { continue } ;
786800
801+ // Report "cannot reexport" errors for exotic cases involving macros 2.0
802+ // privacy bending or invariant-breaking code under deprecation lints.
803+ for decl in [ resolution. non_glob_decl , resolution. glob_decl ] {
804+ if let Some ( decl) = decl
805+ && let DeclKind :: Import { source_decl, import } = decl. kind
806+ {
807+ // The source entity is too private to be reexported
808+ // with the given import declaration's visibility.
809+ let ord = source_decl. vis ( ) . partial_cmp ( decl. vis ( ) , self . tcx ) ;
810+ if matches ! ( ord, None | Some ( Ordering :: Less ) ) {
811+ let ident = match import. kind {
812+ ImportKind :: Single { source, .. } => source,
813+ _ => key. ident . orig ( resolution. orig_ident_span ) ,
814+ } ;
815+ if let Some ( lint) =
816+ self . report_cannot_reexport ( import, source_decl, ident, key. ns )
817+ {
818+ self . lint_buffer . add_early_lint ( lint) ;
819+ }
820+ }
821+ }
822+ }
823+
787824 if let DeclKind :: Import { import, .. } = binding. kind
788825 && let Some ( amb_binding) = binding. ambiguity . get ( )
789826 && binding. res ( ) != Res :: Err
@@ -1515,76 +1552,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
15151552
15161553 let mut reexport_error = None ;
15171554 let mut any_successful_reexport = false ;
1518- let mut crate_private_reexport = false ;
15191555 self . per_ns ( |this, ns| {
1520- let Some ( binding) = bindings[ ns] . get ( ) . decl ( ) . map ( |b| b . import_source ( ) ) else {
1556+ let Some ( binding) = bindings[ ns] . get ( ) . decl ( ) else {
15211557 return ;
15221558 } ;
15231559
15241560 if import. vis . greater_than ( binding. vis ( ) , this. tcx ) {
1525- reexport_error = Some ( ( ns, binding) ) ;
1526- if let Visibility :: Restricted ( binding_def_id) = binding. vis ( )
1527- && binding_def_id. is_top_level_module ( )
1528- {
1529- crate_private_reexport = true ;
1530- }
1561+ // In isolation, a declaration like this is not an error, but if *all* 1-3
1562+ // declarations introduced by the import are more private than the import item's
1563+ // nominal visibility, then it's an error.
1564+ reexport_error = Some ( ( ns, binding. import_source ( ) ) ) ;
15311565 } else {
15321566 any_successful_reexport = true ;
15331567 }
15341568 } ) ;
15351569
1536- // All namespaces must be re-exported with extra visibility for an error to occur.
15371570 if !any_successful_reexport {
15381571 let ( ns, binding) = reexport_error. unwrap ( ) ;
1539- if let Some ( extern_crate_id) =
1540- pub_use_of_private_extern_crate_hack ( import. summary ( ) , binding)
1541- {
1542- let extern_crate_sp = self . tcx . source_span ( self . local_def_id ( extern_crate_id) ) ;
1543- self . lint_buffer . buffer_lint (
1544- PUB_USE_OF_PRIVATE_EXTERN_CRATE ,
1545- import_id,
1546- import. span ,
1547- crate :: errors:: PrivateExternCrateReexport {
1548- ident,
1549- sugg : extern_crate_sp. shrink_to_lo ( ) ,
1550- } ,
1551- ) ;
1552- } else if ns == TypeNS {
1553- let err = if crate_private_reexport {
1554- self . dcx ( )
1555- . create_err ( CannotBeReexportedCratePublicNS { span : import. span , ident } )
1556- } else {
1557- self . dcx ( ) . create_err ( CannotBeReexportedPrivateNS { span : import. span , ident } )
1558- } ;
1559- err. emit ( ) ;
1560- } else {
1561- let mut err = if crate_private_reexport {
1562- self . dcx ( )
1563- . create_err ( CannotBeReexportedCratePublic { span : import. span , ident } )
1564- } else {
1565- self . dcx ( ) . create_err ( CannotBeReexportedPrivate { span : import. span , ident } )
1566- } ;
1567-
1568- match binding. kind {
1569- DeclKind :: Def ( Res :: Def ( DefKind :: Macro ( _) , def_id) )
1570- // exclude decl_macro
1571- if self . get_macro_by_def_id ( def_id) . macro_rules =>
1572- {
1573- err. subdiagnostic ( ConsiderAddingMacroExport {
1574- span : binding. span ,
1575- } ) ;
1576- err. subdiagnostic ( ConsiderMarkingAsPubCrate {
1577- vis_span : import. vis_span ,
1578- } ) ;
1579- }
1580- _ => {
1581- err. subdiagnostic ( ConsiderMarkingAsPub {
1582- span : import. span ,
1583- ident,
1584- } ) ;
1585- }
1586- }
1587- err. emit ( ) ;
1572+ if let Some ( lint) = self . report_cannot_reexport ( import, binding, ident, ns) {
1573+ self . lint_buffer . add_early_lint ( lint) ;
15881574 }
15891575 }
15901576
@@ -1613,6 +1599,61 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
16131599 None
16141600 }
16151601
1602+ fn report_cannot_reexport (
1603+ & self ,
1604+ import : Import < ' ra > ,
1605+ decl : Decl < ' ra > ,
1606+ ident : Ident ,
1607+ ns : Namespace ,
1608+ ) -> Option < BufferedEarlyLint > {
1609+ let crate_private_reexport = match decl. vis ( ) {
1610+ Visibility :: Restricted ( def_id) if def_id. is_top_level_module ( ) => true ,
1611+ _ => false ,
1612+ } ;
1613+
1614+ if let Some ( extern_crate_id) = pub_use_of_private_extern_crate_hack ( import. summary ( ) , decl)
1615+ {
1616+ let ImportKind :: Single { id, .. } = import. kind else { unreachable ! ( ) } ;
1617+ let sugg = self . tcx . source_span ( self . local_def_id ( extern_crate_id) ) . shrink_to_lo ( ) ;
1618+ let diagnostic = crate :: errors:: PrivateExternCrateReexport { ident, sugg } ;
1619+ return Some ( BufferedEarlyLint {
1620+ lint_id : LintId :: of ( PUB_USE_OF_PRIVATE_EXTERN_CRATE ) ,
1621+ node_id : id,
1622+ span : Some ( import. span . into ( ) ) ,
1623+ diagnostic : diagnostic. into ( ) ,
1624+ } ) ;
1625+ } else if ns == TypeNS {
1626+ let err = if crate_private_reexport {
1627+ self . dcx ( ) . create_err ( CannotBeReexportedCratePublicNS { span : import. span , ident } )
1628+ } else {
1629+ self . dcx ( ) . create_err ( CannotBeReexportedPrivateNS { span : import. span , ident } )
1630+ } ;
1631+ err. emit ( ) ;
1632+ } else {
1633+ let mut err = if crate_private_reexport {
1634+ self . dcx ( ) . create_err ( CannotBeReexportedCratePublic { span : import. span , ident } )
1635+ } else {
1636+ self . dcx ( ) . create_err ( CannotBeReexportedPrivate { span : import. span , ident } )
1637+ } ;
1638+
1639+ match decl. kind {
1640+ // exclude decl_macro
1641+ DeclKind :: Def ( Res :: Def ( DefKind :: Macro ( _) , def_id) )
1642+ if self . get_macro_by_def_id ( def_id) . macro_rules =>
1643+ {
1644+ err. subdiagnostic ( ConsiderAddingMacroExport { span : decl. span } ) ;
1645+ err. subdiagnostic ( ConsiderMarkingAsPubCrate { vis_span : import. vis_span } ) ;
1646+ }
1647+ _ => {
1648+ err. subdiagnostic ( ConsiderMarkingAsPub { span : import. span , ident } ) ;
1649+ }
1650+ }
1651+ err. emit ( ) ;
1652+ }
1653+
1654+ None
1655+ }
1656+
16161657 pub ( crate ) fn check_for_redundant_imports ( & mut self , import : Import < ' ra > ) -> bool {
16171658 // This function is only called for single imports.
16181659 let ImportKind :: Single { source, target, ref decls, id, .. } = import. kind else {
0 commit comments