@@ -61,6 +61,7 @@ use rustc_hir::definitions::DisambiguatorState;
6161use rustc_hir:: { PrimTy , TraitCandidate , find_attr} ;
6262use rustc_index:: bit_set:: DenseBitSet ;
6363use rustc_metadata:: creader:: CStore ;
64+ use rustc_middle:: bug;
6465use rustc_middle:: metadata:: { AmbigModChild , ModChild , Reexport } ;
6566use rustc_middle:: middle:: privacy:: EffectiveVisibilities ;
6667use rustc_middle:: query:: Providers ;
@@ -445,6 +446,11 @@ enum ModuleOrUniformRoot<'ra> {
445446 /// Used only for resolving single-segment imports. The reason it exists is that import paths
446447 /// are always split into two parts, the first of which should be some kind of module.
447448 CurrentScope ,
449+
450+ /// Virtual module for the resolution of base names of namespaced crates,
451+ /// where the base name doesn't correspond to a module in the extern prelude.
452+ /// E.g. `my_api::utils` is in the prelude, but `my_api` is not.
453+ OpenModule ( Symbol ) ,
448454}
449455
450456#[ derive( Debug ) ]
@@ -1105,13 +1111,20 @@ impl<'ra> DeclData<'ra> {
11051111 }
11061112}
11071113
1114+ #[ derive( Debug ) ]
11081115struct ExternPreludeEntry < ' ra > {
11091116 /// Name declaration from an `extern crate` item.
11101117 /// The boolean flag is true is `item_decl` is non-redundant, happens either when
11111118 /// `flag_decl` is `None`, or when `extern crate` introducing `item_decl` used renaming.
11121119 item_decl : Option < ( Decl < ' ra > , Span , /* introduced by item */ bool ) > ,
11131120 /// Name declaration from an `--extern` flag, lazily populated on first use.
1114- flag_decl : Option < CacheCell < ( PendingDecl < ' ra > , /* finalized */ bool ) > > ,
1121+ flag_decl : Option <
1122+ CacheCell < (
1123+ PendingDecl < ' ra > ,
1124+ /* finalized */ bool ,
1125+ /* open flag (namespaced crate) */ bool ,
1126+ ) > ,
1127+ > ,
11151128}
11161129
11171130impl ExternPreludeEntry < ' _ > {
@@ -1122,7 +1135,14 @@ impl ExternPreludeEntry<'_> {
11221135 fn flag ( ) -> Self {
11231136 ExternPreludeEntry {
11241137 item_decl : None ,
1125- flag_decl : Some ( CacheCell :: new ( ( PendingDecl :: Pending , false ) ) ) ,
1138+ flag_decl : Some ( CacheCell :: new ( ( PendingDecl :: Pending , false , false ) ) ) ,
1139+ }
1140+ }
1141+
1142+ fn open_flag ( ) -> Self {
1143+ ExternPreludeEntry {
1144+ item_decl : None ,
1145+ flag_decl : Some ( CacheCell :: new ( ( PendingDecl :: Pending , false , true ) ) ) ,
11261146 }
11271147 }
11281148
@@ -1643,35 +1663,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
16431663 let mut invocation_parents = FxHashMap :: default ( ) ;
16441664 invocation_parents. insert ( LocalExpnId :: ROOT , InvocationParent :: ROOT ) ;
16451665
1646- let mut extern_prelude: FxIndexMap < _ , _ > = tcx
1647- . sess
1648- . opts
1649- . externs
1650- . iter ( )
1651- . filter_map ( |( name, entry) | {
1652- // Make sure `self`, `super`, `_` etc do not get into extern prelude.
1653- // FIXME: reject `--extern self` and similar in option parsing instead.
1654- if entry. add_prelude
1655- && let name = Symbol :: intern ( name)
1656- && name. can_be_raw ( )
1657- {
1658- let ident = IdentKey :: with_root_ctxt ( name) ;
1659- Some ( ( ident, ExternPreludeEntry :: flag ( ) ) )
1660- } else {
1661- None
1662- }
1663- } )
1664- . collect ( ) ;
1665-
1666- if !attr:: contains_name ( attrs, sym:: no_core) {
1667- let ident = IdentKey :: with_root_ctxt ( sym:: core) ;
1668- extern_prelude. insert ( ident, ExternPreludeEntry :: flag ( ) ) ;
1669- if !attr:: contains_name ( attrs, sym:: no_std) {
1670- let ident = IdentKey :: with_root_ctxt ( sym:: std) ;
1671- extern_prelude. insert ( ident, ExternPreludeEntry :: flag ( ) ) ;
1672- }
1673- }
1674-
1666+ let extern_prelude = build_extern_prelude ( tcx, attrs) ;
16751667 let registered_tools = tcx. registered_tools ( ( ) ) ;
16761668 let edition = tcx. sess . edition ( ) ;
16771669
@@ -2326,10 +2318,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
23262318 ) -> Option < Decl < ' ra > > {
23272319 let entry = self . extern_prelude . get ( & ident) ;
23282320 entry. and_then ( |entry| entry. flag_decl . as_ref ( ) ) . and_then ( |flag_decl| {
2329- let ( pending_decl, finalized) = flag_decl. get ( ) ;
2321+ let ( pending_decl, finalized, is_open ) = flag_decl. get ( ) ;
23302322 let decl = match pending_decl {
23312323 PendingDecl :: Ready ( decl) => {
2332- if finalize && !finalized {
2324+ if finalize && !finalized && !is_open {
23332325 self . cstore_mut ( ) . process_path_extern (
23342326 self . tcx ,
23352327 ident. name ,
@@ -2340,18 +2332,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
23402332 }
23412333 PendingDecl :: Pending => {
23422334 debug_assert ! ( !finalized) ;
2343- let crate_id = if finalize {
2344- self . cstore_mut ( ) . process_path_extern ( self . tcx , ident. name , orig_ident_span)
2335+ if is_open {
2336+ let res = Res :: OpenMod ( ident. name ) ;
2337+ Some ( self . arenas . new_pub_def_decl ( res, DUMMY_SP , LocalExpnId :: ROOT ) )
23452338 } else {
2346- self . cstore_mut ( ) . maybe_process_path_extern ( self . tcx , ident. name )
2347- } ;
2348- crate_id. map ( |crate_id| {
2349- let res = Res :: Def ( DefKind :: Mod , crate_id. as_def_id ( ) ) ;
2350- self . arenas . new_pub_def_decl ( res, DUMMY_SP , LocalExpnId :: ROOT )
2351- } )
2339+ let crate_id = if finalize {
2340+ self . cstore_mut ( ) . process_path_extern (
2341+ self . tcx ,
2342+ ident. name ,
2343+ orig_ident_span,
2344+ )
2345+ } else {
2346+ self . cstore_mut ( ) . maybe_process_path_extern ( self . tcx , ident. name )
2347+ } ;
2348+ crate_id. map ( |crate_id| {
2349+ let def_id = crate_id. as_def_id ( ) ;
2350+ let res = Res :: Def ( DefKind :: Mod , def_id) ;
2351+ self . arenas . new_pub_def_decl ( res, DUMMY_SP , LocalExpnId :: ROOT )
2352+ } )
2353+ }
23522354 }
23532355 } ;
2354- flag_decl. set ( ( PendingDecl :: Ready ( decl) , finalize || finalized) ) ;
2356+ flag_decl. set ( ( PendingDecl :: Ready ( decl) , finalize || finalized, is_open ) ) ;
23552357 decl. or_else ( || finalize. then_some ( self . dummy_decl ) )
23562358 } )
23572359 }
@@ -2393,7 +2395,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
23932395 PathResult :: Module ( ModuleOrUniformRoot :: ExternPrelude ) | PathResult :: Failed { .. } => {
23942396 None
23952397 }
2396- PathResult :: Module ( ..) | PathResult :: Indeterminate => unreachable ! ( ) ,
2398+ path_result @ ( PathResult :: Module ( ..) | PathResult :: Indeterminate ) => {
2399+ bug ! ( "got invalid path_result: {path_result:?}" )
2400+ }
23972401 }
23982402 }
23992403
@@ -2511,6 +2515,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
25112515 }
25122516}
25132517
2518+ fn build_extern_prelude < ' tcx , ' ra > (
2519+ tcx : TyCtxt < ' tcx > ,
2520+ attrs : & [ ast:: Attribute ] ,
2521+ ) -> FxIndexMap < IdentKey , ExternPreludeEntry < ' ra > > {
2522+ let mut extern_prelude: FxIndexMap < IdentKey , ExternPreludeEntry < ' ra > > = tcx
2523+ . sess
2524+ . opts
2525+ . externs
2526+ . iter ( )
2527+ . filter_map ( |( name, entry) | {
2528+ // Make sure `self`, `super`, `_` etc do not get into extern prelude.
2529+ // FIXME: reject `--extern self` and similar in option parsing instead.
2530+ if entry. add_prelude
2531+ && let sym = Symbol :: intern ( name)
2532+ && sym. can_be_raw ( )
2533+ {
2534+ Some ( ( IdentKey :: with_root_ctxt ( sym) , ExternPreludeEntry :: flag ( ) ) )
2535+ } else {
2536+ None
2537+ }
2538+ } )
2539+ . collect ( ) ;
2540+
2541+ // Add open base entries for namespaced crates whose base segment
2542+ // is missing from the prelude (e.g. `foo::bar` without `foo`).
2543+ // These are necessary in order to resolve the open modules, whereas
2544+ // the namespaced names are necessary in `extern_prelude` for actually
2545+ // resolving the namespaced crates.
2546+ let missing_open_bases: Vec < IdentKey > = extern_prelude
2547+ . keys ( )
2548+ . filter_map ( |ident| {
2549+ let ( base, _) = ident. name . as_str ( ) . split_once ( "::" ) ?;
2550+ let base_sym = Symbol :: intern ( base) ;
2551+ base_sym. can_be_raw ( ) . then ( || IdentKey :: with_root_ctxt ( base_sym) )
2552+ } )
2553+ . filter ( |base_ident| !extern_prelude. contains_key ( base_ident) )
2554+ . collect ( ) ;
2555+
2556+ extern_prelude. extend (
2557+ missing_open_bases. into_iter ( ) . map ( |ident| ( ident, ExternPreludeEntry :: open_flag ( ) ) ) ,
2558+ ) ;
2559+
2560+ // Inject `core` / `std` unless suppressed by attributes.
2561+ if !attr:: contains_name ( attrs, sym:: no_core) {
2562+ extern_prelude. insert ( IdentKey :: with_root_ctxt ( sym:: core) , ExternPreludeEntry :: flag ( ) ) ;
2563+
2564+ if !attr:: contains_name ( attrs, sym:: no_std) {
2565+ extern_prelude. insert ( IdentKey :: with_root_ctxt ( sym:: std) , ExternPreludeEntry :: flag ( ) ) ;
2566+ }
2567+ }
2568+
2569+ extern_prelude
2570+ }
2571+
25142572fn names_to_string ( names : impl Iterator < Item = Symbol > ) -> String {
25152573 let mut result = String :: new ( ) ;
25162574 for ( i, name) in names. enumerate ( ) . filter ( |( _, name) | * name != kw:: PathRoot ) {
0 commit comments