Skip to content

Commit

Permalink
rustc_interface: Add a new query pre_configure
Browse files Browse the repository at this point in the history
It partially expands crate attributes before the main expansion pass (without modifying the crate), and the produced preliminary crate attribute list is used for querying a few attributes that are required very early.

Crate-level cfg attributes are then expanded normally during the main expansion pass, like attributes on any other nodes.
  • Loading branch information
petrochenkov committed Mar 23, 2023
1 parent f26da39 commit aca1b1e
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 84 deletions.
17 changes: 12 additions & 5 deletions compiler/rustc_builtin_macros/src/standard_library_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::DUMMY_SP;
use thin_vec::thin_vec;

pub fn inject(krate: &mut ast::Crate, resolver: &mut dyn ResolverExpand, sess: &Session) {
pub fn inject(
krate: &mut ast::Crate,
pre_configured_attrs: &[ast::Attribute],
resolver: &mut dyn ResolverExpand,
sess: &Session,
) -> usize {
let orig_num_items = krate.items.len();
let edition = sess.parse_sess.edition;

// the first name in this list is the crate name of the crate with the prelude
let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
return;
} else if attr::contains_name(&krate.attrs, sym::no_std) {
if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) {
return 0;
} else if attr::contains_name(pre_configured_attrs, sym::no_std) {
if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) {
&[sym::core]
} else {
&[sym::core, sym::compiler_builtins]
Expand Down Expand Up @@ -84,4 +90,5 @@ pub fn inject(krate: &mut ast::Crate, resolver: &mut dyn ResolverExpand, sess: &
);

krate.items.insert(0, use_item);
krate.items.len() - orig_num_items
}
2 changes: 1 addition & 1 deletion compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ fn run_compiler(

{
let plugins = queries.register_plugins()?;
let (_, lint_store) = &*plugins.borrow();
let (.., lint_store) = &*plugins.borrow();

// Lint plugins are registered; now we can process command line flags.
if sess.opts.describe_lints {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,7 @@ pub struct ExpansionData {
pub struct ExtCtxt<'a> {
pub sess: &'a Session,
pub ecfg: expand::ExpansionConfig<'a>,
pub num_standard_library_imports: usize,
pub reduced_recursion_limit: Option<Limit>,
pub root_path: PathBuf,
pub resolver: &'a mut dyn ResolverExpand,
Expand Down Expand Up @@ -1030,6 +1031,7 @@ impl<'a> ExtCtxt<'a> {
ExtCtxt {
sess,
ecfg,
num_standard_library_imports: 0,
reduced_recursion_limit: None,
resolver,
lint_store,
Expand Down
40 changes: 11 additions & 29 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use rustc_session::Session;
use rustc_span::edition::{Edition, ALL_EDITIONS};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use thin_vec::ThinVec;

/// A folder that strips out items that do not belong in the current configuration.
pub struct StripUnconfigured<'a> {
Expand All @@ -37,7 +36,7 @@ pub struct StripUnconfigured<'a> {
pub lint_node_id: NodeId,
}

fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) {
sess.emit_err(FeatureRemoved {
span,
Expand Down Expand Up @@ -191,33 +190,16 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
features
}

/// `cfg_attr`-process the crate's attributes and compute the crate's features.
pub fn features(sess: &Session, krate: &mut ast::Crate, lint_node_id: NodeId) -> Features {
let mut strip_unconfigured =
StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id };

let mut unconfigured_attrs = krate.attrs.clone();
let diag = &sess.parse_sess.span_diagnostic;
let err_count = diag.err_count();

krate.attrs.flat_map_in_place(|attr| strip_unconfigured.process_cfg_attr(&attr));
if !strip_unconfigured.in_cfg(&krate.attrs) {
// The entire crate is unconfigured.
krate.attrs = ast::AttrVec::new();
krate.items = ThinVec::new();
Features::default()
} else {
let features = get_features(sess, &krate.attrs);
if err_count == diag.err_count() {
// Avoid reconfiguring malformed `cfg_attr`s.
strip_unconfigured.features = Some(&features);
// Run configuration again, this time with features available
// so that we can perform feature-gating.
unconfigured_attrs.flat_map_in_place(|attr| strip_unconfigured.process_cfg_attr(&attr));
strip_unconfigured.in_cfg(&unconfigured_attrs);
}
features
}
pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec {
let strip_unconfigured = StripUnconfigured {
sess,
features: None,
config_tokens: false,
lint_node_id: ast::CRATE_NODE_ID,
};
let attrs: ast::AttrVec =
attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect();
if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() }
}

#[macro_export]
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
) -> Result<Self::OutputTy, Self> {
Ok(noop_flat_map(node, collector))
}
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) {
collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
}
}

impl InvocationCollectorNode for P<ast::Item> {
Expand Down Expand Up @@ -1378,6 +1381,11 @@ impl InvocationCollectorNode for ast::Crate {
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
noop_visit_crate(self, visitor)
}
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) {
self.attrs.clear();
// Standard prelude imports are left in the crate for backward compatibility.
self.items.truncate(collector.cx.num_standard_library_imports);
}
}

impl InvocationCollectorNode for P<ast::Ty> {
Expand Down Expand Up @@ -1756,7 +1764,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
continue;
}

self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() });
node.expand_cfg_false(self, span);
continue;
}
sym::cfg_attr => {
Expand Down
51 changes: 27 additions & 24 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::interface::{Compiler, Result};
use crate::proc_macro_decls;
use crate::util;

use ast::CRATE_NODE_ID;
use rustc_ast::{self as ast, visit};
use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::traits::CodegenBackend;
Expand Down Expand Up @@ -76,22 +75,14 @@ pub fn register_plugins<'a>(
sess: &'a Session,
metadata_loader: &'a dyn MetadataLoader,
register_lints: impl Fn(&Session, &mut LintStore),
krate: &mut ast::Crate,
pre_configured_attrs: &[ast::Attribute],
crate_name: Symbol,
) -> Result<LintStore> {
sess.time("attributes_injection", || {
rustc_builtin_macros::cmdline_attrs::inject(
krate,
&sess.parse_sess,
&sess.opts.unstable_opts.crate_attr,
)
});

let features = rustc_expand::config::features(sess, krate, CRATE_NODE_ID);
// these need to be set "early" so that expansion sees `quote` if enabled.
let features = rustc_expand::config::features(sess, pre_configured_attrs);
sess.init_features(features);

let crate_types = util::collect_crate_types(sess, &krate.attrs);
let crate_types = util::collect_crate_types(sess, pre_configured_attrs);
sess.init_crate_types(crate_types);

let stable_crate_id = StableCrateId::new(
Expand All @@ -117,8 +108,9 @@ pub fn register_plugins<'a>(
let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
register_lints(sess, &mut lint_store);

let registrars = sess
.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate.attrs));
let registrars = sess.time("plugin_loading", || {
plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs)
});
sess.time("plugin_registration", || {
let mut registry = plugin::Registry { lint_store: &mut lint_store };
for registrar in registrars {
Expand Down Expand Up @@ -173,19 +165,29 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> {
/// harness if one is to be provided, injection of a dependency on the
/// standard library and prelude, and name resolution.
#[instrument(level = "trace", skip(krate, resolver))]
fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) -> ast::Crate {
fn configure_and_expand(
mut krate: ast::Crate,
pre_configured_attrs: &[ast::Attribute],
resolver: &mut Resolver<'_, '_>,
) -> ast::Crate {
let tcx = resolver.tcx();
let sess = tcx.sess;
let lint_store = unerased_lint_store(tcx);
let crate_name = tcx.crate_name(LOCAL_CRATE);
pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name);
let lint_check_node = (&krate, pre_configured_attrs);
pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), lint_check_node, crate_name);
rustc_builtin_macros::register_builtin_macros(resolver);

sess.time("crate_injection", || {
rustc_builtin_macros::standard_library_imports::inject(&mut krate, resolver, sess)
let num_standard_library_imports = sess.time("crate_injection", || {
rustc_builtin_macros::standard_library_imports::inject(
&mut krate,
pre_configured_attrs,
resolver,
sess,
)
});

util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer());
util::check_attr_crate_type(sess, pre_configured_attrs, &mut resolver.lint_buffer());

// Expand all macros
krate = sess.time("macro_expand_crate", || {
Expand Down Expand Up @@ -222,7 +224,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)

// Create the config for macro expansion
let features = sess.features_untracked();
let recursion_limit = get_recursion_limit(&krate.attrs, sess);
let recursion_limit = get_recursion_limit(pre_configured_attrs, sess);
let cfg = rustc_expand::expand::ExpansionConfig {
features: Some(features),
recursion_limit,
Expand All @@ -235,6 +237,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)

let lint_store = LintStoreExpandImpl(lint_store);
let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
ecx.num_standard_library_imports = num_standard_library_imports;
// Expand macros now!
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));

Expand Down Expand Up @@ -356,7 +359,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
tcx.registered_tools(()),
Some(lint_buffer),
rustc_lint::BuiltinCombinedEarlyLintPass::new(),
&**krate,
(&**krate, &*krate.attrs),
)
}

