Skip to content
1 change: 1 addition & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ Guillaume Gomez <guillaume1.gomez@gmail.com>
Guillaume Gomez <guillaume1.gomez@gmail.com> ggomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <guillaume.gomez@huawei.com>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <contact@guillaume-gomez.fr>
gnzlbg <gonzalobg88@gmail.com> <gnzlbg@users.noreply.github.com>
hamidreza kalbasi <hamidrezakalbasi@protonmail.com>
Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
Expand Down
19 changes: 16 additions & 3 deletions compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,13 @@ pub enum Res<Id = hir::HirId> {
/// **Belongs to the type namespace.**
ToolMod,

/// The resolution for an open module in a namespaced crate. E.g. `my_api`
/// in the namespaced crate `my_api::utils` when `my_api` isn't part of the
/// extern prelude.
///
/// **Belongs to the type namespace.**
OpenMod(Symbol),

// Macro namespace
/// An attribute that is *not* implemented via macro.
/// E.g., `#[inline]` and `#[rustfmt::skip]`, which are essentially directives,
Expand Down Expand Up @@ -838,6 +845,7 @@ impl<Id> Res<Id> {
| Res::SelfTyAlias { .. }
| Res::SelfCtor(..)
| Res::ToolMod
| Res::OpenMod(..)
| Res::NonMacroAttr(..)
| Res::Err => None,
}
Expand Down Expand Up @@ -869,6 +877,7 @@ impl<Id> Res<Id> {
Res::Local(..) => "local variable",
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => "self type",
Res::ToolMod => "tool module",
Res::OpenMod(..) => "namespaced crate",
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
Res::Err => "unresolved item",
}
Expand All @@ -895,6 +904,7 @@ impl<Id> Res<Id> {
Res::SelfTyAlias { alias_to, is_trait_impl }
}
Res::ToolMod => Res::ToolMod,
Res::OpenMod(sym) => Res::OpenMod(sym),
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
}
Expand All @@ -911,6 +921,7 @@ impl<Id> Res<Id> {
Res::SelfTyAlias { alias_to, is_trait_impl }
}
Res::ToolMod => Res::ToolMod,
Res::OpenMod(sym) => Res::OpenMod(sym),
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
})
Expand All @@ -936,9 +947,11 @@ impl<Id> Res<Id> {
pub fn ns(&self) -> Option<Namespace> {
match self {
Res::Def(kind, ..) => kind.ns(),
Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::ToolMod => {
Some(Namespace::TypeNS)
}
Res::PrimTy(..)
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. }
| Res::ToolMod
| Res::OpenMod(..) => Some(Namespace::TypeNS),
Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
Res::Err => None,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2830,6 +2830,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
| Res::SelfCtor(_)
| Res::Local(_)
| Res::ToolMod
| Res::OpenMod(..)
| Res::NonMacroAttr(_)
| Res::Err) => Const::new_error_with_message(
tcx,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
Res::Def(_, def_id) => self.check_def_id(def_id),
Res::SelfTyParam { trait_: t } => self.check_def_id(t),
Res::SelfTyAlias { alias_to: i, .. } => self.check_def_id(i),
Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {}
Res::ToolMod | Res::NonMacroAttr(..) | Res::OpenMod(..) | Res::Err => {}
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. }
| Res::SelfCtor(..)
| Res::OpenMod(..)
| Res::Err => bug!("unexpected resolution: {:?}", res),
}
}
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1740,8 +1740,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Res::Def(DefKind::Macro(kinds), _) => {
format!("{} {}", kinds.article(), kinds.descr())
}
Res::ToolMod => {
// Don't confuse the user with tool modules.
Res::ToolMod | Res::OpenMod(..) => {
// Don't confuse the user with tool modules or open modules.
continue;
}
Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
Expand Down Expand Up @@ -1978,7 +1978,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let (built_in, from) = match scope {
Scope::StdLibPrelude | Scope::MacroUsePrelude => ("", " from prelude"),
Scope::ExternPreludeFlags
if self.tcx.sess.opts.externs.get(ident.as_str()).is_some() =>
if self.tcx.sess.opts.externs.get(ident.as_str()).is_some()
|| matches!(res, Res::OpenMod(..)) =>
{
("", " passed with `--extern`")
}
Expand Down
16 changes: 13 additions & 3 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingKey, CmResolver, Decl, DeclKind,
Determinacy, Finalize, IdentKey, ImportKind, LateDecl, Module, ModuleKind, ModuleOrUniformRoot,
ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet,
Segment, Stage, Used, errors,
Segment, Stage, Symbol, Used, errors,
};

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -386,7 +386,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}

