Skip to content

Add compiler support for namespaced crates #140271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

/// Check an expr with an expectation type which may be used to eagerly
/// guide inference when evaluating that expr.
#[instrument(skip(self, expr), level = "debug")]
pub(super) fn check_expr_with_expectation(
&self,
expr: &'tcx hir::Expr<'tcx>,
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use rustc_session::search_paths::PathKind;
use rustc_span::edition::Edition;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
use rustc_target::spec::{PanicStrategy, Target, TargetTuple};
use tracing::{debug, info, trace};
use tracing::{debug, info, instrument, trace};

use crate::errors;
use crate::locator::{CrateError, CrateLocator, CratePaths};
Expand Down Expand Up @@ -1225,11 +1225,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
}

#[instrument(skip(self, krate), level = "debug")]
fn report_unused_deps(&mut self, krate: &ast::Crate) {
// Make a point span rather than covering the whole file
let span = krate.spans.inner_span.shrink_to_lo();
// Complain about anything left over
for (name, entry) in self.sess.opts.externs.iter() {
debug!(?name, ?entry);
debug!("used_extern_options: {:?}", self.used_extern_options);
if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
// Don't worry about pathless `--extern foo` sysroot references
continue;
Expand Down
132 changes: 123 additions & 9 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use rustc_middle::metadata::ModChild;
use rustc_middle::ty::Feed;
use rustc_middle::{bug, ty};
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
use rustc_span::{Ident, Span, Symbol, kw, sym};
use tracing::debug;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
use tracing::{debug, instrument};

use crate::Namespace::{MacroNS, TypeNS, ValueNS};
use crate::def_collector::collect_definitions;
Expand Down Expand Up @@ -70,6 +70,7 @@ impl<'ra, Id: Into<DefId>> ToNameBinding<'ra> for (Res, ty::Visibility<Id>, Span
impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
/// otherwise, reports an error.
#[instrument(level = "debug", skip(self, def))]
pub(crate) fn define<T>(&mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, def: T)
where
T: ToNameBinding<'ra>,
Expand Down Expand Up @@ -118,6 +119,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
return module.copied();
}

//if def_id.is_crate_root() && !def_id.is_local() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expected this to hold, but it fails when compiling libc. Likely here: https://github.com/rust-lang/libc/blob/e8b01525c30545041af1ad7ba24c05ee3251016b/src/lib.rs#L33-L37

// bug!(
// "expected module for external crate {:?} to be created via `create_module_for_external_crate`",
// def_id
// );
//}

if !def_id.is_local() {
// Query `def_kind` is not used because query system overhead is too expensive here.
let def_kind = self.cstore().def_kind_untracked(def_id);
Expand All @@ -143,6 +151,52 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
None
}

/// Creates `Module` instance for an external crate.
/// `Module`s are usually created via `get_module`, but namespaced crates depend
/// on the crate name passed via `--extern`, whereas `get_module` uses the metadata's
/// crate name. We need a way to pass that name to a `Module` and this method does that.
#[instrument(level = "debug", skip(self))]
pub(crate) fn create_module_for_external_crate(
&mut self,
def_id: DefId,
ident: Ident,
finalize: bool,
) -> Module<'ra> {
if finalize {
self.used_extern_options.insert(ident.name);
}

if let Some(module) = self.module_map.get(&def_id) {
return *module;
}

let def_kind = self.cstore().def_kind_untracked(def_id);
match def_kind {
DefKind::Mod => {
let parent = self
.tcx
.opt_parent(def_id)
.map(|parent_id| self.get_nearest_non_block_module(parent_id));
// Query `expn_that_defined` is not used because
// hashing spans in its result is expensive.
let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess);
let module = self.new_module(
parent,
ModuleKind::Def(def_kind, def_id, Some(ident.name)),
expn_id,
self.def_span(def_id),
// FIXME: Account for `#[no_implicit_prelude]` attributes.
parent.is_some_and(|module| module.no_implicit_prelude),
);

return module;
}
_ => {
bug!("expected DefKind::Mod for external crate");
}
}
}

pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'ra> {
match expn_id.expn_data().macro_def_id {
Some(def_id) => self.macro_def_scope(def_id),
Expand Down Expand Up @@ -196,7 +250,33 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
visitor.parent_scope.macro_rules
}

