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]] [[package]]
name = "rustfmt-nightly" name = "rustfmt-nightly"
version = "1.4.25" version = "1.4.26"
dependencies = [ dependencies = [
"annotate-snippets 0.6.1", "annotate-snippets 0.6.1",
"anyhow", "anyhow",

View File

@ -1192,6 +1192,7 @@ impl Expr {
ExprKind::Field(..) => ExprPrecedence::Field, ExprKind::Field(..) => ExprPrecedence::Field,
ExprKind::Index(..) => ExprPrecedence::Index, ExprKind::Index(..) => ExprPrecedence::Index,
ExprKind::Range(..) => ExprPrecedence::Range, ExprKind::Range(..) => ExprPrecedence::Range,
ExprKind::Underscore => ExprPrecedence::Path,
ExprKind::Path(..) => ExprPrecedence::Path, ExprKind::Path(..) => ExprPrecedence::Path,
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf, ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
ExprKind::Break(..) => ExprPrecedence::Break, ExprKind::Break(..) => ExprPrecedence::Break,
@ -1324,6 +1325,8 @@ pub enum ExprKind {
Index(P<Expr>, P<Expr>), Index(P<Expr>, P<Expr>),
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment). /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment).
Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits), 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 /// Variable reference, possibly containing `::` and/or type
/// parameters (e.g., `foo::bar::<baz>`). /// 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(e1, |e1| vis.visit_expr(e1));
visit_opt(e2, |e2| vis.visit_expr(e2)); visit_opt(e2, |e2| vis.visit_expr(e2));
} }
ExprKind::Underscore => {}
ExprKind::Path(qself, path) => { ExprKind::Path(qself, path) => {
vis.visit_qself(qself); vis.visit_qself(qself);
vis.visit_path(path); 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, start);
walk_list!(visitor, visit_expr, end); walk_list!(visitor, visit_expr, end);
} }
ExprKind::Underscore => {}
ExprKind::Path(ref maybe_qself, ref path) => { ExprKind::Path(ref maybe_qself, ref path) => {
if let Some(ref qself) = *maybe_qself { if let Some(ref qself) = *maybe_qself {
visitor.visit_ty(&qself.ty); visitor.visit_ty(&qself.ty);

View File

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

View File

@ -53,7 +53,6 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::intravisit; use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_hir::{ConstArg, GenericArg, ParamName};
use rustc_index::vec::{Idx, IndexVec}; 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::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_session::Session; use rustc_session::Session;
@ -1398,8 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
"`impl Trait` not allowed outside of {}", "`impl Trait` not allowed outside of {}",
allowed_in, allowed_in,
); );
if pos == ImplTraitPosition::Binding && nightly_options::is_nightly_build() if pos == ImplTraitPosition::Binding && self.sess.is_nightly_build() {
{
err.help( err.help(
"add `#![feature(impl_trait_in_bindings)]` to the crate \ "add `#![feature(impl_trait_in_bindings)]` to the crate \
attributes to enable", 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!(const_trait_impl, "const trait impls are experimental");
gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental"); 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, // All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded). // and subsequently disabled (with the non-early gating readded).

View File

@ -109,7 +109,6 @@ pub fn print_crate<'a>(
ann: &'a dyn PpAnn, ann: &'a dyn PpAnn,
is_expanded: bool, is_expanded: bool,
edition: Edition, edition: Edition,
has_injected_crate: bool,
) -> String { ) -> String {
let mut s = State { let mut s = State {
s: pp::mk_printer(), s: pp::mk_printer(),
@ -119,7 +118,7 @@ pub fn print_crate<'a>(
insert_extra_parens: true, 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 // We need to print `#![no_std]` (and its feature gate) so that
// compiling pretty-printed source won't inject libstd again. // compiling pretty-printed source won't inject libstd again.
// However, we don't want these attributes in the AST because // 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); 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(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::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
ast::ExprKind::Break(opt_label, ref opt_expr) => { ast::ExprKind::Break(opt_label, ref opt_expr) => {

View File

@ -13,12 +13,12 @@ pub fn inject(
resolver: &mut dyn ResolverExpand, resolver: &mut dyn ResolverExpand,
sess: &Session, sess: &Session,
alt_std_name: Option<Symbol>, alt_std_name: Option<Symbol>,
) -> (ast::Crate, Option<Symbol>) { ) -> ast::Crate {
let rust_2018 = sess.parse_sess.edition >= Edition::Edition2018; 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 // 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) { 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) { } else if sess.contains_name(&krate.attrs, sym::no_std) {
if sess.contains_name(&krate.attrs, sym::compiler_builtins) { if sess.contains_name(&krate.attrs, sym::compiler_builtins) {
&[sym::core] &[sym::core]
@ -81,5 +81,5 @@ pub fn inject(
krate.module.items.insert(0, use_item); 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 libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features; use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_feature::UnstableFeatures;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_session::config::PrintRequest; use rustc_session::config::PrintRequest;
use rustc_session::Session; use rustc_session::Session;
@ -147,13 +146,11 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
let target_machine = create_informational_target_machine(sess); let target_machine = create_informational_target_machine(sess);
supported_target_features(sess) supported_target_features(sess)
.iter() .iter()
.filter_map(|&(feature, gate)| { .filter_map(
if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() { |&(feature, gate)| {
Some(feature) if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
} else { },
None )
}
})
.filter(|feature| { .filter(|feature| {
let llvm_feature = to_llvm_feature(sess, feature); let llvm_feature = to_llvm_feature(sess, feature);
let cstr = CString::new(llvm_feature).unwrap(); 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_export]
macro_rules! likely { macro_rules! likely {
($e:expr) => { ($e:expr) => {
#[allow(unused_unsafe)] match $e {
{ #[allow(unused_unsafe)]
unsafe { std::intrinsics::likely($e) } e => unsafe { std::intrinsics::likely(e) },
} }
}; };
} }
@ -57,9 +57,9 @@ macro_rules! likely {
#[macro_export] #[macro_export]
macro_rules! unlikely { macro_rules! unlikely {
($e:expr) => { ($e:expr) => {
#[allow(unused_unsafe)] match $e {
{ #[allow(unused_unsafe)]
unsafe { std::intrinsics::unlikely($e) } e => unsafe { std::intrinsics::unlikely(e) },
} }
}; };
} }
@ -102,6 +102,7 @@ pub mod work_queue;
pub use atomic_ref::AtomicRef; pub use atomic_ref::AtomicRef;
pub mod frozen; pub mod frozen;
pub mod sso; pub mod sso;
pub mod steal;
pub mod tagged_ptr; pub mod tagged_ptr;
pub mod temp_dir; pub mod temp_dir;
pub mod unhash; 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. /// The `Steal` struct is intended to used as the value for a query.
/// Specifically, we sometimes have queries (*cough* MIR *cough*) /// Specifically, we sometimes have queries (*cough* MIR *cough*)
@ -31,7 +32,7 @@ impl<T> Steal<T> {
pub fn borrow(&self) -> MappedReadGuard<'_, T> { pub fn borrow(&self) -> MappedReadGuard<'_, T> {
ReadGuard::map(self.value.borrow(), |opt| match *opt { 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, Some(ref v) => v,
}) })
} }
@ -42,3 +43,9 @@ impl<T> Steal<T> {
value.expect("attempt to read from stolen value") 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_data_structures::sync::SeqCst;
use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorReported, PResult}; 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_hir::def_id::LOCAL_CRATE;
use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend}; use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
use rustc_interface::{interface, Queries}; use rustc_interface::{interface, Queries};
@ -746,9 +746,6 @@ impl RustcDefaultCalls {
} }
} }
Cfg => { Cfg => {
let allow_unstable_cfg =
UnstableFeatures::from_environment().is_nightly_build();
let mut cfgs = sess let mut cfgs = sess
.parse_sess .parse_sess
.config .config
@ -763,7 +760,7 @@ impl RustcDefaultCalls {
// it, this is intended to get into Cargo and then go // it, this is intended to get into Cargo and then go
// through to build scripts. // through to build scripts.
if (name != sym::target_feature || value != Some(sym::crt_dash_static)) 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() && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
{ {
return None; 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 groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
let mut options = getopts::Options::new(); let mut options = getopts::Options::new();
for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) { for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
(option.apply)(&mut options); (option.apply)(&mut options);
} }
let message = "Usage: rustc [OPTIONS] INPUT"; 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" "\n -Z help Print unstable compiler options"
} else { } else {
"" ""
@ -831,7 +828,7 @@ fn usage(verbose: bool, include_unstable_options: bool) {
} else { } else {
"\n --help -v Print the full set of options rustc accepts" "\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" " @path Read newline separated options from `path`\n"
} else { } else {
"" ""
@ -1034,7 +1031,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
if args.is_empty() { if args.is_empty() {
// user did not write `-v` nor `-Z unstable-options`, so do not // user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information. // 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; return None;
} }
@ -1063,7 +1062,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
if matches.opt_present("h") || matches.opt_present("help") { if matches.opt_present("h") || matches.opt_present("help") {
// Only show unstable options in --help if we accept unstable options. // 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; return None;
} }

View File

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

View File

@ -59,7 +59,7 @@ pub enum Stability {
Deprecated(&'static str, Option<&'static str>), Deprecated(&'static str, Option<&'static str>),
} }
#[derive(Clone, Copy, Hash)] #[derive(Clone, Copy, Debug, Hash)]
pub enum UnstableFeatures { pub enum UnstableFeatures {
/// Hard errors for unstable features are active, as on beta/stable channels. /// Hard errors for unstable features are active, as on beta/stable channels.
Disallow, Disallow,
@ -73,11 +73,20 @@ pub enum UnstableFeatures {
} }
impl 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. // `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(); 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. // `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) { match (disable_unstable_features, bootstrap) {
(_, true) => UnstableFeatures::Cheat, (_, true) => UnstableFeatures::Cheat,
(true, _) => UnstableFeatures::Disallow, (true, _) => UnstableFeatures::Disallow,
@ -140,3 +149,30 @@ pub use builtin_attrs::{
AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
}; };
pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; 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 std::path::Path;
use rustc_serialize::opaque::Encoder; use rustc_serialize::opaque::Encoder;
use rustc_session::config::nightly_options;
/// The first few bytes of files generated by incremental compilation. /// The first few bytes of files generated by incremental compilation.
const FILE_MAGIC: &[u8] = b"RSIC"; const FILE_MAGIC: &[u8] = b"RSIC";
@ -28,12 +27,12 @@ const HEADER_FORMAT_VERSION: u16 = 0;
/// the Git commit hash. /// the Git commit hash.
const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); 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(FILE_MAGIC);
stream stream
.emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]); .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); 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.len() as u8]);
stream.emit_raw_bytes(rustc_version.as_bytes()); stream.emit_raw_bytes(rustc_version.as_bytes());
@ -51,6 +50,7 @@ pub fn write_file_header(stream: &mut Encoder) {
pub fn read_file( pub fn read_file(
report_incremental_info: bool, report_incremental_info: bool,
path: &Path, path: &Path,
nightly_build: bool,
) -> io::Result<Option<(Vec<u8>, usize)>> { ) -> io::Result<Option<(Vec<u8>, usize)>> {
if !path.exists() { if !path.exists() {
return Ok(None); return Ok(None);
@ -93,7 +93,7 @@ pub fn read_file(
let mut buffer = vec![0; rustc_version_str_len]; let mut buffer = vec![0; rustc_version_str_len];
file.read_exact(&mut buffer)?; 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"); report_format_mismatch(report_incremental_info, path, "Different compiler version");
return Ok(None); return Ok(None);
} }
@ -115,8 +115,8 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
} }
} }
fn rustc_version() -> String { fn rustc_version(nightly_build: bool) -> String {
if nightly_options::is_nightly_build() { if nightly_build {
if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") { if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
return val.to_string_lossy().into_owned(); 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)> { fn load_data(
match file_format::read_file(report_incremental_info, path) { 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(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
Ok(None) => { Ok(None) => {
// The file either didn't exist or was produced by an incompatible // 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 expected_hash = sess.opts.dep_tracking_hash();
let mut prev_work_products = FxHashMap::default(); 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 // If we are only building with -Zquery-dep-graph but without an actual
// incr. comp. session directory, we skip this. Otherwise we'd fail // incr. comp. session directory, we skip this. Otherwise we'd fail
// when trying to load work products. // when trying to load work products.
if sess.incr_comp_session_dir_opt().is_some() { if sess.incr_comp_session_dir_opt().is_some() {
let work_products_path = work_products_path(sess); 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 { if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
// Decode the list of work_products // Decode the list of work_products
@ -163,7 +168,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
MaybeAsync::Async(std::thread::spawn(move || { MaybeAsync::Async(std::thread::spawn(move || {
let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph"); 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::DataOutOfDate => LoadResult::DataOutOfDate,
LoadResult::Error { message } => LoadResult::Error { message }, LoadResult::Error { message } => LoadResult::Error { message },
LoadResult::Ok { data: (bytes, start_pos) } => { 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"); 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), LoadResult::Ok { data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
_ => OnDiskCache::new_empty(sess.source_map()), _ => OnDiskCache::new_empty(sess.source_map()),
} }

View File

@ -119,7 +119,7 @@ where
// generate the data in a memory buffer // generate the data in a memory buffer
let mut encoder = Encoder::new(Vec::new()); 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); encode(&mut encoder);
// write the data out // 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_ast::{self as ast, visit};
use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_ssa::traits::CodegenBackend; 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::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; 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;
use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn}; use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::steal::Steal;
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_mir as mir; use rustc_mir as mir;
use rustc_mir_build as mir_build; use rustc_mir_build as mir_build;
@ -239,16 +239,12 @@ fn configure_and_expand_inner<'a>(
krate = sess.time("crate_injection", || { krate = sess.time("crate_injection", || {
let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s)); 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, krate,
&mut resolver, &mut resolver,
&sess, &sess,
alt_std_name, 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()); 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_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh; use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_errors::ErrorReported; use rustc_errors::ErrorReported;
@ -12,7 +13,6 @@ use rustc_incremental::DepGraphFuture;
use rustc_lint::LintStore; use rustc_lint::LintStore;
use rustc_middle::arena::Arena; use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph; use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::steal::Steal;
use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_serialize::json; use rustc_serialize::json;
use rustc_session::config::{self, OutputFilenames, OutputType}; use rustc_session::config::{self, OutputFilenames, OutputType};

View File

@ -14,10 +14,10 @@ macro_rules! arena_types {
[] layouts: rustc_target::abi::Layout, [] layouts: rustc_target::abi::Layout,
// AdtDef are interned and compared by address // AdtDef are interned and compared by address
[] adt_def: rustc_middle::ty::AdtDef, [] 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>, [decode] mir: rustc_middle::mir::Body<$tcx>,
[] steal_promoted: [] steal_promoted:
rustc_middle::ty::steal::Steal< rustc_data_structures::steal::Steal<
rustc_index::vec::IndexVec< rustc_index::vec::IndexVec<
rustc_middle::mir::Promoted, rustc_middle::mir::Promoted,
rustc_middle::mir::Body<$tcx> 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 { impl<'a> HashStable<StableHashingContext<'a>> for crate::middle::privacy::AccessLevels {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { 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::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
use crate::traits; use crate::traits;
use crate::ty::query::{self, TyCtxtAt}; use crate::ty::query::{self, TyCtxtAt};
use crate::ty::steal::Steal;
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
use crate::ty::TyKind::*; use crate::ty::TyKind::*;
use crate::ty::{ use crate::ty::{
@ -33,6 +32,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{ use rustc_data_structures::stable_hasher::{
hash_stable_hashmap, HashStable, StableHasher, StableVec, 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::sync::{self, Lock, Lrc, WorkerLocal};
use rustc_data_structures::unhash::UnhashMap; use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::ErrorReported; use rustc_errors::ErrorReported;

View File

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

View File

@ -28,13 +28,13 @@ use crate::traits::query::{
}; };
use crate::traits::specialization_graph; use crate::traits::specialization_graph;
use crate::traits::{self, ImplSource}; use crate::traits::{self, ImplSource};
use crate::ty::steal::Steal;
use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::util::AlwaysRequiresDrop; use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::stable_hasher::StableVec; use rustc_data_structures::stable_hasher::StableVec;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh; use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::ErrorReported; 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 as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol};
@ -104,7 +103,7 @@ impl NonConstOp for FnCallUnstable {
if ccx.is_const_stable_const_fn() { if ccx.is_const_stable_const_fn() {
err.help("Const-stable functions can only call other const-stable functions"); 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 { if let Some(feature) = feature {
err.help(&format!( err.help(&format!(
"add `#![feature({})]` to the crate attributes to enable", "add `#![feature({})]` to the crate attributes to enable",

View File

@ -1,6 +1,7 @@
use crate::{shim, util}; use crate::{shim, util};
use required_consts::RequiredConstsVisitor; use required_consts::RequiredConstsVisitor;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::steal::Steal;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; 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::visit::Visitor as _;
use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted}; use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::steal::Steal;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol};
use std::borrow::Cow; 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> { impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { 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() { if self.reachable_blocks.contains(location.block) && context.is_use() {
// Uses of locals must occur while the local's storage is allocated. // Uses of locals must occur while the local's storage is allocated.
self.storage_liveness.seek_after_primary_effect(location); self.storage_liveness.seek_after_primary_effect(location);

View File

@ -24,7 +24,7 @@ use super::lints;
crate fn mir_built<'tcx>( crate fn mir_built<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>, 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) { if let Some(def) = def.try_upgrade(tcx) {
return tcx.mir_built(def); 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::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{HirId, Pat}; use rustc_hir::{HirId, Pat};
use rustc_middle::ty::{self, Ty, TyCtxt}; 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::BINDINGS_WITH_VARIANT_NAME;
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS}; use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
@ -502,7 +501,7 @@ fn check_exhaustive<'p, 'tcx>(
so a wildcard `_` is necessary to match exhaustively", so a wildcard `_` is necessary to match exhaustively",
scrut_ty, scrut_ty,
)); ));
if nightly_options::is_nightly_build() { if cx.tcx.sess.is_nightly_build() {
err.help(&format!( err.help(&format!(
"add `#![feature(precise_pointer_size_matching)]` \ "add `#![feature(precise_pointer_size_matching)]` \
to the crate attributes to enable precise `{}` matching", to the crate attributes to enable precise `{}` matching",

View File

@ -1089,6 +1089,9 @@ impl<'a> Parser<'a> {
self.parse_yield_expr(attrs) self.parse_yield_expr(attrs)
} else if self.eat_keyword(kw::Let) { } else if self.eat_keyword(kw::Let) {
self.parse_let_expr(attrs) 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) { } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
// Don't complain about bare semicolons after unclosed braces // Don't complain about bare semicolons after unclosed braces
// recovery in order to keep the error count down. Fixing the // 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::hir::map::Map;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol}; 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 // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
// is a pretty narrow case, however. // is a pretty narrow case, however.
if nightly_options::is_nightly_build() { if tcx.sess.is_nightly_build() {
for gate in missing_secondary { for gate in missing_secondary {
let note = format!( let note = format!(
"add `#![feature({})]` to the crate attributes to enable", "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); 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"); 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.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id))
self.r.invocation_macro_rules_scopes.entry(invoc_id).or_default().insert(scope);
scope
} }
fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { 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::{self, CtorKind, CtorOf, DefKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::PrimTy; use rustc_hir::PrimTy;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::hygiene::MacroKind; use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol}; 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(_)) => { (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
err.span_label(span, "type aliases cannot be used as traits"); 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 \ let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
`type` alias"; `type` alias";
if let Some(span) = self.def_span(def_id) { 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 && !self.tcx.features().in_band_lifetimes
&& suggests_in_band && suggests_in_band
{ {

View File

@ -976,9 +976,6 @@ pub struct Resolver<'a> {
/// `macro_rules` scopes *produced* by expanding the macro invocations, /// `macro_rules` scopes *produced* by expanding the macro invocations,
/// include all the `macro_rules` items and other invocations generated by them. /// include all the `macro_rules` items and other invocations generated by them.
output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>, 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 attributes that are in scope for the given expansion.
helper_attrs: FxHashMap<ExpnId, Vec<Ident>>, 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)], non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
invocation_parent_scopes: Default::default(), invocation_parent_scopes: Default::default(),
output_macro_rules_scopes: Default::default(), output_macro_rules_scopes: Default::default(),
invocation_macro_rules_scopes: Default::default(),
helper_attrs: Default::default(), helper_attrs: Default::default(),
local_macro_def_scopes: FxHashMap::default(), local_macro_def_scopes: FxHashMap::default(),
name_already_seen: 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)) !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive))
} }
Scope::DeriveHelpersCompat => true, 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::CrateRoot => true,
Scope::Module(..) => true, Scope::Module(..) => true,
Scope::RegisteredAttrs => use_prelude, Scope::RegisteredAttrs => use_prelude,
@ -1716,11 +1725,9 @@ impl<'a> Resolver<'a> {
MacroRulesScope::Binding(binding) => { MacroRulesScope::Binding(binding) => {
Scope::MacroRules(binding.parent_macro_rules_scope) Scope::MacroRules(binding.parent_macro_rules_scope)
} }
MacroRulesScope::Invocation(invoc_id) => Scope::MacroRules( MacroRulesScope::Invocation(invoc_id) => {
self.output_macro_rules_scopes.get(&invoc_id).cloned().unwrap_or_else( Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
|| self.invocation_parent_scopes[&invoc_id].macro_rules, }
),
),
MacroRulesScope::Empty => Scope::Module(module), MacroRulesScope::Empty => Scope::Module(module),
}, },
Scope::CrateRoot => match ns { 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. /// `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)` /// The reason is that we update scopes with value `MacroRulesScope::Invocation(invoc_id)`
/// in-place immediately after `invoc_id` gets expanded. /// in-place after `invoc_id` gets expanded.
/// This helps to avoid uncontrollable growth of `macro_rules!` scope chains, /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains,
/// which usually grow lineraly with the number of macro invocations /// which usually grow lineraly with the number of macro invocations
/// in a module (including derives) and hurt performance. /// 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); let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope);
self.output_macro_rules_scopes.insert(expansion, output_macro_rules_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); 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)) Ok((macro_rules_binding.binding, Flags::MACRO_RULES))
} }
MacroRulesScope::Invocation(invoc_id) MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined),
if !this.output_macro_rules_scopes.contains_key(&invoc_id) =>
{
Err(Determinacy::Undetermined)
}
_ => Err(Determinacy::Determined), _ => Err(Determinacy::Determined),
}, },
Scope::CrateRoot => { Scope::CrateRoot => {

View File

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

View File

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

View File

@ -745,6 +745,9 @@ impl Session {
pub fn unstable_options(&self) -> bool { pub fn unstable_options(&self) -> bool {
self.opts.debugging_opts.unstable_options 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 { pub fn overflow_checks(&self) -> bool {
self.opts self.opts
.cg .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::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::nightly_options;
use rustc_span::Span; use rustc_span::Span;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -602,7 +601,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}; };
err.span_label(span, label); 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"); err.help("add #![feature(member_constraints)] to the crate attributes to enable");
} }

View File

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

View File

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

View File

@ -1,5 +1,6 @@
use crate::astconv::{ use crate::astconv::{
AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, PathSeg,
}; };
use crate::check::callee::{self, DeferredCallResolution}; use crate::check::callee::{self, DeferredCallResolution};
use crate::check::method::{self, MethodCallee, SelfSource}; 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(|| { let substs = self_ctor_substs.unwrap_or_else(|| {
AstConv::create_substs_for_generic_args( AstConv::create_substs_for_generic_args(
tcx, tcx,
@ -1306,68 +1395,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
has_self, has_self,
self_ty, self_ty,
arg_count, arg_count,
// Provide the generic args, and whether types should be inferred. &mut CreateCtorSubstsContext {
|def_id| { fcx: self,
if let Some(&PathSeg(_, index)) = span,
path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) path_segs: &path_segs,
{ infer_args_for_err: &infer_args_for_err,
// If we've encountered an `impl Trait`-related error, we're just segments,
// 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)
}
}
}, },
) )
}); });

View File

@ -1,6 +1,6 @@
use super::{probe, MethodCallee}; use super::{probe, MethodCallee};
use crate::astconv::AstConv; use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt};
use crate::check::{callee, FnCtxt}; use crate::check::{callee, FnCtxt};
use crate::hir::def_id::DefId; use crate::hir::def_id::DefId;
use crate::hir::GenericArg; 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::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable; 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_middle::ty::{self, GenericParamDefKind, Ty};
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
@ -307,6 +307,52 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// parameters from the type and those from the method. // parameters from the type and those from the method.
assert_eq!(generics.parent_count, parent_substs.len()); 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( AstConv::create_substs_for_generic_args(
self.tcx, self.tcx,
pick.item.def_id, pick.item.def_id,
@ -314,29 +360,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
false, false,
None, None,
arg_count_correct, arg_count_correct,
// Provide the generic args, and whether types should be inferred. &mut MethodSubstsCtxt { cfcx: self, pick, seg },
|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),
) )
} }

View File

@ -25,7 +25,6 @@ use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
}; };
use rustc_session::config::nightly_options;
use rustc_session::lint; use rustc_session::lint;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; 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), 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 { for (candidate, feature) in unstable_candidates {
diag.help(&format!( diag.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`", "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. /// Moves all elements from `other` into `Self`, leaving `other` empty.
/// ///
/// # Examples /// # Examples

View File

@ -808,6 +808,17 @@ fn test_range_mut() {
map.check(); 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 { mod test_drain_filter {
use super::*; use super::*;

View File

@ -798,6 +798,30 @@ impl<T: Ord> BTreeSet<T> {
Recover::take(&mut self.map, value) 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. /// Moves all elements from `other` into `Self`, leaving `other` empty.
/// ///
/// # Examples /// # Examples

View File

@ -324,6 +324,17 @@ fn test_is_subset() {
assert_eq!(is_subset(&[99, 100], &large), false); 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] #[test]
fn test_drain_filter() { fn test_drain_filter() {
let mut x: BTreeSet<_> = [1].iter().copied().collect(); let mut x: BTreeSet<_> = [1].iter().copied().collect();

View File

@ -19,7 +19,7 @@ use crate::compile;
use crate::config::TargetSelection; use crate::config::TargetSelection;
use crate::dist; use crate::dist;
use crate::doc; use crate::doc;
use crate::flags::Subcommand; use crate::flags::{Color, Subcommand};
use crate::install; use crate::install;
use crate::native; use crate::native;
use crate::run; use crate::run;
@ -811,6 +811,16 @@ impl<'a> Builder<'a> {
cargo.env("REAL_LIBRARY_PATH", e); 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" { if cmd != "install" {
cargo.arg("--target").arg(target.rustc_target_arg()); cargo.arg("--target").arg(target.rustc_target_arg());
} else { } else {

View File

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

View File

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

View File

@ -15,6 +15,31 @@ use crate::config::{Config, TargetSelection};
use crate::setup::Profile; use crate::setup::Profile;
use crate::{Build, DocTests}; 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. /// Deserialized version of all flags for this compile.
pub struct Flags { pub struct Flags {
pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo 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 rustc_error_format: Option<String>,
pub json_output: bool, pub json_output: bool,
pub dry_run: bool, pub dry_run: bool,
pub color: Color,
// This overrides the deny-warnings configuration option, // This overrides the deny-warnings configuration option,
// which passes -Dwarnings to the compiler invocations. // 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.optopt("", "error-format", "rustc error format", "FORMAT");
opts.optflag("", "json-output", "use message-format=json"); opts.optflag("", "json-output", "use message-format=json");
opts.optopt("", "color", "whether to use color in cargo and rustc output", "STYLE");
opts.optopt( opts.optopt(
"", "",
"llvm-skip-rebuild", "llvm-skip-rebuild",
@ -644,6 +671,9 @@ Arguments:
llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map( 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"), |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), def_id: self.cx.next_def_id(param_env_def_id.krate),
stability: None, stability: None,
deprecation: None, deprecation: None,
inner: ImplItem(Impl { kind: ImplItem(Impl {
unsafety: hir::Unsafety::Normal, unsafety: hir::Unsafety::Normal,
generics: new_generics, generics: new_generics,
provided_trait_methods: Default::default(), 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), def_id: self.cx.next_def_id(impl_def_id.krate),
stability: None, stability: None,
deprecation: None, deprecation: None,
inner: ImplItem(Impl { kind: ImplItem(Impl {
unsafety: hir::Unsafety::Normal, unsafety: hir::Unsafety::Normal,
generics: ( generics: (
self.cx.tcx.generics_of(impl_def_id), self.cx.tcx.generics_of(impl_def_id),

View File

@ -54,7 +54,7 @@ crate fn try_inline(
debug!("attrs={:?}", attrs); debug!("attrs={:?}", attrs);
let attrs_clone = attrs; let attrs_clone = attrs;
let inner = match res { let kind = match res {
Res::Def(DefKind::Trait, did) => { Res::Def(DefKind::Trait, did) => {
record_extern_fqn(cx, did, clean::TypeKind::Trait); record_extern_fqn(cx, did, clean::TypeKind::Trait);
ret.extend(build_impls(cx, Some(parent_module), did, attrs)); 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), source: cx.tcx.def_span(did).clean(cx),
name: Some(name.clean(cx)), name: Some(name.clean(cx)),
attrs, attrs,
inner, kind,
visibility: clean::Public, visibility: clean::Public,
stability: cx.tcx.lookup_stability(did).cloned(), stability: cx.tcx.lookup_stability(did).cloned(),
deprecation: cx.tcx.lookup_deprecation(did).clean(cx), 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()); debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
ret.push(clean::Item { ret.push(clean::Item {
inner: clean::ImplItem(clean::Impl { kind: clean::ImplItem(clean::Impl {
unsafety: hir::Unsafety::Normal, unsafety: hir::Unsafety::Normal,
generics, generics,
provided_trait_methods: provided, provided_trait_methods: provided,
@ -498,7 +498,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>)
visibility: clean::Public, visibility: clean::Public,
stability: None, stability: None,
deprecation: None, deprecation: None,
inner: clean::ImportItem(clean::Import::new_simple( kind: clean::ImportItem(clean::Import::new_simple(
item.ident.to_string(), item.ident.to_string(),
clean::ImportSource { clean::ImportSource {
path: clean::Path { 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); let imported_from = cx.tcx.original_crate_name(did.krate);
match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) { match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
LoadedMacro::MacroDef(def, _) => { 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 utils::{get_auto_trait_and_blanket_impls, krate, register_res};
pub use self::types::FnRetTy::*; pub use self::types::FnRetTy::*;
pub use self::types::ItemEnum::*; pub use self::types::ItemKind::*;
pub use self::types::SelfTy::*; pub use self::types::SelfTy::*;
pub use self::types::Type::*; pub use self::types::Type::*;
pub use self::types::Visibility::{Inherited, Public}; pub use self::types::Visibility::{Inherited, Public};
@ -276,7 +276,7 @@ impl Clean<Item> for doctree::Module<'_> {
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), 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), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
def_id: did.to_def_id(), def_id: did.to_def_id(),
inner: FunctionItem(Function { kind: FunctionItem(Function {
decl, decl,
generics, generics,
header: hir::FnHeader { constness, ..self.header }, header: hir::FnHeader { constness, ..self.header },
@ -1023,7 +1023,7 @@ impl Clean<Item> for doctree::Trait<'_> {
visibility: self.vis.clean(cx), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: TraitItem(Trait { kind: TraitItem(Trait {
auto: self.is_auto.clean(cx), auto: self.is_auto.clean(cx),
unsafety: self.unsafety, unsafety: self.unsafety,
items: self.items.iter().map(|ti| ti.clean(cx)).collect(), 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), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: TraitAliasItem(TraitAlias { kind: TraitAliasItem(TraitAlias {
generics: self.generics.clean(cx), generics: self.generics.clean(cx),
bounds: self.bounds.clean(cx), bounds: self.bounds.clean(cx),
}), }),
@ -1102,7 +1102,7 @@ impl Clean<TypeKind> for hir::def::DefKind {
impl Clean<Item> for hir::TraitItem<'_> { impl Clean<Item> for hir::TraitItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item { fn clean(&self, cx: &DocContext<'_>) -> Item {
let local_did = cx.tcx.hir().local_def_id(self.hir_id); 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) => { hir::TraitItemKind::Const(ref ty, default) => {
AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e))) 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, visibility: Visibility::Inherited,
stability: get_stability(cx, local_did.to_def_id()), stability: get_stability(cx, local_did.to_def_id()),
deprecation: get_deprecation(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<'_> { impl Clean<Item> for hir::ImplItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item { fn clean(&self, cx: &DocContext<'_>) -> Item {
let local_did = cx.tcx.hir().local_def_id(self.hir_id); 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) => { hir::ImplItemKind::Const(ref ty, expr) => {
AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, 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), visibility: self.vis.clean(cx),
stability: get_stability(cx, local_did.to_def_id()), stability: get_stability(cx, local_did.to_def_id()),
deprecation: get_deprecation(cx, local_did.to_def_id()), deprecation: get_deprecation(cx, local_did.to_def_id()),
inner, kind,
} }
} }
} }
impl Clean<Item> for ty::AssocItem { impl Clean<Item> for ty::AssocItem {
fn clean(&self, cx: &DocContext<'_>) -> Item { fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.kind { let kind = match self.kind {
ty::AssocKind::Const => { ty::AssocKind::Const => {
let ty = cx.tcx.type_of(self.def_id); let ty = cx.tcx.type_of(self.def_id);
let default = if self.defaultness.has_value() { let default = if self.defaultness.has_value() {
@ -1343,7 +1343,7 @@ impl Clean<Item> for ty::AssocItem {
def_id: self.def_id, def_id: self.def_id,
attrs: inline::load_attrs(cx, self.def_id).clean(cx), attrs: inline::load_attrs(cx, self.def_id).clean(cx),
source: cx.tcx.def_span(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()), stability: get_stability(cx, local_did.to_def_id()),
deprecation: get_deprecation(cx, local_did.to_def_id()), deprecation: get_deprecation(cx, local_did.to_def_id()),
def_id: 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), stability: get_stability(cx, self.did),
deprecation: get_deprecation(cx, self.did), deprecation: get_deprecation(cx, self.did),
def_id: 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), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: StructItem(Struct { kind: StructItem(Struct {
struct_type: self.struct_type, struct_type: self.struct_type,
generics: self.generics.clean(cx), generics: self.generics.clean(cx),
fields: self.fields.clean(cx), fields: self.fields.clean(cx),
@ -1855,7 +1855,7 @@ impl Clean<Item> for doctree::Union<'_> {
visibility: self.vis.clean(cx), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: UnionItem(Union { kind: UnionItem(Union {
struct_type: self.struct_type, struct_type: self.struct_type,
generics: self.generics.clean(cx), generics: self.generics.clean(cx),
fields: self.fields.clean(cx), fields: self.fields.clean(cx),
@ -1885,7 +1885,7 @@ impl Clean<Item> for doctree::Enum<'_> {
visibility: self.vis.clean(cx), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: EnumItem(Enum { kind: EnumItem(Enum {
variants: self.variants.iter().map(|v| v.clean(cx)).collect(), variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
generics: self.generics.clean(cx), generics: self.generics.clean(cx),
variants_stripped: false, variants_stripped: false,
@ -1904,7 +1904,7 @@ impl Clean<Item> for doctree::Variant<'_> {
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), 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, def_id: field.did,
stability: get_stability(cx, field.did), stability: get_stability(cx, field.did),
deprecation: get_deprecation(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(), .collect(),
}), }),
@ -1941,7 +1941,7 @@ impl Clean<Item> for ty::VariantDef {
source: cx.tcx.def_span(self.def_id).clean(cx), source: cx.tcx.def_span(self.def_id).clean(cx),
visibility: Inherited, visibility: Inherited,
def_id: self.def_id, def_id: self.def_id,
inner: VariantItem(Variant { kind }), kind: VariantItem(Variant { kind }),
stability: get_stability(cx, self.def_id), stability: get_stability(cx, self.def_id),
deprecation: get_deprecation(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), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), 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), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: OpaqueTyItem(OpaqueTy { kind: OpaqueTyItem(OpaqueTy {
bounds: self.opaque_ty.bounds.clean(cx), bounds: self.opaque_ty.bounds.clean(cx),
generics: self.opaque_ty.generics.clean(cx), generics: self.opaque_ty.generics.clean(cx),
}), }),
@ -2100,7 +2100,7 @@ impl Clean<Item> for doctree::Static<'_> {
visibility: self.vis.clean(cx), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: StaticItem(Static { kind: StaticItem(Static {
type_: self.type_.clean(cx), type_: self.type_.clean(cx),
mutability: self.mutability, mutability: self.mutability,
expr: print_const_expr(cx, self.expr), expr: print_const_expr(cx, self.expr),
@ -2121,7 +2121,7 @@ impl Clean<Item> for doctree::Constant<'_> {
visibility: self.vis.clean(cx), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: ConstantItem(Constant { kind: ConstantItem(Constant {
type_: self.type_.clean(cx), type_: self.type_.clean(cx),
expr: print_const_expr(cx, self.expr), expr: print_const_expr(cx, self.expr),
value: print_evaluated_const(cx, def_id.to_def_id()), 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), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner: ImplItem(Impl { kind: ImplItem(Impl {
unsafety: self.unsafety, unsafety: self.unsafety,
generics: self.generics.clean(cx), generics: self.generics.clean(cx),
provided_trait_methods: provided.clone(), provided_trait_methods: provided.clone(),
@ -2231,7 +2231,7 @@ impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
visibility: self.vis.clean(cx), visibility: self.vis.clean(cx),
stability: None, stability: None,
deprecation: 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), visibility: self.vis.clean(cx),
stability: None, stability: None,
deprecation: None, deprecation: None,
inner: ImportItem(Import::new_simple( kind: ImportItem(Import::new_simple(
self.name.clean(cx), self.name.clean(cx),
resolve_use_source(cx, path), resolve_use_source(cx, path),
false, false,
@ -2322,14 +2322,14 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
visibility: self.vis.clean(cx), visibility: self.vis.clean(cx),
stability: None, stability: None,
deprecation: None, deprecation: None,
inner: ImportItem(inner), kind: ImportItem(inner),
}] }]
} }
} }
impl Clean<Item> for doctree::ForeignItem<'_> { impl Clean<Item> for doctree::ForeignItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item { 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) => { hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
let abi = cx.tcx.hir().get_foreign_abi(self.id); let abi = cx.tcx.hir().get_foreign_abi(self.id);
let (generics, decl) = let (generics, decl) =
@ -2364,7 +2364,7 @@ impl Clean<Item> for doctree::ForeignItem<'_> {
visibility: self.vis.clean(cx), visibility: self.vis.clean(cx),
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
inner, kind,
} }
} }
} }
@ -2380,7 +2380,7 @@ impl Clean<Item> for doctree::Macro<'_> {
stability: cx.stability(self.hid), stability: cx.stability(self.hid),
deprecation: cx.deprecation(self.hid).clean(cx), deprecation: cx.deprecation(self.hid).clean(cx),
def_id: self.def_id, def_id: self.def_id,
inner: MacroItem(Macro { kind: MacroItem(Macro {
source: format!( source: format!(
"macro_rules! {} {{\n{}}}", "macro_rules! {} {{\n{}}}",
name, name,
@ -2405,7 +2405,7 @@ impl Clean<Item> for doctree::ProcMacro<'_> {
stability: cx.stability(self.id), stability: cx.stability(self.id),
deprecation: cx.deprecation(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), 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 crate::html::render::cache::ExternalLocation;
use self::FnRetTy::*; use self::FnRetTy::*;
use self::ItemEnum::*; use self::ItemKind::*;
use self::SelfTy::*; use self::SelfTy::*;
use self::Type::*; use self::Type::*;
@ -81,7 +81,7 @@ pub struct Item {
/// Not everything has a name. E.g., impls /// Not everything has a name. E.g., impls
pub name: Option<String>, pub name: Option<String>,
pub attrs: Attributes, pub attrs: Attributes,
pub inner: ItemEnum, pub kind: ItemKind,
pub visibility: Visibility, pub visibility: Visibility,
pub def_id: DefId, pub def_id: DefId,
pub stability: Option<Stability>, pub stability: Option<Stability>,
@ -90,14 +90,13 @@ pub struct Item {
impl fmt::Debug for Item { impl fmt::Debug for Item {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let fake = self.is_fake(); let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };
fmt.debug_struct("Item") fmt.debug_struct("Item")
.field("source", &self.source) .field("source", &self.source)
.field("name", &self.name) .field("name", &self.name)
.field("attrs", &self.attrs) .field("attrs", &self.attrs)
.field("inner", &self.inner) .field("kind", &self.kind)
.field("visibility", &self.visibility) .field("visibility", &self.visibility)
.field("def_id", def_id) .field("def_id", def_id)
.field("stability", &self.stability) .field("stability", &self.stability)
@ -124,7 +123,7 @@ impl Item {
} }
pub fn is_crate(&self) -> bool { pub fn is_crate(&self) -> bool {
match self.inner { match self.kind {
StrippedItem(box ModuleItem(Module { is_crate: true, .. })) StrippedItem(box ModuleItem(Module { is_crate: true, .. }))
| ModuleItem(Module { is_crate: true, .. }) => true, | ModuleItem(Module { is_crate: true, .. }) => true,
_ => false, _ => false,
@ -176,14 +175,14 @@ impl Item {
self.type_() == ItemType::Keyword self.type_() == ItemType::Keyword
} }
pub fn is_stripped(&self) -> bool { pub fn is_stripped(&self) -> bool {
match self.inner { match self.kind {
StrippedItem(..) => true, StrippedItem(..) => true,
ImportItem(ref i) => !i.should_be_displayed, ImportItem(ref i) => !i.should_be_displayed,
_ => false, _ => false,
} }
} }
pub fn has_stripped_fields(&self) -> Option<bool> { pub fn has_stripped_fields(&self) -> Option<bool> {
match self.inner { match self.kind {
StructItem(ref _struct) => Some(_struct.fields_stripped), StructItem(ref _struct) => Some(_struct.fields_stripped),
UnionItem(ref union) => Some(union.fields_stripped), UnionItem(ref union) => Some(union.fields_stripped),
VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => { VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => {
@ -227,8 +226,8 @@ impl Item {
} }
pub fn is_default(&self) -> bool { pub fn is_default(&self) -> bool {
match self.inner { match self.kind {
ItemEnum::MethodItem(ref meth) => { ItemKind::MethodItem(ref meth) => {
if let Some(defaultness) = meth.defaultness { if let Some(defaultness) = meth.defaultness {
defaultness.has_value() && !defaultness.is_final() defaultness.has_value() && !defaultness.is_final()
} else { } else {
@ -248,7 +247,7 @@ impl Item {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ItemEnum { pub enum ItemKind {
ExternCrateItem(String, Option<String>), ExternCrateItem(String, Option<String>),
ImportItem(Import), ImportItem(Import),
StructItem(Struct), StructItem(Struct),
@ -282,23 +281,23 @@ pub enum ItemEnum {
AssocConstItem(Type, Option<String>), AssocConstItem(Type, Option<String>),
AssocTypeItem(Vec<GenericBound>, Option<Type>), AssocTypeItem(Vec<GenericBound>, Option<Type>),
/// An item that has been stripped by a rustdoc pass /// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemEnum>), StrippedItem(Box<ItemKind>),
KeywordItem(String), KeywordItem(String),
} }
impl ItemEnum { impl ItemKind {
pub fn is_type_alias(&self) -> bool { pub fn is_type_alias(&self) -> bool {
match *self { match *self {
ItemEnum::TypedefItem(_, _) | ItemEnum::AssocTypeItem(_, _) => true, ItemKind::TypedefItem(_, _) | ItemKind::AssocTypeItem(_, _) => true,
_ => false, _ => false,
} }
} }
pub fn as_assoc_kind(&self) -> Option<AssocKind> { pub fn as_assoc_kind(&self) -> Option<AssocKind> {
match *self { match *self {
ItemEnum::AssocConstItem(..) => Some(AssocKind::Const), ItemKind::AssocConstItem(..) => Some(AssocKind::Const),
ItemEnum::AssocTypeItem(..) => Some(AssocKind::Type), ItemKind::AssocTypeItem(..) => Some(AssocKind::Type),
ItemEnum::TyMethodItem(..) | ItemEnum::MethodItem(..) => Some(AssocKind::Fn), ItemKind::TyMethodItem(..) | ItemKind::MethodItem(..) => Some(AssocKind::Fn),
_ => None, _ => None,
} }
} }
@ -681,7 +680,9 @@ impl Attributes {
} }
Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(), Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(),
Some(&(_, _, ExternalLocation::Unknown)) | None => String::from( 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" "https://doc.rust-lang.org/nightly"
} else { } else {
"https://doc.rust-lang.org" "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::blanket_impl::BlanketImplFinder;
use crate::clean::{ use crate::clean::{
inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg, 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, MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Type, TypeBinding,
TypeKind, Visibility, WherePredicate, TypeKind, Visibility, WherePredicate,
}; };
@ -44,8 +44,8 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
let mut module = module.clean(cx); let mut module = module.clean(cx);
let mut masked_crates = FxHashSet::default(); let mut masked_crates = FxHashSet::default();
match module.inner { match module.kind {
ItemEnum::ModuleItem(ref module) => { ItemKind::ModuleItem(ref module) => {
for it in &module.items { for it in &module.items {
// `compiler_builtins` should be masked too, but we can't apply // `compiler_builtins` should be masked too, but we can't apply
// `#[doc(masked)]` to the injected `extern crate` because it's unstable. // `#[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 ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
{ {
let m = match module.inner { let m = match module.kind {
ItemEnum::ModuleItem(ref mut m) => m, ItemKind::ModuleItem(ref mut m) => m,
_ => unreachable!(), _ => unreachable!(),
}; };
m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| Item { 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), stability: get_stability(cx, def_id),
deprecation: get_deprecation(cx, def_id), deprecation: get_deprecation(cx, def_id),
def_id, def_id,
inner: ItemEnum::PrimitiveItem(prim), kind: ItemKind::PrimitiveItem(prim),
})); }));
m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| Item { m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| Item {
source: Span::empty(), source: Span::empty(),
@ -84,7 +84,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
stability: get_stability(cx, def_id), stability: get_stability(cx, def_id),
deprecation: get_deprecation(cx, def_id), deprecation: get_deprecation(cx, def_id),
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; let tcx = cx.tcx;
for item in items { for item in items {
let target = match item.inner { let target = match item.kind {
ItemEnum::TypedefItem(ref t, true) => &t.type_, ItemKind::TypedefItem(ref t, true) => &t.type_,
_ => continue, _ => continue,
}; };
let primitive = match *target { let primitive = match *target {

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground}; use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
use crate::rustc_span::edition::Edition; use crate::rustc_span::edition::Edition;
use rustc_feature::UnstableFeatures;
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use std::str; use std::str;
@ -25,12 +24,13 @@ impl ExternalHtml {
after_content: &[String], after_content: &[String],
md_before_content: &[String], md_before_content: &[String],
md_after_content: &[String], md_after_content: &[String],
nightly_build: bool,
diag: &rustc_errors::Handler, diag: &rustc_errors::Handler,
id_map: &mut IdMap, id_map: &mut IdMap,
edition: Edition, edition: Edition,
playground: &Option<Playground>, playground: &Option<Playground>,
) -> Option<ExternalHtml> { ) -> 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 ih = load_external_files(in_header, diag)?;
let bc = load_external_files(before_content, diag)?; let bc = load_external_files(before_content, diag)?;
let m_bc = load_external_files(md_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 { impl StripItem {
pub fn strip(self) -> Option<Item> { pub fn strip(self) -> Option<Item> {
match self.0 { match self.0 {
Item { inner: StrippedItem(..), .. } => Some(self.0), Item { kind: StrippedItem(..), .. } => Some(self.0),
mut i => { mut i => {
i.inner = StrippedItem(box i.inner); i.kind = StrippedItem(box i.kind);
Some(i) Some(i)
} }
} }
@ -20,8 +20,8 @@ pub trait DocFolder: Sized {
} }
/// don't override! /// don't override!
fn fold_inner_recur(&mut self, inner: ItemEnum) -> ItemEnum { fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
match inner { match kind {
StrippedItem(..) => unreachable!(), StrippedItem(..) => unreachable!(),
ModuleItem(i) => ModuleItem(self.fold_mod(i)), ModuleItem(i) => ModuleItem(self.fold_mod(i)),
StructItem(mut i) => { StructItem(mut i) => {
@ -72,14 +72,14 @@ pub trait DocFolder: Sized {
/// don't override! /// don't override!
fn fold_item_recur(&mut self, item: Item) -> Option<Item> { 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)), 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 { fn fold_mod(&mut self, m: Module) -> Module {

View File

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

View File

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

View File

@ -32,7 +32,7 @@ pub struct Impl {
impl Impl { impl Impl {
pub fn inner_impl(&self) -> &clean::Impl { pub fn inner_impl(&self) -> &clean::Impl {
match self.impl_item.inner { match self.impl_item.kind {
clean::ImplItem(ref impl_) => impl_, clean::ImplItem(ref impl_) => impl_,
_ => panic!("non-impl item found in 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)?; 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, clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m,
_ => unreachable!(), _ => 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> { 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::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
clean::MethodItem(ref m) => (&m.all_types, &m.ret_types), clean::MethodItem(ref m) => (&m.all_types, &m.ret_types),
clean::TyMethodItem(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_attr::StabilityLevel;
use rustc_data_structures::flock; use rustc_data_structures::flock;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_feature::UnstableFeatures;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::Mutability; use rustc_hir::Mutability;
@ -397,6 +396,7 @@ impl FormatRenderer for Context {
resource_suffix, resource_suffix,
static_root_path, static_root_path,
generate_search_filter, generate_search_filter,
unstable_features,
.. ..
} = options; } = options;
@ -466,7 +466,7 @@ impl FormatRenderer for Context {
static_root_path, static_root_path,
fs: DocFS::new(sender), fs: DocFS::new(sender),
edition, edition,
codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), codes: ErrorCodes::from(unstable_features.is_nightly_build()),
playground, playground,
}; };
@ -618,7 +618,7 @@ impl FormatRenderer for Context {
// Render sidebar-items.js used throughout this module. // Render sidebar-items.js used throughout this module.
if !self.render_redirect_pages { 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, clean::StrippedItem(box clean::ModuleItem(ref m)) | clean::ModuleItem(ref m) => m,
_ => unreachable!(), _ => 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>"); // out-of-band
write!(buf, "<span class=\"in-band\">"); write!(buf, "<span class=\"in-band\">");
let name = match item.inner { let name = match item.kind {
clean::ModuleItem(ref m) => { clean::ModuleItem(ref m) => {
if m.is_crate { if m.is_crate {
"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 write!(buf, "</span></h1>"); // in-band
match item.inner { match item.kind {
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items), clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => { clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
item_function(buf, cx, item, 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) => { clean::ExternCrateItem(ref name, ref src) => {
use crate::html::format::anchor; use crate::html::format::anchor;
@ -2169,7 +2169,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
continue; continue;
} }
let unsafety_flag = match myitem.inner { let unsafety_flag = match myitem.kind {
clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func) clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
if func.header.unsafety == hir::Unsafety::Unsafe => 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() { for (pos, m) in provided.iter().enumerate() {
render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait); 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() => { clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => {
write!(w, ",\n {{ ... }}\n"); write!(w, ",\n {{ ... }}\n");
} }
@ -2958,7 +2958,7 @@ fn render_assoc_item(
where_clause = WhereClause { gens: g, indent, end_newline } where_clause = WhereClause { gens: g, indent, end_newline }
) )
} }
match item.inner { match item.kind {
clean::StrippedItem(..) => {} clean::StrippedItem(..) => {}
clean::TyMethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent), 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), 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 let mut fields = s
.fields .fields
.iter() .iter()
.filter_map(|f| match f.inner { .filter_map(|f| match f.kind {
clean::StructFieldItem(ref ty) => Some((f, ty)), clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None, _ => None,
}) })
@ -3044,7 +3044,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union,
let mut fields = s let mut fields = s
.fields .fields
.iter() .iter()
.filter_map(|f| match f.inner { .filter_map(|f| match f.kind {
clean::StructFieldItem(ref ty) => Some((f, ty)), clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None, _ => 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 { for v in &e.variants {
write!(w, " "); write!(w, " ");
let name = v.name.as_ref().unwrap(); let name = v.name.as_ref().unwrap();
match v.inner { match v.kind {
clean::VariantItem(ref var) => match var.kind { clean::VariantItem(ref var) => match var.kind {
clean::VariantKind::CLike => write!(w, "{}", name), clean::VariantKind::CLike => write!(w, "{}", name),
clean::VariantKind::Tuple(ref tys) => { 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, id = id,
name = variant.name.as_ref().unwrap() 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 { if let clean::VariantKind::Tuple(ref tys) = var.kind {
write!(w, "("); write!(w, "(");
for (i, ty) in tys.iter().enumerate() { 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); document_non_exhaustive(w, variant);
use crate::clean::{Variant, VariantKind}; 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!( let variant_id = cx.derive_id(format!(
"{}.{}.fields", "{}.{}.fields",
ItemType::Variant, 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 { for field in &s.fields {
use crate::clean::StructFieldItem; use crate::clean::StructFieldItem;
if let StructFieldItem(ref ty) = field.inner { if let StructFieldItem(ref ty) = field.kind {
let id = cx.derive_id(format!( let id = cx.derive_id(format!(
"variant.{}.field.{}", "variant.{}.field.{}",
variant.name.as_ref().unwrap(), variant.name.as_ref().unwrap(),
@ -3275,7 +3274,7 @@ fn render_struct(
let mut has_visible_fields = false; let mut has_visible_fields = false;
write!(w, " {{"); write!(w, " {{");
for field in fields { for field in fields {
if let clean::StructFieldItem(ref ty) = field.inner { if let clean::StructFieldItem(ref ty) = field.kind {
write!( write!(
w, w,
"\n{} {}{}: {},", "\n{} {}{}: {},",
@ -3306,7 +3305,7 @@ fn render_struct(
if i > 0 { if i > 0 {
write!(w, ", "); write!(w, ", ");
} }
match field.inner { match field.kind {
clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
clean::StructFieldItem(ref ty) => { clean::StructFieldItem(ref ty) => {
write!(w, "{}{}", field.visibility.print_with_space(), ty.print()) write!(w, "{}{}", field.visibility.print_with_space(), ty.print())
@ -3352,7 +3351,7 @@ fn render_union(
write!(w, " {{\n{}", tab); write!(w, " {{\n{}", tab);
for field in fields { for field in fields {
if let clean::StructFieldItem(ref ty) = field.inner { if let clean::StructFieldItem(ref ty) = field.kind {
write!( write!(
w, w,
" {}{}: {},\n{}", " {}{}: {},\n{}",
@ -3516,7 +3515,7 @@ fn render_deref_methods(
.inner_impl() .inner_impl()
.items .items
.iter() .iter()
.find_map(|item| match item.inner { .find_map(|item| match item.kind {
clean::TypedefItem(ref t, true) => Some(match *t { clean::TypedefItem(ref t, true) => Some(match *t {
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_), clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
_ => (&t.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 { 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::MethodItem(ref method) => method.decl.self_type(),
clean::TyMethodItem(ref method) => method.decl.self_type(), clean::TyMethodItem(ref method) => method.decl.self_type(),
_ => None, _ => None,
@ -3589,7 +3588,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
)); ));
let t_did = impl_.trait_.def_id().unwrap(); let t_did = impl_.trait_.def_id().unwrap();
for it in &impl_.items { 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\"> "); out.push_str("<span class=\"where fmt-newline\"> ");
assoc_type( assoc_type(
&mut out, &mut out,
@ -3657,7 +3656,7 @@ fn render_impl(
fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute); fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute);
if show_def_docs { if show_def_docs {
for it in &i.inner_impl().items { 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\"> "); write!(w, "<span class=\"where fmt-newline\"> ");
assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), ""); assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "");
write!(w, ";</span>"); write!(w, ";</span>");
@ -3728,14 +3727,14 @@ fn render_impl(
}; };
let (is_hidden, extra_class) = 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 && !is_default_item
{ {
(false, "") (false, "")
} else { } else {
(true, " hidden") (true, " hidden")
}; };
match item.inner { match item.kind {
clean::MethodItem(clean::Method { .. }) clean::MethodItem(clean::Method { .. })
| clean::TyMethodItem(clean::TyMethod { .. }) => { | clean::TyMethodItem(clean::TyMethod { .. }) => {
// Only render when the method is not static or we allow static methods // 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!( write!(
buffer, buffer,
"<p class=\"location\">{}{}</p>", "<p class=\"location\">{}{}</p>",
match it.inner { match it.kind {
clean::StructItem(..) => "Struct ", clean::StructItem(..) => "Struct ",
clean::TraitItem(..) => "Trait ", clean::TraitItem(..) => "Trait ",
clean::PrimitiveItem(..) => "Primitive Type ", 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") 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::StructItem(ref s) => sidebar_struct(buffer, it, s),
clean::TraitItem(ref t) => sidebar_trait(buffer, it, t), clean::TraitItem(ref t) => sidebar_trait(buffer, it, t),
clean::PrimitiveItem(_) => sidebar_primitive(buffer, it), 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) .find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did)
{ {
if let Some((target, real_target)) = 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::TypedefItem(ref t, true) => Some(match *t {
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_), clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
_ => (&t.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)> { fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> {
match item.inner { match item.kind {
clean::ItemEnum::ImplItem(ref i) => { clean::ItemKind::ImplItem(ref i) => {
if let Some(ref trait_) = i.trait_ { if let Some(ref trait_) = i.trait_ {
Some(( Some((
format!("{:#}", i.for_.print()), 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 { fn get_struct_fields_name(fields: &[clean::Item]) -> String {
let mut fields = fields let mut fields = fields
.iter() .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 { .filter_map(|f| match f.name {
Some(ref name) => { Some(ref name) => {
Some(format!("<a href=\"#structfield.{name}\">{name}</a>", name = 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::io::prelude::*;
use std::path::Path; use std::path::Path;
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::source_map::DUMMY_SP; use rustc_span::source_map::DUMMY_SP;
@ -66,7 +65,7 @@ pub fn render<P: AsRef<Path>>(
let title = metadata[0]; let title = metadata[0];
let mut ids = IdMap::new(); 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 { let text = if !options.markdown_no_toc {
MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string() MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string()
} else { } else {
@ -131,7 +130,7 @@ pub fn test(mut options: Options) -> Result<(), String> {
options.enable_per_target_ignores, options.enable_per_target_ignores,
); );
collector.set_position(DUMMY_SP); 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); 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> { impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> { fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
match i.inner { match i.kind {
_ if !i.def_id.is_local() => { _ if !i.def_id.is_local() => {
// non-local items are skipped because they can be out of the users control, // 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 // 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 implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did);
let mut candidates: Vec<_> = implicit_impls let mut candidates: Vec<_> = implicit_impls
.flat_map(|impl_outer| { .flat_map(|impl_outer| {
match impl_outer.inner { match impl_outer.kind {
clean::ImplItem(impl_) => { clean::ImplItem(impl_) => {
debug!("considering auto or blanket impl for trait {:?}", impl_.trait_); debug!("considering auto or blanket impl for trait {:?}", impl_.trait_);
// Give precedence to methods that were overridden // Give precedence to methods that were overridden
@ -681,14 +681,14 @@ fn resolve_associated_trait_item(
return None; return None;
} }
let kind = assoc let kind = assoc
.inner .kind
.as_assoc_kind() .as_assoc_kind()
.expect("inner items for a trait should be associated items"); .expect("inner items for a trait should be associated items");
if kind.namespace() != ns { if kind.namespace() != ns {
return None; 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, // We have a slight issue: normal methods come from `clean` types,
// but provided methods come directly from `tcx`. // but provided methods come directly from `tcx`.
// Fortunately, we don't need the whole method, we just need to know // 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); 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(..) => { clean::ModuleItem(..) => {
if item.attrs.inner_docs { if item.attrs.inner_docs {
if item.def_id.is_top_level_module() { item.name.clone() } else { None } 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 // scan through included items ahead of time to splice in Deref targets to the "valid" sets
for it in &new_items { 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() { if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
let target = items let target = items
.iter() .iter()
.find_map(|item| match item.inner { .find_map(|item| match item.kind {
TypedefItem(ref t, true) => Some(&t.type_), TypedefItem(ref t, true) => Some(&t.type_),
_ => None, _ => None,
}) })
@ -75,7 +75,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
} }
new_items.retain(|it| { 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_) cleaner.keep_item(for_)
|| trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) || trait_.as_ref().map_or(false, |t| cleaner.keep_item(t))
|| blanket_impl.is_some() || 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 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(synth.impls);
items.extend(new_items); items.extend(new_items);
} else { } 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 { pub fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
if matches!(item.inner, if matches!(item.kind,
clean::StructFieldItem(_) clean::StructFieldItem(_)
| clean::VariantItem(_) | clean::VariantItem(_)
| clean::AssocConstItem(_, _) | 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); find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
if tests.found_tests == 0 if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() {
&& rustc_feature::UnstableFeatures::from_environment().is_nightly_build()
{
if should_have_doc_example(cx, &item) { if should_have_doc_example(cx, &item) {
debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); 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 crate::html::markdown::opts;
use core::ops::Range; use core::ops::Range;
use pulldown_cmark::{Event, Parser}; use pulldown_cmark::{Event, Parser};
use rustc_feature::UnstableFeatures;
use rustc_session::lint; use rustc_session::lint;
use std::iter::Peekable; use std::iter::Peekable;
use std::str::CharIndices; 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 { 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 krate
} else { } else {
let mut coll = InvalidHtmlTagsLinter::new(cx); let mut coll = InvalidHtmlTagsLinter::new(cx);

View File

@ -7,7 +7,6 @@ use core::ops::Range;
use pulldown_cmark::{Event, LinkType, Parser, Tag}; use pulldown_cmark::{Event, LinkType, Parser, Tag};
use regex::Regex; use regex::Regex;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_feature::UnstableFeatures;
use rustc_session::lint; use rustc_session::lint;
pub const CHECK_NON_AUTOLINKS: Pass = Pass { 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 { 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 krate
} else { } else {
let mut coll = NonAutolinksLinter::new(cx); 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) { if i.attrs.lists(sym::doc).has_word(sym::hidden) {
debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name); debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
// use a dedicated hidden item for given item type if any // use a dedicated hidden item for given item type if any
match i.inner { match i.kind {
clean::StructFieldItem(..) | clean::ModuleItem(..) => { clean::StructFieldItem(..) | clean::ModuleItem(..) => {
// We need to recurse into stripped modules to // We need to recurse into stripped modules to
// strip things like impl methods but when doing so // 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> { impl<'a> DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> { fn fold_item(&mut self, i: Item) -> Option<Item> {
match i.inner { match i.kind {
clean::StrippedItem(..) => { clean::StrippedItem(..) => {
// We need to recurse into stripped modules to strip things // We need to recurse into stripped modules to strip things
// like impl methods but when doing so we must not add any // like impl methods but when doing so we must not add any
@ -86,7 +86,7 @@ impl<'a> DocFolder for Stripper<'a> {
clean::KeywordItem(..) => {} clean::KeywordItem(..) => {}
} }
let fastreturn = match i.inner { let fastreturn = match i.kind {
// nothing left to do for traits (don't want to filter their // nothing left to do for traits (don't want to filter their
// methods out, visibility controlled by the trait) // methods out, visibility controlled by the trait)
clean::TraitItem(..) => true, clean::TraitItem(..) => true,
@ -123,7 +123,7 @@ pub struct ImplStripper<'a> {
impl<'a> DocFolder for ImplStripper<'a> { impl<'a> DocFolder for ImplStripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> { 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 // emptied none trait impls can be stripped
if imp.trait_.is_none() && imp.items.is_empty() { if imp.trait_.is_none() && imp.items.is_empty() {
return None; return None;
@ -162,7 +162,7 @@ pub struct ImportStripper;
impl DocFolder for ImportStripper { impl DocFolder for ImportStripper {
fn fold_item(&mut self, i: Item) -> Option<Item> { fn fold_item(&mut self, i: Item) -> Option<Item> {
match i.inner { match i.kind {
clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => { clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => {
None None
} }

View File

@ -3,5 +3,6 @@ mod underscore;
fn main() { fn main() {
underscore!(); 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 --> $DIR/underscore.rs:8:9
| |
LL | _ 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 ::: $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) = 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((a, b), c), b: [d] } =
Struct { a: TupleStruct((0, 1), 2), b: [3] }; Struct { a: TupleStruct((0, 1), 2), b: [3] };
assert_eq!((a, b, c, d), (0, 1, 2, 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; let mut c;
[a, .., b, c] = [1, 2, 3, 4, 5]; [a, .., b, c] = [1, 2, 3, 4, 5];
assert_eq!((a, b, c), (1, 4, 5)); assert_eq!((a, b, c), (1, 4, 5));
[_, a, _] = [1, 2, 3];
assert_eq!((a, b), (2, 4));
[..] = [1, 2, 3]; [..] = [1, 2, 3];
[c, ..] = [5, 6, 6]; [c, ..] = [5, 6, 6];
assert_eq!(c, 5); assert_eq!(c, 5);

View File

@ -4,4 +4,5 @@ fn main() {
let (mut a, mut b); let (mut a, mut b);
[a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern [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 [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]; LL | [a, a, b] = [1, 2];
| ^^^^^^^^^ expected 2 elements | ^^^^^^^^^ 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`. For more information about this error, try `rustc --explain E0527`.

View File

@ -12,8 +12,10 @@ fn main() {
assert_eq!((a, b), (0, 1)); assert_eq!((a, b), (0, 1));
Struct { a: b, b: a } = Struct { a: 1, b: 2 }; Struct { a: b, b: a } = Struct { a: 1, b: 2 };
assert_eq!((a,b), (2, 1)); 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 }; 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 }; 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 mut c;
let d = Struct { a: 0, b: 1 }; 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, 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 }; Struct { a, ..d } = Struct { a: 1, b: 2 };
//~^ ERROR functional record updates are not allowed in destructuring assignments //~^ ERROR functional record updates are not allowed in destructuring assignments
Struct { a, .. }; //~ ERROR base expression required after `..` 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 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 }; LL | Struct { a, ..d } = Struct { a: 1, b: 2 };
| ^ help: consider removing the trailing pattern | ^ help: consider removing the trailing pattern
error: base expression required after `..` error: base expression required after `..`
--> $DIR/struct_destructure_fail.rs:14:19 --> $DIR/struct_destructure_fail.rs:16:19
| |
LL | Struct { a, .. }; LL | Struct { a, .. };
| ^ add a base expression here | ^ 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 }; LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
| ^ struct `Struct` does not have this field | ^ 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)); assert_eq!((a, b), (2, 2));
(b, ..) = (5, 6, 7); (b, ..) = (5, 6, 7);
assert_eq!(b, 5); assert_eq!(b, 5);
(a, _) = (8, 9);
assert_eq!(a, 8);
// Test for a non-Copy type (String): // Test for a non-Copy type (String):
let (mut c, mut d); 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, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern
(a, a, b) = (1, 2); //~ ERROR mismatched types (a, a, b) = (1, 2); //~ ERROR mismatched types
(C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment (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 | 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. Some errors have detailed explanations: E0070, E0308.
For more information about an error, try `rustc --explain E0070`. For more information about an error, try `rustc --explain E0070`.

View File

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

View File

@ -29,8 +29,12 @@ fn main() {
TupleStruct(a, a, b) = TupleStruct(1, 2); TupleStruct(a, a, b) = TupleStruct(1, 2);
//~^ ERROR this pattern has 3 fields, but the corresponding tuple struct has 2 fields //~^ 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); Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
//~^ ERROR this pattern has 3 fields, but the corresponding tuple variant has 2 fields //~^ 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: // Check if `test` is recognized as not a tuple struct but a function call:
test() = TupleStruct(0, 0); 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); LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
| ^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3 | ^^^^^^^^^^^^^^^^^^^^ 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 --> $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) LL | SingleVariant(S, T)
| ------------------- tuple variant defined here | ------------------- tuple variant defined here
... ...
LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2); LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 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); LL | test() = TupleStruct(0, 0);
| ------ ^ | ------ ^
@ -41,7 +59,7 @@ LL | test() = TupleStruct(0, 0);
| cannot assign to this expression | cannot assign to this expression
error[E0070]: invalid left-hand side of assignment 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); LL | (test)() = TupleStruct(0, 0);
| -------- ^ | -------- ^
@ -49,14 +67,14 @@ LL | (test)() = TupleStruct(0, 0);
| cannot assign to this expression | cannot assign to this expression
error[E0070]: invalid left-hand side of assignment 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); LL | <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
| -------------------------------- ^ | -------------------------------- ^
| | | |
| cannot assign to this expression | 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. Some errors have detailed explanations: E0023, E0070.
For more information about an error, try `rustc --explain E0023`. For more information about an error, try `rustc --explain E0023`.

View File

@ -4,5 +4,7 @@ struct S { x : u32 }
#[cfg(FALSE)] #[cfg(FALSE)]
fn foo() { fn foo() {
_; //~ ERROR destructuring assignments are unstable
S { x: 5, .. }; //~ 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 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, .. }; 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 = 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 = 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`. For more information about this error, try `rustc --explain E0658`.

View File

@ -8,12 +8,18 @@ trait T {
fn main() { fn main() {
let _: usize = foo(_, _); let _: usize = foo(_, _);
//~^ ERROR expected expression //~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR expected expression //~| 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(_, _); let _: S = S(_, _);
//~^ ERROR expected expression //~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR expected expression //~| 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(_, _); let _: usize = T::baz(_, _);
//~^ ERROR expected expression //~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR expected expression //~| 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 --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
| |
LL | let _: usize = foo(_, _); 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 --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27
| |
LL | let _: usize = foo(_, _); 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:13:18 --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18
| |
LL | let _: S = S(_, _); 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 `_` error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:21 --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21
| |
LL | let _: S = S(_, _); 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 `_` error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:27 --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27
| |
LL | let _: usize = T::baz(_, _); 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 `_` error[E0658]: destructuring assignments are unstable
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:30 --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30
| |
LL | let _: usize = T::baz(_, _); 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::MacCall(..)
| ast::ExprKind::MethodCall(..) | ast::ExprKind::MethodCall(..)
| ast::ExprKind::Paren(..) | ast::ExprKind::Paren(..)
| ast::ExprKind::Underscore
| ast::ExprKind::Path(..) | ast::ExprKind::Path(..)
| ast::ExprKind::Repeat(..) | ast::ExprKind::Repeat(..)
| ast::ExprKind::Ret(..) | ast::ExprKind::Ret(..)

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