/// Resolve an identifier in the specified set of scopes.
#[instrument(level = "debug", skip(self))]
pub(crate) fn resolve_ident_in_scope_set<'r>(
self: CmResolver<'r, 'ra, 'tcx>,
orig_ident: Ident,
Expand Down Expand Up @@ -976,6 +975,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ignore_import,
)
}
ModuleOrUniformRoot::OpenModule(sym) => {
let open_ns_name = format!("{}::{}", sym.as_str(), ident.name);
let ns_ident = IdentKey::with_root_ctxt(Symbol::intern(&open_ns_name));
match self.extern_prelude_get_flag(ns_ident, ident.span, finalize.is_some()) {
Some(decl) => Ok(decl),
None => Err(Determinacy::Determined),
}
}
ModuleOrUniformRoot::ModuleAndExternPrelude(module) => self.resolve_ident_in_scope_set(
ident,
ScopeSet::ModuleAndExternPrelude(ns, module),
Expand Down Expand Up @@ -1962,7 +1969,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}

let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
if let Some(def_id) = binding.res().module_like_def_id() {
if let Res::OpenMod(sym) = binding.res() {
module = Some(ModuleOrUniformRoot::OpenModule(sym));
record_segment_res(self.reborrow(), finalize, res, id);
} else if let Some(def_id) = binding.res().module_like_def_id() {
if self.mods_with_parse_errors.contains(&def_id) {
module_had_parse_errors = true;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type Res = def::Res<NodeId>;

/// A potential import declaration in the process of being planted into a module.
/// Also used for lazily planting names from `--extern` flags to extern prelude.
#[derive(Clone, Copy, Default, PartialEq)]
#[derive(Clone, Copy, Default, PartialEq, Debug)]
pub(crate) enum PendingDecl<'ra> {
Ready(Option<Decl<'ra>>),
#[default]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3381,7 +3381,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
&& def_id.is_local()
&& let Some(local_def_id) = def_id.as_local()
&& let Some(struct_generics) = self.r.struct_generics.get(&local_def_id)
&& let target_param = &struct_generics.params[idx]
&& let Some(target_param) = &struct_generics.params.get(idx)
&& let GenericParamKind::Const { ty, .. } = &target_param.kind
&& let TyKind::Path(_, path) = &ty.kind
{
Expand Down
144 changes: 101 additions & 43 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ use rustc_hir::definitions::DisambiguatorState;
use rustc_hir::{PrimTy, TraitCandidate, find_attr};
use rustc_index::bit_set::DenseBitSet;
use rustc_metadata::creader::CStore;
use rustc_middle::bug;
use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport};
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::query::Providers;
Expand Down Expand Up @@ -445,6 +446,11 @@ enum ModuleOrUniformRoot<'ra> {
/// Used only for resolving single-segment imports. The reason it exists is that import paths
/// are always split into two parts, the first of which should be some kind of module.
CurrentScope,

/// Virtual module for the resolution of base names of namespaced crates,
/// where the base name doesn't correspond to a module in the extern prelude.
/// E.g. `my_api::utils` is in the prelude, but `my_api` is not.
OpenModule(Symbol),
}

#[derive(Debug)]
Expand Down Expand Up @@ -1105,13 +1111,20 @@ impl<'ra> DeclData<'ra> {
}
}

#[derive(Debug)]
struct ExternPreludeEntry<'ra> {
/// Name declaration from an `extern crate` item.
/// The boolean flag is true is `item_decl` is non-redundant, happens either when
/// `flag_decl` is `None`, or when `extern crate` introducing `item_decl` used renaming.
item_decl: Option<(Decl<'ra>, Span, /* introduced by item */ bool)>,
/// Name declaration from an `--extern` flag, lazily populated on first use.
flag_decl: Option<CacheCell<(PendingDecl<'ra>, /* finalized */ bool)>>,
flag_decl: Option<
CacheCell<(
PendingDecl<'ra>,
/* finalized */ bool,
/* open flag (namespaced crate) */ bool,
)>,
>,
}

impl ExternPreludeEntry<'_> {
Expand All @@ -1122,7 +1135,14 @@ impl ExternPreludeEntry<'_> {
fn flag() -> Self {
ExternPreludeEntry {
item_decl: None,
flag_decl: Some(CacheCell::new((PendingDecl::Pending, false))),
flag_decl: Some(CacheCell::new((PendingDecl::Pending, false, false))),
}
}

fn open_flag() -> Self {
ExternPreludeEntry {
item_decl: None,
flag_decl: Some(CacheCell::new((PendingDecl::Pending, false, true))),
}
}

Expand Down Expand Up @@ -1643,35 +1663,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let mut invocation_parents = FxHashMap::default();
invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT);

let mut extern_prelude: FxIndexMap<_, _> = tcx
.sess
.opts
.externs
.iter()
.filter_map(|(name, entry)| {
// Make sure `self`, `super`, `_` etc do not get into extern prelude.
// FIXME: reject `--extern self` and similar in option parsing instead.
if entry.add_prelude
&& let name = Symbol::intern(name)
&& name.can_be_raw()
{
let ident = IdentKey::with_root_ctxt(name);
Some((ident, ExternPreludeEntry::flag()))
} else {
None
}
})
.collect();

if !attr::contains_name(attrs, sym::no_core) {
let ident = IdentKey::with_root_ctxt(sym::core);
extern_prelude.insert(ident, ExternPreludeEntry::flag());
if !attr::contains_name(attrs, sym::no_std) {
let ident = IdentKey::with_root_ctxt(sym::std);
extern_prelude.insert(ident, ExternPreludeEntry::flag());
}
}

let extern_prelude = build_extern_prelude(tcx, attrs);
let registered_tools = tcx.registered_tools(());
let edition = tcx.sess.edition();

Expand Down Expand Up @@ -2326,10 +2318,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
) -> Option<Decl<'ra>> {
let entry = self.extern_prelude.get(&ident);
entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| {
let (pending_decl, finalized) = flag_decl.get();
let (pending_decl, finalized, is_open) = flag_decl.get();
let decl = match pending_decl {
PendingDecl::Ready(decl) => {
if finalize && !finalized {
if finalize && !finalized && !is_open {
self.cstore_mut().process_path_extern(
self.tcx,
ident.name,
Expand All @@ -2340,18 +2332,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
PendingDecl::Pending => {
debug_assert!(!finalized);
let crate_id = if finalize {
self.cstore_mut().process_path_extern(self.tcx, ident.name, orig_ident_span)
if is_open {
let res = Res::OpenMod(ident.name);
Some(self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT))
} else {
self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
};
crate_id.map(|crate_id| {
let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT)
})
let crate_id = if finalize {
self.cstore_mut().process_path_extern(
self.tcx,
ident.name,
orig_ident_span,
)
} else {
self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
};
crate_id.map(|crate_id| {
let def_id = crate_id.as_def_id();
let res = Res::Def(DefKind::Mod, def_id);
self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT)
})
}
}
};
flag_decl.set((PendingDecl::Ready(decl), finalize || finalized));
flag_decl.set((PendingDecl::Ready(decl), finalize || finalized, is_open));
decl.or_else(|| finalize.then_some(self.dummy_decl))
})
}
Expand Down Expand Up @@ -2393,7 +2395,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
None
}
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
path_result @ (PathResult::Module(..) | PathResult::Indeterminate) => {
bug!("got invalid path_result: {path_result:?}")
}
}
}