Expand Down Expand Up @@ -557,9 +560,9 @@ fn resolver_for_lowering<'tcx>(
) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> {
let arenas = Resolver::arenas();
let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`.
let krate = tcx.crate_for_resolver(()).steal();
let mut resolver = Resolver::new(tcx, &krate, &arenas);
let krate = configure_and_expand(krate, &mut resolver);
let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal();
let mut resolver = Resolver::new(tcx, &pre_configured_attrs, krate.spans.inner_span, &arenas);
let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);

// Make sure we don't mutate the cstore from here on.
tcx.untracked().cstore.leak();
Expand Down
41 changes: 31 additions & 10 deletions compiler/rustc_interface/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ pub struct Queries<'tcx> {

dep_graph_future: Query<Option<DepGraphFuture>>,
parse: Query<ast::Crate>,
pre_configure: Query<(ast::Crate, ast::AttrVec)>,
crate_name: Query<Symbol>,
register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>,
dep_graph: Query<DepGraph>,
// This just points to what's in `gcx_cell`.
gcx: Query<&'tcx GlobalCtxt<'tcx>>,
Expand All @@ -106,6 +107,7 @@ impl<'tcx> Queries<'tcx> {
hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
dep_graph_future: Default::default(),
parse: Default::default(),
pre_configure: Default::default(),
crate_name: Default::default(),
register_plugins: Default::default(),
dep_graph: Default::default(),
Expand Down Expand Up @@ -133,17 +135,36 @@ impl<'tcx> Queries<'tcx> {
.compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
}

pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> {
pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
self.pre_configure.compute(|| {
let mut krate = self.parse()?.steal();

let sess = self.session();
rustc_builtin_macros::cmdline_attrs::inject(
&mut krate,
&sess.parse_sess,
&sess.opts.unstable_opts.crate_attr,
);

let pre_configured_attrs =
rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
Ok((krate, pre_configured_attrs))
})
}

pub fn register_plugins(
&self,
) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> {
self.register_plugins.compute(|| {
let crate_name = *self.crate_name()?.borrow();
let mut krate = self.parse()?.steal();
let (krate, pre_configured_attrs) = self.pre_configure()?.steal();

let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
let lint_store = passes::register_plugins(
self.session(),
&*self.codegen_backend().metadata_loader(),
self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
&mut krate,
&pre_configured_attrs,
crate_name,
)?;

Expand All @@ -154,17 +175,17 @@ impl<'tcx> Queries<'tcx> {
// called, which happens within passes::register_plugins().
self.dep_graph_future().ok();

Ok((krate, Lrc::new(lint_store)))
Ok((krate, pre_configured_attrs, Lrc::new(lint_store)))
})
}

fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
self.crate_name.compute(|| {
Ok({
let parse_result = self.parse()?;
let krate = parse_result.borrow();
let pre_configure_result = self.pre_configure()?;
let (_, pre_configured_attrs) = &*pre_configure_result.borrow();
// parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
find_crate_name(self.session(), &krate.attrs)
find_crate_name(self.session(), pre_configured_attrs)
})
})
}
Expand All @@ -188,7 +209,7 @@ impl<'tcx> Queries<'tcx> {
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
self.gcx.compute(|| {
let crate_name = *self.crate_name()?.borrow();
let (krate, lint_store) = self.register_plugins()?.steal();
let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal();

let sess = self.session();

Expand All @@ -215,7 +236,7 @@ impl<'tcx> Queries<'tcx> {
feed.crate_name(crate_name);

let feed = tcx.feed_unit_query();
feed.crate_for_resolver(tcx.arena.alloc(Steal::new(krate)));
feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
feed.metadata_loader(
tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())),
);
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_lint/src/early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,23 +341,23 @@ pub trait EarlyCheckNode<'a>: Copy {
'a: 'b;
}

impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) {
fn id(self) -> ast::NodeId {
ast::CRATE_NODE_ID
}
fn attrs<'b>(self) -> &'b [ast::Attribute]
where
'a: 'b,
{
&self.attrs
&self.1
}
fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>)
where
'a: 'b,
{
lint_callback!(cx, check_crate, self);
ast_visit::walk_crate(cx, self);
lint_callback!(cx, check_crate_post, self);
lint_callback!(cx, check_crate, self.0);
ast_visit::walk_crate(cx, self.0);
lint_callback!(cx, check_crate_post, self.0);
}
}

Expand Down
Loading

0 comments on commit aca1b1e

Please sign in to comment.