Auto merge of #79070 - jonas-schievink:rollup-wacn2b8, r=jonas-schievink

Rollup of 13 pull requests

Successful merges:

 - #77802 (Allow making `RUSTC_BOOTSTRAP` conditional on the crate name)
 - #79004 (Add `--color` support to bootstrap)
 - #79005 (cleanup: Remove `ParseSess::injected_crate_name`)
 - #79016 (Make `_` an expression, to discard values in destructuring assignments)
 - #79019 (astconv: extract closures into a separate trait)
 - #79026 (Implement BTreeMap::retain and BTreeSet::retain)
 - #79031 (Validate that locals have a corresponding `LocalDecl`)
 - #79034 (rustc_resolve: Make `macro_rules` scope chain compression lazy)
 - #79036 (Move Steal to rustc_data_structures.)
 - #79041 (Rename clean::{ItemEnum -> ItemKind}, clean::Item::{inner -> kind})
 - #79058 (Move likely/unlikely argument outside of invisible unsafe block)
 - #79059 (Print 'checking cranelift artifacts' to easily separate it from other artifacts)
 - #79063 (Update rustfmt to v1.4.26)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2020-11-15 13:19:05 +00:00
commit 5fab31e5dd
100 changed files with 978 additions and 522 deletions

View File

@ -4337,7 +4337,7 @@ dependencies = [
[[package]]
name = "rustfmt-nightly"
version = "1.4.25"
version = "1.4.26"
dependencies = [
"annotate-snippets 0.6.1",
"anyhow",

View File

@ -1192,6 +1192,7 @@ impl Expr {
ExprKind::Field(..) => ExprPrecedence::Field,
ExprKind::Index(..) => ExprPrecedence::Index,
ExprKind::Range(..) => ExprPrecedence::Range,
ExprKind::Underscore => ExprPrecedence::Path,
ExprKind::Path(..) => ExprPrecedence::Path,
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
ExprKind::Break(..) => ExprPrecedence::Break,
@ -1324,6 +1325,8 @@ pub enum ExprKind {
Index(P<Expr>, P<Expr>),
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment).
Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
/// An underscore, used in destructuring assignment to ignore a value.
Underscore,
/// Variable reference, possibly containing `::` and/or type
/// parameters (e.g., `foo::bar::<baz>`).

View File

@ -1232,6 +1232,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
visit_opt(e1, |e1| vis.visit_expr(e1));
visit_opt(e2, |e2| vis.visit_expr(e2));
}
ExprKind::Underscore => {}
ExprKind::Path(qself, path) => {
vis.visit_qself(qself);
vis.visit_path(path);

View File

@ -806,6 +806,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
walk_list!(visitor, visit_expr, start);
walk_list!(visitor, visit_expr, end);
}
ExprKind::Underscore => {}
ExprKind::Path(ref maybe_qself, ref path) => {
if let Some(ref qself) = *maybe_qself {
visitor.visit_ty(&qself.ty);

View File

@ -164,6 +164,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Range(ref e1, ref e2, lims) => {
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
}
ExprKind::Underscore => {
self.sess
.struct_span_err(
e.span,
"in expressions, `_` can only be used on the left-hand side of an assignment",
)
.span_label(e.span, "`_` not allowed here")
.emit();
hir::ExprKind::Err
}
ExprKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
e.id,
@ -863,7 +873,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Return early in case of an ordinary assignment.
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
match &lhs.kind {
ExprKind::Array(..) | ExprKind::Struct(..) | ExprKind::Tup(..) => false,
ExprKind::Array(..)
| ExprKind::Struct(..)
| ExprKind::Tup(..)
| ExprKind::Underscore => false,
// Check for tuple struct constructor.
ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
ExprKind::Paren(e) => {
@ -943,6 +956,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
assignments: &mut Vec<hir::Stmt<'hir>>,
) -> &'hir hir::Pat<'hir> {
match &lhs.kind {
// Underscore pattern.
ExprKind::Underscore => {
return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);
}
// Slice patterns.
ExprKind::Array(elements) => {
let (pats, rest) =

View File

@ -53,7 +53,6 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, ParamName};
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::config::nightly_options;
use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::ParseSess;
use rustc_session::Session;
@ -1398,8 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
"`impl Trait` not allowed outside of {}",
allowed_in,
);
if pos == ImplTraitPosition::Binding && nightly_options::is_nightly_build()
{
if pos == ImplTraitPosition::Binding && self.sess.is_nightly_build() {
err.help(
"add `#![feature(impl_trait_in_bindings)]` to the crate \
attributes to enable",

View File

@ -630,7 +630,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(const_trait_impl, "const trait impls are experimental");
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
gate_all!(destructuring_assignment, "destructuring assignments are unstable");
if sess.parse_sess.span_diagnostic.err_count() == 0 {
// Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
// involved, so we only emit errors where there are no other parsing errors.
gate_all!(destructuring_assignment, "destructuring assignments are unstable");
}
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).

View File

@ -109,7 +109,6 @@ pub fn print_crate<'a>(
ann: &'a dyn PpAnn,
is_expanded: bool,
edition: Edition,
has_injected_crate: bool,
) -> String {
let mut s = State {
s: pp::mk_printer(),
@ -119,7 +118,7 @@ pub fn print_crate<'a>(
insert_extra_parens: true,
};
if is_expanded && has_injected_crate {
if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
// We need to print `#![no_std]` (and its feature gate) so that
// compiling pretty-printed source won't inject libstd again.
// However, we don't want these attributes in the AST because
@ -2068,6 +2067,7 @@ impl<'a> State<'a> {
self.print_expr_maybe_paren(e, fake_prec);
}
}
ast::ExprKind::Underscore => self.s.word("_"),
ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
ast::ExprKind::Break(opt_label, ref opt_expr) => {

View File

@ -13,12 +13,12 @@ pub fn inject(
resolver: &mut dyn ResolverExpand,
sess: &Session,
alt_std_name: Option<Symbol>,
) -> (ast::Crate, Option<Symbol>) {
) -> ast::Crate {
let rust_2018 = sess.parse_sess.edition >= Edition::Edition2018;
// 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, None);
return krate;
} else if sess.contains_name(&krate.attrs, sym::no_std) {
if sess.contains_name(&krate.attrs, sym::compiler_builtins) {
&[sym::core]
@ -81,5 +81,5 @@ pub fn inject(
krate.module.items.insert(0, use_item);
(krate, Some(name))
krate
}

View File

@ -3,7 +3,6 @@ use crate::llvm;
use libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet;
use rustc_feature::UnstableFeatures;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
use rustc_session::Session;
@ -147,13 +146,11 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
let target_machine = create_informational_target_machine(sess);
supported_target_features(sess)
.iter()
.filter_map(|&(feature, gate)| {
if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
Some(feature)
} else {
None
}
})
.filter_map(
|&(feature, gate)| {
if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
},
)
.filter(|feature| {
let llvm_feature = to_llvm_feature(sess, feature);
let cstr = CString::new(llvm_feature).unwrap();

View File

@ -47,9 +47,9 @@ pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
#[macro_export]
macro_rules! likely {
($e:expr) => {
#[allow(unused_unsafe)]
{
unsafe { std::intrinsics::likely($e) }
match $e {
#[allow(unused_unsafe)]
e => unsafe { std::intrinsics::likely(e) },
}
};
}
@ -57,9 +57,9 @@ macro_rules! likely {
#[macro_export]
macro_rules! unlikely {
($e:expr) => {
#[allow(unused_unsafe)]
{
unsafe { std::intrinsics::unlikely($e) }
match $e {
#[allow(unused_unsafe)]
e => unsafe { std::intrinsics::unlikely(e) },
}
};
}
@ -102,6 +102,7 @@ pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod sso;
pub mod steal;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;

View File

@ -1,4 +1,5 @@
use rustc_data_structures::sync::{MappedReadGuard, ReadGuard, RwLock};
use crate::stable_hasher::{HashStable, StableHasher};
use crate::sync::{MappedReadGuard, ReadGuard, RwLock};
/// The `Steal` struct is intended to used as the value for a query.
/// Specifically, we sometimes have queries (*cough* MIR *cough*)
@ -31,7 +32,7 @@ impl<T> Steal<T> {
pub fn borrow(&self) -> MappedReadGuard<'_, T> {
ReadGuard::map(self.value.borrow(), |opt| match *opt {
None => bug!("attempted to read from stolen value"),
None => panic!("attempted to read from stolen value"),
Some(ref v) => v,
})
}
@ -42,3 +43,9 @@ impl<T> Steal<T> {
value.expect("attempt to read from stolen value")
}
}
impl<CTX, T: HashStable<CTX>> HashStable<CTX> for Steal<T> {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
self.borrow().hash_stable(hcx, hasher);
}
}

View File

@ -20,7 +20,7 @@ use rustc_data_structures::profiling::print_time_passes_entry;
use rustc_data_structures::sync::SeqCst;
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorReported, PResult};
use rustc_feature::{find_gated_cfg, UnstableFeatures};
use rustc_feature::find_gated_cfg;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
use rustc_interface::{interface, Queries};
@ -746,9 +746,6 @@ impl RustcDefaultCalls {
}
}
Cfg => {
let allow_unstable_cfg =
UnstableFeatures::from_environment().is_nightly_build();
let mut cfgs = sess
.parse_sess
.config
@ -763,7 +760,7 @@ impl RustcDefaultCalls {
// it, this is intended to get into Cargo and then go
// through to build scripts.
if (name != sym::target_feature || value != Some(sym::crt_dash_static))
&& !allow_unstable_cfg
&& !sess.is_nightly_build()
&& find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
{
return None;
@ -814,14 +811,14 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
}
}
fn usage(verbose: bool, include_unstable_options: bool) {
fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
let mut options = getopts::Options::new();
for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
(option.apply)(&mut options);
}
let message = "Usage: rustc [OPTIONS] INPUT";
let nightly_help = if nightly_options::is_nightly_build() {
let nightly_help = if nightly_build {
"\n -Z help Print unstable compiler options"
} else {
""
@ -831,7 +828,7 @@ fn usage(verbose: bool, include_unstable_options: bool) {
} else {
"\n --help -v Print the full set of options rustc accepts"
};
let at_path = if verbose && nightly_options::is_nightly_build() {
let at_path = if verbose && nightly_build {
" @path Read newline separated options from `path`\n"
} else {
""
@ -1034,7 +1031,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
if args.is_empty() {
// user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information.
usage(false, false);
let nightly_build =
rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
usage(false, false, nightly_build);
return None;
}
@ -1063,7 +1062,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
if matches.opt_present("h") || matches.opt_present("help") {
// Only show unstable options in --help if we accept unstable options.
usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches));
let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
let nightly_build = nightly_options::match_is_nightly_build(&matches);
usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
return None;
}

View File

@ -404,7 +404,6 @@ pub fn print_after_parsing(
annotation.pp_ann(),
false,
parse.edition,
parse.injected_crate_name.get().is_some(),
)
})
} else {
@ -446,7 +445,6 @@ pub fn print_after_hir_lowering<'tcx>(
annotation.pp_ann(),
true,
parse.edition,
parse.injected_crate_name.get().is_some(),
)
})
}

View File

@ -59,7 +59,7 @@ pub enum Stability {
Deprecated(&'static str, Option<&'static str>),
}
#[derive(Clone, Copy, Hash)]
#[derive(Clone, Copy, Debug, Hash)]
pub enum UnstableFeatures {
/// Hard errors for unstable features are active, as on beta/stable channels.
Disallow,
@ -73,11 +73,20 @@ pub enum UnstableFeatures {
}
impl UnstableFeatures {
pub fn from_environment() -> UnstableFeatures {
/// This takes into account `RUSTC_BOOTSTRAP`.
///
/// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly features.
/// Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
pub fn from_environment(krate: Option<&str>) -> Self {
// `true` if this is a feature-staged build, i.e., on the beta or stable channel.
let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
// Returns whether `krate` should be counted as unstable
let is_unstable_crate = |var: &str| {
krate.map_or(false, |name| var.split(',').any(|new_krate| new_krate == name))
};
// `true` if we should enable unstable features for bootstrapping.
let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok();
let bootstrap = std::env::var("RUSTC_BOOTSTRAP")
.map_or(false, |var| var == "1" || is_unstable_crate(&var));
match (disable_unstable_features, bootstrap) {
(_, true) => UnstableFeatures::Cheat,
(true, _) => UnstableFeatures::Disallow,
@ -140,3 +149,30 @@ pub use builtin_attrs::{
AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
};
pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
#[cfg(test)]
mod test {
use super::UnstableFeatures;
#[test]
fn rustc_bootstrap_parsing() {
let is_bootstrap = |env, krate| {
std::env::set_var("RUSTC_BOOTSTRAP", env);
matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Cheat)
};
assert!(is_bootstrap("1", None));
assert!(is_bootstrap("1", Some("x")));
// RUSTC_BOOTSTRAP allows specifying a specific crate
assert!(is_bootstrap("x", Some("x")));
// RUSTC_BOOTSTRAP allows multiple comma-delimited crates
assert!(is_bootstrap("x,y,z", Some("x")));
assert!(is_bootstrap("x,y,z", Some("y")));
// Crate that aren't specified do not get unstable features
assert!(!is_bootstrap("x", Some("a")));
assert!(!is_bootstrap("x,y,z", Some("a")));
assert!(!is_bootstrap("x,y,z", None));
// this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP
assert!(!is_bootstrap("0", None));
}
}

View File

@ -15,7 +15,6 @@ use std::io::{self, Read};
use std::path::Path;
use rustc_serialize::opaque::Encoder;
use rustc_session::config::nightly_options;
/// The first few bytes of files generated by incremental compilation.
const FILE_MAGIC: &[u8] = b"RSIC";
@ -28,12 +27,12 @@ const HEADER_FORMAT_VERSION: u16 = 0;
/// the Git commit hash.
const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
pub fn write_file_header(stream: &mut Encoder) {
pub fn write_file_header(stream: &mut Encoder, nightly_build: bool) {
stream.emit_raw_bytes(FILE_MAGIC);
stream
.emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]);
let rustc_version = rustc_version();
let rustc_version = rustc_version(nightly_build);
assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
stream.emit_raw_bytes(&[rustc_version.len() as u8]);
stream.emit_raw_bytes(rustc_version.as_bytes());
@ -51,6 +50,7 @@ pub fn write_file_header(stream: &mut Encoder) {
pub fn read_file(
report_incremental_info: bool,
path: &Path,
nightly_build: bool,
) -> io::Result<Option<(Vec<u8>, usize)>> {
if !path.exists() {
return Ok(None);
@ -93,7 +93,7 @@ pub fn read_file(
let mut buffer = vec![0; rustc_version_str_len];
file.read_exact(&mut buffer)?;
if buffer != rustc_version().as_bytes() {
if buffer != rustc_version(nightly_build).as_bytes() {
report_format_mismatch(report_incremental_info, path, "Different compiler version");
return Ok(None);
}
@ -115,8 +115,8 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
}
}
fn rustc_version() -> String {
if nightly_options::is_nightly_build() {
fn rustc_version(nightly_build: bool) -> String {
if nightly_build {
if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
return val.to_string_lossy().into_owned();
}

View File

@ -53,8 +53,12 @@ impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
}
}
fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>, usize)> {
match file_format::read_file(report_incremental_info, path) {
fn load_data(
report_incremental_info: bool,
path: &Path,
nightly_build: bool,
) -> LoadResult<(Vec<u8>, usize)> {
match file_format::read_file(report_incremental_info, path, nightly_build) {
Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
Ok(None) => {
// The file either didn't exist or was produced by an incompatible
@ -111,13 +115,14 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
let expected_hash = sess.opts.dep_tracking_hash();
let mut prev_work_products = FxHashMap::default();
let nightly_build = sess.is_nightly_build();
// If we are only building with -Zquery-dep-graph but without an actual
// incr. comp. session directory, we skip this. Otherwise we'd fail
// when trying to load work products.
if sess.incr_comp_session_dir_opt().is_some() {
let work_products_path = work_products_path(sess);
let load_result = load_data(report_incremental_info, &work_products_path);
let load_result = load_data(report_incremental_info, &work_products_path, nightly_build);
if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
// Decode the list of work_products
@ -163,7 +168,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
MaybeAsync::Async(std::thread::spawn(move || {
let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
match load_data(report_incremental_info, &path) {
match load_data(report_incremental_info, &path, nightly_build) {
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
LoadResult::Error { message } => LoadResult::Error { message },
LoadResult::Ok { data: (bytes, start_pos) } => {
@ -201,7 +206,11 @@ pub fn load_query_result_cache(sess: &Session) -> OnDiskCache<'_> {
let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) {
match load_data(
sess.opts.debugging_opts.incremental_info,
&query_cache_path(sess),
sess.is_nightly_build(),
) {
LoadResult::Ok { data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
_ => OnDiskCache::new_empty(sess.source_map()),
}

View File

@ -119,7 +119,7 @@ where
// generate the data in a memory buffer
let mut encoder = Encoder::new(Vec::new());
file_format::write_file_header(&mut encoder);
file_format::write_file_header(&mut encoder, sess.is_nightly_build());
encode(&mut encoder);
// write the data out

View File

@ -6,6 +6,7 @@ use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::{self as ast, visit};
use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
@ -20,7 +21,6 @@ use rustc_middle::dep_graph::DepGraph;
use rustc_middle::middle;
use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::steal::Steal;
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_mir as mir;
use rustc_mir_build as mir_build;
@ -239,16 +239,12 @@ fn configure_and_expand_inner<'a>(
krate = sess.time("crate_injection", || {
let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
let (krate, name) = rustc_builtin_macros::standard_library_imports::inject(
rustc_builtin_macros::standard_library_imports::inject(
krate,
&mut resolver,
&sess,
alt_std_name,
);
if let Some(name) = name {
sess.parse_sess.injected_crate_name.set(name).expect("not yet initialized");
}
krate
)
});
util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer());

View File

@ -3,6 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext};
use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_errors::ErrorReported;
@ -12,7 +13,6 @@ use rustc_incremental::DepGraphFuture;
use rustc_lint::LintStore;
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::steal::Steal;
use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_serialize::json;
use rustc_session::config::{self, OutputFilenames, OutputType};

View File

@ -14,10 +14,10 @@ macro_rules! arena_types {
[] layouts: rustc_target::abi::Layout,
// AdtDef are interned and compared by address
[] adt_def: rustc_middle::ty::AdtDef,
[] steal_mir: rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>,
[] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<$tcx>>,
[decode] mir: rustc_middle::mir::Body<$tcx>,
[] steal_promoted:
rustc_middle::ty::steal::Steal<
rustc_data_structures::steal::Steal<
rustc_index::vec::IndexVec<
rustc_middle::mir::Promoted,
rustc_middle::mir::Body<$tcx>

View File

@ -184,15 +184,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::FloatVid {
}
}
impl<'a, T> HashStable<StableHashingContext<'a>> for ty::steal::Steal<T>
where
T: HashStable<StableHashingContext<'a>>,
{
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.borrow().hash_stable(hcx, hasher);
}
}
impl<'a> HashStable<StableHashingContext<'a>> for crate::middle::privacy::AccessLevels {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {

View File

@ -14,7 +14,6 @@ use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
use crate::traits;
use crate::ty::query::{self, TyCtxtAt};
use crate::ty::steal::Steal;
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
use crate::ty::TyKind::*;
use crate::ty::{
@ -33,6 +32,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{
hash_stable_hashmap, HashStable, StableHasher, StableVec,
};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::ErrorReported;

View File

@ -106,7 +106,6 @@ pub mod outlives;
pub mod print;
pub mod query;
pub mod relate;
pub mod steal;
pub mod subst;
pub mod trait_def;
pub mod util;

View File

@ -28,13 +28,13 @@ use crate::traits::query::{
};
use crate::traits::specialization_graph;
use crate::traits::{self, ImplSource};
use crate::ty::steal::Steal;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::stable_hasher::StableVec;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
use rustc_errors::ErrorReported;

View File

@ -4,7 +4,6 @@ use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::mir;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
@ -104,7 +103,7 @@ impl NonConstOp for FnCallUnstable {
if ccx.is_const_stable_const_fn() {
err.help("Const-stable functions can only call other const-stable functions");
} else if nightly_options::is_nightly_build() {
} else if ccx.tcx.sess.is_nightly_build() {
if let Some(feature) = feature {
err.help(&format!(
"add `#![feature({})]` to the crate attributes to enable",

View File

@ -1,6 +1,7 @@
use crate::{shim, util};
use required_consts::RequiredConstsVisitor;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::steal::Steal;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@ -8,7 +9,6 @@ use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::steal::Steal;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
use std::borrow::Cow;

View File

@ -181,6 +181,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) {
if self.body.local_decls.get(*local).is_none() {
self.fail(
location,
format!("local {:?} has no corresponding declaration in `body.local_decls`", local),
);
}
if self.reachable_blocks.contains(location.block) && context.is_use() {
// Uses of locals must occur while the local's storage is allocated.
self.storage_liveness.seek_after_primary_effect(location);

View File

@ -24,7 +24,7 @@ use super::lints;
crate fn mir_built<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx ty::steal::Steal<Body<'tcx>> {
) -> &'tcx rustc_data_structures::steal::Steal<Body<'tcx>> {
if let Some(def) = def.try_upgrade(tcx) {
return tcx.mir_built(def);
}

View File

@ -12,7 +12,6 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{HirId, Pat};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::nightly_options;
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
use rustc_session::parse::feature_err;
@ -502,7 +501,7 @@ fn check_exhaustive<'p, 'tcx>(
so a wildcard `_` is necessary to match exhaustively",
scrut_ty,
));
if nightly_options::is_nightly_build() {
if cx.tcx.sess.is_nightly_build() {
err.help(&format!(
"add `#![feature(precise_pointer_size_matching)]` \
to the crate attributes to enable precise `{}` matching",

View File

@ -1089,6 +1089,9 @@ impl<'a> Parser<'a> {
self.parse_yield_expr(attrs)
} else if self.eat_keyword(kw::Let) {
self.parse_let_expr(attrs)
} else if self.eat_keyword(kw::Underscore) {
self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span);
Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs))
} else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
// Don't complain about bare semicolons after unclosed braces
// recovery in order to keep the error count down. Fixing the

View File

@ -15,7 +15,6 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};
@ -145,7 +144,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
//
// FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
// is a pretty narrow case, however.
if nightly_options::is_nightly_build() {
if tcx.sess.is_nightly_build() {
for gate in missing_secondary {
let note = format!(
"add `#![feature({})]` to the crate attributes to enable",

View File

@ -1163,9 +1163,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope);
assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");
let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id));
self.r.invocation_macro_rules_scopes.entry(invoc_id).or_default().insert(scope);
scope
self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id))
}
fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {

View File

@ -16,7 +16,6 @@ use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@ -890,7 +889,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
(Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
err.span_label(span, "type aliases cannot be used as traits");
if nightly_options::is_nightly_build() {
if self.r.session.is_nightly_build() {
let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
`type` alias";
if let Some(span) = self.def_span(def_id) {
@ -1675,7 +1674,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
_ => {}
}
}
if nightly_options::is_nightly_build()
if self.tcx.sess.is_nightly_build()
&& !self.tcx.features().in_band_lifetimes
&& suggests_in_band
{

View File

@ -976,9 +976,6 @@ pub struct Resolver<'a> {
/// `macro_rules` scopes *produced* by expanding the macro invocations,
/// include all the `macro_rules` items and other invocations generated by them.
output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>,
/// References to all `MacroRulesScope::Invocation(invoc_id)`s, used to update such scopes
/// when their corresponding `invoc_id`s get expanded.
invocation_macro_rules_scopes: FxHashMap<ExpnId, FxHashSet<MacroRulesScopeRef<'a>>>,
/// Helper attributes that are in scope for the given expansion.
helper_attrs: FxHashMap<ExpnId, Vec<Ident>>,
@ -1310,7 +1307,6 @@ impl<'a> Resolver<'a> {
non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
invocation_parent_scopes: Default::default(),
output_macro_rules_scopes: Default::default(),
invocation_macro_rules_scopes: Default::default(),
helper_attrs: Default::default(),
local_macro_def_scopes: FxHashMap::default(),
name_already_seen: FxHashMap::default(),
@ -1680,7 +1676,20 @@ impl<'a> Resolver<'a> {
!(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive))
}
Scope::DeriveHelpersCompat => true,
Scope::MacroRules(..) => true,
Scope::MacroRules(macro_rules_scope) => {
// Use "path compression" on `macro_rules` scope chains. This is an optimization
// used to avoid long scope chains, see the comments on `MacroRulesScopeRef`.
// As another consequence of this optimization visitors never observe invocation
// scopes for macros that were already expanded.
while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() {
if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) {
macro_rules_scope.set(next_scope.get());
} else {
break;
}
}
true
}
Scope::CrateRoot => true,
Scope::Module(..) => true,
Scope::RegisteredAttrs => use_prelude,
@ -1716,11 +1725,9 @@ impl<'a> Resolver<'a> {
MacroRulesScope::Binding(binding) => {
Scope::MacroRules(binding.parent_macro_rules_scope)
}
MacroRulesScope::Invocation(invoc_id) => Scope::MacroRules(
self.output_macro_rules_scopes.get(&invoc_id).cloned().unwrap_or_else(
|| self.invocation_parent_scopes[&invoc_id].macro_rules,
),
),
MacroRulesScope::Invocation(invoc_id) => {
Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
}
MacroRulesScope::Empty => Scope::Module(module),
},
Scope::CrateRoot => match ns {

View File

@ -62,8 +62,8 @@ pub enum MacroRulesScope<'a> {
}
/// `macro_rules!` scopes are always kept by reference and inside a cell.
/// The reason is that we update all scopes with value `MacroRulesScope::Invocation(invoc_id)`
/// in-place immediately after `invoc_id` gets expanded.
/// The reason is that we update scopes with value `MacroRulesScope::Invocation(invoc_id)`
/// in-place after `invoc_id` gets expanded.
/// This helps to avoid uncontrollable growth of `macro_rules!` scope chains,
/// which usually grow lineraly with the number of macro invocations
/// in a module (including derives) and hurt performance.
@ -173,22 +173,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope);
self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
// Update all `macro_rules` scopes referring to this invocation. This is an optimization
// used to avoid long scope chains, see the comments on `MacroRulesScopeRef`.
if let Some(invocation_scopes) = self.invocation_macro_rules_scopes.remove(&expansion) {
for invocation_scope in &invocation_scopes {
invocation_scope.set(output_macro_rules_scope.get());
}
// All `macro_rules` scopes that previously referred to `expansion`
// are now rerouted to its output scope, if it's also an invocation.
if let MacroRulesScope::Invocation(invoc_id) = output_macro_rules_scope.get() {
self.invocation_macro_rules_scopes
.entry(invoc_id)
.or_default()
.extend(invocation_scopes);
}
}
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
}
@ -687,11 +671,7 @@ impl<'a> Resolver<'a> {
{
Ok((macro_rules_binding.binding, Flags::MACRO_RULES))
}
MacroRulesScope::Invocation(invoc_id)
if !this.output_macro_rules_scopes.contains_key(&invoc_id) =>
{
Err(Determinacy::Undetermined)
}
MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined),
_ => Err(Determinacy::Determined),
},
Scope::CrateRoot => {

View File

@ -1250,7 +1250,7 @@ fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
None => DEFAULT_EDITION,
};
if !edition.is_stable() && !nightly_options::is_nightly_build() {
if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) {
early_error(
ErrorOutputType::default(),
&format!(
@ -1547,7 +1547,9 @@ fn parse_libs(
);
}
};
if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() {
if kind == NativeLibKind::StaticNoBundle
&& !nightly_options::match_is_nightly_build(matches)
{
early_error(
error_format,
"the library kind 'static-nobundle' is only \
@ -1836,10 +1838,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
cg,
error_format,
externs,
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
crate_name,
alt_std_name: None,
libs,
unstable_features: UnstableFeatures::from_environment(),
debug_assertions,
actually_rustdoc: false,
trimmed_def_paths: TrimmedDefPaths::default(),
@ -1960,17 +1962,21 @@ pub mod nightly_options {
use rustc_feature::UnstableFeatures;
pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
match_is_nightly_build(matches)
&& matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
}
pub fn is_nightly_build() -> bool {
UnstableFeatures::from_environment().is_nightly_build()
pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
is_nightly_build(matches.opt_str("crate-name").as_deref())
}
pub fn is_nightly_build(krate: Option<&str>) -> bool {
UnstableFeatures::from_environment(krate).is_nightly_build()
}
pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
let really_allows_unstable_options =
UnstableFeatures::from_environment().is_nightly_build();
let really_allows_unstable_options = match_is_nightly_build(matches);
for opt in flags.iter() {
if opt.stability == OptionStability::Stable {

View File

@ -4,7 +4,7 @@
use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{Lock, Lrc, OnceCell};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{error_code, Applicability, DiagnosticBuilder};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
@ -129,7 +129,6 @@ pub struct ParseSess {
/// operation token that followed it, but that the parser cannot identify without further
/// analysis.
pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
pub injected_crate_name: OnceCell<Symbol>,
pub gated_spans: GatedSpans,
pub symbol_gallery: SymbolGallery,
/// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
@ -150,7 +149,7 @@ impl ParseSess {
pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
Self {
span_diagnostic: handler,
unstable_features: UnstableFeatures::from_environment(),
unstable_features: UnstableFeatures::from_environment(None),
config: FxHashSet::default(),
edition: ExpnId::root().expn_data().edition,
raw_identifier_spans: Lock::new(Vec::new()),
@ -158,7 +157,6 @@ impl ParseSess {
source_map,
buffered_lints: Lock::new(vec![]),
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
injected_crate_name: OnceCell::new(),
gated_spans: GatedSpans::default(),
symbol_gallery: SymbolGallery::default(),
reached_eof: Lock::new(false),

View File

@ -745,6 +745,9 @@ impl Session {
pub fn unstable_options(&self) -> bool {
self.opts.debugging_opts.unstable_options
}
pub fn is_nightly_build(&self) -> bool {
self.opts.unstable_features.is_nightly_build()
}
pub fn overflow_checks(&self) -> bool {
self.opts
.cg

View File

@ -12,7 +12,6 @@ use rustc_infer::infer::{self, InferCtxt, InferOk};
use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::nightly_options;
use rustc_span::Span;
use std::ops::ControlFlow;
@ -602,7 +601,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
};
err.span_label(span, label);
if nightly_options::is_nightly_build() {
if self.tcx.sess.is_nightly_build() {
err.help("add #![feature(member_constraints)] to the crate attributes to enable");
}

View File

@ -1,12 +1,13 @@
use crate::astconv::{
AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, GenericArgPosition,
};
use crate::errors::AssocTypeBindingNotAllowed;
use rustc_ast::ast::ParamKindOrd;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{GenericArg, GenericArgs};
use rustc_hir::GenericArg;
use rustc_middle::ty::{
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
};
@ -90,20 +91,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// instantiate a `GenericArg`.
/// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
/// creates a suitable inference variable.
pub fn create_substs_for_generic_args<'b>(
pub fn create_substs_for_generic_args<'a>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
parent_substs: &[subst::GenericArg<'tcx>],
has_self: bool,
self_ty: Option<Ty<'tcx>>,
arg_count: GenericArgCountResult,
args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool),
mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>,
mut inferred_kind: impl FnMut(
Option<&[subst::GenericArg<'tcx>]>,
&GenericParamDef,
bool,
) -> subst::GenericArg<'tcx>,
ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
) -> SubstsRef<'tcx> {
// Collect the segments of the path; we need to substitute arguments
// for parameters throughout the entire path (wherever there are
@ -142,7 +137,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
substs.push(
self_ty
.map(|ty| ty.into())
.unwrap_or_else(|| inferred_kind(None, param, true)),
.unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
);
params.next();
}
@ -151,7 +146,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
// Check whether this segment takes generic arguments and the user has provided any.
let (generic_args, infer_args) = args_for_def_id(def_id);
let (generic_args, infer_args) = ctx.args_for_def_id(def_id);
let mut args =
generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable();
@ -173,7 +168,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
| (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _)
| (GenericArg::Const(_), GenericParamDefKind::Const, _) => {
substs.push(provided_kind(param, arg));
substs.push(ctx.provided_kind(param, arg));
args.next();
params.next();
}
@ -184,7 +179,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) => {
// We expected a lifetime argument, but got a type or const
// argument. That means we're inferring the lifetimes.
substs.push(inferred_kind(None, param, infer_args));
substs.push(ctx.inferred_kind(None, param, infer_args));
force_infer_lt = Some(arg);
params.next();
}
@ -302,7 +297,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(None, Some(&param)) => {
// If there are fewer arguments than parameters, it means
// we're inferring the remaining arguments.
substs.push(inferred_kind(Some(&substs), param, infer_args));
substs.push(ctx.inferred_kind(Some(&substs), param, infer_args));
params.next();
}

View File

@ -165,6 +165,23 @@ pub struct GenericArgCountResult {
pub correct: Result<(), GenericArgCountMismatch>,
}
pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> {
fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'a>>, bool);
fn provided_kind(
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx>;
fn inferred_kind(
&mut self,
substs: Option<&[subst::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
) -> subst::GenericArg<'tcx>;
}
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
pub fn ast_region_to_region(
&self,
@ -321,81 +338,102 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self);
let default_needs_object_self = |param: &ty::GenericParamDef| {
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
if is_object && has_default {
let default_ty = tcx.at(span).type_of(param.def_id);
let self_param = tcx.types.self_param;
if default_ty.walk().any(|arg| arg == self_param.into()) {
// There is no suitable inference default for a type parameter
// that references self, in an object type.
return true;
struct SubstsForAstPathCtxt<'a, 'tcx> {
astconv: &'a (dyn AstConv<'tcx> + 'a),
def_id: DefId,
generic_args: &'a GenericArgs<'a>,
span: Span,
missing_type_params: Vec<String>,
inferred_params: Vec<Span>,
infer_args: bool,
is_object: bool,
}
impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> {
fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool {
let tcx = self.astconv.tcx();
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
if self.is_object && has_default {
let default_ty = tcx.at(self.span).type_of(param.def_id);
let self_param = tcx.types.self_param;
if default_ty.walk().any(|arg| arg == self_param.into()) {
// There is no suitable inference default for a type parameter
// that references self, in an object type.
return true;
}
}
}
false
}
}
false
};
let mut missing_type_params = vec![];
let mut inferred_params = vec![];
let substs = Self::create_substs_for_generic_args(
tcx,
def_id,
parent_substs,
self_ty.is_some(),
self_ty,
arg_count.clone(),
// Provide the generic args, and whether types should be inferred.
|did| {
if did == def_id {
(Some(generic_args), infer_args)
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) {
if did == self.def_id {
(Some(self.generic_args), self.infer_args)
} else {
// The last component of this tuple is unimportant.
(None, false)
}
},
// Provide substitutions for parameters for which (valid) arguments have been provided.
|param, arg| match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.ast_region_to_region(&lt, Some(param)).into()
}
(GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
if *has_default {
tcx.check_optional_stability(
param.def_id,
Some(arg.id()),
arg.span(),
|_, _| {
// Default generic parameters may not be marked
// with stability attributes, i.e. when the
// default parameter was defined at the same time
// as the rest of the type. As such, we ignore missing
// stability attributes.
}
fn provided_kind(
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.astconv.ast_region_to_region(&lt, Some(param)).into()
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
if has_default {
tcx.check_optional_stability(
param.def_id,
Some(arg.id()),
arg.span(),
|_, _| {
// Default generic parameters may not be marked
// with stability attributes, i.e. when the
// default parameter was defined at the same time
// as the rest of the type. As such, we ignore missing
// stability attributes.
},
)
}
if let (hir::TyKind::Infer, false) =
(&ty.kind, self.astconv.allow_ty_infer())
{
self.inferred_params.push(ty.span);
tcx.ty_error().into()
} else {
self.astconv.ast_ty_to_ty(&ty).into()
}
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
ty::Const::from_opt_const_arg_anon_const(
tcx,
ty::WithOptConstParam {
did: tcx.hir().local_def_id(ct.value.hir_id),
const_param_did: Some(param.def_id),
},
)
.into()
}
if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) {
inferred_params.push(ty.span);
tcx.ty_error().into()
} else {
self.ast_ty_to_ty(&ty).into()
}
_ => unreachable!(),
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
ty::Const::from_opt_const_arg_anon_const(
tcx,
ty::WithOptConstParam {
did: tcx.hir().local_def_id(ct.value.hir_id),
const_param_did: Some(param.def_id),
},
)
.into()
}
_ => unreachable!(),
},
// Provide substitutions for parameters for which arguments are inferred.
|substs, param, infer_args| {
}
fn inferred_kind(
&mut self,
substs: Option<&[subst::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
GenericParamDefKind::Type { has_default, .. } => {
@ -407,48 +445,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// other type parameters may reference `Self` in their
// defaults. This will lead to an ICE if we are not
// careful!
if default_needs_object_self(param) {
missing_type_params.push(param.name.to_string());
if self.default_needs_object_self(param) {
self.missing_type_params.push(param.name.to_string());
tcx.ty_error().into()
} else {
// This is a default type parameter.
self.normalize_ty(
span,
tcx.at(span).type_of(param.def_id).subst_spanned(
tcx,
substs.unwrap(),
Some(span),
),
)
.into()
self.astconv
.normalize_ty(
self.span,
tcx.at(self.span).type_of(param.def_id).subst_spanned(
tcx,
substs.unwrap(),
Some(self.span),
),
)
.into()
}
} else if infer_args {
// No type parameters were provided, we can infer all.
let param =
if !default_needs_object_self(param) { Some(param) } else { None };
self.ty_infer(param, span).into()
let param = if !self.default_needs_object_self(param) {
Some(param)
} else {
None
};
self.astconv.ty_infer(param, self.span).into()
} else {
// We've already errored above about the mismatch.
tcx.ty_error().into()
}
}
GenericParamDefKind::Const => {
let ty = tcx.at(span).type_of(param.def_id);
let ty = tcx.at(self.span).type_of(param.def_id);
// FIXME(const_generics:defaults)
if infer_args {
// No const parameters were provided, we can infer all.
self.ct_infer(ty, Some(param), span).into()
self.astconv.ct_infer(ty, Some(param), self.span).into()
} else {
// We've already errored above about the mismatch.
tcx.const_error(ty).into()
}
}
}
},
}
}
let mut substs_ctx = SubstsForAstPathCtxt {
astconv: self,
def_id,
span,
generic_args,
missing_type_params: vec![],
inferred_params: vec![],
infer_args,
is_object,
};
let substs = Self::create_substs_for_generic_args(
tcx,
def_id,
parent_substs,
self_ty.is_some(),
self_ty,
arg_count.clone(),
&mut substs_ctx,
);
self.complain_about_missing_type_params(
missing_type_params,
substs_ctx.missing_type_params,
def_id,
span,
generic_args.args.is_empty(),

View File

@ -1,5 +1,6 @@
use crate::astconv::{
AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg,
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, PathSeg,
};
use crate::check::callee::{self, DeferredCallResolution};
use crate::check::method::{self, MethodCallee, SelfSource};
@ -1298,6 +1299,94 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
};
struct CreateCtorSubstsContext<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
span: Span,
path_segs: &'a [PathSeg],
infer_args_for_err: &'a FxHashSet<usize>,
segments: &'a [hir::PathSegment<'a>],
}
impl<'tcx, 'a> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for CreateCtorSubstsContext<'a, 'tcx> {
fn args_for_def_id(
&mut self,
def_id: DefId,
) -> (Option<&'a hir::GenericArgs<'a>>, bool) {
if let Some(&PathSeg(_, index)) =
self.path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
{
// If we've encountered an `impl Trait`-related error, we're just
// going to infer the arguments for better error messages.
if !self.infer_args_for_err.contains(&index) {
// Check whether the user has provided generic arguments.
if let Some(ref data) = self.segments[index].args {
return (Some(data), self.segments[index].infer_args);
}
}
return (None, self.segments[index].infer_args);
}
(None, true)
}
fn provided_kind(
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx> {
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.fcx.to_ty(ty).into()
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
self.fcx.const_arg_to_const(&ct.value, param.def_id).into()
}
_ => unreachable!(),
}
}
fn inferred_kind(
&mut self,
substs: Option<&[subst::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
) -> subst::GenericArg<'tcx> {
let tcx = self.fcx.tcx();
match param.kind {
GenericParamDefKind::Lifetime => {
self.fcx.re_infer(Some(param), self.span).unwrap().into()
}
GenericParamDefKind::Type { has_default, .. } => {
if !infer_args && has_default {
// If we have a default, then we it doesn't matter that we're not
// inferring the type arguments: we provide the default where any
// is missing.
let default = tcx.type_of(param.def_id);
self.fcx
.normalize_ty(
self.span,
default.subst_spanned(tcx, substs.unwrap(), Some(self.span)),
)
.into()
} else {
// If no type arguments were provided, we have to infer them.
// This case also occurs as a result of some malformed input, e.g.
// a lifetime argument being given instead of a type parameter.
// Using inference instead of `Error` gives better error messages.
self.fcx.var_for_def(self.span, param)
}
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
// No const parameters were provided, we have to infer them.
self.fcx.var_for_def(self.span, param)
}
}
}
}
let substs = self_ctor_substs.unwrap_or_else(|| {
AstConv::create_substs_for_generic_args(
tcx,
@ -1306,68 +1395,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
has_self,
self_ty,
arg_count,
// Provide the generic args, and whether types should be inferred.
|def_id| {
if let Some(&PathSeg(_, index)) =
path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
{
// If we've encountered an `impl Trait`-related error, we're just
// going to infer the arguments for better error messages.
if !infer_args_for_err.contains(&index) {
// Check whether the user has provided generic arguments.
if let Some(ref data) = segments[index].args {
return (Some(data), segments[index].infer_args);
}
}
return (None, segments[index].infer_args);
}
(None, true)
},
// Provide substitutions for parameters for which (valid) arguments have been provided.
|param, arg| match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
AstConv::ast_region_to_region(self, lt, Some(param)).into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.to_ty(ty).into()
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
self.const_arg_to_const(&ct.value, param.def_id).into()
}
_ => unreachable!(),
},
// Provide substitutions for parameters for which arguments are inferred.
|substs, param, infer_args| {
match param.kind {
GenericParamDefKind::Lifetime => {
self.re_infer(Some(param), span).unwrap().into()
}
GenericParamDefKind::Type { has_default, .. } => {
if !infer_args && has_default {
// If we have a default, then we it doesn't matter that we're not
// inferring the type arguments: we provide the default where any
// is missing.
let default = tcx.type_of(param.def_id);
self.normalize_ty(
span,
default.subst_spanned(tcx, substs.unwrap(), Some(span)),
)
.into()
} else {
// If no type arguments were provided, we have to infer them.
// This case also occurs as a result of some malformed input, e.g.
// a lifetime argument being given instead of a type parameter.
// Using inference instead of `Error` gives better error messages.
self.var_for_def(span, param)
}
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
// No const parameters were provided, we have to infer them.
self.var_for_def(span, param)
}
}
&mut CreateCtorSubstsContext {
fcx: self,
span,
path_segs: &path_segs,
infer_args_for_err: &infer_args_for_err,
segments,
},
)
});

View File

@ -1,6 +1,6 @@
use super::{probe, MethodCallee};
use crate::astconv::AstConv;
use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt};
use crate::check::{callee, FnCtxt};
use crate::hir::def_id::DefId;
use crate::hir::GenericArg;
@ -10,7 +10,7 @@ use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::subst::{self, Subst, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits;
@ -307,6 +307,52 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// parameters from the type and those from the method.
assert_eq!(generics.parent_count, parent_substs.len());
struct MethodSubstsCtxt<'a, 'tcx> {
cfcx: &'a ConfirmContext<'a, 'tcx>,
pick: &'a probe::Pick<'tcx>,
seg: &'a hir::PathSegment<'a>,
}
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> {
fn args_for_def_id(
&mut self,
def_id: DefId,
) -> (Option<&'a hir::GenericArgs<'a>>, bool) {
if def_id == self.pick.item.def_id {
if let Some(ref data) = self.seg.args {
return (Some(data), false);
}
}
(None, false)
}
fn provided_kind(
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx> {
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
AstConv::ast_region_to_region(self.cfcx.fcx, lt, Some(param)).into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.cfcx.to_ty(ty).into()
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
self.cfcx.const_arg_to_const(&ct.value, param.def_id).into()
}
_ => unreachable!(),
}
}
fn inferred_kind(
&mut self,
_substs: Option<&[subst::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
_infer_args: bool,
) -> subst::GenericArg<'tcx> {
self.cfcx.var_for_def(self.cfcx.span, param)
}
}
AstConv::create_substs_for_generic_args(
self.tcx,
pick.item.def_id,
@ -314,29 +360,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
false,
None,
arg_count_correct,
// Provide the generic args, and whether types should be inferred.
|def_id| {
// The last component of the returned tuple here is unimportant.
if def_id == pick.item.def_id {
if let Some(ref data) = seg.args {
return (Some(data), false);
}
}
(None, false)
},
// Provide substitutions for parameters for which (valid) arguments have been provided.
|param, arg| match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => self.to_ty(ty).into(),
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
self.const_arg_to_const(&ct.value, param.def_id).into()
}
_ => unreachable!(),
},
// Provide substitutions for parameters for which arguments are inferred.
|_, param, _| self.var_for_def(self.span, param),
&mut MethodSubstsCtxt { cfcx: self, pick, seg },
)
}

View File

@ -25,7 +25,6 @@ use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{
self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
use rustc_session::config::nightly_options;
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
@ -1272,7 +1271,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.tcx.def_path_str(stable_pick.item.def_id),
));
if nightly_options::is_nightly_build() {
if self.tcx.sess.is_nightly_build() {
for (candidate, feature) in unstable_candidates {
diag.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",

View File

@ -863,6 +863,30 @@ impl<K: Ord, V> BTreeMap<K, V> {
}
}
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
///
/// # Examples
///
/// ```
/// #![feature(btree_retain)]
/// use std::collections::BTreeMap;
///
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x*10)).collect();
/// // Keep only the elements with even-numbered keys.
/// map.retain(|&k, _| k % 2 == 0);
/// assert!(map.into_iter().eq(vec![(0, 0), (2, 20), (4, 40), (6, 60)]));
/// ```
#[inline]
#[unstable(feature = "btree_retain", issue = "79025")]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
self.drain_filter(|k, v| !f(k, v));
}
/// Moves all elements from `other` into `Self`, leaving `other` empty.
///
/// # Examples

View File

@ -808,6 +808,17 @@ fn test_range_mut() {
map.check();
}
#[test]
fn test_retain() {
let mut map: BTreeMap<i32, i32> = (0..100).map(|x| (x, x * 10)).collect();
map.retain(|&k, _| k % 2 == 0);
assert_eq!(map.len(), 50);
assert_eq!(map[&2], 20);
assert_eq!(map[&4], 40);
assert_eq!(map[&6], 60);
}
mod test_drain_filter {
use super::*;

View File

@ -798,6 +798,30 @@ impl<T: Ord> BTreeSet<T> {
Recover::take(&mut self.map, value)
}
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
///
/// # Examples
///
/// ```
/// #![feature(btree_retain)]
/// use std::collections::BTreeSet;
///
/// let xs = [1, 2, 3, 4, 5, 6];
/// let mut set: BTreeSet<i32> = xs.iter().cloned().collect();
/// // Keep only the even numbers.
/// set.retain(|&k| k % 2 == 0);
/// assert!(set.iter().eq([2, 4, 6].iter()));
/// ```
#[unstable(feature = "btree_retain", issue = "79025")]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
{
self.drain_filter(|v| !f(v));
}
/// Moves all elements from `other` into `Self`, leaving `other` empty.
///
/// # Examples

View File

@ -324,6 +324,17 @@ fn test_is_subset() {
assert_eq!(is_subset(&[99, 100], &large), false);
}
#[test]
fn test_retain() {
let xs = [1, 2, 3, 4, 5, 6];
let mut set: BTreeSet<i32> = xs.iter().cloned().collect();
set.retain(|&k| k % 2 == 0);
assert_eq!(set.len(), 3);
assert!(set.contains(&2));
assert!(set.contains(&4));
assert!(set.contains(&6));
}
#[test]
fn test_drain_filter() {
let mut x: BTreeSet<_> = [1].iter().copied().collect();

View File

@ -19,7 +19,7 @@ use crate::compile;
use crate::config::TargetSelection;
use crate::dist;
use crate::doc;
use crate::flags::Subcommand;
use crate::flags::{Color, Subcommand};
use crate::install;
use crate::native;
use crate::run;
@ -811,6 +811,16 @@ impl<'a> Builder<'a> {
cargo.env("REAL_LIBRARY_PATH", e);
}
match self.build.config.color {
Color::Always => {
cargo.arg("--color=always");
}
Color::Never => {
cargo.arg("--color=never");
}
Color::Auto => {} // nothing to do
}
if cmd != "install" {
cargo.arg("--target").arg(target.rustc_target_arg());
} else {

View File

@ -232,6 +232,11 @@ impl Step for CodegenBackend {
.arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
rustc_cargo_env(builder, &mut cargo, target);
builder.info(&format!(
"Checking {} artifacts ({} -> {})",
backend, &compiler.host.triple, target.triple
));
run_cargo(
builder,
cargo,

View File

@ -13,8 +13,8 @@ use std::path::{Path, PathBuf};
use std::str::FromStr;
use crate::cache::{Interned, INTERNER};
use crate::flags::Flags;
pub use crate::flags::Subcommand;
use crate::flags::{Color, Flags};
use crate::util::exe;
use build_helper::t;
use merge::Merge;
@ -67,6 +67,7 @@ pub struct Config {
pub json_output: bool,
pub test_compare_mode: bool,
pub llvm_libunwind: Option<LlvmLibunwind>,
pub color: Color,
pub on_fail: Option<String>,
pub stage: u32,
@ -577,6 +578,7 @@ impl Config {
config.keep_stage = flags.keep_stage;
config.keep_stage_std = flags.keep_stage_std;
config.bindir = "bin".into(); // default
config.color = flags.color;
if let Some(value) = flags.deny_warnings {
config.deny_warnings = value;
}

View File

@ -15,6 +15,31 @@ use crate::config::{Config, TargetSelection};
use crate::setup::Profile;
use crate::{Build, DocTests};
pub enum Color {
Always,
Never,
Auto,
}
impl Default for Color {
fn default() -> Self {
Self::Auto
}
}
impl std::str::FromStr for Color {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"always" => Ok(Self::Always),
"never" => Ok(Self::Never),
"auto" => Ok(Self::Auto),
_ => Err(()),
}
}
}
/// Deserialized version of all flags for this compile.
pub struct Flags {
pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo
@ -34,6 +59,7 @@ pub struct Flags {
pub rustc_error_format: Option<String>,
pub json_output: bool,
pub dry_run: bool,
pub color: Color,
// This overrides the deny-warnings configuration option,
// which passes -Dwarnings to the compiler invocations.
@ -184,6 +210,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
);
opts.optopt("", "error-format", "rustc error format", "FORMAT");
opts.optflag("", "json-output", "use message-format=json");
opts.optopt("", "color", "whether to use color in cargo and rustc output", "STYLE");
opts.optopt(
"",
"llvm-skip-rebuild",
@ -644,6 +671,9 @@ Arguments:
llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map(
|s| s.parse::<bool>().expect("`llvm-skip-rebuild` should be either true or false"),
),
color: matches
.opt_get_default("color", Color::Auto)
.expect("`color` should be `always`, `never`, or `auto`"),
}
}
}

View File

@ -125,7 +125,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
def_id: self.cx.next_def_id(param_env_def_id.krate),
stability: None,
deprecation: None,
inner: ImplItem(Impl {
kind: ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: new_generics,
provided_trait_methods: Default::default(),

View File

@ -114,7 +114,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
def_id: self.cx.next_def_id(impl_def_id.krate),
stability: None,
deprecation: None,
inner: ImplItem(Impl {
kind: ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: (
self.cx.tcx.generics_of(impl_def_id),

View File

@ -54,7 +54,7 @@ crate fn try_inline(
debug!("attrs={:?}", attrs);
let attrs_clone = attrs;
let inner = match res {
let kind = match res {
Res::Def(DefKind::Trait, did) => {
record_extern_fqn(cx, did, clean::TypeKind::Trait);
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
@ -128,7 +128,7 @@ crate fn try_inline(
source: cx.tcx.def_span(did).clean(cx),
name: Some(name.clean(cx)),
attrs,
inner,
kind,
visibility: clean::Public,
stability: cx.tcx.lookup_stability(did).cloned(),
deprecation: cx.tcx.lookup_deprecation(did).clean(cx),
@ -446,7 +446,7 @@ crate fn build_impl(
debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
ret.push(clean::Item {
inner: clean::ImplItem(clean::Impl {
kind: clean::ImplItem(clean::Impl {
unsafety: hir::Unsafety::Normal,
generics,
provided_trait_methods: provided,
@ -498,7 +498,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>)
visibility: clean::Public,
stability: None,
deprecation: None,
inner: clean::ImportItem(clean::Import::new_simple(
kind: clean::ImportItem(clean::Import::new_simple(
item.ident.to_string(),
clean::ImportSource {
path: clean::Path {
@ -555,7 +555,7 @@ fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static
}
}
fn build_macro(cx: &DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemEnum {
fn build_macro(cx: &DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
let imported_from = cx.tcx.original_crate_name(did.krate);
match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
LoadedMacro::MacroDef(def, _) => {

View File

@ -42,7 +42,7 @@ use utils::*;
pub use utils::{get_auto_trait_and_blanket_impls, krate, register_res};
pub use self::types::FnRetTy::*;
pub use self::types::ItemEnum::*;
pub use self::types::ItemKind::*;
pub use self::types::SelfTy::*;
pub use self::types::Type::*;
pub use self::types::Visibility::{Inherited, Public};
@ -276,7 +276,7 @@ impl Clean<Item> for doctree::Module<'_> {
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
inner: ModuleItem(Module { is_crate: self.is_crate, items }),
kind: ModuleItem(Module { is_crate: self.is_crate, items }),
}
}
}
@ -916,7 +916,7 @@ impl Clean<Item> for doctree::Function<'_> {
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
def_id: did.to_def_id(),
inner: FunctionItem(Function {
kind: FunctionItem(Function {
decl,
generics,
header: hir::FnHeader { constness, ..self.header },
@ -1023,7 +1023,7 @@ impl Clean<Item> for doctree::Trait<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: TraitItem(Trait {
kind: TraitItem(Trait {
auto: self.is_auto.clean(cx),
unsafety: self.unsafety,
items: self.items.iter().map(|ti| ti.clean(cx)).collect(),
@ -1047,7 +1047,7 @@ impl Clean<Item> for doctree::TraitAlias<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: TraitAliasItem(TraitAlias {
kind: TraitAliasItem(TraitAlias {
generics: self.generics.clean(cx),
bounds: self.bounds.clean(cx),
}),
@ -1102,7 +1102,7 @@ impl Clean<TypeKind> for hir::def::DefKind {
impl Clean<Item> for hir::TraitItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let local_did = cx.tcx.hir().local_def_id(self.hir_id);
let inner = match self.kind {
let kind = match self.kind {
hir::TraitItemKind::Const(ref ty, default) => {
AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e)))
}
@ -1140,7 +1140,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
visibility: Visibility::Inherited,
stability: get_stability(cx, local_did.to_def_id()),
deprecation: get_deprecation(cx, local_did.to_def_id()),
inner,
kind,
}
}
}
@ -1148,7 +1148,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
impl Clean<Item> for hir::ImplItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let local_did = cx.tcx.hir().local_def_id(self.hir_id);
let inner = match self.kind {
let kind = match self.kind {
hir::ImplItemKind::Const(ref ty, expr) => {
AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr)))
}
@ -1175,14 +1175,14 @@ impl Clean<Item> for hir::ImplItem<'_> {
visibility: self.vis.clean(cx),
stability: get_stability(cx, local_did.to_def_id()),
deprecation: get_deprecation(cx, local_did.to_def_id()),
inner,
kind,
}
}
}
impl Clean<Item> for ty::AssocItem {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.kind {
let kind = match self.kind {
ty::AssocKind::Const => {
let ty = cx.tcx.type_of(self.def_id);
let default = if self.defaultness.has_value() {
@ -1343,7 +1343,7 @@ impl Clean<Item> for ty::AssocItem {
def_id: self.def_id,
attrs: inline::load_attrs(cx, self.def_id).clean(cx),
source: cx.tcx.def_span(self.def_id).clean(cx),
inner,
kind,
}
}
}
@ -1784,7 +1784,7 @@ impl Clean<Item> for hir::StructField<'_> {
stability: get_stability(cx, local_did.to_def_id()),
deprecation: get_deprecation(cx, local_did.to_def_id()),
def_id: local_did.to_def_id(),
inner: StructFieldItem(self.ty.clean(cx)),
kind: StructFieldItem(self.ty.clean(cx)),
}
}
}
@ -1799,7 +1799,7 @@ impl Clean<Item> for ty::FieldDef {
stability: get_stability(cx, self.did),
deprecation: get_deprecation(cx, self.did),
def_id: self.did,
inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
kind: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
}
}
}
@ -1835,7 +1835,7 @@ impl Clean<Item> for doctree::Struct<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: StructItem(Struct {
kind: StructItem(Struct {
struct_type: self.struct_type,
generics: self.generics.clean(cx),
fields: self.fields.clean(cx),
@ -1855,7 +1855,7 @@ impl Clean<Item> for doctree::Union<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: UnionItem(Union {
kind: UnionItem(Union {
struct_type: self.struct_type,
generics: self.generics.clean(cx),
fields: self.fields.clean(cx),
@ -1885,7 +1885,7 @@ impl Clean<Item> for doctree::Enum<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: EnumItem(Enum {
kind: EnumItem(Enum {
variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
generics: self.generics.clean(cx),
variants_stripped: false,
@ -1904,7 +1904,7 @@ impl Clean<Item> for doctree::Variant<'_> {
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
inner: VariantItem(Variant { kind: self.def.clean(cx) }),
kind: VariantItem(Variant { kind: self.def.clean(cx) }),
}
}
}
@ -1930,7 +1930,7 @@ impl Clean<Item> for ty::VariantDef {
def_id: field.did,
stability: get_stability(cx, field.did),
deprecation: get_deprecation(cx, field.did),
inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx)),
kind: StructFieldItem(cx.tcx.type_of(field.did).clean(cx)),
})
.collect(),
}),
@ -1941,7 +1941,7 @@ impl Clean<Item> for ty::VariantDef {
source: cx.tcx.def_span(self.def_id).clean(cx),
visibility: Inherited,
def_id: self.def_id,
inner: VariantItem(Variant { kind }),
kind: VariantItem(Variant { kind }),
stability: get_stability(cx, self.def_id),
deprecation: get_deprecation(cx, self.def_id),
}
@ -2057,7 +2057,7 @@ impl Clean<Item> for doctree::Typedef<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false),
kind: TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false),
}
}
}
@ -2072,7 +2072,7 @@ impl Clean<Item> for doctree::OpaqueTy<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: OpaqueTyItem(OpaqueTy {
kind: OpaqueTyItem(OpaqueTy {
bounds: self.opaque_ty.bounds.clean(cx),
generics: self.opaque_ty.generics.clean(cx),
}),
@ -2100,7 +2100,7 @@ impl Clean<Item> for doctree::Static<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: StaticItem(Static {
kind: StaticItem(Static {
type_: self.type_.clean(cx),
mutability: self.mutability,
expr: print_const_expr(cx, self.expr),
@ -2121,7 +2121,7 @@ impl Clean<Item> for doctree::Constant<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: ConstantItem(Constant {
kind: ConstantItem(Constant {
type_: self.type_.clean(cx),
expr: print_const_expr(cx, self.expr),
value: print_evaluated_const(cx, def_id.to_def_id()),
@ -2175,7 +2175,7 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner: ImplItem(Impl {
kind: ImplItem(Impl {
unsafety: self.unsafety,
generics: self.generics.clean(cx),
provided_trait_methods: provided.clone(),
@ -2231,7 +2231,7 @@ impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
visibility: self.vis.clean(cx),
stability: None,
deprecation: None,
inner: ExternCrateItem(self.name.clean(cx), self.path.clone()),
kind: ExternCrateItem(self.name.clean(cx), self.path.clone()),
}]
}
}
@ -2302,7 +2302,7 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
visibility: self.vis.clean(cx),
stability: None,
deprecation: None,
inner: ImportItem(Import::new_simple(
kind: ImportItem(Import::new_simple(
self.name.clean(cx),
resolve_use_source(cx, path),
false,
@ -2322,14 +2322,14 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
visibility: self.vis.clean(cx),
stability: None,
deprecation: None,
inner: ImportItem(inner),
kind: ImportItem(inner),
}]
}
}
impl Clean<Item> for doctree::ForeignItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.kind {
let kind = match self.kind {
hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
let abi = cx.tcx.hir().get_foreign_abi(self.id);
let (generics, decl) =
@ -2364,7 +2364,7 @@ impl Clean<Item> for doctree::ForeignItem<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
inner,
kind,
}
}
}
@ -2380,7 +2380,7 @@ impl Clean<Item> for doctree::Macro<'_> {
stability: cx.stability(self.hid),
deprecation: cx.deprecation(self.hid).clean(cx),
def_id: self.def_id,
inner: MacroItem(Macro {
kind: MacroItem(Macro {
source: format!(
"macro_rules! {} {{\n{}}}",
name,
@ -2405,7 +2405,7 @@ impl Clean<Item> for doctree::ProcMacro<'_> {
stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
inner: ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx) }),
kind: ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx) }),
}
}
}

View File

@ -41,7 +41,7 @@ use crate::formats::item_type::ItemType;
use crate::html::render::cache::ExternalLocation;
use self::FnRetTy::*;
use self::ItemEnum::*;
use self::ItemKind::*;
use self::SelfTy::*;
use self::Type::*;
@ -81,7 +81,7 @@ pub struct Item {
/// Not everything has a name. E.g., impls
pub name: Option<String>,
pub attrs: Attributes,
pub inner: ItemEnum,
pub kind: ItemKind,
pub visibility: Visibility,
pub def_id: DefId,
pub stability: Option<Stability>,
@ -90,14 +90,13 @@ pub struct Item {
impl fmt::Debug for Item {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let fake = self.is_fake();
let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };
let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
fmt.debug_struct("Item")
.field("source", &self.source)
.field("name", &self.name)
.field("attrs", &self.attrs)
.field("inner", &self.inner)
.field("kind", &self.kind)
.field("visibility", &self.visibility)
.field("def_id", def_id)
.field("stability", &self.stability)
@ -124,7 +123,7 @@ impl Item {
}
pub fn is_crate(&self) -> bool {
match self.inner {
match self.kind {
StrippedItem(box ModuleItem(Module { is_crate: true, .. }))
| ModuleItem(Module { is_crate: true, .. }) => true,
_ => false,
@ -176,14 +175,14 @@ impl Item {
self.type_() == ItemType::Keyword
}
pub fn is_stripped(&self) -> bool {
match self.inner {
match self.kind {
StrippedItem(..) => true,
ImportItem(ref i) => !i.should_be_displayed,
_ => false,
}
}
pub fn has_stripped_fields(&self) -> Option<bool> {
match self.inner {
match self.kind {
StructItem(ref _struct) => Some(_struct.fields_stripped),
UnionItem(ref union) => Some(union.fields_stripped),
VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => {
@ -227,8 +226,8 @@ impl Item {
}
pub fn is_default(&self) -> bool {
match self.inner {
ItemEnum::MethodItem(ref meth) => {
match self.kind {
ItemKind::MethodItem(ref meth) => {
if let Some(defaultness) = meth.defaultness {
defaultness.has_value() && !defaultness.is_final()
} else {
@ -248,7 +247,7 @@ impl Item {
}
#[derive(Clone, Debug)]
pub enum ItemEnum {
pub enum ItemKind {
ExternCrateItem(String, Option<String>),
ImportItem(Import),
StructItem(Struct),
@ -282,23 +281,23 @@ pub enum ItemEnum {
AssocConstItem(Type, Option<String>),
AssocTypeItem(Vec<GenericBound>, Option<Type>),
/// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemEnum>),
StrippedItem(Box<ItemKind>),
KeywordItem(String),
}
impl ItemEnum {
impl ItemKind {
pub fn is_type_alias(&self) -> bool {
match *self {
ItemEnum::TypedefItem(_, _) | ItemEnum::AssocTypeItem(_, _) => true,
ItemKind::TypedefItem(_, _) | ItemKind::AssocTypeItem(_, _) => true,
_ => false,
}
}
pub fn as_assoc_kind(&self) -> Option<AssocKind> {
match *self {
ItemEnum::AssocConstItem(..) => Some(AssocKind::Const),
ItemEnum::AssocTypeItem(..) => Some(AssocKind::Type),
ItemEnum::TyMethodItem(..) | ItemEnum::MethodItem(..) => Some(AssocKind::Fn),
ItemKind::AssocConstItem(..) => Some(AssocKind::Const),
ItemKind::AssocTypeItem(..) => Some(AssocKind::Type),
ItemKind::TyMethodItem(..) | ItemKind::MethodItem(..) => Some(AssocKind::Fn),
_ => None,
}
}
@ -681,7 +680,9 @@ impl Attributes {
}
Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(),
Some(&(_, _, ExternalLocation::Unknown)) | None => String::from(
if UnstableFeatures::from_environment().is_nightly_build() {
// NOTE: intentionally doesn't pass crate name to avoid having
// different primitive links between crates
if UnstableFeatures::from_environment(None).is_nightly_build() {
"https://doc.rust-lang.org/nightly"
} else {
"https://doc.rust-lang.org"

View File

@ -2,7 +2,7 @@ use crate::clean::auto_trait::AutoTraitFinder;
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg,
GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, Lifetime,
GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemKind, Lifetime,
MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Type, TypeBinding,
TypeKind, Visibility, WherePredicate,
};
@ -44,8 +44,8 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
let mut module = module.clean(cx);
let mut masked_crates = FxHashSet::default();
match module.inner {
ItemEnum::ModuleItem(ref module) => {
match module.kind {
ItemKind::ModuleItem(ref module) => {
for it in &module.items {
// `compiler_builtins` should be masked too, but we can't apply
// `#[doc(masked)]` to the injected `extern crate` because it's unstable.
@ -62,8 +62,8 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
{
let m = match module.inner {
ItemEnum::ModuleItem(ref mut m) => m,
let m = match module.kind {
ItemKind::ModuleItem(ref mut m) => m,
_ => unreachable!(),
};
m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| Item {
@ -74,7 +74,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
stability: get_stability(cx, def_id),
deprecation: get_deprecation(cx, def_id),
def_id,
inner: ItemEnum::PrimitiveItem(prim),
kind: ItemKind::PrimitiveItem(prim),
}));
m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| Item {
source: Span::empty(),
@ -84,7 +84,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
stability: get_stability(cx, def_id),
deprecation: get_deprecation(cx, def_id),
def_id,
inner: ItemEnum::KeywordItem(kw),
kind: ItemKind::KeywordItem(kw),
}));
}
@ -355,8 +355,8 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V
let tcx = cx.tcx;
for item in items {
let target = match item.inner {
ItemEnum::TypedefItem(ref t, true) => &t.type_,
let target = match item.kind {
ItemKind::TypedefItem(ref t, true) => &t.type_,
_ => continue,
};
let primitive = match *target {

View File

@ -257,6 +257,7 @@ pub struct RenderOptions {
pub document_private: bool,
/// Document items that have `doc(hidden)`.
pub document_hidden: bool,
pub unstable_features: rustc_feature::UnstableFeatures,
}
/// Temporary storage for data obtained during `RustdocVisitor::clean()`.
@ -299,7 +300,7 @@ impl Options {
println_condition(p.condition);
}
if nightly_options::is_nightly_build() {
if nightly_options::match_is_nightly_build(matches) {
println!("\nPasses run with `--show-coverage`:");
for p in passes::COVERAGE_PASSES {
print!("{:>20}", p.pass.name);
@ -483,6 +484,7 @@ impl Options {
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
&matches.opt_strs("markdown-after-content"),
nightly_options::match_is_nightly_build(&matches),
&diag,
&mut id_map,
edition,
@ -539,7 +541,9 @@ impl Options {
let output_format = match matches.opt_str("output-format") {
Some(s) => match OutputFormat::try_from(s.as_str()) {
Ok(o) => {
if o.is_json() && !(show_coverage || nightly_options::is_nightly_build()) {
if o.is_json()
&& !(show_coverage || nightly_options::match_is_nightly_build(matches))
{
diag.struct_err("json output format isn't supported for doc generation")
.emit();
return Err(1);
@ -591,7 +595,6 @@ impl Options {
Ok(Options {
input,
crate_name,
proc_macro_crate,
error_format,
libs,
@ -643,7 +646,11 @@ impl Options {
generate_search_filter,
document_private,
document_hidden,
unstable_features: rustc_feature::UnstableFeatures::from_environment(
crate_name.as_deref(),
),
},
crate_name,
output_format,
})
}
@ -661,7 +668,8 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han
for flag in deprecated_flags.iter() {
if matches.opt_present(flag) {
if *flag == "output-format"
&& (matches.opt_present("show-coverage") || nightly_options::is_nightly_build())
&& (matches.opt_present("show-coverage")
|| nightly_options::match_is_nightly_build(matches))
{
continue;
}

View File

@ -371,7 +371,7 @@ pub fn run_core(
cg: codegen_options,
externs,
target_triple: target,
unstable_features: UnstableFeatures::from_environment(),
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
actually_rustdoc: true,
debugging_opts,
error_format,

View File

@ -1,7 +1,6 @@
use rustc_ast as ast;
use rustc_data_structures::sync::Lrc;
use rustc_errors::ErrorReported;
use rustc_feature::UnstableFeatures;
use rustc_hir as hir;
use rustc_hir::intravisit;
use rustc_hir::{HirId, CRATE_HIR_ID};
@ -70,7 +69,7 @@ pub fn run(options: Options) -> Result<(), ErrorReported> {
lint_cap: Some(options.lint_cap.clone().unwrap_or_else(|| lint::Forbid)),
cg: options.codegen_options.clone(),
externs: options.externs.clone(),
unstable_features: UnstableFeatures::from_environment(),
unstable_features: options.render_options.unstable_features,
actually_rustdoc: true,
debugging_opts: config::DebuggingOptions { ..config::basic_debugging_options() },
edition: options.edition,

View File

@ -1,6 +1,5 @@
use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
use crate::rustc_span::edition::Edition;
use rustc_feature::UnstableFeatures;
use std::fs;
use std::path::Path;
use std::str;
@ -25,12 +24,13 @@ impl ExternalHtml {
after_content: &[String],
md_before_content: &[String],
md_after_content: &[String],
nightly_build: bool,
diag: &rustc_errors::Handler,
id_map: &mut IdMap,
edition: Edition,
playground: &Option<Playground>,
) -> Option<ExternalHtml> {
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let codes = ErrorCodes::from(nightly_build);
let ih = load_external_files(in_header, diag)?;
let bc = load_external_files(before_content, diag)?;
let m_bc = load_external_files(md_before_content, diag)?;

View File

@ -5,9 +5,9 @@ pub struct StripItem(pub Item);
impl StripItem {
pub fn strip(self) -> Option<Item> {
match self.0 {
Item { inner: StrippedItem(..), .. } => Some(self.0),
Item { kind: StrippedItem(..), .. } => Some(self.0),
mut i => {
i.inner = StrippedItem(box i.inner);
i.kind = StrippedItem(box i.kind);
Some(i)
}
}
@ -20,8 +20,8 @@ pub trait DocFolder: Sized {
}
/// don't override!
fn fold_inner_recur(&mut self, inner: ItemEnum) -> ItemEnum {
match inner {
fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
match kind {
StrippedItem(..) => unreachable!(),
ModuleItem(i) => ModuleItem(self.fold_mod(i)),
StructItem(mut i) => {
@ -72,14 +72,14 @@ pub trait DocFolder: Sized {
/// don't override!
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item;
let Item { attrs, name, source, visibility, def_id, kind, stability, deprecation } = item;
let inner = match inner {
let kind = match kind {
StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
_ => self.fold_inner_recur(inner),
_ => self.fold_inner_recur(kind),
};
Some(Item { attrs, name, source, inner, visibility, stability, deprecation, def_id })
Some(Item { attrs, name, source, kind, visibility, stability, deprecation, def_id })
}
fn fold_mod(&mut self, m: Module) -> Module {

View File

@ -218,7 +218,7 @@ impl DocFolder for Cache {
// If this is a stripped module,
// we don't want it or its children in the search index.
let orig_stripped_mod = match item.inner {
let orig_stripped_mod = match item.kind {
clean::StrippedItem(box clean::ModuleItem(..)) => {
mem::replace(&mut self.stripped_mod, true)
}
@ -227,7 +227,7 @@ impl DocFolder for Cache {
// If the impl is from a masked crate or references something from a
// masked crate then remove it completely.
if let clean::ImplItem(ref i) = item.inner {
if let clean::ImplItem(ref i) = item.kind {
if self.masked_crates.contains(&item.def_id.krate)
|| i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate))
|| i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate))
@ -238,12 +238,12 @@ impl DocFolder for Cache {
// Propagate a trait method's documentation to all implementors of the
// trait.
if let clean::TraitItem(ref t) = item.inner {
if let clean::TraitItem(ref t) = item.kind {
self.traits.entry(item.def_id).or_insert_with(|| t.clone());
}
// Collect all the implementors of traits.
if let clean::ImplItem(ref i) = item.inner {
if let clean::ImplItem(ref i) = item.kind {
if let Some(did) = i.trait_.def_id() {
if i.blanket_impl.is_none() {
self.implementors
@ -256,7 +256,7 @@ impl DocFolder for Cache {
// Index this method for searching later on.
if let Some(ref s) = item.name {
let (parent, is_inherent_impl_item) = match item.inner {
let (parent, is_inherent_impl_item) = match item.kind {
clean::StrippedItem(..) => ((None, None), false),
clean::AssocConstItem(..) | clean::TypedefItem(_, true)
if self.parent_is_trait_impl =>
@ -345,7 +345,7 @@ impl DocFolder for Cache {
_ => false,
};
match item.inner {
match item.kind {
clean::StructItem(..)
| clean::EnumItem(..)
| clean::TypedefItem(..)
@ -384,7 +384,7 @@ impl DocFolder for Cache {
// Maintain the parent stack
let orig_parent_is_trait_impl = self.parent_is_trait_impl;
let parent_pushed = match item.inner {
let parent_pushed = match item.kind {
clean::TraitItem(..)
| clean::EnumItem(..)
| clean::ForeignTypeItem
@ -422,12 +422,12 @@ impl DocFolder for Cache {
// Once we've recursively found all the generics, hoard off all the
// implementations elsewhere.
let ret = self.fold_item_recur(item).and_then(|item| {
if let clean::Item { inner: clean::ImplItem(_), .. } = item {
if let clean::Item { kind: clean::ImplItem(_), .. } = item {
// Figure out the id of this impl. This may map to a
// primitive rather than always to a struct/enum.
// Note: matching twice to restrict the lifetime of the `i` borrow.
let mut dids = FxHashSet::default();
if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
if let clean::Item { kind: clean::ImplItem(ref i), .. } = item {
match i.for_ {
clean::ResolvedPath { did, .. }
| clean::BorrowedRef {

View File

@ -60,12 +60,12 @@ impl Serialize for ItemType {
impl<'a> From<&'a clean::Item> for ItemType {
fn from(item: &'a clean::Item) -> ItemType {
let inner = match item.inner {
let kind = match item.kind {
clean::StrippedItem(box ref item) => item,
ref inner => inner,
ref kind => kind,
};
match *inner {
match *kind {
clean::ModuleItem(..) => ItemType::Module,
clean::ExternCrateItem(..) => ItemType::ExternCrate,
clean::ImportItem(..) => ItemType::Import,

View File

@ -32,7 +32,7 @@ pub struct Impl {
impl Impl {
pub fn inner_impl(&self) -> &clean::Impl {
match self.impl_item.inner {
match self.impl_item.kind {
clean::ImplItem(ref impl_) => impl_,
_ => panic!("non-impl item found in impl"),
}

View File

@ -86,7 +86,7 @@ pub fn run_format<T: FormatRenderer>(
}
cx.mod_item_in(&item, &name, &cache)?;
let module = match item.inner {
let module = match item.kind {
clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m,
_ => unreachable!(),
};

View File

@ -165,7 +165,7 @@ pub fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
}
crate fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
let (all_types, ret_types) = match item.inner {
let (all_types, ret_types) = match item.kind {
clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
clean::MethodItem(ref m) => (&m.all_types, &m.ret_types),
clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),

View File

@ -52,7 +52,6 @@ use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel;
use rustc_data_structures::flock;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_feature::UnstableFeatures;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::Mutability;
@ -397,6 +396,7 @@ impl FormatRenderer for Context {
resource_suffix,
static_root_path,
generate_search_filter,
unstable_features,
..
} = options;
@ -466,7 +466,7 @@ impl FormatRenderer for Context {
static_root_path,
fs: DocFS::new(sender),
edition,
codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
codes: ErrorCodes::from(unstable_features.is_nightly_build()),
playground,
};
@ -618,7 +618,7 @@ impl FormatRenderer for Context {
// Render sidebar-items.js used throughout this module.
if !self.render_redirect_pages {
let module = match item.inner {
let module = match item.kind {
clean::StrippedItem(box clean::ModuleItem(ref m)) | clean::ModuleItem(ref m) => m,
_ => unreachable!(),
};
@ -1717,7 +1717,7 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache)
write!(buf, "</span>"); // out-of-band
write!(buf, "<span class=\"in-band\">");
let name = match item.inner {
let name = match item.kind {
clean::ModuleItem(ref m) => {
if m.is_crate {
"Crate "
@ -1766,7 +1766,7 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache)
write!(buf, "</span></h1>"); // in-band
match item.inner {
match item.kind {
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
item_function(buf, cx, item, f)
@ -2133,7 +2133,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
);
}
match myitem.inner {
match myitem.kind {
clean::ExternCrateItem(ref name, ref src) => {
use crate::html::format::anchor;
@ -2169,7 +2169,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
continue;
}
let unsafety_flag = match myitem.inner {
let unsafety_flag = match myitem.kind {
clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
if func.header.unsafety == hir::Unsafety::Unsafe =>
{
@ -2582,7 +2582,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
}
for (pos, m) in provided.iter().enumerate() {
render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
match m.inner {
match m.kind {
clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => {
write!(w, ",\n {{ ... }}\n");
}
@ -2958,7 +2958,7 @@ fn render_assoc_item(
where_clause = WhereClause { gens: g, indent, end_newline }
)
}
match item.inner {
match item.kind {
clean::StrippedItem(..) => {}
clean::TyMethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent),
clean::MethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent),
@ -2994,7 +2994,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct
let mut fields = s
.fields
.iter()
.filter_map(|f| match f.inner {
.filter_map(|f| match f.kind {
clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None,
})
@ -3044,7 +3044,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union,
let mut fields = s
.fields
.iter()
.filter_map(|f| match f.inner {
.filter_map(|f| match f.kind {
clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None,
})
@ -3097,7 +3097,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca
for v in &e.variants {
write!(w, " ");
let name = v.name.as_ref().unwrap();
match v.inner {
match v.kind {
clean::VariantItem(ref var) => match var.kind {
clean::VariantKind::CLike => write!(w, "{}", name),
clean::VariantKind::Tuple(ref tys) => {
@ -3147,7 +3147,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca
id = id,
name = variant.name.as_ref().unwrap()
);
if let clean::VariantItem(ref var) = variant.inner {
if let clean::VariantItem(ref var) = variant.kind {
if let clean::VariantKind::Tuple(ref tys) = var.kind {
write!(w, "(");
for (i, ty) in tys.iter().enumerate() {
@ -3164,8 +3164,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca
document_non_exhaustive(w, variant);
use crate::clean::{Variant, VariantKind};
if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = variant.inner
{
if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = variant.kind {
let variant_id = cx.derive_id(format!(
"{}.{}.fields",
ItemType::Variant,
@ -3179,7 +3178,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca
);
for field in &s.fields {
use crate::clean::StructFieldItem;
if let StructFieldItem(ref ty) = field.inner {
if let StructFieldItem(ref ty) = field.kind {
let id = cx.derive_id(format!(
"variant.{}.field.{}",
variant.name.as_ref().unwrap(),
@ -3275,7 +3274,7 @@ fn render_struct(
let mut has_visible_fields = false;
write!(w, " {{");
for field in fields {
if let clean::StructFieldItem(ref ty) = field.inner {
if let clean::StructFieldItem(ref ty) = field.kind {
write!(
w,
"\n{} {}{}: {},",
@ -3306,7 +3305,7 @@ fn render_struct(
if i > 0 {
write!(w, ", ");
}
match field.inner {
match field.kind {
clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
clean::StructFieldItem(ref ty) => {
write!(w, "{}{}", field.visibility.print_with_space(), ty.print())
@ -3352,7 +3351,7 @@ fn render_union(
write!(w, " {{\n{}", tab);
for field in fields {
if let clean::StructFieldItem(ref ty) = field.inner {
if let clean::StructFieldItem(ref ty) = field.kind {
write!(
w,
" {}{}: {},\n{}",
@ -3516,7 +3515,7 @@ fn render_deref_methods(
.inner_impl()
.items
.iter()
.find_map(|item| match item.inner {
.find_map(|item| match item.kind {
clean::TypedefItem(ref t, true) => Some(match *t {
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
_ => (&t.type_, &t.type_),
@ -3538,7 +3537,7 @@ fn render_deref_methods(
}
fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
let self_type_opt = match item.inner {
let self_type_opt = match item.kind {
clean::MethodItem(ref method) => method.decl.self_type(),
clean::TyMethodItem(ref method) => method.decl.self_type(),
_ => None,
@ -3589,7 +3588,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
));
let t_did = impl_.trait_.def_id().unwrap();
for it in &impl_.items {
if let clean::TypedefItem(ref tydef, _) = it.inner {
if let clean::TypedefItem(ref tydef, _) = it.kind {
out.push_str("<span class=\"where fmt-newline\"> ");
assoc_type(
&mut out,
@ -3657,7 +3656,7 @@ fn render_impl(
fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute);
if show_def_docs {
for it in &i.inner_impl().items {
if let clean::TypedefItem(ref tydef, _) = it.inner {
if let clean::TypedefItem(ref tydef, _) = it.kind {
write!(w, "<span class=\"where fmt-newline\"> ");
assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "");
write!(w, ";</span>");
@ -3728,14 +3727,14 @@ fn render_impl(
};
let (is_hidden, extra_class) =
if (trait_.is_none() || item.doc_value().is_some() || item.inner.is_type_alias())
if (trait_.is_none() || item.doc_value().is_some() || item.kind.is_type_alias())
&& !is_default_item
{
(false, "")
} else {
(true, " hidden")
};
match item.inner {
match item.kind {
clean::MethodItem(clean::Method { .. })
| clean::TyMethodItem(clean::TyMethod { .. }) => {
// Only render when the method is not static or we allow static methods
@ -4000,7 +3999,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca
write!(
buffer,
"<p class=\"location\">{}{}</p>",
match it.inner {
match it.kind {
clean::StructItem(..) => "Struct ",
clean::TraitItem(..) => "Trait ",
clean::PrimitiveItem(..) => "Primitive Type ",
@ -4040,7 +4039,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca
it.name.as_ref().expect("crates always have a name")
);
}
match it.inner {
match it.kind {
clean::StructItem(ref s) => sidebar_struct(buffer, it, s),
clean::TraitItem(ref t) => sidebar_trait(buffer, it, t),
clean::PrimitiveItem(_) => sidebar_primitive(buffer, it),
@ -4180,7 +4179,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
.find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did)
{
if let Some((target, real_target)) =
impl_.inner_impl().items.iter().find_map(|item| match item.inner {
impl_.inner_impl().items.iter().find_map(|item| match item.kind {
clean::TypedefItem(ref t, true) => Some(match *t {
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
_ => (&t.type_, &t.type_),
@ -4319,8 +4318,8 @@ fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) ->
}
fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> {
match item.inner {
clean::ItemEnum::ImplItem(ref i) => {
match item.kind {
clean::ItemKind::ImplItem(ref i) => {
if let Some(ref trait_) = i.trait_ {
Some((
format!("{:#}", i.for_.print()),
@ -4470,7 +4469,7 @@ fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item) {
fn get_struct_fields_name(fields: &[clean::Item]) -> String {
let mut fields = fields
.iter()
.filter(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false })
.filter(|f| if let clean::StructFieldItem(..) = f.kind { true } else { false })
.filter_map(|f| match f.name {
Some(ref name) => {
Some(format!("<a href=\"#structfield.{name}\">{name}</a>", name = name))

View File

@ -2,7 +2,6 @@ use std::fs::{create_dir_all, read_to_string, File};
use std::io::prelude::*;
use std::path::Path;
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_span::source_map::DUMMY_SP;
@ -66,7 +65,7 @@ pub fn render<P: AsRef<Path>>(
let title = metadata[0];
let mut ids = IdMap::new();
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let error_codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
let text = if !options.markdown_no_toc {
MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string()
} else {
@ -131,7 +130,7 @@ pub fn test(mut options: Options) -> Result<(), String> {
options.enable_per_target_ignores,
);
collector.set_position(DUMMY_SP);
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let codes = ErrorCodes::from(options.render_options.unstable_features.is_nightly_build());
find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);

View File

@ -187,7 +187,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> {
impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
match i.inner {
match i.kind {
_ if !i.def_id.is_local() => {
// non-local items are skipped because they can be out of the users control,
// especially in the case of trait impls, which rustdoc eagerly inlines

View File

@ -671,7 +671,7 @@ fn resolve_associated_trait_item(
let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did);
let mut candidates: Vec<_> = implicit_impls
.flat_map(|impl_outer| {
match impl_outer.inner {
match impl_outer.kind {
clean::ImplItem(impl_) => {
debug!("considering auto or blanket impl for trait {:?}", impl_.trait_);
// Give precedence to methods that were overridden
@ -681,14 +681,14 @@ fn resolve_associated_trait_item(
return None;
}
let kind = assoc
.inner
.kind
.as_assoc_kind()
.expect("inner items for a trait should be associated items");
if kind.namespace() != ns {
return None;
}
trace!("considering associated item {:?}", assoc.inner);
trace!("considering associated item {:?}", assoc.kind);
// We have a slight issue: normal methods come from `clean` types,
// but provided methods come directly from `tcx`.
// Fortunately, we don't need the whole method, we just need to know
@ -832,7 +832,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
}
let current_item = match item.inner {
let current_item = match item.kind {
clean::ModuleItem(..) => {
if item.attrs.inner_docs {
if item.def_id.is_top_level_module() { item.name.clone() } else { None }

View File

@ -55,11 +55,11 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
for it in &new_items {
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.inner {
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.kind {
if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
let target = items
.iter()
.find_map(|item| match item.inner {
.find_map(|item| match item.kind {
TypedefItem(ref t, true) => Some(&t.type_),
_ => None,
})
@ -75,7 +75,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
}
new_items.retain(|it| {
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.inner {
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.kind {
cleaner.keep_item(for_)
|| trait_.as_ref().map_or(false, |t| cleaner.keep_item(t))
|| blanket_impl.is_some()
@ -96,7 +96,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
}
if let Some(ref mut it) = krate.module {
if let ModuleItem(Module { ref mut items, .. }) = it.inner {
if let ModuleItem(Module { ref mut items, .. }) = it.kind {
items.extend(synth.impls);
items.extend(new_items);
} else {

View File

@ -58,7 +58,7 @@ impl crate::doctest::Tester for Tests {
}
pub fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
if matches!(item.inner,
if matches!(item.kind,
clean::StructFieldItem(_)
| clean::VariantItem(_)
| clean::AssocConstItem(_, _)
@ -92,9 +92,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
if tests.found_tests == 0
&& rustc_feature::UnstableFeatures::from_environment().is_nightly_build()
{
if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() {
if should_have_doc_example(cx, &item) {
debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());

View File

@ -5,7 +5,6 @@ use crate::fold::DocFolder;
use crate::html::markdown::opts;
use core::ops::Range;
use pulldown_cmark::{Event, Parser};
use rustc_feature::UnstableFeatures;
use rustc_session::lint;
use std::iter::Peekable;
use std::str::CharIndices;
@ -27,7 +26,7 @@ impl<'a, 'tcx> InvalidHtmlTagsLinter<'a, 'tcx> {
}
pub fn check_invalid_html_tags(krate: Crate, cx: &DocContext<'_>) -> Crate {
if !UnstableFeatures::from_environment().is_nightly_build() {
if !cx.tcx.sess.is_nightly_build() {
krate
} else {
let mut coll = InvalidHtmlTagsLinter::new(cx);

View File

@ -7,7 +7,6 @@ use core::ops::Range;
use pulldown_cmark::{Event, LinkType, Parser, Tag};
use regex::Regex;
use rustc_errors::Applicability;
use rustc_feature::UnstableFeatures;
use rustc_session::lint;
pub const CHECK_NON_AUTOLINKS: Pass = Pass {
@ -54,7 +53,7 @@ impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> {
}
pub fn check_non_autolinks(krate: Crate, cx: &DocContext<'_>) -> Crate {
if !UnstableFeatures::from_environment().is_nightly_build() {
if !cx.tcx.sess.is_nightly_build() {
krate
} else {
let mut coll = NonAutolinksLinter::new(cx);

View File

@ -41,7 +41,7 @@ impl<'a> DocFolder for Stripper<'a> {
if i.attrs.lists(sym::doc).has_word(sym::hidden) {
debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
// use a dedicated hidden item for given item type if any
match i.inner {
match i.kind {
clean::StructFieldItem(..) | clean::ModuleItem(..) => {
// We need to recurse into stripped modules to
// strip things like impl methods but when doing so

View File

@ -13,7 +13,7 @@ pub struct Stripper<'a> {
impl<'a> DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
match i.inner {
match i.kind {
clean::StrippedItem(..) => {
// We need to recurse into stripped modules to strip things
// like impl methods but when doing so we must not add any
@ -86,7 +86,7 @@ impl<'a> DocFolder for Stripper<'a> {
clean::KeywordItem(..) => {}
}
let fastreturn = match i.inner {
let fastreturn = match i.kind {
// nothing left to do for traits (don't want to filter their
// methods out, visibility controlled by the trait)
clean::TraitItem(..) => true,
@ -123,7 +123,7 @@ pub struct ImplStripper<'a> {
impl<'a> DocFolder for ImplStripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if let clean::ImplItem(ref imp) = i.inner {
if let clean::ImplItem(ref imp) = i.kind {
// emptied none trait impls can be stripped
if imp.trait_.is_none() && imp.items.is_empty() {
return None;
@ -162,7 +162,7 @@ pub struct ImportStripper;
impl DocFolder for ImportStripper {
fn fold_item(&mut self, i: Item) -> Option<Item> {
match i.inner {
match i.kind {
clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => {
None
}

View File

@ -3,5 +3,6 @@ mod underscore;
fn main() {
underscore!();
//~^ ERROR expected expression, found reserved identifier `_`
//~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR destructuring assignments are unstable
}

View File

@ -1,8 +1,23 @@
error: expected expression, found reserved identifier `_`
error[E0658]: destructuring assignments are unstable
--> $DIR/underscore.rs:8:9
|
LL | _
| ^ expected expression
| ^
|
::: $DIR/main.rs:5:5
|
LL | underscore!();
| -------------- in this macro invocation
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/underscore.rs:8:9
|
LL | _
| ^ `_` not allowed here
|
::: $DIR/main.rs:5:5
|
@ -11,5 +26,6 @@ LL | underscore!();
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -14,4 +14,7 @@ fn main() {
Struct { a: TupleStruct((a, b), c), b: [d] } =
Struct { a: TupleStruct((0, 1), 2), b: [3] };
assert_eq!((a, b, c, d), (0, 1, 2, 3));
// unnested underscore: just discard
_ = 1;
}

View File

@ -9,6 +9,8 @@ fn main() {
let mut c;
[a, .., b, c] = [1, 2, 3, 4, 5];
assert_eq!((a, b, c), (1, 4, 5));
[_, a, _] = [1, 2, 3];
assert_eq!((a, b), (2, 4));
[..] = [1, 2, 3];
[c, ..] = [5, 6, 6];
assert_eq!(c, 5);

View File

@ -4,4 +4,5 @@ fn main() {
let (mut a, mut b);
[a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern
[a, a, b] = [1, 2]; //~ ERROR pattern requires 3 elements but array has 2
[_] = [1, 2]; //~ ERROR pattern requires 1 element but array has 2
}

View File

@ -12,6 +12,12 @@ error[E0527]: pattern requires 3 elements but array has 2
LL | [a, a, b] = [1, 2];
| ^^^^^^^^^ expected 2 elements
error: aborting due to 2 previous errors
error[E0527]: pattern requires 1 element but array has 2
--> $DIR/slice_destructure_fail.rs:7:3
|
LL | [_] = [1, 2];
| ^^^ expected 2 elements
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0527`.

View File

@ -12,8 +12,10 @@ fn main() {
assert_eq!((a, b), (0, 1));
Struct { a: b, b: a } = Struct { a: 1, b: 2 };
assert_eq!((a,b), (2, 1));
Struct { a: _, b } = Struct { a: 1, b: 2 };
assert_eq!((a, b), (2, 2));
Struct { a, .. } = Struct { a: 1, b: 3 };
assert_eq!((a, b), (1, 1));
assert_eq!((a, b), (1, 2));
Struct { .. } = Struct { a: 1, b: 4 };
assert_eq!((a, b), (1, 1));
assert_eq!((a, b), (1, 2));
}

View File

@ -9,6 +9,8 @@ fn main() {
let mut c;
let d = Struct { a: 0, b: 1 };
Struct { a, b, c } = Struct { a: 0, b: 1 }; //~ ERROR does not have a field named `c`
Struct { a, _ } = Struct { a: 1, b: 2 }; //~ ERROR pattern does not mention field `b`
//~| ERROR expected identifier, found reserved identifier `_`
Struct { a, ..d } = Struct { a: 1, b: 2 };
//~^ ERROR functional record updates are not allowed in destructuring assignments
Struct { a, .. }; //~ ERROR base expression required after `..`

View File

@ -1,11 +1,19 @@
error: expected identifier, found reserved identifier `_`
--> $DIR/struct_destructure_fail.rs:12:17
|
LL | Struct { a, _ } = Struct { a: 1, b: 2 };
| ------ ^ expected identifier, found reserved identifier
| |
| while parsing this struct
error: functional record updates are not allowed in destructuring assignments
--> $DIR/struct_destructure_fail.rs:12:19
--> $DIR/struct_destructure_fail.rs:14:19
|
LL | Struct { a, ..d } = Struct { a: 1, b: 2 };
| ^ help: consider removing the trailing pattern
error: base expression required after `..`
--> $DIR/struct_destructure_fail.rs:14:19
--> $DIR/struct_destructure_fail.rs:16:19
|
LL | Struct { a, .. };
| ^ add a base expression here
@ -16,6 +24,22 @@ error[E0026]: struct `Struct` does not have a field named `c`
LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
| ^ struct `Struct` does not have this field
error: aborting due to 3 previous errors
error[E0027]: pattern does not mention field `b`
--> $DIR/struct_destructure_fail.rs:12:5
|
LL | Struct { a, _ } = Struct { a: 1, b: 2 };
| ^^^^^^^^^^^^^^^ missing field `b`
|
help: include the missing field in the pattern
|
LL | Struct { a, b, _ } = Struct { a: 1, b: 2 };
| ^^^
help: if you don't care about this missing field, you can explicitly ignore it
|
LL | Struct { a, .., _ } = Struct { a: 1, b: 2 };
| ^^^^
For more information about this error, try `rustc --explain E0026`.
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0026, E0027.
For more information about an error, try `rustc --explain E0026`.

View File

@ -16,6 +16,8 @@ fn main() {
assert_eq!((a, b), (2, 2));
(b, ..) = (5, 6, 7);
assert_eq!(b, 5);
(a, _) = (8, 9);
assert_eq!(a, 8);
// Test for a non-Copy type (String):
let (mut c, mut d);

View File

@ -7,4 +7,5 @@ fn main() {
(a, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern
(a, a, b) = (1, 2); //~ ERROR mismatched types
(C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment
(_,) = (1, 2); //~ ERROR mismatched types
}

View File

@ -25,7 +25,18 @@ LL | (C, ..) = (0,1);
| |
| cannot assign to this expression
error: aborting due to 3 previous errors
error[E0308]: mismatched types
--> $DIR/tuple_destructure_fail.rs:10:5
|
LL | (_,) = (1, 2);
| ^^^^ ------ this expression has type `({integer}, {integer})`
| |
| expected a tuple with 2 elements, found one with 1 element
|
= note: expected type `({integer}, {integer})`
found tuple `(_,)`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0070, E0308.
For more information about an error, try `rustc --explain E0070`.

View File

@ -23,8 +23,10 @@ fn main() {
assert_eq!((a, b), (0, 1));
TupleStruct(a, .., b) = TupleStruct(1, 2);
assert_eq!((a, b), (1, 2));
TupleStruct(_, a) = TupleStruct(2, 2);
assert_eq!((a, b), (2, 2));
TupleStruct(..) = TupleStruct(3, 4);
assert_eq!((a, b), (1, 2));
assert_eq!((a, b), (2, 2));
TupleStruct(5,6).assign(&mut a, &mut b);
assert_eq!((a, b), (5, 6));
Enum::SingleVariant(a, b) = Enum::SingleVariant(7, 8);

View File

@ -29,8 +29,12 @@ fn main() {
TupleStruct(a, a, b) = TupleStruct(1, 2);
//~^ ERROR this pattern has 3 fields, but the corresponding tuple struct has 2 fields
TupleStruct(_) = TupleStruct(1, 2);
//~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
//~^ ERROR this pattern has 3 fields, but the corresponding tuple variant has 2 fields
Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
//~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
// Check if `test` is recognized as not a tuple struct but a function call:
test() = TupleStruct(0, 0);

View File

@ -23,17 +23,35 @@ LL | struct TupleStruct<S, T>(S, T);
LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
| ^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
--> $DIR/tuple_struct_destructure_fail.rs:32:5
|
LL | struct TupleStruct<S, T>(S, T);
| ------------------------------- tuple struct defined here
...
LL | TupleStruct(_) = TupleStruct(1, 2);
| ^^^^^^^^^^^^^^ expected 2 fields, found 1
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
--> $DIR/tuple_struct_destructure_fail.rs:34:5
|
LL | SingleVariant(S, T)
| ------------------- tuple variant defined here
...
LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
--> $DIR/tuple_struct_destructure_fail.rs:36:5
|
LL | SingleVariant(S, T)
| ------------------- tuple variant defined here
...
LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
| ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1
error[E0070]: invalid left-hand side of assignment
--> $DIR/tuple_struct_destructure_fail.rs:36:12
--> $DIR/tuple_struct_destructure_fail.rs:40:12
|
LL | test() = TupleStruct(0, 0);
| ------ ^
@ -41,7 +59,7 @@ LL | test() = TupleStruct(0, 0);
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
--> $DIR/tuple_struct_destructure_fail.rs:38:14
--> $DIR/tuple_struct_destructure_fail.rs:42:14
|
LL | (test)() = TupleStruct(0, 0);
| -------- ^
@ -49,14 +67,14 @@ LL | (test)() = TupleStruct(0, 0);
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
--> $DIR/tuple_struct_destructure_fail.rs:40:38
--> $DIR/tuple_struct_destructure_fail.rs:44:38
|
LL | <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
| -------------------------------- ^
| |
| cannot assign to this expression
error: aborting due to 7 previous errors
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0023, E0070.
For more information about an error, try `rustc --explain E0023`.

View File

@ -4,5 +4,7 @@ struct S { x : u32 }
#[cfg(FALSE)]
fn foo() {
_; //~ ERROR destructuring assignments are unstable
S { x: 5, .. }; //~ ERROR destructuring assignments are unstable
}

View File

@ -1,5 +1,14 @@
error[E0658]: destructuring assignments are unstable
--> $DIR/underscore-range-expr-gating.rs:7:15
--> $DIR/underscore-range-expr-gating.rs:7:5
|
LL | _;
| ^
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0658]: destructuring assignments are unstable
--> $DIR/underscore-range-expr-gating.rs:9:15
|
LL | S { x: 5, .. };
| ^^
@ -7,6 +16,6 @@ LL | S { x: 5, .. };
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: aborting due to previous error
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -8,12 +8,18 @@ trait T {
fn main() {
let _: usize = foo(_, _);
//~^ ERROR expected expression
//~| ERROR expected expression
//~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR destructuring assignments are unstable
//~| ERROR destructuring assignments are unstable
let _: S = S(_, _);
//~^ ERROR expected expression
//~| ERROR expected expression
//~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR destructuring assignments are unstable
//~| ERROR destructuring assignments are unstable
let _: usize = T::baz(_, _);
//~^ ERROR expected expression
//~| ERROR expected expression
//~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR destructuring assignments are unstable
//~| ERROR destructuring assignments are unstable
}

View File

@ -1,38 +1,93 @@
error: expected expression, found reserved identifier `_`
error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
|
LL | let _: usize = foo(_, _);
| ^ expected expression
| ^
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: expected expression, found reserved identifier `_`
error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27
|
LL | let _: usize = foo(_, _);
| ^ expected expression
| ^
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: expected expression, found reserved identifier `_`
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:18
error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18
|
LL | let _: S = S(_, _);
| ^ expected expression
| ^
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: expected expression, found reserved identifier `_`
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:21
error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21
|
LL | let _: S = S(_, _);
| ^ expected expression
| ^
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: expected expression, found reserved identifier `_`
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:27
error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27
|
LL | let _: usize = T::baz(_, _);
| ^ expected expression
| ^
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: expected expression, found reserved identifier `_`
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:30
error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30
|
LL | let _: usize = T::baz(_, _);
| ^ expected expression
| ^
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: aborting due to 6 previous errors
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
|
LL | let _: usize = foo(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27
|
LL | let _: usize = foo(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18
|
LL | let _: S = S(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21
|
LL | let _: S = S(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27
|
LL | let _: usize = T::baz(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30
|
LL | let _: usize = T::baz(_, _);
| ^ `_` not allowed here
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -170,6 +170,7 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::MacCall(..)
| ast::ExprKind::MethodCall(..)
| ast::ExprKind::Paren(..)
| ast::ExprKind::Underscore
| ast::ExprKind::Path(..)
| ast::ExprKind::Repeat(..)
| ast::ExprKind::Ret(..)

@ -1 +1 @@
Subproject commit 0f29ff6da0c5ff622e739beb8fc3bbe77119b3c1
Subproject commit 293d7d01118c9fb5479649399e1dae60322b8e09