// Builds the reduced graph for an external crate.
// It builds the graph for each child module of the crate and it also checks whether
// namespaced crates with the same base name exist. If any exist it builds a graph for
// each of those crates.
#[instrument(level = "debug", skip(self))]
pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'ra>) {
// Check if `module`'s name is the base crate name for a namespaced crate
// (i.e. `my_api` for the namespaced crates `my_api::utils` and `my_api::core`),
// and process the extern crate for the namespaced crates if they exist.
if let Some(module_name) = module.kind.name() {
let namespace_crate_name = self
.namespaced_crate_names
.get(module_name.as_str())
.map(|names| names.iter().map(|s| s.to_string().clone()).collect::<Vec<String>>());

if let Some(namespaced_crate_names) = namespace_crate_name {
debug!(?namespaced_crate_names);
for namespaced_crate_name in namespaced_crate_names {
let parent_scope = ParentScope::module(module, self);
self.build_reduced_graph_for_namespaced_crate(
&namespaced_crate_name,
parent_scope,
);
}
}
}

for child in self.tcx.module_children(module.def_id()) {
let parent_scope = ParentScope::module(module, self);
self.build_reduced_graph_for_external_crate_res(child, parent_scope)
Expand Down Expand Up @@ -273,6 +353,43 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
| Res::Err => bug!("unexpected resolution: {:?}", res),
}
}

// Builds the reduced graph for a namespaced external crate (crate names like `foo::bar`).
#[instrument(level = "debug", skip(self))]
fn build_reduced_graph_for_namespaced_crate(
&mut self,
name: &str,
parent_scope: ParentScope<'ra>,
) {
let crate_id = self.crate_loader(|c| {
c.maybe_process_path_extern(Symbol::intern(&name))
.expect(&format!("no crate_num for namespaced crate {}", name))
});

let module = self.create_module_for_external_crate(
crate_id.as_def_id(),
Ident::from_str(name),
false,
);
let ident = Ident::from_str(
name.split("::").nth(1).expect("namespaced crate name has unexpected form"),
);
let parent = parent_scope.module;
let res = module.res().expect("namespaced crate has no Res").expect_non_local();
let expansion = parent_scope.expansion;

match res {
Res::Def(DefKind::Mod, _) => {
self.define(
parent,
ident,
TypeNS,
(module, ty::Visibility::<DefId>::Public, DUMMY_SP, expansion),
);
}
_ => bug!("expected namespaced crate to have Res Def(DefKind::Mod)"),
}
}
}

struct BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
Expand Down Expand Up @@ -469,6 +586,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
}

#[instrument(level = "debug", skip(self))]
fn build_reduced_graph_for_use_tree(
&mut self,
// This particular use tree
Expand All @@ -482,11 +600,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
vis: ty::Visibility,
root_span: Span,
) {
debug!(
"build_reduced_graph_for_use_tree(parent_prefix={:?}, use_tree={:?}, nested={})",
parent_prefix, use_tree, nested
);

// Top level use tree reuses the item's id and list stems reuse their parent
// use tree's ids, so in both cases their visibilities are already filled.
if nested && !list_stem {
Expand Down Expand Up @@ -589,7 +702,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
let crate_root = self.r.resolve_crate_root(source.ident);
let crate_name = match crate_root.kind {
ModuleKind::Def(.., name) => name,
ModuleKind::Block => unreachable!(),
ModuleKind::Block | ModuleKind::NamespaceCrate(..) => unreachable!(),
};
// HACK(eddyb) unclear how good this is, but keeping `$crate`
// in `source` breaks `tests/ui/imports/import-crate-var.rs`,
Expand Down Expand Up @@ -897,6 +1010,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
}

#[instrument(level = "debug", skip(self))]
fn build_reduced_graph_for_extern_crate(
&mut self,
orig_name: Option<Symbol>,
Expand All @@ -922,7 +1036,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
});
crate_id.map(|crate_id| {
self.r.extern_crate_map.insert(local_def_id, crate_id);
self.r.expect_module(crate_id.as_def_id())
self.r.create_module_for_external_crate(crate_id.as_def_id(), ident, true)
})
}
.map(|module| {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// indirectly *calls* the resolver, and would cause a query cycle.
ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
ModuleKind::Block => "block",
ModuleKind::NamespaceCrate(..) => {
// `NamespaceCrate`s are virtual modules
unreachable!();
}
};

let (name, span) =
Expand Down
Loading
Loading