Expand Down Expand Up @@ -2511,6 +2515,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}

fn build_extern_prelude<'tcx, 'ra>(
tcx: TyCtxt<'tcx>,
attrs: &[ast::Attribute],
) -> FxIndexMap<IdentKey, ExternPreludeEntry<'ra>> {
let mut extern_prelude: FxIndexMap<IdentKey, ExternPreludeEntry<'ra>> = tcx
.sess
.opts
.externs
.iter()
.filter_map(|(name, entry)| {
// Make sure `self`, `super`, `_` etc do not get into extern prelude.
// FIXME: reject `--extern self` and similar in option parsing instead.
if entry.add_prelude
&& let sym = Symbol::intern(name)
&& sym.can_be_raw()
{
Some((IdentKey::with_root_ctxt(sym), ExternPreludeEntry::flag()))
} else {
None
}
})
.collect();

// Add open base entries for namespaced crates whose base segment
// is missing from the prelude (e.g. `foo::bar` without `foo`).
// These are necessary in order to resolve the open modules, whereas
// the namespaced names are necessary in `extern_prelude` for actually
// resolving the namespaced crates.
let missing_open_bases: Vec<IdentKey> = extern_prelude
.keys()
.filter_map(|ident| {
let (base, _) = ident.name.as_str().split_once("::")?;
let base_sym = Symbol::intern(base);
base_sym.can_be_raw().then(|| IdentKey::with_root_ctxt(base_sym))
})
.filter(|base_ident| !extern_prelude.contains_key(base_ident))
.collect();

extern_prelude.extend(
missing_open_bases.into_iter().map(|ident| (ident, ExternPreludeEntry::open_flag())),
);

// Inject `core` / `std` unless suppressed by attributes.
if !attr::contains_name(attrs, sym::no_core) {
extern_prelude.insert(IdentKey::with_root_ctxt(sym::core), ExternPreludeEntry::flag());

if !attr::contains_name(attrs, sym::no_std) {
extern_prelude.insert(IdentKey::with_root_ctxt(sym::std), ExternPreludeEntry::flag());
}
}

extern_prelude
}

fn names_to_string(names: impl Iterator<Item = Symbol>) -> String {
let mut result = String::new();
for (i, name) in names.enumerate().filter(|(_, name)| *name != kw::PathRoot) {
Expand Down
Loading
Loading