@@ -64,6 +64,7 @@ use rustc_hir::definitions::DisambiguatorState;
6464use rustc_hir:: { PrimTy , TraitCandidate , find_attr} ;
6565use rustc_index:: bit_set:: DenseBitSet ;
6666use rustc_metadata:: creader:: CStore ;
67+ use rustc_middle:: bug;
6768use rustc_middle:: metadata:: { AmbigModChild , ModChild , Reexport } ;
6869use rustc_middle:: middle:: privacy:: EffectiveVisibilities ;
6970use rustc_middle:: query:: Providers ;
@@ -448,6 +449,11 @@ enum ModuleOrUniformRoot<'ra> {
448449 /// Used only for resolving single-segment imports. The reason it exists is that import paths
449450 /// are always split into two parts, the first of which should be some kind of module.
450451 CurrentScope ,
452+
453+ /// Virtual module for the resolution of base names of namespaced crates,
454+ /// where the base name doesn't correspond to a module in the extern prelude.
455+ /// E.g. `my_api::utils` is in the prelude, but `my_api` is not.
456+ OpenModule ( Symbol ) ,
451457}
452458
453459#[ derive( Debug ) ]
@@ -1108,13 +1114,20 @@ impl<'ra> DeclData<'ra> {
11081114 }
11091115}
11101116
1117+ #[ derive( Debug ) ]
11111118struct ExternPreludeEntry < ' ra > {
11121119 /// Name declaration from an `extern crate` item.
11131120 /// The boolean flag is true is `item_decl` is non-redundant, happens either when
11141121 /// `flag_decl` is `None`, or when `extern crate` introducing `item_decl` used renaming.
11151122 item_decl : Option < ( Decl < ' ra > , Span , /* introduced by item */ bool ) > ,
11161123 /// Name declaration from an `--extern` flag, lazily populated on first use.
1117- flag_decl : Option < CacheCell < ( PendingDecl < ' ra > , /* finalized */ bool ) > > ,
1124+ flag_decl : Option <
1125+ CacheCell < (
1126+ PendingDecl < ' ra > ,
1127+ /* finalized */ bool ,
1128+ /* open flag (namespaced crate) */ bool ,
1129+ ) > ,
1130+ > ,
11181131}
11191132
11201133impl ExternPreludeEntry < ' _ > {
@@ -1125,7 +1138,14 @@ impl ExternPreludeEntry<'_> {
11251138 fn flag ( ) -> Self {
11261139 ExternPreludeEntry {
11271140 item_decl : None ,
1128- flag_decl : Some ( CacheCell :: new ( ( PendingDecl :: Pending , false ) ) ) ,
1141+ flag_decl : Some ( CacheCell :: new ( ( PendingDecl :: Pending , false , false ) ) ) ,
1142+ }
1143+ }
1144+
1145+ fn open_flag ( ) -> Self {
1146+ ExternPreludeEntry {
1147+ item_decl : None ,
1148+ flag_decl : Some ( CacheCell :: new ( ( PendingDecl :: Pending , false , true ) ) ) ,
11291149 }
11301150 }
11311151
@@ -1637,35 +1657,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
16371657 let mut invocation_parents = FxHashMap :: default ( ) ;
16381658 invocation_parents. insert ( LocalExpnId :: ROOT , InvocationParent :: ROOT ) ;
16391659
1640- let mut extern_prelude: FxIndexMap < _ , _ > = tcx
1641- . sess
1642- . opts
1643- . externs
1644- . iter ( )
1645- . filter_map ( |( name, entry) | {
1646- // Make sure `self`, `super`, `_` etc do not get into extern prelude.
1647- // FIXME: reject `--extern self` and similar in option parsing instead.
1648- if entry. add_prelude
1649- && let name = Symbol :: intern ( name)
1650- && name. can_be_raw ( )
1651- {
1652- let ident = IdentKey :: with_root_ctxt ( name) ;
1653- Some ( ( ident, ExternPreludeEntry :: flag ( ) ) )
1654- } else {
1655- None
1656- }
1657- } )
1658- . collect ( ) ;
1659-
1660- if !attr:: contains_name ( attrs, sym:: no_core) {
1661- let ident = IdentKey :: with_root_ctxt ( sym:: core) ;
1662- extern_prelude. insert ( ident, ExternPreludeEntry :: flag ( ) ) ;
1663- if !attr:: contains_name ( attrs, sym:: no_std) {
1664- let ident = IdentKey :: with_root_ctxt ( sym:: std) ;
1665- extern_prelude. insert ( ident, ExternPreludeEntry :: flag ( ) ) ;
1666- }
1667- }
1668-
1660+ let extern_prelude = build_extern_prelude ( tcx, attrs) ;
16691661 let registered_tools = tcx. registered_tools ( ( ) ) ;
16701662 let edition = tcx. sess . edition ( ) ;
16711663
@@ -2320,10 +2312,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
23202312 ) -> Option < Decl < ' ra > > {
23212313 let entry = self . extern_prelude . get ( & ident) ;
23222314 entry. and_then ( |entry| entry. flag_decl . as_ref ( ) ) . and_then ( |flag_decl| {
2323- let ( pending_decl, finalized) = flag_decl. get ( ) ;
2315+ let ( pending_decl, finalized, is_open ) = flag_decl. get ( ) ;
23242316 let decl = match pending_decl {
23252317 PendingDecl :: Ready ( decl) => {
2326- if finalize && !finalized {
2318+ if finalize && !finalized && !is_open {
23272319 self . cstore_mut ( ) . process_path_extern (
23282320 self . tcx ,
23292321 ident. name ,
@@ -2334,18 +2326,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
23342326 }
23352327 PendingDecl :: Pending => {
23362328 debug_assert ! ( !finalized) ;
2337- let crate_id = if finalize {
2338- self . cstore_mut ( ) . process_path_extern ( self . tcx , ident. name , orig_ident_span)
2329+ if is_open {
2330+ let res = Res :: OpenMod ( ident. name ) ;
2331+ Some ( self . arenas . new_pub_def_decl ( res, DUMMY_SP , LocalExpnId :: ROOT ) )
23392332 } else {
2340- self . cstore_mut ( ) . maybe_process_path_extern ( self . tcx , ident. name )
2341- } ;
2342- crate_id. map ( |crate_id| {
2343- let res = Res :: Def ( DefKind :: Mod , crate_id. as_def_id ( ) ) ;
2344- self . arenas . new_pub_def_decl ( res, DUMMY_SP , LocalExpnId :: ROOT )
2345- } )
2333+ let crate_id = if finalize {
2334+ self . cstore_mut ( ) . process_path_extern (
2335+ self . tcx ,
2336+ ident. name ,
2337+ orig_ident_span,
2338+ )
2339+ } else {
2340+ self . cstore_mut ( ) . maybe_process_path_extern ( self . tcx , ident. name )
2341+ } ;
2342+ crate_id. map ( |crate_id| {
2343+ let def_id = crate_id. as_def_id ( ) ;
2344+ let res = Res :: Def ( DefKind :: Mod , def_id) ;
2345+ self . arenas . new_pub_def_decl ( res, DUMMY_SP , LocalExpnId :: ROOT )
2346+ } )
2347+ }
23462348 }
23472349 } ;
2348- flag_decl. set ( ( PendingDecl :: Ready ( decl) , finalize || finalized) ) ;
2350+ flag_decl. set ( ( PendingDecl :: Ready ( decl) , finalize || finalized, is_open ) ) ;
23492351 decl. or_else ( || finalize. then_some ( self . dummy_decl ) )
23502352 } )
23512353 }
@@ -2387,7 +2389,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
23872389 PathResult :: Module ( ModuleOrUniformRoot :: ExternPrelude ) | PathResult :: Failed { .. } => {
23882390 None
23892391 }
2390- PathResult :: Module ( ..) | PathResult :: Indeterminate => unreachable ! ( ) ,
2392+ path_result @ ( PathResult :: Module ( ..) | PathResult :: Indeterminate ) => {
2393+ bug ! ( "got invalid path_result: {path_result:?}" )
2394+ }
23912395 }
23922396 }
23932397
@@ -2505,6 +2509,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
25052509 }
25062510}
25072511
2512+ fn build_extern_prelude < ' tcx , ' ra > (
2513+ tcx : TyCtxt < ' tcx > ,
2514+ attrs : & [ ast:: Attribute ] ,
2515+ ) -> FxIndexMap < IdentKey , ExternPreludeEntry < ' ra > > {
2516+ let mut extern_prelude: FxIndexMap < IdentKey , ExternPreludeEntry < ' ra > > = tcx
2517+ . sess
2518+ . opts
2519+ . externs
2520+ . iter ( )
2521+ . filter_map ( |( name, entry) | {
2522+ // Make sure `self`, `super`, `_` etc do not get into extern prelude.
2523+ // FIXME: reject `--extern self` and similar in option parsing instead.
2524+ if entry. add_prelude
2525+ && let sym = Symbol :: intern ( name)
2526+ && sym. can_be_raw ( )
2527+ {
2528+ Some ( ( IdentKey :: with_root_ctxt ( sym) , ExternPreludeEntry :: flag ( ) ) )
2529+ } else {
2530+ None
2531+ }
2532+ } )
2533+ . collect ( ) ;
2534+
2535+ // Add open base entries for namespaced crates whose base segment
2536+ // is missing from the prelude (e.g. `foo::bar` without `foo`).
2537+ // These are necessary in order to resolve the open modules, whereas
2538+ // the namespaced names are necessary in `extern_prelude` for actually
2539+ // resolving the namespaced crates.
2540+ let missing_open_bases: Vec < IdentKey > = extern_prelude
2541+ . keys ( )
2542+ . filter_map ( |ident| {
2543+ let ( base, _) = ident. name . as_str ( ) . split_once ( "::" ) ?;
2544+ let base_sym = Symbol :: intern ( base) ;
2545+ base_sym. can_be_raw ( ) . then ( || IdentKey :: with_root_ctxt ( base_sym) )
2546+ } )
2547+ . filter ( |base_ident| !extern_prelude. contains_key ( base_ident) )
2548+ . collect ( ) ;
2549+
2550+ extern_prelude. extend (
2551+ missing_open_bases. into_iter ( ) . map ( |ident| ( ident, ExternPreludeEntry :: open_flag ( ) ) ) ,
2552+ ) ;
2553+
2554+ // Inject `core` / `std` unless suppressed by attributes.
2555+ if !attr:: contains_name ( attrs, sym:: no_core) {
2556+ extern_prelude. insert ( IdentKey :: with_root_ctxt ( sym:: core) , ExternPreludeEntry :: flag ( ) ) ;
2557+
2558+ if !attr:: contains_name ( attrs, sym:: no_std) {
2559+ extern_prelude. insert ( IdentKey :: with_root_ctxt ( sym:: std) , ExternPreludeEntry :: flag ( ) ) ;
2560+ }
2561+ }
2562+
2563+ extern_prelude
2564+ }
2565+
25082566fn names_to_string ( names : impl Iterator < Item = Symbol > ) -> String {
25092567 let mut result = String :: new ( ) ;
25102568 for ( i, name) in names. enumerate ( ) . filter ( |( _, name) | * name != kw:: PathRoot ) {
0 commit comments