From 82297a52753d1420dfbf71839c0274a50b025df8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Feb 2023 16:23:57 +0400 Subject: [PATCH 01/12] expand: Pass `ast::Crate` by reference to AST transforming passes Also some more attributes are passed by reference. --- .../rustc_builtin_macros/src/cmdline_attrs.rs | 4 +- .../src/proc_macro_harness.rs | 12 ++-- .../src/standard_library_imports.rs | 10 +-- .../rustc_builtin_macros/src/test_harness.rs | 2 +- compiler/rustc_expand/src/config.rs | 71 +++++++++---------- compiler/rustc_expand/src/expand.rs | 6 +- compiler/rustc_interface/src/passes.rs | 24 +++---- compiler/rustc_interface/src/queries.rs | 6 +- compiler/rustc_plugin_impl/src/load.rs | 6 +- 9 files changed, 62 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index db05c00d2118a..2b6fcc169be06 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -6,7 +6,7 @@ use rustc_ast::{self as ast, AttrItem, AttrStyle}; use rustc_session::parse::ParseSess; use rustc_span::FileName; -pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { +pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { let mut parser = rustc_parse::new_parser_from_source_str( parse_sess, @@ -36,6 +36,4 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - start_span.to(end_span), )); } - - krate } diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index bc513607ddd1d..b2fcd8c5734da 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -44,14 +44,14 @@ struct CollectProcMacros<'a> { } pub fn inject( + krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand, - mut krate: ast::Crate, is_proc_macro_crate: bool, has_proc_macro_decls: bool, is_test_crate: bool, handler: &rustc_errors::Handler, -) -> ast::Crate { +) { let ecfg = ExpansionConfig::default("proc_macro".to_string()); let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); @@ -66,22 +66,20 @@ pub fn inject( }; if has_proc_macro_decls || is_proc_macro_crate { - visit::walk_crate(&mut collect, &krate); + visit::walk_crate(&mut collect, krate); } let macros = collect.macros; if !is_proc_macro_crate { - return krate; + return; } if is_test_crate { - return krate; + return; } let decls = mk_decls(&mut cx, ¯os); krate.items.push(decls); - - krate } impl<'a> CollectProcMacros<'a> { diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e67c0dba68597..d62d5b4cb1487 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -8,16 +8,12 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::DUMMY_SP; use thin_vec::thin_vec; -pub fn inject( - mut krate: ast::Crate, - resolver: &mut dyn ResolverExpand, - sess: &Session, -) -> ast::Crate { +pub fn inject(krate: &mut ast::Crate, resolver: &mut dyn ResolverExpand, sess: &Session) { 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 sess.contains_name(&krate.attrs, sym::no_core) { - return krate; + return; } else if sess.contains_name(&krate.attrs, sym::no_std) { if sess.contains_name(&krate.attrs, sym::compiler_builtins) { &[sym::core] @@ -88,6 +84,4 @@ pub fn inject( ); krate.items.insert(0, use_item); - - krate } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index d8e3db9e8ee09..82bb86892d7ef 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -37,7 +37,7 @@ struct TestCtxt<'a> { /// Traverse the crate, collecting all the test functions, eliding any /// existing main functions, and synthesizing a main test harness -pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) { +pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand) { let span_diagnostic = sess.diagnostic(); let panic_strategy = sess.panic_strategy(); let platform_panic_strategy = sess.target.panic_strategy; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index d6cb173ba9ba0..9ef185e9497ce 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -192,38 +192,32 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { } /// `cfg_attr`-process the crate's attributes and compute the crate's features. -pub fn features( - sess: &Session, - mut krate: ast::Crate, - lint_node_id: NodeId, -) -> (ast::Crate, 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 unconfigured_attrs = krate.attrs.clone(); + let mut unconfigured_attrs = krate.attrs.clone(); let diag = &sess.parse_sess.span_diagnostic; let err_count = diag.err_count(); - let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) { - None => { - // The entire crate is unconfigured. - krate.attrs = ast::AttrVec::new(); - krate.items = ThinVec::new(); - Features::default() - } - Some(attrs) => { - krate.attrs = attrs; - 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. - strip_unconfigured.configure_krate_attrs(unconfigured_attrs); - } - features + + 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); } - }; - (krate, features) + features + } } #[macro_export] @@ -254,11 +248,6 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); - self.in_cfg(&attrs).then_some(attrs) - } - /// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`. /// This is only used during the invocation of `derive` proc-macros, /// which require that we cfg-expand their entire input. @@ -281,7 +270,7 @@ impl<'a> StripUnconfigured<'a> { .iter() .flat_map(|tree| match tree.clone() { AttrTokenTree::Attributes(mut data) => { - data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); if self.in_cfg(&data.attrs) { data.tokens = LazyAttrTokenStream::new( @@ -319,12 +308,16 @@ impl<'a> StripUnconfigured<'a> { /// the syntax of any `cfg_attr` is incorrect. fn process_cfg_attrs(&self, node: &mut T) { node.visit_attrs(|attrs| { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); }); } - fn process_cfg_attr(&self, attr: Attribute) -> Vec { - if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] } + fn process_cfg_attr(&self, attr: &Attribute) -> Vec { + if attr.has_name(sym::cfg_attr) { + self.expand_cfg_attr(attr, true) + } else { + vec![attr.clone()] + } } /// Parse and expand a single `cfg_attr` attribute into a list of attributes @@ -334,9 +327,9 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec { + pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec { let Some((cfg_predicate, expanded_attrs)) = - rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else { + rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess) else { return vec![]; }; @@ -365,10 +358,10 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs .into_iter() - .flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item))) + .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item))) .collect() } else { - expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect() + expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect() } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 4092a192e0c34..6408ccf7c4324 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1688,7 +1688,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { res } - fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) { + fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) { node.visit_attrs(|attrs| { // Repeated `insert` calls is inefficient, but the number of // insertions is almost always 0 or 1 in practice. @@ -1712,7 +1712,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Default::default() } sym::cfg_attr => { - self.expand_cfg_attr(&mut node, attr, pos); + self.expand_cfg_attr(&mut node, &attr, pos); continue; } _ => { @@ -1760,7 +1760,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { continue; } sym::cfg_attr => { - self.expand_cfg_attr(node, attr, pos); + self.expand_cfg_attr(node, &attr, pos); continue; } _ => visit_clobber(node, |node| { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 71bdd4df95ba3..7c1f6d8c9b872 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -76,10 +76,10 @@ pub fn register_plugins<'a>( sess: &'a Session, metadata_loader: &'a dyn MetadataLoader, register_lints: impl Fn(&Session, &mut LintStore), - mut krate: ast::Crate, + krate: &mut ast::Crate, crate_name: Symbol, -) -> Result<(ast::Crate, LintStore)> { - krate = sess.time("attributes_injection", || { +) -> Result { + sess.time("attributes_injection", || { rustc_builtin_macros::cmdline_attrs::inject( krate, &sess.parse_sess, @@ -87,7 +87,7 @@ pub fn register_plugins<'a>( ) }); - let (krate, features) = rustc_expand::config::features(sess, krate, CRATE_NODE_ID); + let features = rustc_expand::config::features(sess, krate, CRATE_NODE_ID); // these need to be set "early" so that expansion sees `quote` if enabled. sess.init_features(features); @@ -117,8 +117,8 @@ 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)); + let registrars = sess + .time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate.attrs)); sess.time("plugin_registration", || { let mut registry = plugin::Registry { lint_store: &mut lint_store }; for registrar in registrars { @@ -126,7 +126,7 @@ pub fn register_plugins<'a>( } }); - Ok((krate, lint_store)) + Ok(lint_store) } fn pre_expansion_lint<'a>( @@ -181,8 +181,8 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); - krate = sess.time("crate_injection", || { - rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess) + sess.time("crate_injection", || { + rustc_builtin_macros::standard_library_imports::inject(&mut krate, resolver, sess) }); util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer()); @@ -263,7 +263,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) }); sess.time("maybe_building_test_harness", || { - rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate) + rustc_builtin_macros::test_harness::inject(&mut krate, sess, resolver) }); let has_proc_macro_decls = sess.time("AST_validation", || { @@ -287,12 +287,12 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) sess.emit_warning(errors::ProcMacroCratePanicAbort); } - krate = sess.time("maybe_create_a_macro_crate", || { + sess.time("maybe_create_a_macro_crate", || { let is_test_crate = sess.opts.test; rustc_builtin_macros::proc_macro_harness::inject( + &mut krate, sess, resolver, - krate, is_proc_macro_crate, has_proc_macro_decls, is_test_crate, diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 58ad044b399b6..c618297bdc04d 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -136,14 +136,14 @@ impl<'tcx> Queries<'tcx> { pub fn register_plugins(&self) -> Result)>> { self.register_plugins.compute(|| { let crate_name = *self.crate_name()?.borrow(); - let krate = self.parse()?.steal(); + let mut krate = self.parse()?.steal(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; - let (krate, lint_store) = passes::register_plugins( + let lint_store = passes::register_plugins( self.session(), &*self.codegen_backend().metadata_loader(), self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), - krate, + &mut krate, crate_name, )?; diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs index 8e75e969ae032..27e5cb9f0d014 100644 --- a/compiler/rustc_plugin_impl/src/load.rs +++ b/compiler/rustc_plugin_impl/src/load.rs @@ -3,7 +3,7 @@ use crate::errors::{LoadPluginError, MalformedPluginAttribute}; use crate::Registry; use libloading::Library; -use rustc_ast::Crate; +use rustc_ast::Attribute; use rustc_metadata::locator; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; @@ -20,11 +20,11 @@ type PluginRegistrarFn = fn(&mut Registry<'_>); pub fn load_plugins( sess: &Session, metadata_loader: &dyn MetadataLoader, - krate: &Crate, + attrs: &[Attribute], ) -> Vec { let mut plugins = Vec::new(); - for attr in &krate.attrs { + for attr in attrs { if !attr.has_name(sym::plugin) { continue; } From 0261d25a46a33adbad617365381df1460e06d851 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 14 Mar 2023 16:09:39 +0400 Subject: [PATCH 02/12] Add some tests for the current `#![cfg(FALSE)]` crate behavior --- tests/ui/cfg/auxiliary/cfg_false_lib.rs | 6 +++++ tests/ui/cfg/cfg-false-feature.rs | 20 ++++++++++++++ tests/ui/cfg/cfg-false-feature.stderr | 35 +++++++++++++++++++++++++ tests/ui/cfg/cfg_false_no_std.rs | 11 ++++++++ 4 files changed, 72 insertions(+) create mode 100644 tests/ui/cfg/auxiliary/cfg_false_lib.rs create mode 100644 tests/ui/cfg/cfg-false-feature.rs create mode 100644 tests/ui/cfg/cfg-false-feature.stderr create mode 100644 tests/ui/cfg/cfg_false_no_std.rs diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib.rs b/tests/ui/cfg/auxiliary/cfg_false_lib.rs new file mode 100644 index 0000000000000..3c011d72b02c5 --- /dev/null +++ b/tests/ui/cfg/auxiliary/cfg_false_lib.rs @@ -0,0 +1,6 @@ +// It is unclear whether a fully unconfigured crate should link to standard library, +// or what its `no_std`/`no_core`/`compiler_builtins` status, more precisely. +// Currently the usual standard library prelude is added to such crates, +// and therefore they link to libstd. + +#![cfg(FALSE)] diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs new file mode 100644 index 0000000000000..21ea3ec79b4d6 --- /dev/null +++ b/tests/ui/cfg/cfg-false-feature.rs @@ -0,0 +1,20 @@ +// It is unclear which features should be in effect in a fully unconfigured crate (issue #104633). +// Currently none on the features are in effect, so we get the feature gates reported. + +// check-pass +// compile-flags: --crate-type lib + +#![feature(decl_macro)] +#![cfg(FALSE)] +#![feature(box_syntax)] + +macro mac() {} //~ WARN `macro` is experimental + //~| WARN unstable syntax can change at any point in the future + +trait A = Clone; //~ WARN trait aliases are experimental + //~| WARN unstable syntax can change at any point in the future + +fn main() { + let box _ = Box::new(0); //~ WARN box pattern syntax is experimental + //~| WARN unstable syntax can change at any point in the future +} diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr new file mode 100644 index 0000000000000..14673fbdb1444 --- /dev/null +++ b/tests/ui/cfg/cfg-false-feature.stderr @@ -0,0 +1,35 @@ +warning: trait aliases are experimental + --> $DIR/cfg-false-feature.rs:14:1 + | +LL | trait A = Clone; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: `macro` is experimental + --> $DIR/cfg-false-feature.rs:11:1 + | +LL | macro mac() {} + | ^^^^^^^^^^^^^^ + | + = note: see issue #39412 for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: box pattern syntax is experimental + --> $DIR/cfg-false-feature.rs:18:9 + | +LL | let box _ = Box::new(0); + | ^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 3 warnings emitted + diff --git a/tests/ui/cfg/cfg_false_no_std.rs b/tests/ui/cfg/cfg_false_no_std.rs new file mode 100644 index 0000000000000..319ea078187c2 --- /dev/null +++ b/tests/ui/cfg/cfg_false_no_std.rs @@ -0,0 +1,11 @@ +// Currently no error because the panic handler is supplied by libstd linked though the empty +// library, but the desirable behavior is unclear (see comments in cfg_false_lib.rs). + +// check-pass +// aux-build: cfg_false_lib.rs + +#![no_std] + +extern crate cfg_false_lib as _; + +fn main() {} From bf00e7da03723fdce3045da0ba6ba0e0f1b1ca3f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 14 Mar 2023 16:53:04 +0400 Subject: [PATCH 03/12] rustc_interface: Add a new query `pre_configure` 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. --- .../src/standard_library_imports.rs | 17 +++++-- compiler/rustc_driver_impl/src/lib.rs | 2 +- compiler/rustc_expand/src/base.rs | 2 + compiler/rustc_expand/src/config.rs | 40 +++++----------- compiler/rustc_expand/src/expand.rs | 10 +++- compiler/rustc_interface/src/passes.rs | 46 ++++++++++--------- compiler/rustc_interface/src/queries.rs | 41 +++++++++++++---- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 11 +++-- compiler/rustc_resolve/src/macros.rs | 4 +- tests/ui-fulldeps/lint-tool-test.rs | 1 - tests/ui-fulldeps/lint-tool-test.stderr | 32 ++++++------- 13 files changed, 113 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index d62d5b4cb1487..e977f43eb6a2b 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -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 sess.contains_name(&krate.attrs, sym::no_core) { - return; - } else if sess.contains_name(&krate.attrs, sym::no_std) { - if sess.contains_name(&krate.attrs, sym::compiler_builtins) { + let names: &[Symbol] = if sess.contains_name(pre_configured_attrs, sym::no_core) { + return 0; + } else if sess.contains_name(pre_configured_attrs, sym::no_std) { + if sess.contains_name(pre_configured_attrs, sym::compiler_builtins) { &[sym::core] } else { &[sym::core, sym::compiler_builtins] @@ -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 } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 555917c8b5e9c..3fd18a98b12cf 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -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 { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 713e4fbbdce23..53fa3f096b9dd 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1004,6 +1004,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, pub root_path: PathBuf, pub resolver: &'a mut dyn ResolverExpand, @@ -1032,6 +1033,7 @@ impl<'a> ExtCtxt<'a> { ExtCtxt { sess, ecfg, + num_standard_library_imports: 0, reduced_recursion_limit: None, resolver, lint_store, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 9ef185e9497ce..a78dc0678d5da 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -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> { @@ -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, @@ -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] diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6408ccf7c4324..ec40911545f50 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1038,6 +1038,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { ) -> Result { 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 { @@ -1378,6 +1381,11 @@ impl InvocationCollectorNode for ast::Crate { fn noop_visit(&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 { @@ -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 => { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7c1f6d8c9b872..adaf33ef271e0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -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; @@ -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 { - 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( @@ -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 { @@ -173,7 +165,11 @@ 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); @@ -181,11 +177,16 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, 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", || { @@ -222,7 +223,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, @@ -235,6 +236,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)); @@ -557,9 +559,9 @@ fn resolver_for_lowering<'tcx>( ) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc)> { 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(); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index c618297bdc04d..d2293780836d5 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -88,8 +88,9 @@ pub struct Queries<'tcx> { dep_graph_future: Query>, parse: Query, + pre_configure: Query<(ast::Crate, ast::AttrVec)>, crate_name: Query, - register_plugins: Query<(ast::Crate, Lrc)>, + register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc)>, dep_graph: Query, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, @@ -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(), @@ -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)>> { + pub fn pre_configure(&self) -> Result> { + 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)>> { 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, )?; @@ -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> { 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) }) }) } @@ -188,7 +209,7 @@ impl<'tcx> Queries<'tcx> { pub fn global_ctxt(&'tcx self) -> Result>> { 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(); @@ -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())), ); diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 72907fba5e62c..9f16ecbdaa933 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -36,7 +36,7 @@ macro_rules! arena_types { )>, [] output_filenames: std::sync::Arc, [] metadata_loader: rustc_data_structures::steal::Steal>, - [] crate_for_resolver: rustc_data_structures::steal::Steal, + [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>, [] resolutions: rustc_middle::ty::ResolverGlobalCtxt, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 75f05c4af23da..919fa3eceaac2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2116,7 +2116,7 @@ rustc_queries! { desc { "raw operations for metadata file access" } } - query crate_for_resolver((): ()) -> &'tcx Steal { + query crate_for_resolver((): ()) -> &'tcx Steal<(rustc_ast::Crate, rustc_ast::AttrVec)> { feedable no_hash desc { "the ast before macro expansion and name resolution" } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cd90fd3ef84d8..aba391bd38975 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1180,7 +1180,8 @@ impl<'tcx> Resolver<'_, 'tcx> { impl<'a, 'tcx> Resolver<'a, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - krate: &Crate, + attrs: &[ast::Attribute], + crate_span: Span, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); @@ -1189,8 +1190,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None, ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), ExpnId::root(), - krate.spans.inner_span, - tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude), + crate_span, + tcx.sess.contains_name(attrs, sym::no_implicit_prelude), &mut module_map, ); let empty_module = arenas.new_module( @@ -1222,9 +1223,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .map(|(name, _)| (Ident::from_str(name), Default::default())) .collect(); - if !tcx.sess.contains_name(&krate.attrs, sym::no_core) { + if !tcx.sess.contains_name(attrs, sym::no_core) { extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); - if !tcx.sess.contains_name(&krate.attrs, sym::no_std) { + if !tcx.sess.contains_name(attrs, sym::no_std) { extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 37153854f7e7f..e055ea1bb6ec9 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -112,8 +112,8 @@ fn fast_print_path(path: &ast::Path) -> Symbol { pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); - let krate = tcx.crate_for_resolver(()).borrow(); - for attr in tcx.sess.filter_by_name(&krate.attrs, sym::register_tool) { + let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); + for attr in tcx.sess.filter_by_name(pre_configured_attrs, sym::register_tool) { for nested_meta in attr.meta_item_list().unwrap_or_default() { match nested_meta.ident() { Some(ident) => { diff --git a/tests/ui-fulldeps/lint-tool-test.rs b/tests/ui-fulldeps/lint-tool-test.rs index f92bcd213b844..9a87646e77833 100644 --- a/tests/ui-fulldeps/lint-tool-test.rs +++ b/tests/ui-fulldeps/lint-tool-test.rs @@ -9,7 +9,6 @@ #![cfg_attr(foo, warn(test_lint))] //~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future //~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future -//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future #![deny(clippy_group)] //~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future //~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future diff --git a/tests/ui-fulldeps/lint-tool-test.stderr b/tests/ui-fulldeps/lint-tool-test.stderr index 027cf8f80cff2..9dafcbc039db4 100644 --- a/tests/ui-fulldeps/lint-tool-test.stderr +++ b/tests/ui-fulldeps/lint-tool-test.stderr @@ -1,19 +1,13 @@ -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:9:23 - | -LL | #![cfg_attr(foo, warn(test_lint))] - | ^^^^^^^^^ help: change it to: `clippy::test_lint` - | - = note: `#[warn(renamed_and_removed_lints)]` on by default - warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` + | + = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 + --> $DIR/lint-tool-test.rs:28:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` @@ -25,26 +19,26 @@ LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` error: item is named 'lintme' - --> $DIR/lint-tool-test.rs:18:1 + --> $DIR/lint-tool-test.rs:17:1 | LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-tool-test.rs:13:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ = note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]` error: item is named 'lintmetoo' - --> $DIR/lint-tool-test.rs:26:5 + --> $DIR/lint-tool-test.rs:25:5 | LL | fn lintmetoo() { } | ^^^^^^^^^^^^^^^^^^ @@ -52,13 +46,13 @@ LL | fn lintmetoo() { } = note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]` warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 + --> $DIR/lint-tool-test.rs:28:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` warning: unknown lint: `this_lint_does_not_exist` - --> $DIR/lint-tool-test.rs:33:8 + --> $DIR/lint-tool-test.rs:32:8 | LL | #[deny(this_lint_does_not_exist)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,16 +74,16 @@ LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 + --> $DIR/lint-tool-test.rs:28:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` -error: aborting due to 2 previous errors; 11 warnings emitted +error: aborting due to 2 previous errors; 10 warnings emitted From 663953857556bfaa049a3492bb4ec531ec0127b9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 17 Mar 2023 20:48:34 +0000 Subject: [PATCH 04/12] Remove VecMap --- compiler/rustc_borrowck/src/lib.rs | 3 +- compiler/rustc_borrowck/src/nll.rs | 6 +- .../src/region_infer/opaque_types.rs | 7 +- compiler/rustc_borrowck/src/type_check/mod.rs | 3 +- compiler/rustc_data_structures/src/lib.rs | 1 - compiler/rustc_data_structures/src/vec_map.rs | 192 ------------------ .../src/vec_map/tests.rs | 48 ----- .../rustc_hir_analysis/src/collect/type_of.rs | 2 +- .../src/infer/canonical/query_response.rs | 4 +- .../rustc_infer/src/infer/opaque_types.rs | 4 +- compiler/rustc_middle/src/mir/query.rs | 4 +- .../rustc_middle/src/ty/typeck_results.rs | 5 +- 12 files changed, 16 insertions(+), 263 deletions(-) delete mode 100644 compiler/rustc_data_structures/src/vec_map.rs delete mode 100644 compiler/rustc_data_structures/src/vec_map/tests.rs diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 5e77f6b190a69..2f2f7d0aaa459 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -19,7 +19,6 @@ extern crate tracing; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -141,7 +140,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> &Bor debug!("Skipping borrowck because of injected body"); // Let's make up a borrowck result! Fun times! let result = BorrowCheckResult { - concrete_opaque_types: VecMap::new(), + concrete_opaque_types: FxIndexMap::default(), closure_requirements: None, used_mut_upvars: SmallVec::new(), tainted_by_errors: None, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 96228338a4c22..f0068fc9226be 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -2,7 +2,7 @@ #![deny(rustc::diagnostic_outside_of_impl)] //! The entry point of the NLL borrow checker. -use rustc_data_structures::vec_map::VecMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; @@ -44,7 +44,7 @@ pub type PoloniusOutput = Output; /// closure requirements to propagate, and any generated errors. pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: VecMap>, + pub opaque_type_values: FxIndexMap>, pub polonius_input: Option>, pub polonius_output: Option>, pub opt_closure_req: Option>, @@ -377,7 +377,7 @@ pub(super) fn dump_annotation<'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, - opaque_type_values: &VecMap>, + opaque_type_values: &FxIndexMap>, errors: &mut crate::error::BorrowckErrors<'tcx>, ) { let tcx = infcx.tcx; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 748c8b9e4420c..9deac71809c2a 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; @@ -61,9 +60,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'tcx>, - opaque_ty_decls: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, - ) -> VecMap> { - let mut result: VecMap> = VecMap::new(); + opaque_ty_decls: FxIndexMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + ) -> FxIndexMap> { + let mut result: FxIndexMap> = FxIndexMap::default(); let member_constraints: FxIndexMap<_, _> = self .member_constraints diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 53fef4d75bf67..f67dae9beb925 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -10,7 +10,6 @@ use either::Either; use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -894,7 +893,7 @@ pub(crate) struct MirTypeckResults<'tcx> { pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) universal_region_relations: Frozen>, pub(crate) opaque_type_values: - VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + FxIndexMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, } /// A collection of region constraints that must be satisfied for the diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index c595bf830a3dc..0339fb925d458 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -79,7 +79,6 @@ pub mod sync; pub mod tiny_list; pub mod transitive_relation; pub mod vec_linked_list; -pub mod vec_map; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs deleted file mode 100644 index d1a99bcaeb754..0000000000000 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ /dev/null @@ -1,192 +0,0 @@ -use std::borrow::Borrow; -use std::fmt::Debug; -use std::slice::Iter; -use std::vec::IntoIter; - -use crate::stable_hasher::{HashStable, StableHasher}; - -/// A map type implemented as a vector of pairs `K` (key) and `V` (value). -/// It currently provides a subset of all the map operations, the rest could be added as needed. -#[derive(Clone, Encodable, Decodable, Debug)] -pub struct VecMap(Vec<(K, V)>); - -impl VecMap -where - K: Debug + PartialEq, - V: Debug, -{ - pub fn new() -> Self { - VecMap(Default::default()) - } - - /// Sets the value of the entry, and returns the entry's old value. - pub fn insert(&mut self, k: K, v: V) -> Option { - if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) { - Some(std::mem::replace(&mut elem.1, v)) - } else { - self.0.push((k, v)); - None - } - } - - /// Removes the entry from the map and returns the removed value - pub fn remove(&mut self, k: &K) -> Option { - self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1) - } - - /// Gets a reference to the value in the entry. - pub fn get(&self, k: &Q) -> Option<&V> - where - K: Borrow, - Q: Eq, - { - self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1) - } - - /// Gets a mutable reference to the value in the entry. - pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Eq, - { - self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1) - } - - /// Returns the any value corresponding to the supplied predicate filter. - /// - /// The supplied predicate will be applied to each (key, value) pair and it will return a - /// reference to the values where the predicate returns `true`. - pub fn any_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> { - self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1) - } - - /// Returns the value corresponding to the supplied predicate filter. It crashes if there's - /// more than one matching element. - /// - /// The supplied predicate will be applied to each (key, value) pair and it will return a - /// reference to the value where the predicate returns `true`. - pub fn get_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> { - let mut filter = self.0.iter().filter(|kv| predicate(kv)); - let (_, value) = filter.next()?; - // This should return just one element, otherwise it's a bug - assert!( - filter.next().is_none(), - "Collection {self:#?} should have just one matching element" - ); - Some(value) - } - - /// Returns `true` if the map contains a value for the specified key. - /// - /// The key may be any borrowed form of the map's key type, - /// [`Eq`] on the borrowed form *must* match those for - /// the key type. - pub fn contains_key(&self, k: &Q) -> bool - where - K: Borrow, - Q: Eq, - { - self.get(k).is_some() - } - - /// Returns `true` if the map contains no elements. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn iter(&self) -> Iter<'_, (K, V)> { - self.into_iter() - } - - pub fn iter_mut(&mut self) -> impl Iterator { - self.into_iter() - } - - pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) { - self.0.retain(f) - } -} - -impl Default for VecMap { - #[inline] - fn default() -> Self { - Self(Default::default()) - } -} - -impl From> for VecMap { - fn from(vec: Vec<(K, V)>) -> Self { - Self(vec) - } -} - -impl Into> for VecMap { - fn into(self) -> Vec<(K, V)> { - self.0 - } -} - -impl FromIterator<(K, V)> for VecMap { - fn from_iter>(iter: I) -> Self { - Self(iter.into_iter().collect()) - } -} - -impl<'a, K, V> IntoIterator for &'a VecMap { - type Item = &'a (K, V); - type IntoIter = Iter<'a, (K, V)>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut VecMap { - type Item = (&'a K, &'a mut V); - type IntoIter = impl Iterator; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut().map(|(k, v)| (&*k, v)) - } -} - -impl IntoIterator for VecMap { - type Item = (K, V); - type IntoIter = IntoIter<(K, V)>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl Extend<(K, V)> for VecMap { - fn extend>(&mut self, iter: I) { - for (k, v) in iter { - self.insert(k, v); - } - } - - fn extend_one(&mut self, (k, v): (K, V)) { - self.insert(k, v); - } - - fn extend_reserve(&mut self, additional: usize) { - self.0.extend_reserve(additional); - } -} - -impl HashStable for VecMap -where - K: HashStable + Eq, - V: HashStable, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.0.hash_stable(hcx, hasher) - } -} - -#[cfg(test)] -mod tests; diff --git a/compiler/rustc_data_structures/src/vec_map/tests.rs b/compiler/rustc_data_structures/src/vec_map/tests.rs deleted file mode 100644 index 458b60077dc75..0000000000000 --- a/compiler/rustc_data_structures/src/vec_map/tests.rs +++ /dev/null @@ -1,48 +0,0 @@ -use super::*; - -impl VecMap { - fn into_vec(self) -> Vec<(K, V)> { - self.0.into() - } -} - -#[test] -fn test_from_iterator() { - assert_eq!( - std::iter::empty().collect::>().into_vec(), - Vec::<(i32, bool)>::new() - ); - assert_eq!(std::iter::once((42, true)).collect::>().into_vec(), vec![(42, true)]); - assert_eq!( - [(1, true), (2, false)].into_iter().collect::>().into_vec(), - vec![(1, true), (2, false)] - ); -} - -#[test] -fn test_into_iterator_owned() { - assert_eq!(VecMap::new().into_iter().collect::>(), Vec::<(i32, bool)>::new()); - assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::>(), vec![(1, true)]); - assert_eq!( - VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::>(), - vec![(1, true), (2, false)] - ); -} - -#[test] -fn test_insert() { - let mut v = VecMap::new(); - assert_eq!(v.insert(1, true), None); - assert_eq!(v.insert(2, false), None); - assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]); - assert_eq!(v.insert(1, false), Some(true)); - assert_eq!(v.into_vec(), vec![(1, false), (2, false)]); -} - -#[test] -fn test_get() { - let v = [(1, true), (2, false)].into_iter().collect::>(); - assert_eq!(v.get(&1), Some(&true)); - assert_eq!(v.get(&2), Some(&false)); - assert_eq!(v.get(&3), None); -} diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index fe44fabf57df9..82689b14fc8c2 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -765,7 +765,7 @@ fn find_opaque_ty_constraints_for_rpit( // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; debug!(?concrete_opaque_types); - for &(def_id, concrete_type) in concrete_opaque_types { + for (&def_id, &concrete_type) in concrete_opaque_types { if def_id != self.def_id { // Ignore constraints for other opaque types. continue; diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 156a7e68ed1a0..268896b671adf 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -159,9 +159,7 @@ impl<'tcx> InferCtxt<'tcx> { .opaque_type_storage .opaque_types .iter() - .map(|&(k, ref v)| { - (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty) - }) + .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) .collect() } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 49f823a47b83d..3a0a0494a7ed3 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -5,8 +5,8 @@ use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -21,7 +21,7 @@ use std::ops::ControlFlow; mod table; -pub type OpaqueTypeMap<'tcx> = VecMap, OpaqueTypeDecl<'tcx>>; +pub type OpaqueTypeMap<'tcx> = FxIndexMap, OpaqueTypeDecl<'tcx>>; pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; /// Information about the opaque types whose values we diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index d85d68870d7d8..786c2e9cd943e 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,8 +2,8 @@ use crate::mir::{Body, ConstantKind, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -227,7 +227,7 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: VecMap>, + pub concrete_opaque_types: FxIndexMap>, pub closure_requirements: Option>, pub used_mut_upvars: SmallVec<[Field; 8]>, pub tainted_by_errors: Option, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 586958247fcdc..2b0fb4dc2b7d6 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -8,10 +8,9 @@ use crate::{ }, }; use rustc_data_structures::{ - fx::FxHashMap, + fx::{FxHashMap, FxIndexMap}, sync::Lrc, unord::{UnordItems, UnordSet}, - vec_map::VecMap, }; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -155,7 +154,7 @@ pub struct TypeckResults<'tcx> { /// by this function. We also store the /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, /// even if they are only set in dead code (which doesn't show up in MIR). - pub concrete_opaque_types: VecMap>, + pub concrete_opaque_types: FxIndexMap>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. From 572c56cb7e4c31e15d36fabe4e15cff6aa8ce405 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 19 Jan 2023 08:57:26 -0800 Subject: [PATCH 05/12] Update links for custom discriminants. --- compiler/rustc_error_codes/src/error_codes/E0080.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0080.md b/compiler/rustc_error_codes/src/error_codes/E0080.md index 7b1bbde614094..71d6c6fe2ef2c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0080.md +++ b/compiler/rustc_error_codes/src/error_codes/E0080.md @@ -15,9 +15,8 @@ or causing an integer overflow are two ways to induce this error. Ensure that the expressions given can be evaluated as the desired integer type. -See the [Custom Discriminants][custom-discriminants] section of the Reference -for more information about setting custom integer types on fieldless enums -using the [`repr` attribute][repr-attribute]. +See the [Discriminants] section of the Reference for more information about +setting custom integer types on enums using the [`repr` attribute][repr-attribute]. -[custom-discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations -[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#reprc-enums +[discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#discriminants +[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations From d3352def96f9bd8e32fddfc1d8cdfb56c47040f2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 18 Mar 2023 13:25:47 -0400 Subject: [PATCH 06/12] Add #[inline] to as_deref --- library/core/src/option.rs | 2 ++ library/core/src/result.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0f2475a8bdea6..aab3bf1bc122e 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1310,6 +1310,7 @@ impl Option { /// let x: Option = None; /// assert_eq!(x.as_deref(), None); /// ``` + #[inline] #[stable(feature = "option_deref", since = "1.40.0")] #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] pub const fn as_deref(&self) -> Option<&T::Target> @@ -1336,6 +1337,7 @@ impl Option { /// x /// }), Some("HEY".to_owned().as_mut_str())); /// ``` + #[inline] #[stable(feature = "option_deref", since = "1.40.0")] #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target> diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 208b220c24a94..c8168c3f358a4 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -908,6 +908,7 @@ impl Result { /// let y: Result<&str, &u32> = Err(&42); /// assert_eq!(x.as_deref(), y); /// ``` + #[inline] #[stable(feature = "inner_deref", since = "1.47.0")] pub fn as_deref(&self) -> Result<&T::Target, &E> where @@ -934,6 +935,7 @@ impl Result { /// let y: Result<&mut str, &mut u32> = Err(&mut i); /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); /// ``` + #[inline] #[stable(feature = "inner_deref", since = "1.47.0")] pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> where From 9da1da94efd45cf28e9e72c81cacbdbcb1aeabd1 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 20 Mar 2023 12:21:19 +0100 Subject: [PATCH 07/12] Allow optional RET type annotation --- library/core/src/intrinsics/mir.rs | 3 ++- .../building/custom/composite_return.rs | 21 +++++++++++++++++++ .../composite_return.tuple.built.after.mir | 11 ++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/mir-opt/building/custom/composite_return.rs create mode 100644 tests/mir-opt/building/custom/composite_return.tuple.built.after.mir diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index d2d9771bdce2e..f391474b8436b 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -342,6 +342,7 @@ define!( #[rustc_macro_transparency = "transparent"] pub macro mir { ( + $(type RET = $ret_ty:ty ;)? $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)* { @@ -362,7 +363,7 @@ pub macro mir { { // Now all locals #[allow(non_snake_case)] - let RET; + let RET $(: $ret_ty)?; $( let $local_decl $(: $local_decl_ty)? ; )* diff --git a/tests/mir-opt/building/custom/composite_return.rs b/tests/mir-opt/building/custom/composite_return.rs new file mode 100644 index 0000000000000..701d6b1ab7131 --- /dev/null +++ b/tests/mir-opt/building/custom/composite_return.rs @@ -0,0 +1,21 @@ +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +// EMIT_MIR composite_return.tuple.built.after.mir +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn tuple() -> (i32, bool) { + mir!( + type RET = (i32, bool); + { + RET.0 = 1; + RET.1 = true; + Return() + } + ) +} + +fn main() { + assert_eq!(tuple(), (1, true)); +} diff --git a/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir b/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir new file mode 100644 index 0000000000000..d159c1a655eb5 --- /dev/null +++ b/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir @@ -0,0 +1,11 @@ +// MIR for `tuple` after built + +fn tuple() -> (i32, bool) { + let mut _0: (i32, bool); // return place in scope 0 at $DIR/composite_return.rs:+0:15: +0:26 + + bb0: { + (_0.0: i32) = const 1_i32; // scope 0 at $DIR/composite_return.rs:+4:13: +4:22 + (_0.1: bool) = const true; // scope 0 at $DIR/composite_return.rs:+5:13: +5:25 + return; // scope 0 at $DIR/composite_return.rs:+6:13: +6:21 + } +} From 9dc275bb54ab088ac85a08dc807984afd57a78c7 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 20 Mar 2023 15:23:27 +0100 Subject: [PATCH 08/12] Add documentation for `type RET = ...` --- library/core/src/intrinsics/mir.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index f391474b8436b..77e207ecc6c7f 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -49,6 +49,8 @@ //! //! The input to the [`mir!`] macro is: //! +//! - An optional return type annotation in the form of `type RET = ...;`. This may be required +//! if the compiler cannot infer the type of RET. //! - A possibly empty list of local declarations. Locals can also be declared inline on //! assignments via `let`. Type inference generally works. Shadowing does not. //! - A list of basic blocks. The first of these is the start block and is where execution begins. @@ -124,6 +126,18 @@ //! } //! ) //! } +//! +//! #[custom_mir(dialect = "runtime", phase = "optimized")] +//! fn annotated_return_type() -> (i32, bool) { +//! mir!( +//! type RET = (i32, bool); +//! { +//! RET.0 = 1; +//! RET.1 = true; +//! Return() +//! } +//! ) +//! } //! ``` //! //! We can also set off compilation failures that happen in sufficiently late stages of the From 460ecd288a34f73f9178acc723a459cbfe77607a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Mar 2023 10:05:09 +0000 Subject: [PATCH 09/12] Eagerly intern and check CrateNum/StableCrateId collisions --- Cargo.lock | 1 + compiler/rustc_metadata/src/creader.rs | 75 ++++++------------- compiler/rustc_metadata/src/rmeta/decoder.rs | 4 - .../src/rmeta/decoder/cstore_impl.rs | 5 +- compiler/rustc_span/Cargo.toml | 1 + compiler/rustc_span/src/def_id.rs | 6 +- tests/run-make-fulldeps/issue-83045/Makefile | 2 +- 7 files changed, 33 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c0b5d6ab3b57..aa4d79ed26117 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5294,6 +5294,7 @@ name = "rustc_span" version = "0.0.0" dependencies = [ "cfg-if", + "indexmap", "md-5", "rustc_arena", "rustc_data_structures", diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f870a1db82d9c..538e61c985104 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -6,11 +6,11 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::{self as ast, *}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard}; use rustc_expand::base::SyntaxExtension; -use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_index::vec::IndexVec; use rustc_middle::ty::TyCtxt; @@ -46,9 +46,8 @@ pub struct CStore { /// This crate has a `#[alloc_error_handler]` item. has_alloc_error_handler: bool, - /// This map is used to verify we get no hash conflicts between - /// `StableCrateId` values. - pub(crate) stable_crate_ids: FxHashMap, + /// The interned [StableCrateId]s. + pub(crate) stable_crate_ids: StableCrateIdMap, /// Unused externs of the crate unused_externs: Vec, @@ -144,9 +143,21 @@ impl CStore { }) } - fn alloc_new_crate_num(&mut self) -> CrateNum { - self.metas.push(None); - CrateNum::new(self.metas.len() - 1) + fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result { + assert_eq!(self.metas.len(), self.stable_crate_ids.len()); + let num = CrateNum::new(self.stable_crate_ids.len()); + if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) { + let crate_name0 = root.name(); + if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) { + Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)) + } else { + Err(CrateError::SymbolConflictsCurrent(crate_name0)) + } + } else { + self.metas.push(None); + self.stable_crate_ids.insert(root.stable_crate_id(), num); + Ok(num) + } } pub fn has_crate_data(&self, cnum: CrateNum) -> bool { @@ -247,7 +258,7 @@ impl CStore { } pub fn new(sess: &Session) -> CStore { - let mut stable_crate_ids = FxHashMap::default(); + let mut stable_crate_ids = StableCrateIdMap::default(); stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE); CStore { // We add an empty entry for LOCAL_CRATE (which maps to zero) in @@ -342,42 +353,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None } - fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError> { - // Check for (potential) conflicts with the local crate - if self.sess.local_stable_crate_id() == root.stable_crate_id() { - return Err(CrateError::SymbolConflictsCurrent(root.name())); - } - - // Check for conflicts with any crate loaded so far - for (_, other) in self.cstore.iter_crate_data() { - // Same stable crate id but different SVH - if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() { - bug!( - "Previously returned E0523 here. \ - See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\ - root.name() = {}.", - root.name() - ); - } - } - - Ok(()) - } - - fn verify_no_stable_crate_id_hash_conflicts( - &mut self, - root: &CrateRoot, - cnum: CrateNum, - ) -> Result<(), CrateError> { - if let Some(existing) = self.cstore.stable_crate_ids.insert(root.stable_crate_id(), cnum) { - let crate_name0 = root.name(); - let crate_name1 = self.cstore.get_crate_data(existing).name(); - return Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)); - } - - Ok(()) - } - fn register_crate( &mut self, host_lib: Option, @@ -396,7 +371,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep); // Claim this crate number and cache it - let cnum = self.cstore.alloc_new_crate_num(); + let cnum = self.cstore.intern_stable_crate_id(&crate_root)?; info!( "register crate `{}` (cnum = {}. private_dep = {})", @@ -432,14 +407,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None }; - // Perform some verification *after* resolve_crate_deps() above is - // known to have been successful. It seems that - in error cases - the - // cstore can be in a temporarily invalid state between cnum allocation - // and dependency resolution and the verification code would produce - // ICEs in that case (see #83045). - self.verify_no_symbol_conflicts(&crate_root)?; - self.verify_no_stable_crate_id_hash_conflicts(&crate_root, cnum)?; - let crate_metadata = CrateMetadata::new( self.sess, &self.cstore, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 0070e46ffdf02..cabc144077fd5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1709,10 +1709,6 @@ impl CrateMetadata { self.root.name } - pub(crate) fn stable_crate_id(&self) -> StableCrateId { - self.root.stable_crate_id - } - pub(crate) fn hash(&self) -> Svh { self.root.hash } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index a98433953367b..e0f1435ccb3ae 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -615,7 +615,10 @@ impl CrateStore for CStore { } fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum { - self.stable_crate_ids[&stable_crate_id] + *self + .stable_crate_ids + .get(&stable_crate_id) + .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")) } /// Returns the `DefKey` for a given `DefId`. This indicates the diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index ae81d95e27967..98d6e0ab117a3 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -18,3 +18,4 @@ tracing = "0.1" sha1 = "0.10.0" sha2 = "0.10.1" md5 = { package = "md-5", version = "0.10.0" } +indexmap = { version = "1.9.1" } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 162c15574b56c..b2c58caff2ec4 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,13 +1,17 @@ use crate::{HashStableContext, Symbol}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::unhash::Unhasher; use rustc_data_structures::AtomicRef; use rustc_index::vec::Idx; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::borrow::Borrow; use std::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::{BuildHasherDefault, Hash, Hasher}; + +pub type StableCrateIdMap = + indexmap::IndexMap>; rustc_index::newtype_index! { #[custom_encodable] diff --git a/tests/run-make-fulldeps/issue-83045/Makefile b/tests/run-make-fulldeps/issue-83045/Makefile index 34853cb1d31e5..fc180ccfe28e2 100644 --- a/tests/run-make-fulldeps/issue-83045/Makefile +++ b/tests/run-make-fulldeps/issue-83045/Makefile @@ -29,5 +29,5 @@ all: --crate-type=rlib \ --edition=2018 \ c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0 - $(CGREP) E0463 < $(TMPDIR)/output.txt + $(CGREP) E0519 < $(TMPDIR)/output.txt $(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt From d3a55419391ab2d5b75b8c8107b37459ca9b2b83 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Mar 2023 19:18:51 +0400 Subject: [PATCH 10/12] rustdoc: Cleanup parent module tracking for doc links Keep ids of the documented items themselves, not their parent modules. Parent modules can be retreived from those ids when necessary. --- compiler/rustc_resolve/src/rustdoc.rs | 18 +-- src/librustdoc/clean/inline.rs | 75 ++++------- src/librustdoc/clean/mod.rs | 26 ++-- src/librustdoc/clean/types/tests.rs | 2 +- src/librustdoc/clean/utils.rs | 4 +- .../passes/collect_intra_doc_links.rs | 126 ++++++------------ src/librustdoc/passes/collect_trait_impls.rs | 6 +- src/librustdoc/passes/propagate_doc_cfg.rs | 3 +- .../intra-doc/auxiliary/inner-crate-doc.rs | 1 + .../intra-doc/import-inline-merge-module.rs | 10 ++ 10 files changed, 103 insertions(+), 168 deletions(-) create mode 100644 tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs create mode 100644 tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index b8853c1744c92..0e40f794f1860 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -26,11 +26,13 @@ pub enum DocFragmentKind { #[derive(Clone, PartialEq, Eq, Debug)] pub struct DocFragment { pub span: Span, - /// The module this doc-comment came from. - /// - /// This allows distinguishing between the original documentation and a pub re-export. - /// If it is `None`, the item was not re-exported. - pub parent_module: Option, + /// The item this doc-comment came from. + /// Used to determine the scope in which doc links in this fragment are resolved. + /// Typically filled for reexport docs when they are merged into the docs of the + /// original reexported item. + /// If the id is not filled, which happens for the original reexported item, then + /// it has to be taken from somewhere else during doc link resolution. + pub item_id: Option, pub doc: Symbol, pub kind: DocFragmentKind, pub indent: usize, @@ -186,7 +188,7 @@ pub fn attrs_to_doc_fragments<'a>( ) -> (Vec, ast::AttrVec) { let mut doc_fragments = Vec::new(); let mut other_attrs = ast::AttrVec::new(); - for (attr, parent_module) in attrs { + for (attr, item_id) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { let doc = beautify_doc_string(doc_str, comment_kind); let kind = if attr.is_doc_comment() { @@ -194,7 +196,7 @@ pub fn attrs_to_doc_fragments<'a>( } else { DocFragmentKind::RawDoc }; - let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 }; + let fragment = DocFragment { span: attr.span, doc, kind, item_id, indent: 0 }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -216,7 +218,7 @@ pub fn prepare_to_doc_link_resolution( ) -> FxHashMap, String> { let mut res = FxHashMap::default(); for fragment in doc_fragments { - let out_str = res.entry(fragment.parent_module).or_default(); + let out_str = res.entry(fragment.item_id).or_default(); add_doc_fragment(out_str, fragment); } res diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 148243683cbbf..768f8bb7bc899 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -36,15 +36,11 @@ use crate::formats::item_type::ItemType; /// /// The returned value is `None` if the definition could not be inlined, /// and `Some` of a vector of items if it was successfully expanded. -/// -/// `parent_module` refers to the parent of the *re-export*, not the original item. pub(crate) fn try_inline( cx: &mut DocContext<'_>, - parent_module: DefId, - import_def_id: Option, res: Res, name: Symbol, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option)>, visited: &mut DefIdSet, ) -> Option> { let did = res.opt_def_id()?; @@ -55,38 +51,17 @@ pub(crate) fn try_inline( debug!("attrs={:?}", attrs); - let attrs_without_docs = attrs.map(|attrs| { - attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::>() + let attrs_without_docs = attrs.map(|(attrs, def_id)| { + (attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::>(), def_id) }); - // We need this ugly code because: - // - // ``` - // attrs_without_docs.map(|a| a.as_slice()) - // ``` - // - // will fail because it returns a temporary slice and: - // - // ``` - // attrs_without_docs.map(|s| { - // vec = s.as_slice(); - // vec - // }) - // ``` - // - // will fail because we're moving an uninitialized variable into a closure. - let vec; - let attrs_without_docs = match attrs_without_docs { - Some(s) => { - vec = s; - Some(vec.as_slice()) - } - None => None, - }; + let attrs_without_docs = + attrs_without_docs.as_ref().map(|(attrs, def_id)| (&attrs[..], *def_id)); + let import_def_id = attrs.and_then(|(_, def_id)| def_id); let kind = match res { Res::Def(DefKind::Trait, did) => { record_extern_fqn(cx, did, ItemType::Trait); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::TraitItem(Box::new(build_external_trait(cx, did))) } Res::Def(DefKind::Fn, did) => { @@ -95,27 +70,27 @@ pub(crate) fn try_inline( } Res::Def(DefKind::Struct, did) => { record_extern_fqn(cx, did, ItemType::Struct); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::StructItem(build_struct(cx, did)) } Res::Def(DefKind::Union, did) => { record_extern_fqn(cx, did, ItemType::Union); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::UnionItem(build_union(cx, did)) } Res::Def(DefKind::TyAlias, did) => { record_extern_fqn(cx, did, ItemType::Typedef); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::TypedefItem(build_type_alias(cx, did)) } Res::Def(DefKind::Enum, did) => { record_extern_fqn(cx, did, ItemType::Enum); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::EnumItem(build_enum(cx, did)) } Res::Def(DefKind::ForeignTy, did) => { record_extern_fqn(cx, did, ItemType::ForeignType); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. @@ -149,7 +124,7 @@ pub(crate) fn try_inline( _ => return None, }; - let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs); + let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); cx.inlined.insert(did.into()); let mut item = clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg); @@ -316,9 +291,8 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box /// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport. pub(crate) fn build_impls( cx: &mut DocContext<'_>, - parent_module: Option, did: DefId, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option)>, ret: &mut Vec, ) { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls"); @@ -326,7 +300,7 @@ pub(crate) fn build_impls( // for each implementation of an item represented by `did`, build the clean::Item for that impl for &did in tcx.inherent_impls(did).iter() { - build_impl(cx, parent_module, did, attrs, ret); + build_impl(cx, did, attrs, ret); } // This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate. @@ -340,28 +314,26 @@ pub(crate) fn build_impls( let type_ = if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) }; for &did in tcx.incoherent_impls(type_) { - build_impl(cx, parent_module, did, attrs, ret); + build_impl(cx, did, attrs, ret); } } } -/// `parent_module` refers to the parent of the re-export, not the original item pub(crate) fn merge_attrs( cx: &mut DocContext<'_>, - parent_module: Option, old_attrs: &[ast::Attribute], - new_attrs: Option<&[ast::Attribute]>, + new_attrs: Option<(&[ast::Attribute], Option)>, ) -> (clean::Attributes, Option>) { // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export // doc comments show up before the original doc comments // when we render them. - if let Some(inner) = new_attrs { + if let Some((inner, item_id)) = new_attrs { let mut both = inner.to_vec(); both.extend_from_slice(old_attrs); ( - if let Some(new_id) = parent_module { - Attributes::from_ast_with_additional(old_attrs, (inner, new_id)) + if let Some(item_id) = item_id { + Attributes::from_ast_with_additional(old_attrs, (inner, item_id)) } else { Attributes::from_ast(&both) }, @@ -375,9 +347,8 @@ pub(crate) fn merge_attrs( /// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`. pub(crate) fn build_impl( cx: &mut DocContext<'_>, - parent_module: Option, did: DefId, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option)>, ret: &mut Vec, ) { if !cx.inlined.insert(did.into()) { @@ -539,7 +510,7 @@ pub(crate) fn build_impl( record_extern_trait(cx, did); } - let (merged_attrs, cfg) = merge_attrs(cx, parent_module, load_attrs(cx, did), attrs); + let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); trace!("merged_attrs={:?}", merged_attrs); trace!( @@ -635,7 +606,7 @@ fn build_module_items( cfg: None, inline_stmt_id: None, }); - } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) { + } else if let Some(i) = try_inline(cx, res, item.ident.name, None, visited) { items.extend(i) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e3e5454ef5443..2e1f456f50e2f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2388,12 +2388,12 @@ fn clean_maybe_renamed_item<'tcx>( target_attrs.extend_from_slice(inline::load_attrs(cx, def_id)); } - let import_parent = import_id.map(|import_id| cx.tcx.local_parent(import_id).to_def_id()); - let (attrs, cfg) = merge_attrs(cx, import_parent, &target_attrs, Some(&import_attrs)); + let import_id = import_id.map(|def_id| def_id.to_def_id()); + let (attrs, cfg) = merge_attrs(cx, &target_attrs, Some((&import_attrs, import_id))); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg); - item.inline_stmt_id = import_id.map(|def_id| def_id.to_def_id()); + item.inline_stmt_id = import_id; vec![item] }) } @@ -2478,18 +2478,12 @@ fn clean_extern_crate<'tcx>( let krate_owner_def_id = krate.owner_id.to_def_id(); if please_inline { - let mut visited = DefIdSet::default(); - - let res = Res::Def(DefKind::Mod, crate_def_id); - if let Some(items) = inline::try_inline( cx, - cx.tcx.parent_module(krate.hir_id()).to_def_id(), - Some(krate_owner_def_id), - res, + Res::Def(DefKind::Mod, crate_def_id), name, - Some(attrs), - &mut visited, + Some((attrs, Some(krate_owner_def_id))), + &mut Default::default(), ) { return items; } @@ -2613,17 +2607,13 @@ fn clean_use_statement_inner<'tcx>( denied = true; } if !denied { - let mut visited = DefIdSet::default(); let import_def_id = import.owner_id.to_def_id(); - if let Some(mut items) = inline::try_inline( cx, - cx.tcx.parent_module(import.hir_id()).to_def_id(), - Some(import_def_id), path.res, name, - Some(attrs), - &mut visited, + Some((attrs, Some(import_def_id))), + &mut Default::default(), ) { items.push(Item::from_def_id_and_parts( import_def_id, diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 20627c2cfc164..8f2331785f50d 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -10,7 +10,7 @@ use rustc_span::symbol::Symbol; fn create_doc_fragment(s: &str) -> Vec { vec![DocFragment { span: DUMMY_SP, - parent_module: None, + item_id: None, doc: Symbol::intern(s), kind: DocFragmentKind::SugaredDoc, indent: 0, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index cafb00df51ed2..cca50df0db213 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -195,12 +195,12 @@ pub(crate) fn build_deref_target_impls( if let Some(prim) = target.primitive_type() { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); for did in prim.impls(tcx).filter(|did| !did.is_local()) { - inline::build_impl(cx, None, did, None, ret); + inline::build_impl(cx, did, None, ret); } } else if let Type::Path { path } = target { let did = path.def_id(); if !did.is_local() { - inline::build_impls(cx, None, did, None, ret); + inline::build_impls(cx, did, None, ret); } } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 6ed7b98999977..769cc7ddfae61 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -28,7 +28,7 @@ use std::mem; use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module}; -use crate::clean::{Crate, Item, ItemId, ItemLink, PrimitiveType}; +use crate::clean::{Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; use crate::html::markdown::{markdown_links, MarkdownLink}; use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; @@ -42,8 +42,7 @@ pub(crate) const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut collector = - LinkCollector { cx, mod_ids: Vec::new(), visited_links: FxHashMap::default() }; + let mut collector = LinkCollector { cx, visited_links: FxHashMap::default() }; collector.visit_crate(&krate); krate } @@ -149,7 +148,7 @@ impl TryFrom for Res { #[derive(Debug)] struct UnresolvedPath<'a> { /// Item on which the link is resolved, used for resolving `Self`. - item_id: ItemId, + item_id: DefId, /// The scope the link was resolved in. module_id: DefId, /// If part of the link resolved, this has the `Res`. @@ -225,7 +224,7 @@ impl UrlFragment { #[derive(Clone, Debug, Hash, PartialEq, Eq)] struct ResolutionInfo { - item_id: ItemId, + item_id: DefId, module_id: DefId, dis: Option, path_str: Box, @@ -242,11 +241,6 @@ struct DiagnosticInfo<'a> { struct LinkCollector<'a, 'tcx> { cx: &'a mut DocContext<'tcx>, - /// A stack of modules used to decide what scope to resolve in. - /// - /// The last module will be used if the parent scope of the current item is - /// unknown. - mod_ids: Vec, /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link. /// The link will be `None` if it could not be resolved (i.e. the error was cached). visited_links: FxHashMap)>>, @@ -262,7 +256,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn variant_field<'path>( &self, path_str: &'path str, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Result<(Res, DefId), UnresolvedPath<'path>> { let tcx = self.cx.tcx; @@ -333,35 +327,33 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) } - fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Option { + fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option { if ns != TypeNS || path_str != "Self" { return None; } let tcx = self.cx.tcx; - item_id - .as_def_id() - .map(|def_id| match tcx.def_kind(def_id) { - def_kind @ (DefKind::AssocFn - | DefKind::AssocConst - | DefKind::AssocTy - | DefKind::Variant - | DefKind::Field) => { - let parent_def_id = tcx.parent(def_id); - if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant - { - tcx.parent(parent_def_id) - } else { - parent_def_id - } + let self_id = match tcx.def_kind(item_id) { + def_kind @ (DefKind::AssocFn + | DefKind::AssocConst + | DefKind::AssocTy + | DefKind::Variant + | DefKind::Field) => { + let parent_def_id = tcx.parent(item_id); + if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant { + tcx.parent(parent_def_id) + } else { + parent_def_id } - _ => def_id, - }) - .and_then(|self_id| match tcx.def_kind(self_id) { - DefKind::Impl { .. } => self.def_id_to_res(self_id), - DefKind::Use => None, - def_kind => Some(Res::Def(def_kind, self_id)), - }) + } + _ => item_id, + }; + + match tcx.def_kind(self_id) { + DefKind::Impl { .. } => self.def_id_to_res(self_id), + DefKind::Use => None, + def_kind => Some(Res::Def(def_kind, self_id)), + } } /// Convenience wrapper around `doc_link_resolutions`. @@ -373,7 +365,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &self, path_str: &str, ns: Namespace, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Option { if let res @ Some(..) = self.resolve_self_ty(path_str, ns, item_id) { @@ -400,7 +392,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &mut self, path_str: &'path str, ns: Namespace, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Result<(Res, Option), UnresolvedPath<'path>> { if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) { @@ -779,48 +771,31 @@ fn is_derive_trait_collision(ns: &PerNS DocVisitor for LinkCollector<'a, 'tcx> { fn visit_item(&mut self, item: &Item) { - let parent_node = - item.item_id.as_def_id().and_then(|did| find_nearest_parent_module(self.cx.tcx, did)); - if parent_node.is_some() { - trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.item_id); - } - - let inner_docs = item.inner_docs(self.cx.tcx); - - if item.is_mod() && inner_docs { - self.mod_ids.push(item.item_id.expect_def_id()); - } - // We want to resolve in the lexical scope of the documentation. // In the presence of re-exports, this is not the same as the module of the item. // Rather than merging all documentation into one, resolve it one attribute at a time // so we know which module it came from. - for (parent_module, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { + for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { if !may_have_doc_links(&doc) { continue; } debug!("combined_docs={}", doc); // NOTE: if there are links that start in one crate and end in another, this will not resolve them. // This is a degenerate case and it's not supported by rustdoc. - let parent_node = parent_module.or(parent_node); + let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); + let module_id = match self.cx.tcx.def_kind(item_id) { + DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id, + _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), + }; for md_link in preprocessed_markdown_links(&doc) { - let link = self.resolve_link(item, &doc, parent_node, &md_link); + let link = self.resolve_link(item, item_id, module_id, &doc, &md_link); if let Some(link) = link { self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link); } } } - if item.is_mod() { - if !inner_docs { - self.mod_ids.push(item.item_id.expect_def_id()); - } - - self.visit_item_recur(item); - self.mod_ids.pop(); - } else { - self.visit_item_recur(item) - } + self.visit_item_recur(item) } } @@ -952,8 +927,9 @@ impl LinkCollector<'_, '_> { fn resolve_link( &mut self, item: &Item, + item_id: DefId, + module_id: DefId, dox: &str, - parent_node: Option, link: &PreprocessedMarkdownLink, ) -> Option { let PreprocessedMarkdownLink(pp_link, ori_link) = link; @@ -970,25 +946,9 @@ impl LinkCollector<'_, '_> { pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?; let disambiguator = *disambiguator; - // In order to correctly resolve intra-doc links we need to - // pick a base AST node to work from. If the documentation for - // this module came from an inner comment (//!) then we anchor - // our name resolution *inside* the module. If, on the other - // hand it was an outer comment (///) then we anchor the name - // resolution in the parent module on the basis that the names - // used are more likely to be intended to be parent names. For - // this, we set base_node to None for inner comments since - // we've already pushed this node onto the resolution stack but - // for outer comments we explicitly try and resolve against the - // parent_node first. - let inner_docs = item.inner_docs(self.cx.tcx); - let base_node = - if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node }; - let module_id = base_node.expect("doc link without parent module"); - let (mut res, fragment) = self.resolve_with_disambiguator_cached( ResolutionInfo { - item_id: item.item_id, + item_id, module_id, dis: disambiguator, path_str: path_str.clone(), @@ -1229,11 +1189,11 @@ impl LinkCollector<'_, '_> { let disambiguator = key.dis; let path_str = &key.path_str; let item_id = key.item_id; - let base_node = key.module_id; + let module_id = key.module_id; match disambiguator.map(Disambiguator::ns) { Some(expected_ns) => { - match self.resolve(path_str, expected_ns, item_id, base_node) { + match self.resolve(path_str, expected_ns, item_id, module_id) { Ok(res) => Some(res), Err(err) => { // We only looked in one namespace. Try to give a better error if possible. @@ -1243,7 +1203,7 @@ impl LinkCollector<'_, '_> { for other_ns in [TypeNS, ValueNS, MacroNS] { if other_ns != expected_ns { if let Ok(res) = - self.resolve(path_str, other_ns, item_id, base_node) + self.resolve(path_str, other_ns, item_id, module_id) { err = ResolutionFailure::WrongNamespace { res: full_res(self.cx.tcx, res), @@ -1260,7 +1220,7 @@ impl LinkCollector<'_, '_> { None => { // Try everything! let mut candidate = |ns| { - self.resolve(path_str, ns, item_id, base_node) + self.resolve(path_str, ns, item_id, module_id) .map_err(ResolutionFailure::NotResolved) }; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index d32e8185d3f96..8d204ddb79e39 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -49,7 +49,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls"); for &cnum in cx.tcx.crates(()) { for &impl_def_id in cx.tcx.trait_impls_in_crate(cnum) { - inline::build_impl(cx, None, impl_def_id, None, &mut new_items_external); + inline::build_impl(cx, impl_def_id, None, &mut new_items_external); } } } @@ -75,7 +75,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> ); parent = cx.tcx.opt_parent(did); } - inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local); + inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local); attr_buf.clear(); } } @@ -84,7 +84,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> for def_id in PrimitiveType::all_impls(cx.tcx) { // Try to inline primitive impls from other crates. if !def_id.is_local() { - inline::build_impl(cx, None, def_id, None, &mut new_items_external); + inline::build_impl(cx, def_id, None, &mut new_items_external); } } for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) { diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index f35643af63738..8a33e51b3beb1 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -57,7 +57,8 @@ impl<'a, 'tcx> CfgPropagator<'a, 'tcx> { next_def_id = parent_def_id; } - let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs)); + let (_, cfg) = + merge_attrs(self.cx, item.attrs.other_attrs.as_slice(), Some((&attrs, None))); item.cfg = cfg; } } diff --git a/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs new file mode 100644 index 0000000000000..15bf51e6f8e2b --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs @@ -0,0 +1 @@ +//! Inner doc comment diff --git a/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs b/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs new file mode 100644 index 0000000000000..4d6a325664578 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs @@ -0,0 +1,10 @@ +// Test for issue #108501. +// Module parent scope doesn't hijack import's parent scope for the import's doc links. + +// check-pass +// aux-build: inner-crate-doc.rs +// compile-flags: --extern inner_crate_doc --edition 2018 + +/// Import doc comment [inner_crate_doc] +#[doc(inline)] +pub use inner_crate_doc; From 0f45d855c33aea5e04ea9a1e154bee68fbaa61da Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 21 Mar 2023 17:37:37 +0400 Subject: [PATCH 11/12] rustdoc: Factor out some doc link resolution code into a separate function --- .../passes/collect_intra_doc_links.rs | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 769cc7ddfae61..789523c561e57 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -771,30 +771,7 @@ fn is_derive_trait_collision(ns: &PerNS DocVisitor for LinkCollector<'a, 'tcx> { fn visit_item(&mut self, item: &Item) { - // We want to resolve in the lexical scope of the documentation. - // In the presence of re-exports, this is not the same as the module of the item. - // Rather than merging all documentation into one, resolve it one attribute at a time - // so we know which module it came from. - for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { - if !may_have_doc_links(&doc) { - continue; - } - debug!("combined_docs={}", doc); - // NOTE: if there are links that start in one crate and end in another, this will not resolve them. - // This is a degenerate case and it's not supported by rustdoc. - let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); - let module_id = match self.cx.tcx.def_kind(item_id) { - DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id, - _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), - }; - for md_link in preprocessed_markdown_links(&doc) { - let link = self.resolve_link(item, item_id, module_id, &doc, &md_link); - if let Some(link) = link { - self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link); - } - } - } - + self.resolve_links(item); self.visit_item_recur(item) } } @@ -921,6 +898,32 @@ fn preprocessed_markdown_links(s: &str) -> Vec { } impl LinkCollector<'_, '_> { + fn resolve_links(&mut self, item: &Item) { + // We want to resolve in the lexical scope of the documentation. + // In the presence of re-exports, this is not the same as the module of the item. + // Rather than merging all documentation into one, resolve it one attribute at a time + // so we know which module it came from. + for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { + if !may_have_doc_links(&doc) { + continue; + } + debug!("combined_docs={}", doc); + // NOTE: if there are links that start in one crate and end in another, this will not resolve them. + // This is a degenerate case and it's not supported by rustdoc. + let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); + let module_id = match self.cx.tcx.def_kind(item_id) { + DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id, + _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), + }; + for md_link in preprocessed_markdown_links(&doc) { + let link = self.resolve_link(item, item_id, module_id, &doc, &md_link); + if let Some(link) = link { + self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link); + } + } + } + } + /// This is the entry point for resolving an intra-doc link. /// /// FIXME(jynelson): this is way too many arguments From dfbf61029fec121026eb7a77731cfd52e88a3f4c Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Sun, 19 Mar 2023 19:00:17 -0700 Subject: [PATCH 12/12] Set LLVM `LLVM_UNREACHABLE_OPTIMIZE` to `OFF` This option was added to LLVM in https://reviews.llvm.org/D121750?id=416339. It makes `llvm_unreachable` in builds without assertions compile to an `LLVM_BUILTIN_TRAP` instead of `LLVM_BUILTIN_UNREACHABLE` (which causes undefined behavior and is equivalent to `std::hint::unreachable_unchecked`). Having compiler bugs triggering undefined behavior generally seems undesirable and inconsistent with Rust's goals. There is a check in `src/tools/tidy/src/style.rs` to reject code using `llvm_unreachable`. But it is used a lot within LLVM itself. For instance, this changes a failure I get compiling `libcore` for m68k from a `SIGSEGV` to `SIGILL`, which seems better though it still doesn't provide a useful message without switching to an LLVM build with asserts. It may be best not to do this if it noticeably degrades compiler performance, but worthwhile if it doesn't do so in any significant way. I haven't looked into what benchmarks there are for Rustc. That should be considered before merging. --- src/bootstrap/download-ci-llvm-stamp | 2 +- src/bootstrap/native.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 94630e40f3c4c..36f9aaa595d0f 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/104748 +Last change is for: https://github.com/rust-lang/rust/pull/109373 diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 41ee509655326..6f09c8307fca4 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -309,6 +309,7 @@ impl Step for Llvm { cfg.out_dir(&out_dir) .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) + .define("LLVM_UNREACHABLE_OPTIMIZE", "OFF") .define("LLVM_ENABLE_PLUGINS", plugins) .define("LLVM_TARGETS_TO_BUILD", llvm_targets) .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets)