Skip to content

Commit c8d3cd9

Browse files
committed
fix: Allow public re-export of extern crate import
1 parent 6005446 commit c8d3cd9

File tree

2 files changed

+78
-2
lines changed

2 files changed

+78
-2
lines changed

crates/hir-def/src/nameres/collector.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use crate::{
4545
},
4646
path::{ImportAlias, ModPath, PathKind},
4747
per_ns::PerNs,
48+
src::HasChildSource,
4849
tt,
4950
visibility::{RawVisibility, Visibility},
5051
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantLoc,
@@ -1058,8 +1059,37 @@ impl DefCollector<'_> {
10581059
vis: Visibility,
10591060
def_import_type: Option<ImportType>,
10601061
) -> bool {
1061-
if let Some((_, v, _)) = defs.types.as_mut() {
1062-
*v = v.min(vis, &self.def_map).unwrap_or(vis);
1062+
// `extern crate crate_name` things can be re-exported as `pub use crate_name`.
1063+
// But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
1064+
// or `pub use ::crate_name`.
1065+
//
1066+
// This has been historically allowed, but may be not allowed in future
1067+
// https://github.com/rust-lang/rust/issues/127909
1068+
if let Some((_, v, it)) = defs.types.as_mut() {
1069+
let is_extern_crate_reimport_without_prefix = || {
1070+
let Some(ImportOrExternCrate::ExternCrate(_)) = it else {
1071+
return false;
1072+
};
1073+
let Some(ImportType::Import(id)) = def_import_type else {
1074+
return false;
1075+
};
1076+
let source = id.import.child_source(self.db);
1077+
let Some(use_tree_src) = source.value.get(id.idx) else {
1078+
return false;
1079+
};
1080+
use_tree_src.top_use_tree().path().and_then(|p| p.first_segment()).is_some_and(
1081+
|s| {
1082+
s.crate_token().is_none()
1083+
&& s.self_token().is_none()
1084+
&& s.coloncolon_token().is_none()
1085+
},
1086+
)
1087+
};
1088+
if is_extern_crate_reimport_without_prefix() {
1089+
*v = vis;
1090+
} else {
1091+
*v = v.min(vis, &self.def_map).unwrap_or(vis);
1092+
}
10631093
}
10641094
if let Some((_, v, _)) = defs.values.as_mut() {
10651095
*v = v.min(vis, &self.def_map).unwrap_or(vis);

crates/hir-def/src/nameres/tests.rs

+46
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,52 @@ pub struct Arc;
385385
);
386386
}
387387

388+
#[test]
389+
fn extern_crate_reexport() {
390+
check(
391+
r#"
392+
//- /main.rs crate:main deps:importer
393+
use importer::*;
394+
use importer::extern_crate1::exported::*;
395+
use importer::allowed_reexport::*;
396+
use importer::extern_crate2::*;
397+
use importer::not_allowed_reexport1;
398+
use importer::not_allowed_reexport2;
399+
400+
//- /importer.rs crate:importer deps:extern_crate1,extern_crate2
401+
extern crate extern_crate1;
402+
extern crate extern_crate2;
403+
404+
pub use extern_crate1;
405+
pub use extern_crate1 as allowed_reexport;
406+
407+
pub use ::extern_crate;
408+
pub use self::extern_crate as not_allowed_reexport1;
409+
pub use crate::extern_crate as not_allowed_reexport2;
410+
411+
//- /extern_crate1.rs crate:extern_crate1
412+
pub mod exported {
413+
pub struct PublicItem;
414+
struct PrivateItem;
415+
}
416+
417+
pub struct Exported;
418+
419+
//- /extern_crate2.rs crate:extern_crate2
420+
pub struct NotExported;
421+
"#,
422+
expect![[r#"
423+
crate
424+
Exported: t v
425+
PublicItem: t v
426+
allowed_reexport: t
427+
exported: t
428+
not_allowed_reexport1: _
429+
not_allowed_reexport2: _
430+
"#]],
431+
);
432+
}
433+
388434
#[test]
389435
fn extern_crate_rename_2015_edition() {
390436
check(

0 commit comments

Comments
 (0)