From 0687b78d56b93d28ceeaa05e794849757d7341a4 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 13 Jun 2020 10:29:56 -0700 Subject: [PATCH 01/21] Speed up bootstrap a little. --- src/bootstrap/flags.rs | 7 ++--- src/bootstrap/lib.rs | 2 +- src/bootstrap/metadata.rs | 65 +++++++++++++++++---------------------- src/bootstrap/test.rs | 4 +-- 4 files changed, 33 insertions(+), 45 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index cfaa43f397095..03b7028b2fa55 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -10,12 +10,10 @@ use std::process; use getopts::Options; use crate::builder::Builder; +use crate::cache::{Interned, INTERNER}; use crate::config::Config; -use crate::metadata; use crate::{Build, DocTests}; -use crate::cache::{Interned, INTERNER}; - /// Deserialized version of all flags for this compile. pub struct Flags { pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo @@ -444,8 +442,7 @@ Arguments: // All subcommands except `clean` can have an optional "Available paths" section if matches.opt_present("verbose") { let config = Config::parse(&["build".to_string()]); - let mut build = Build::new(config); - metadata::build(&mut build); + let build = Build::new(config); let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8d8a036caef88..a125b49fc01e6 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -271,7 +271,7 @@ struct Crate { impl Crate { fn is_local(&self, build: &Build) -> bool { - self.path.starts_with(&build.config.src) && !self.path.to_string_lossy().ends_with("_shim") + self.path.starts_with(&build.config.src) } fn local_path(&self, build: &Build) -> PathBuf { diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 292aa3b1e24a7..185f0ddb831e7 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -35,49 +35,24 @@ struct ResolveNode { } pub fn build(build: &mut Build) { - let mut resolves = Vec::new(); - build_krate(&build.std_features(), build, &mut resolves, "src/libstd"); - build_krate("", build, &mut resolves, "src/libtest"); - build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc"); - - let mut id2name = HashMap::with_capacity(build.crates.len()); - for (name, krate) in build.crates.iter() { - id2name.insert(krate.id.clone(), name.clone()); - } - - for node in resolves { - let name = match id2name.get(&node.id) { - Some(name) => name, - None => continue, - }; - - let krate = build.crates.get_mut(name).unwrap(); - for dep in node.dependencies.iter() { - let dep = match id2name.get(dep) { - Some(dep) => dep, - None => continue, - }; - krate.deps.insert(*dep); - } - } -} - -fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec, krate: &str) { // Run `cargo metadata` to figure out what crates we're testing. - // - // Down below we're going to call `cargo test`, but to test the right set - // of packages we're going to have to know what `-p` arguments to pass it - // to know what crates to test. Here we run `cargo metadata` to learn about - // the dependency graph and what `-p` arguments there are. + let features: Vec<_> = build + .std_features() + .split_whitespace() + .map(|f| format!("test/{}", f)) + .chain(build.rustc_features().split_whitespace().map(|f| format!("rustc-main/{}", f))) + .collect(); let mut cargo = Command::new(&build.initial_cargo); cargo .arg("metadata") .arg("--format-version") .arg("1") .arg("--features") - .arg(features) + .arg(features.join(",")) + .arg("-Zpackage-features") .arg("--manifest-path") - .arg(build.src.join(krate).join("Cargo.toml")); + .arg(build.src.join("Cargo.toml")) + .env("RUSTC_BOOTSTRAP", "1"); let output = output(&mut cargo); let output: Output = serde_json::from_str(&output).unwrap(); for package in output.packages { @@ -88,5 +63,23 @@ fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec = + build.crates.iter().map(|(name, krate)| (krate.id.clone(), name.clone())).collect(); + + for node in output.resolve.nodes { + let name = match id2name.get(&node.id) { + Some(name) => name, + None => continue, + }; + + let krate = build.crates.get_mut(name).unwrap(); + for dep in node.dependencies.iter() { + let dep = match id2name.get(dep) { + Some(dep) => dep, + None => continue, + }; + krate.deps.insert(*dep); + } + } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 163132f563425..8659acf1cc5a5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1654,9 +1654,7 @@ impl Step for Crate { fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; for krate in run.builder.in_tree_crates("test") { - if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) { - run = run.path(krate.local_path(&builder).to_str().unwrap()); - } + run = run.path(krate.local_path(&builder).to_str().unwrap()); } run } From e32db8458457849f5d894ffa4a1672b9071708f0 Mon Sep 17 00:00:00 2001 From: asrar Date: Sun, 14 Jun 2020 21:44:11 +0530 Subject: [PATCH 02/21] Add rust features to print target features `crt-static` is a rust specific target feature that's absent from llvm feature table, adding it there. --- src/rustllvm/PassWrapper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 3d252fe70afeb..7586dd91ab68b 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -425,6 +425,9 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) { for (auto &Feature : FeatTable) printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); printf("\n"); + // Rust specific target features + printf(" %-*s - %s.\n", MaxFeatLen, "crt-static", "Enables libraries with C Run-time Libraries(CRT) to be statically linked"); + printf("\n"); printf("Use +feature to enable a feature, or -feature to disable it.\n" "For example, rustc -C -target-cpu=mycpu -C " From 607e85110ef9c79ce5a52286bb69d385471bc675 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 14 Jun 2020 15:57:21 -0700 Subject: [PATCH 03/21] Switch bootstrap metadata to --no-deps. This should run much faster. There are also some drive-by cleanups here to try to simplify things. Also, the paths for in-tree crates are now displayed as relative in `x.py test -h -v`. --- src/bootstrap/builder.rs | 6 +++-- src/bootstrap/doc.rs | 20 ++------------ src/bootstrap/lib.rs | 25 +++++++++++------- src/bootstrap/metadata.rs | 55 +++++++++------------------------------ src/bootstrap/test.rs | 8 ++---- 5 files changed, 37 insertions(+), 77 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ffdd8485181f4..345af600c2adb 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -255,7 +255,8 @@ impl<'a> ShouldRun<'a> { pub fn all_krates(mut self, name: &str) -> Self { let mut set = BTreeSet::new(); for krate in self.builder.in_tree_crates(name) { - set.insert(PathBuf::from(&krate.path)); + let path = krate.local_path(self.builder); + set.insert(path); } self.paths.insert(PathSet::Set(set)); self @@ -263,7 +264,8 @@ impl<'a> ShouldRun<'a> { pub fn krate(mut self, name: &str) -> Self { for krate in self.builder.in_tree_crates(name) { - self.paths.insert(PathSet::one(&krate.path)); + let path = krate.local_path(self.builder); + self.paths.insert(PathSet::one(path)); } self } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 5c01c5e852c48..6d7fb7acfcb04 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -548,8 +548,8 @@ impl Step for Rustc { // Find dependencies for top level crates. let mut compiler_crates = HashSet::new(); for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { - let interned_root_crate = INTERNER.intern_str(root_crate); - find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates); + compiler_crates + .extend(builder.in_tree_crates(root_crate).into_iter().map(|krate| krate.name)); } for krate in &compiler_crates { @@ -564,22 +564,6 @@ impl Step for Rustc { } } -fn find_compiler_crates( - builder: &Builder<'_>, - name: &Interned, - crates: &mut HashSet>, -) { - // Add current crate. - crates.insert(*name); - - // Look for dependencies. - for dep in builder.crates.get(name).unwrap().deps.iter() { - if builder.crates.get(dep).unwrap().is_local(builder) { - find_compiler_crates(builder, dep, crates); - } - } -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustdoc { stage: u32, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a125b49fc01e6..9d3830da39066 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -270,12 +270,7 @@ struct Crate { } impl Crate { - fn is_local(&self, build: &Build) -> bool { - self.path.starts_with(&build.config.src) - } - fn local_path(&self, build: &Build) -> PathBuf { - assert!(self.is_local(build)); self.path.strip_prefix(&build.config.src).unwrap().into() } } @@ -1079,17 +1074,29 @@ impl Build { } } + /// Returns a Vec of all the dependencies of the given root crate, + /// including transitive dependencies and the root itself. Only includes + /// "local" crates (those in the local source tree, not from a registry). fn in_tree_crates(&self, root: &str) -> Vec<&Crate> { let mut ret = Vec::new(); let mut list = vec![INTERNER.intern_str(root)]; let mut visited = HashSet::new(); while let Some(krate) = list.pop() { let krate = &self.crates[&krate]; - if krate.is_local(self) { - ret.push(krate); - } + ret.push(krate); for dep in &krate.deps { - if visited.insert(dep) && dep != "build_helper" { + // Don't include optional deps if their features are not + // enabled. Ideally this would be computed from `cargo + // metadata --features …`, but that is somewhat slow. Just + // skip `build_helper` since there aren't any operations we + // want to perform on it. In the future, we may want to + // consider just filtering all build and dev dependencies in + // metadata::build. + if visited.insert(dep) + && dep != "build_helper" + && (dep != "profiler_builtins" || self.config.profiler) + && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled()) + { list.push(*dep); } } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 185f0ddb831e7..a38391c7b88f2 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; -use std::collections::HashSet; use std::path::PathBuf; use std::process::Command; @@ -12,7 +10,6 @@ use crate::{Build, Crate}; #[derive(Deserialize)] struct Output { packages: Vec, - resolve: Resolve, } #[derive(Deserialize)] @@ -21,38 +18,25 @@ struct Package { name: String, source: Option, manifest_path: String, + dependencies: Vec, } #[derive(Deserialize)] -struct Resolve { - nodes: Vec, -} - -#[derive(Deserialize)] -struct ResolveNode { - id: String, - dependencies: Vec, +struct Dependency { + name: String, + source: Option, } pub fn build(build: &mut Build) { // Run `cargo metadata` to figure out what crates we're testing. - let features: Vec<_> = build - .std_features() - .split_whitespace() - .map(|f| format!("test/{}", f)) - .chain(build.rustc_features().split_whitespace().map(|f| format!("rustc-main/{}", f))) - .collect(); let mut cargo = Command::new(&build.initial_cargo); cargo .arg("metadata") .arg("--format-version") .arg("1") - .arg("--features") - .arg(features.join(",")) - .arg("-Zpackage-features") + .arg("--no-deps") .arg("--manifest-path") - .arg(build.src.join("Cargo.toml")) - .env("RUSTC_BOOTSTRAP", "1"); + .arg(build.src.join("Cargo.toml")); let output = output(&mut cargo); let output: Output = serde_json::from_str(&output).unwrap(); for package in output.packages { @@ -60,26 +44,13 @@ pub fn build(build: &mut Build) { let name = INTERNER.intern_string(package.name); let mut path = PathBuf::from(package.manifest_path); path.pop(); - build.crates.insert(name, Crate { name, id: package.id, deps: HashSet::new(), path }); - } - } - - let id2name: HashMap<_, _> = - build.crates.iter().map(|(name, krate)| (krate.id.clone(), name.clone())).collect(); - - for node in output.resolve.nodes { - let name = match id2name.get(&node.id) { - Some(name) => name, - None => continue, - }; - - let krate = build.crates.get_mut(name).unwrap(); - for dep in node.dependencies.iter() { - let dep = match id2name.get(dep) { - Some(dep) => dep, - None => continue, - }; - krate.deps.insert(*dep); + let deps = package + .dependencies + .into_iter() + .filter(|dep| dep.source.is_none()) + .map(|dep| INTERNER.intern_string(dep.name)) + .collect(); + build.crates.insert(name, Crate { name, id: package.id, deps, path }); } } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 8659acf1cc5a5..c1d0316920be7 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1651,12 +1651,8 @@ impl Step for Crate { type Output = (); const DEFAULT: bool = true; - fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - for krate in run.builder.in_tree_crates("test") { - run = run.path(krate.local_path(&builder).to_str().unwrap()); - } - run + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.krate("test") } fn make_run(run: RunConfig<'_>) { From c2b920fab328201a2b5507b9a484c8c09752af93 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 14 Jun 2020 16:58:45 -0700 Subject: [PATCH 04/21] Show suite paths (`src/test/ui/...`) in help output. --- src/bootstrap/builder.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 345af600c2adb..545ad64ba2cf6 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -489,13 +489,19 @@ impl<'a> Builder<'a> { should_run = (desc.should_run)(should_run); } let mut help = String::from("Available paths:\n"); + let mut add_path = |path: &Path| { + help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display())); + }; for pathset in should_run.paths { - if let PathSet::Set(set) = pathset { - set.iter().for_each(|path| { - help.push_str( - format!(" ./x.py {} {}\n", subcommand, path.display()).as_str(), - ) - }) + match pathset { + PathSet::Set(set) => { + for path in set { + add_path(&path); + } + } + PathSet::Suite(path) => { + add_path(&path.join("...")); + } } } Some(help) From f17fd7b0e692c59075db58ac2e7ca3ac2d5e19bd Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 14 Jun 2020 17:00:34 -0700 Subject: [PATCH 05/21] Add some doc comments regarding PathSet. --- src/bootstrap/builder.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 545ad64ba2cf6..c2f748f161f18 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -97,9 +97,21 @@ struct StepDescription { name: &'static str, } +/// Collection of paths used to match a task rule. #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] pub enum PathSet { + /// A collection of individual paths. + /// + /// These are generally matched as a path suffix. For example, a + /// command-line value of `libstd` will match if `src/libstd` is in the + /// set. Set(BTreeSet), + /// A "suite" of paths. + /// + /// These can match as a path suffix (like `Set`), or as a prefix. For + /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs` + /// will match `src/test/ui`. A command-line value of `ui` would also + /// match `src/test/ui`. Suite(PathBuf), } @@ -249,9 +261,15 @@ impl<'a> ShouldRun<'a> { self } - // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually - // ever be used, but as we transition to having all rules properly handle passing krate(...) by - // actually doing something different for every crate passed. + /// Indicates it should run if the command-line selects the given crate or + /// any of its (local) dependencies. + /// + /// Compared to `krate`, this treats the dependencies as aliases for the + /// same job. Generally it is preferred to use `krate`, and treat each + /// individual path separately. For example `./x.py test src/liballoc` + /// (which uses `krate`) will test just `liballoc`. However, `./x.py check + /// src/liballoc` (which uses `all_krates`) will check all of `libtest`. + /// `all_krates` should probably be removed at some point. pub fn all_krates(mut self, name: &str) -> Self { let mut set = BTreeSet::new(); for krate in self.builder.in_tree_crates(name) { @@ -262,6 +280,10 @@ impl<'a> ShouldRun<'a> { self } + /// Indicates it should run if the command-line selects the given crate or + /// any of its (local) dependencies. + /// + /// `make_run` will be called separately for each matching command-line path. pub fn krate(mut self, name: &str) -> Self { for krate in self.builder.in_tree_crates(name) { let path = krate.local_path(self.builder); From 8e7606f204d8775b051cdd9a427ec6dd89b837b8 Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Mon, 15 Jun 2020 02:11:35 +0800 Subject: [PATCH 06/21] bootstrap/install.rs: support a nonexistent `prefix` in `x.py install` PR #49778 introduced fs::canonicalize() which fails for a nonexistent path. This is a surprise for someone used to GNU Autotools' configure which can create any necessary intermediate directories in prefix. This change makes it run fs::create_dir_all() before canonicalize(). --- src/bootstrap/install.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index fafd3cdf927c0..fbdef9d8272f7 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -70,7 +70,10 @@ fn install_sh( let libdir_default = PathBuf::from("lib"); let mandir_default = datadir_default.join("man"); let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| { - fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display())) + fs::create_dir_all(p) + .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err)); + fs::canonicalize(p) + .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err)) }); let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default); From 4eef51a80d6f2cb3ab559a8d48f4ca109c2693e7 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 10 Jun 2020 09:26:54 +0100 Subject: [PATCH 07/21] Cache decoded predicate shorthands --- src/librustc_metadata/rmeta/decoder.rs | 25 +++++- src/librustc_metadata/rmeta/encoder.rs | 27 +++--- src/librustc_middle/ty/codec.rs | 82 +++++++++++-------- src/librustc_middle/ty/context.rs | 8 +- src/librustc_middle/ty/query/on_disk_cache.rs | 47 +++++++---- 5 files changed, 118 insertions(+), 71 deletions(-) diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 0335aa8358c3c..65cb45653c0d0 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -294,15 +294,36 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand }; - if let Some(&ty) = tcx.rcache.borrow().get(&key) { + if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) { return Ok(ty); } let ty = or_insert_with(self)?; - tcx.rcache.borrow_mut().insert(key, ty); + tcx.ty_rcache.borrow_mut().insert(key, ty); Ok(ty) } + fn cached_predicate_for_shorthand( + &mut self, + shorthand: usize, + or_insert_with: F, + ) -> Result, Self::Error> + where + F: FnOnce(&mut Self) -> Result, Self::Error>, + { + let tcx = self.tcx(); + + let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand }; + + if let Some(&pred) = tcx.pred_rcache.borrow().get(&key) { + return Ok(pred); + } + + let pred = or_insert_with(self)?; + tcx.pred_rcache.borrow_mut().insert(key, pred); + Ok(pred) + } + fn with_position(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R, diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index d797e6d4a34af..5ecc6ced119e9 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -239,6 +239,17 @@ where } } +impl<'b, 'tcx> SpecializedEncoder> for EncodeContext<'tcx> { + fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> { + debug_assert!(self.tcx.lift(predicate).is_some()); + let predicate = + unsafe { std::mem::transmute::<&ty::Predicate<'b>, &ty::Predicate<'tcx>>(predicate) }; + ty_codec::encode_with_shorthand(self, predicate, |encoder| { + &mut encoder.predicate_shorthands + }) + } +} + impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { use std::collections::hash_map::Entry; @@ -256,22 +267,6 @@ impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { } } -impl<'a, 'b, 'tcx> SpecializedEncoder<&'a [(ty::Predicate<'b>, Span)]> for EncodeContext<'tcx> { - fn specialized_encode( - &mut self, - predicates: &&'a [(ty::Predicate<'b>, Span)], - ) -> Result<(), Self::Error> { - debug_assert!(self.tcx.lift(*predicates).is_some()); - let predicates = unsafe { - std::mem::transmute::< - &&'a [(ty::Predicate<'b>, Span)], - &&'tcx [(ty::Predicate<'tcx>, Span)], - >(predicates) - }; - ty_codec::encode_spanned_predicates(self, &predicates, |ecx| &mut ecx.predicate_shorthands) - } -} - impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { f.encode_opaque(&mut self.opaque) diff --git a/src/librustc_middle/ty/codec.rs b/src/librustc_middle/ty/codec.rs index 1a8e5c45dd2f7..67ceaca103e9f 100644 --- a/src/librustc_middle/ty/codec.rs +++ b/src/librustc_middle/ty/codec.rs @@ -10,7 +10,7 @@ use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use crate::mir::{self, interpret::Allocation}; use crate::ty::subst::SubstsRef; -use crate::ty::{self, List, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, List, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; @@ -95,23 +95,6 @@ where Ok(()) } -pub fn encode_spanned_predicates<'tcx, E, C>( - encoder: &mut E, - predicates: &[(ty::Predicate<'tcx>, Span)], - cache: C, -) -> Result<(), E::Error> -where - E: TyEncoder, - C: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap, usize>, -{ - predicates.len().encode(encoder)?; - for (predicate, span) in predicates { - encode_with_shorthand(encoder, predicate, &cache)?; - span.encode(encoder)?; - } - Ok(()) -} - pub trait TyDecoder<'tcx>: Decoder { fn tcx(&self) -> TyCtxt<'tcx>; @@ -127,6 +110,14 @@ pub trait TyDecoder<'tcx>: Decoder { where F: FnOnce(&mut Self) -> Result, Self::Error>; + fn cached_predicate_for_shorthand( + &mut self, + shorthand: usize, + or_insert_with: F, + ) -> Result, Self::Error> + where + F: FnOnce(&mut Self) -> Result, Self::Error>; + fn with_position(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R; @@ -188,6 +179,26 @@ where } } +#[inline] +pub fn decode_predicate(decoder: &mut D) -> Result, D::Error> +where + D: TyDecoder<'tcx>, +{ + // Handle shorthands first, if we have an usize > 0x80. + if decoder.positioned_at_shorthand() { + let pos = decoder.read_usize()?; + assert!(pos >= SHORTHAND_OFFSET); + let shorthand = pos - SHORTHAND_OFFSET; + + decoder.cached_predicate_for_shorthand(shorthand, |decoder| { + decoder.with_position(shorthand, ty::Predicate::decode) + }) + } else { + let tcx = decoder.tcx(); + Ok(tcx.mk_predicate(ty::PredicateKind::decode(decoder)?)) + } +} + #[inline] pub fn decode_spanned_predicates( decoder: &mut D, @@ -198,20 +209,7 @@ where let tcx = decoder.tcx(); Ok(tcx.arena.alloc_from_iter( (0..decoder.read_usize()?) - .map(|_| { - // Handle shorthands first, if we have an usize > 0x80. - let predicate_kind = if decoder.positioned_at_shorthand() { - let pos = decoder.read_usize()?; - assert!(pos >= SHORTHAND_OFFSET); - let shorthand = pos - SHORTHAND_OFFSET; - - decoder.with_position(shorthand, ty::PredicateKind::decode) - } else { - ty::PredicateKind::decode(decoder) - }?; - let predicate = predicate_kind.to_predicate(tcx); - Ok((predicate, Decodable::decode(decoder)?)) - }) + .map(|_| Decodable::decode(decoder)) .collect::, _>>()?, )) } @@ -421,7 +419,6 @@ macro_rules! implement_ty_decoder { // FIXME(#36588): These impls are horribly unsound as they allow // the caller to pick any lifetime for `'tcx`, including `'static`. - rustc_hir::arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx); arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx); impl<$($typaram),*> SpecializedDecoder @@ -436,7 +433,24 @@ macro_rules! implement_ty_decoder { where &'_x ty::TyS<'_y>: UseSpecializedDecodable { fn specialized_decode(&mut self) -> Result<&'_x ty::TyS<'_y>, Self::Error> { - unsafe { transmute::, Self::Error>, Result<&'_x ty::TyS<'_y>, Self::Error>>(decode_ty(self)) } + unsafe { + transmute::< + Result, Self::Error>, + Result<&'_x ty::TyS<'_y>, Self::Error>, + >(decode_ty(self)) + } + } + } + + impl<'_x, $($typaram),*> SpecializedDecoder> + for $DecoderName<$($typaram),*> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + unsafe { + transmute::< + Result, Self::Error>, + Result, Self::Error>, + >(decode_predicate(self)) + } } } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index d5be3508d2d80..88c003cb1efa2 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -939,8 +939,9 @@ pub struct GlobalCtxt<'tcx> { /// via `extern crate` item and not `--extern` option or compiler built-in. pub extern_prelude: FxHashMap, - // Internal cache for metadata decoding. No need to track deps on this. - pub rcache: Lock>>, + // Internal caches for metadata decoding. No need to track deps on this. + pub ty_rcache: Lock>>, + pub pred_rcache: Lock>>, /// Caches the results of trait selection. This cache is used /// for things that do not have to do with the parameters in scope. @@ -1129,7 +1130,8 @@ impl<'tcx> TyCtxt<'tcx> { definitions, def_path_hash_to_def_id, queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache), - rcache: Default::default(), + ty_rcache: Default::default(), + pred_rcache: Default::default(), selection_cache: Default::default(), evaluation_cache: Default::default(), crate_name: Symbol::intern(crate_name), diff --git a/src/librustc_middle/ty/query/on_disk_cache.rs b/src/librustc_middle/ty/query/on_disk_cache.rs index 5374dff422425..c84a7c38d0a0e 100644 --- a/src/librustc_middle/ty/query/on_disk_cache.rs +++ b/src/librustc_middle/ty/query/on_disk_cache.rs @@ -524,16 +524,39 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { let cache_key = ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand }; - if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) { + if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) { return Ok(ty); } let ty = or_insert_with(self)?; // This may overwrite the entry, but it should overwrite with the same value. - tcx.rcache.borrow_mut().insert_same(cache_key, ty); + tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty); Ok(ty) } + fn cached_predicate_for_shorthand( + &mut self, + shorthand: usize, + or_insert_with: F, + ) -> Result, Self::Error> + where + F: FnOnce(&mut Self) -> Result, Self::Error>, + { + let tcx = self.tcx(); + + let cache_key = + ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand }; + + if let Some(&pred) = tcx.pred_rcache.borrow().get(&cache_key) { + return Ok(pred); + } + + let pred = or_insert_with(self)?; + // This may overwrite the entry, but it should overwrite with the same value. + tcx.pred_rcache.borrow_mut().insert_same(cache_key, pred); + Ok(pred) + } + fn with_position(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -820,24 +843,16 @@ where } } -impl<'a, 'b, 'c, 'tcx, E> SpecializedEncoder<&'b [(ty::Predicate<'c>, Span)]> - for CacheEncoder<'a, 'tcx, E> +impl<'a, 'b, 'tcx, E> SpecializedEncoder> for CacheEncoder<'a, 'tcx, E> where E: 'a + TyEncoder, { #[inline] - fn specialized_encode( - &mut self, - predicates: &&'b [(ty::Predicate<'c>, Span)], - ) -> Result<(), Self::Error> { - debug_assert!(self.tcx.lift(*predicates).is_some()); - let predicates = unsafe { - std::mem::transmute::< - &&'b [(ty::Predicate<'c>, Span)], - &&'tcx [(ty::Predicate<'tcx>, Span)], - >(predicates) - }; - ty_codec::encode_spanned_predicates(self, predicates, |encoder| { + fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> { + debug_assert!(self.tcx.lift(predicate).is_some()); + let predicate = + unsafe { std::mem::transmute::<&ty::Predicate<'b>, &ty::Predicate<'tcx>>(predicate) }; + ty_codec::encode_with_shorthand(self, predicate, |encoder| { &mut encoder.predicate_shorthands }) } From 4709f452ec12ce15ed8c482049b22172277b93fa Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 10 Jun 2020 09:30:39 +0100 Subject: [PATCH 08/21] Cache flags and escaping vars for predicates Also hash predicates by address --- src/librustc_middle/arena.rs | 1 + src/librustc_middle/ty/context.rs | 57 ++++++++++++--- src/librustc_middle/ty/flags.rs | 82 +++++++++++++++++++--- src/librustc_middle/ty/fold.rs | 16 +++++ src/librustc_middle/ty/mod.rs | 46 ++++++++++-- src/librustc_middle/ty/structural_impls.rs | 28 +++++++- 6 files changed, 202 insertions(+), 28 deletions(-) diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index f861d63aba0f3..454e7adf99f0c 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -100,6 +100,7 @@ macro_rules! arena_types { // Interned types [] tys: rustc_middle::ty::TyS<$tcx>, rustc_middle::ty::TyS<'_x>; + [] predicates: rustc_middle::ty::PredicateInner<$tcx>, rustc_middle::ty::PredicateInner<'_x>; // HIR query types [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, rustc_middle::hir::map::IndexedHir<'_x>; diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 88c003cb1efa2..e9902cf18adca 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -19,8 +19,9 @@ use crate::ty::TyKind::*; use crate::ty::{ self, query, AdtDef, AdtKind, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, - IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, ProjectionTy, - Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, + IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind, + ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, + TyVid, TypeAndMut, }; use rustc_ast::ast; use rustc_ast::expand::allocator::AllocatorKind; @@ -76,7 +77,7 @@ pub struct CtxtInterners<'tcx> { canonical_var_infos: InternedSet<'tcx, List>, region: InternedSet<'tcx, RegionKind>, existential_predicates: InternedSet<'tcx, List>>, - predicate_kind: InternedSet<'tcx, PredicateKind<'tcx>>, + predicate: InternedSet<'tcx, PredicateInner<'tcx>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, @@ -95,7 +96,7 @@ impl<'tcx> CtxtInterners<'tcx> { region: Default::default(), existential_predicates: Default::default(), canonical_var_infos: Default::default(), - predicate_kind: Default::default(), + predicate: Default::default(), predicates: Default::default(), projs: Default::default(), place_elems: Default::default(), @@ -123,6 +124,23 @@ impl<'tcx> CtxtInterners<'tcx> { }) .0 } + + #[inline(never)] + fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> { + self.predicate + .intern(kind, |kind| { + let flags = super::flags::FlagComputation::for_predicate(&kind); + + let predicate_struct = PredicateInner { + kind, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; + + Interned(self.arena.alloc(predicate_struct)) + }) + .0 + } } pub struct CommonTypes<'tcx> { @@ -1598,7 +1616,7 @@ macro_rules! nop_list_lift { nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} -nop_lift! {predicate_kind; &'a PredicateKind<'a> => &'tcx PredicateKind<'tcx>} +nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} @@ -1957,6 +1975,26 @@ impl<'tcx> Borrow> for Interned<'tcx, TyS<'tcx>> { &self.0.kind } } +// N.B., an `Interned` compares and hashes as a `PredicateKind`. +impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> { + fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool { + self.0.kind == other.0.kind + } +} + +impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {} + +impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> { + fn hash(&self, s: &mut H) { + self.0.kind.hash(s) + } +} + +impl<'tcx> Borrow> for Interned<'tcx, PredicateInner<'tcx>> { + fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> { + &self.0.kind + } +} // N.B., an `Interned>` compares and hashes as its elements. impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List> { @@ -2023,11 +2061,10 @@ macro_rules! direct_interners { } } -direct_interners!( +direct_interners! { region: mk_region(RegionKind), const_: mk_const(Const<'tcx>), - predicate_kind: intern_predicate_kind(PredicateKind<'tcx>), -); +} macro_rules! slice_interners { ($($field:ident: $method:ident($ty:ty)),+) => ( @@ -2091,8 +2128,8 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_predicate(&self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> { - let kind = self.intern_predicate_kind(kind); - Predicate { kind } + let inner = self.interners.intern_predicate(kind); + Predicate { inner } } pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> { diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index edcb69c5e8cbd..966d6f67fb041 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -1,5 +1,6 @@ use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, InferConst, Ty, TypeFlags}; +use std::slice; #[derive(Debug)] pub struct FlagComputation { @@ -21,6 +22,12 @@ impl FlagComputation { result } + pub fn for_predicate(kind: &ty::PredicateKind<'_>) -> FlagComputation { + let mut result = FlagComputation::new(); + result.add_predicate_kind(kind); + result + } + pub fn for_const(c: &ty::Const<'_>) -> TypeFlags { let mut result = FlagComputation::new(); result.add_const(c); @@ -32,7 +39,7 @@ impl FlagComputation { } /// indicates that `self` refers to something at binding level `binder` - fn add_binder(&mut self, binder: ty::DebruijnIndex) { + fn add_bound_var(&mut self, binder: ty::DebruijnIndex) { let exclusive_binder = binder.shifted_in(1); self.add_exclusive_binder(exclusive_binder); } @@ -46,7 +53,7 @@ impl FlagComputation { /// Adds the flags/depth from a set of types that appear within the current type, but within a /// region binder. - fn add_bound_computation(&mut self, computation: &FlagComputation) { + fn add_bound_computation(&mut self, computation: FlagComputation) { self.add_flags(computation.flags); // The types that contributed to `computation` occurred within @@ -84,7 +91,7 @@ impl FlagComputation { &ty::GeneratorWitness(ref ts) => { let mut computation = FlagComputation::new(); computation.add_tys(&ts.skip_binder()[..]); - self.add_bound_computation(&computation); + self.add_bound_computation(computation); } &ty::Closure(_, ref substs) => { @@ -92,7 +99,7 @@ impl FlagComputation { } &ty::Bound(debruijn, _) => { - self.add_binder(debruijn); + self.add_bound_var(debruijn); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } @@ -134,12 +141,12 @@ impl FlagComputation { ty::ExistentialPredicate::Projection(p) => { let mut proj_computation = FlagComputation::new(); proj_computation.add_existential_projection(&p); - self.add_bound_computation(&proj_computation); + self.add_bound_computation(proj_computation); } ty::ExistentialPredicate::AutoTrait(_) => {} } } - self.add_bound_computation(&computation); + self.add_bound_computation(computation); self.add_region(r); } @@ -173,6 +180,63 @@ impl FlagComputation { } } + fn add_predicate_kind(&mut self, kind: &ty::PredicateKind<'_>) { + match kind { + ty::PredicateKind::Trait(trait_pred, _constness) => { + let mut computation = FlagComputation::new(); + computation.add_substs(trait_pred.skip_binder().trait_ref.substs); + + self.add_bound_computation(computation); + } + ty::PredicateKind::RegionOutlives(poly_outlives) => { + let mut computation = FlagComputation::new(); + let ty::OutlivesPredicate(a, b) = poly_outlives.skip_binder(); + computation.add_region(a); + computation.add_region(b); + + self.add_bound_computation(computation); + } + ty::PredicateKind::TypeOutlives(poly_outlives) => { + let mut computation = FlagComputation::new(); + let ty::OutlivesPredicate(ty, region) = poly_outlives.skip_binder(); + computation.add_ty(ty); + computation.add_region(region); + + self.add_bound_computation(computation); + } + ty::PredicateKind::Subtype(poly_subtype) => { + let mut computation = FlagComputation::new(); + let ty::SubtypePredicate { a_is_expected: _, a, b } = poly_subtype.skip_binder(); + computation.add_ty(a); + computation.add_ty(b); + + self.add_bound_computation(computation); + } + ty::PredicateKind::Projection(projection) => { + let mut computation = FlagComputation::new(); + let ty::ProjectionPredicate { projection_ty, ty } = projection.skip_binder(); + computation.add_projection_ty(projection_ty); + computation.add_ty(ty); + + self.add_bound_computation(computation); + } + ty::PredicateKind::WellFormed(arg) => { + self.add_substs(slice::from_ref(arg)); + } + ty::PredicateKind::ObjectSafe(_def_id) => {} + ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => { + self.add_substs(substs); + } + ty::PredicateKind::ConstEvaluatable(_def_id, substs) => { + self.add_substs(substs); + } + ty::PredicateKind::ConstEquate(expected, found) => { + self.add_const(expected); + self.add_const(found); + } + } + } + fn add_ty(&mut self, ty: Ty<'_>) { self.add_flags(ty.flags); self.add_exclusive_binder(ty.outer_exclusive_binder); @@ -190,13 +254,13 @@ impl FlagComputation { computation.add_tys(fn_sig.skip_binder().inputs()); computation.add_ty(fn_sig.skip_binder().output()); - self.add_bound_computation(&computation); + self.add_bound_computation(computation); } fn add_region(&mut self, r: ty::Region<'_>) { self.add_flags(r.type_flags()); if let ty::ReLateBound(debruijn, _) = *r { - self.add_binder(debruijn); + self.add_bound_var(debruijn); } } @@ -215,7 +279,7 @@ impl FlagComputation { } } ty::ConstKind::Bound(debruijn, _) => { - self.add_binder(debruijn); + self.add_bound_var(debruijn); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Param(_) => { diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index 248dd00ef47be..ed1bf655d19a9 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -31,6 +31,7 @@ //! These methods return true to indicate that the visitor has found what it is //! looking for, and does not need to visit anything else. +use crate::ty::structural_impls::PredicateVisitor; use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -905,6 +906,12 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { } } +impl<'tcx> PredicateVisitor<'tcx> for HasEscapingVarsVisitor { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { + predicate.inner.outer_exclusive_binder > self.outer_index + } +} + // FIXME: Optimize for checking for infer flags struct HasTypeFlagsVisitor { flags: ty::TypeFlags, @@ -929,6 +936,15 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } } +impl<'tcx> PredicateVisitor<'tcx> for HasTypeFlagsVisitor { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { + debug!( + "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", + predicate, predicate.inner.flags, self.flags + ); + predicate.inner.flags.intersects(self.flags) + } +} /// Collects all the late-bound regions at the innermost binding level /// into a hash set. struct LateBoundRegionsCollector { diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 93ef73171993c..db34018dedbd4 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -628,7 +628,7 @@ impl<'tcx> Hash for TyS<'tcx> { } } -impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { +impl<'a, 'tcx> HashStable> for TyS<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::TyS { ref kind, @@ -1002,16 +1002,35 @@ impl<'tcx> GenericPredicates<'tcx> { } } -#[derive(Clone, Copy, Hash, RustcEncodable, RustcDecodable, Lift)] -#[derive(HashStable)] +#[derive(Debug)] +crate struct PredicateInner<'tcx> { + kind: PredicateKind<'tcx>, + flags: TypeFlags, + /// See the comment for the corresponding field of [TyS]. + outer_exclusive_binder: ty::DebruijnIndex, +} + +#[cfg(target_arch = "x86_64")] +static_assert_size!(PredicateInner<'_>, 40); + +#[derive(Clone, Copy, Lift)] pub struct Predicate<'tcx> { - kind: &'tcx PredicateKind<'tcx>, + inner: &'tcx PredicateInner<'tcx>, } +impl rustc_serialize::UseSpecializedEncodable for Predicate<'_> {} +impl rustc_serialize::UseSpecializedDecodable for Predicate<'_> {} + impl<'tcx> PartialEq for Predicate<'tcx> { fn eq(&self, other: &Self) -> bool { // `self.kind` is always interned. - ptr::eq(self.kind, other.kind) + ptr::eq(self.inner, other.inner) + } +} + +impl Hash for Predicate<'_> { + fn hash(&self, s: &mut H) { + (self.inner as *const PredicateInner<'_>).hash(s) } } @@ -1020,7 +1039,22 @@ impl<'tcx> Eq for Predicate<'tcx> {} impl<'tcx> Predicate<'tcx> { #[inline(always)] pub fn kind(self) -> &'tcx PredicateKind<'tcx> { - self.kind + &self.inner.kind + } +} + +impl<'a, 'tcx> HashStable> for Predicate<'tcx> { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + let PredicateInner { + ref kind, + + // The other fields just provide fast access to information that is + // also contained in `kind`, so no need to hash them. + flags: _, + outer_exclusive_binder: _, + } = self.inner; + + kind.hash_stable(hcx, hasher); } } diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index f6f5dfd651612..e597c90c22de3 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -987,12 +987,34 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - let new = ty::PredicateKind::super_fold_with(self.kind, folder); - if new != *self.kind { folder.tcx().mk_predicate(new) } else { *self } + let new = ty::PredicateKind::super_fold_with(&self.inner.kind, folder); + if new != self.inner.kind { folder.tcx().mk_predicate(new) } else { *self } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - ty::PredicateKind::super_visit_with(self.kind, visitor) + ty::PredicateKind::super_visit_with(&self.inner.kind, visitor) + } + + fn visit_with>(&self, visitor: &mut V) -> bool { + visitor.visit_predicate(*self) + } + + fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { + self.inner.outer_exclusive_binder > binder + } + + fn has_type_flags(&self, flags: ty::TypeFlags) -> bool { + self.inner.flags.intersects(flags) + } +} + +pub(super) trait PredicateVisitor<'tcx>: TypeVisitor<'tcx> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool; +} + +impl> PredicateVisitor<'tcx> for T { + default fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { + predicate.super_visit_with(self) } } From 2e17245c76a909fc7f62a8d432f0a0535c53f05a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 10 Jun 2020 09:38:13 +0100 Subject: [PATCH 09/21] Replace `is_global` call on data with call on predicate --- src/librustc_trait_selection/traits/fulfill.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 4a08a3426c136..89d9648c4f63a 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -321,7 +321,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { ty::PredicateKind::Trait(ref data, _) => { let trait_obligation = obligation.with(*data); - if data.is_global() { + if obligation.predicate.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(&obligation) { From a4337ccc10db07f72566ad06f62662ab9b27e3bd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 15 Jun 2020 00:35:29 +0300 Subject: [PATCH 10/21] Use `LocalDefId` for import IDs in trait map --- src/librustc_hir/hir.rs | 19 +++-------------- src/librustc_middle/ich/impls_hir.rs | 11 +++++----- src/librustc_middle/ty/mod.rs | 2 +- src/librustc_resolve/late.rs | 9 ++++---- src/librustc_resolve/lib.rs | 25 ++++------------------- src/librustc_typeck/check/method/mod.rs | 10 ++++----- src/librustc_typeck/check/method/probe.rs | 7 ++++--- 7 files changed, 26 insertions(+), 57 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 634ab32a28542..eb5cd53912368 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -12,6 +12,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_macros::HashStable_Generic; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; @@ -2651,25 +2652,11 @@ pub type CaptureModeMap = NodeMap; // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. #[derive(Clone, Debug)] -pub struct TraitCandidate { +pub struct TraitCandidate { pub def_id: DefId, - pub import_ids: SmallVec<[ID; 1]>, + pub import_ids: SmallVec<[LocalDefId; 1]>, } -impl TraitCandidate { - pub fn map_import_ids(self, f: F) -> TraitCandidate - where - F: Fn(ID) -> T, - { - let TraitCandidate { def_id, import_ids } = self; - let import_ids = import_ids.into_iter().map(f).collect(); - TraitCandidate { def_id, import_ids } - } -} - -// Trait method resolution -pub type TraitMap = NodeMap>>; - #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum Node<'hir> { Param(&'hir Param<'hir>), diff --git a/src/librustc_middle/ich/impls_hir.rs b/src/librustc_middle/ich/impls_hir.rs index f668cc99754f4..78b9167ddd967 100644 --- a/src/librustc_middle/ich/impls_hir.rs +++ b/src/librustc_middle/ich/impls_hir.rs @@ -210,16 +210,15 @@ impl<'a> HashStable> for hir::TraitCandidate { } impl<'a> ToStableHashKey> for hir::TraitCandidate { - type KeyType = (DefPathHash, SmallVec<[(DefPathHash, hir::ItemLocalId); 1]>); + type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>); fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { let hir::TraitCandidate { def_id, import_ids } = self; - let import_keys = import_ids - .iter() - .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), hir_id.local_id)) - .collect(); - (hcx.def_path_hash(*def_id), import_keys) + ( + hcx.def_path_hash(*def_id), + import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(), + ) } } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 93ef73171993c..d3160973f2305 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -121,7 +121,7 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, pub extern_crate_map: FxHashMap, - pub trait_map: FxHashMap>>, + pub trait_map: FxHashMap>, pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, pub export_map: ExportMap, diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 7166fef2d1395..61f20df8cc6c0 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -24,6 +24,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::TraitCandidate; use rustc_middle::{bug, span_bug}; use rustc_session::lint; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use smallvec::{smallvec, SmallVec}; @@ -2188,7 +2189,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &mut self, mut ident: Ident, ns: Namespace, - ) -> Vec> { + ) -> Vec { debug!("(getting traits containing item) looking for '{}'", ident.name); let mut found_traits = Vec::new(); @@ -2233,7 +2234,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ident: Ident, ns: Namespace, module: Module<'a>, - found_traits: &mut Vec>, + found_traits: &mut Vec, ) { assert!(ns == TypeNS || ns == ValueNS); let mut traits = module.traits.borrow_mut(); @@ -2292,13 +2293,13 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &mut self, mut kind: &NameBindingKind<'_>, trait_name: Ident, - ) -> SmallVec<[NodeId; 1]> { + ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; while let NameBindingKind::Import { import, binding, .. } = kind { let id = self.r.definitions.local_def_id(import.id); self.r.maybe_unused_trait_imports.insert(id); self.r.add_to_glob_map(&import, trait_name); - import_ids.push(import.id); + import_ids.push(id); kind = &binding.kind; } import_ids diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 61792e039c76e..cf7f1af99d8bd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -38,7 +38,7 @@ use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::{DefKey, Definitions}; use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint}; -use rustc_hir::TraitMap; +use rustc_hir::TraitCandidate; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; @@ -879,7 +879,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap, export_map: ExportMap, - trait_map: TraitMap, + trait_map: NodeMap>, /// A map from nodes to anonymous modules. /// Anonymous modules are pseudo-modules that are implicitly created around items @@ -1285,14 +1285,7 @@ impl<'a> Resolver<'a> { let trait_map = self .trait_map .into_iter() - .map(|(k, v)| { - ( - definitions.node_id_to_hir_id(k), - v.into_iter() - .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id))) - .collect(), - ) - }) + .map(|(k, v)| (definitions.node_id_to_hir_id(k), v)) .collect(); let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let maybe_unused_extern_crates = self.maybe_unused_extern_crates; @@ -1323,17 +1316,7 @@ impl<'a> Resolver<'a> { trait_map: self .trait_map .iter() - .map(|(&k, v)| { - ( - self.definitions.node_id_to_hir_id(k), - v.iter() - .cloned() - .map(|tc| { - tc.map_import_ids(|id| self.definitions.node_id_to_hir_id(id)) - }) - .collect(), - ) - }) + .map(|(&k, v)| (self.definitions.node_id_to_hir_id(k), v.clone())) .collect(), glob_map: self.glob_map.clone(), maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index ac3fa15417e9c..e51523c5c2387 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -194,11 +194,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; for import_id in &pick.import_ids { - let import_def_id = self.tcx.hir().local_def_id(*import_id); - debug!("used_trait_import: {:?}", import_def_id); + debug!("used_trait_import: {:?}", import_id); Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) .unwrap() - .insert(import_def_id.to_def_id()); + .insert(import_id.to_def_id()); } self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span); @@ -461,9 +460,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut tables = self.tables.borrow_mut(); let used_trait_imports = Lrc::get_mut(&mut tables.used_trait_imports).unwrap(); for import_id in pick.import_ids { - let import_def_id = tcx.hir().local_def_id(import_id); - debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id); - used_trait_imports.insert(import_def_id.to_def_id()); + debug!("resolve_ufcs: used_trait_import: {:?}", import_id); + used_trait_imports.insert(import_id.to_def_id()); } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 37652330108c9..89616b1fc7e2f 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -28,6 +28,7 @@ use rustc_middle::ty::{ }; use rustc_session::config::nightly_options; use rustc_session::lint; +use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; @@ -129,7 +130,7 @@ struct Candidate<'tcx> { xform_ret_ty: Option>, item: ty::AssocItem, kind: CandidateKind<'tcx>, - import_ids: SmallVec<[hir::HirId; 1]>, + import_ids: SmallVec<[LocalDefId; 1]>, } #[derive(Debug)] @@ -158,7 +159,7 @@ enum ProbeResult { pub struct Pick<'tcx> { pub item: ty::AssocItem, pub kind: PickKind<'tcx>, - pub import_ids: SmallVec<[hir::HirId; 1]>, + pub import_ids: SmallVec<[LocalDefId; 1]>, // Indicates that the source expression should be autoderef'd N times // @@ -930,7 +931,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn assemble_extension_candidates_for_trait( &mut self, - import_ids: &SmallVec<[hir::HirId; 1]>, + import_ids: &SmallVec<[LocalDefId; 1]>, trait_def_id: DefId, ) -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); From fc13fd03ba0155915f72d0d1578f69c3998e73ad Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 15 Jun 2020 11:21:10 +0300 Subject: [PATCH 11/21] typeck: Use `LocalDefId`s for the unused trait import set --- src/librustc_middle/arena.rs | 1 + src/librustc_middle/query/mod.rs | 2 +- src/librustc_middle/ty/context.rs | 4 ++-- src/librustc_typeck/check/method/mod.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 4 ++-- src/librustc_typeck/check/writeback.rs | 7 +------ src/librustc_typeck/check_unused.rs | 10 +++++----- 7 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index f861d63aba0f3..aaef9871aa557 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -114,6 +114,7 @@ macro_rules! arena_types { // This is used to decode the &'tcx [Span] for InlineAsm's line_spans. [decode] span: rustc_span::Span, rustc_span::Span; + [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet, rustc_data_structures::fx::FxHashSet; ], $tcx); ) } diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 3b6d54a1bc1ee..b3751beede25a 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -526,7 +526,7 @@ rustc_queries! { } Other { - query used_trait_imports(key: LocalDefId) -> &'tcx DefIdSet { + query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet { desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index d5be3508d2d80..e716b2e846923 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -35,7 +35,7 @@ use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathHash, Definitions}; use rustc_hir::lang_items::{self, PanicLocationLangItem}; use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate}; @@ -392,7 +392,7 @@ pub struct TypeckTables<'tcx> { /// This is used for warning unused imports. During type /// checking, this `Lrc` should not be cloned: it must have a ref-count /// of 1 so that we can insert things into the set mutably. - pub used_trait_imports: Lrc, + pub used_trait_imports: Lrc>, /// If any errors occurred while type-checking this body, /// this field will be set to `Some(ErrorReported)`. diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e51523c5c2387..259c4a8664f1b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -197,7 +197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("used_trait_import: {:?}", import_id); Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) .unwrap() - .insert(import_id.to_def_id()); + .insert(*import_id); } self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span); @@ -461,7 +461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let used_trait_imports = Lrc::get_mut(&mut tables.used_trait_imports).unwrap(); for import_id in pick.import_ids { debug!("resolve_ufcs: used_trait_import: {:?}", import_id); - used_trait_imports.insert(import_id.to_def_id()); + used_trait_imports.insert(import_id); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a409e20953da1..f9105a51c49a9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -96,7 +96,7 @@ use rustc_errors::ErrorReported; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::{ @@ -839,7 +839,7 @@ fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &DefIdSet { +fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet { &*tcx.typeck_tables_of(def_id).used_trait_imports } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 159d3d7a538a6..646c802fba318 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -4,10 +4,8 @@ use crate::check::FnCtxt; -use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir as hir; -use rustc_hir::def_id::DefIdSet; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::InferCtxt; @@ -67,10 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_user_provided_sigs(); wbcx.visit_generator_interior_types(); - let used_trait_imports = mem::replace( - &mut self.tables.borrow_mut().used_trait_imports, - Lrc::new(DefIdSet::default()), - ); + let used_trait_imports = mem::take(&mut self.tables.borrow_mut().used_trait_imports); debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.tables.used_trait_imports = used_trait_imports; diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index eaaff70472bfb..81daf064bb368 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -1,14 +1,14 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::TyCtxt; use rustc_session::lint; use rustc_span::{Span, Symbol}; pub fn check_crate(tcx: TyCtxt<'_>) { - let mut used_trait_imports = DefIdSet::default(); + let mut used_trait_imports = FxHashSet::default(); for &body_id in tcx.hir().krate().bodies.keys() { let item_def_id = tcx.hir().body_owner_def_id(body_id); let imports = tcx.used_trait_imports(item_def_id); @@ -39,7 +39,7 @@ impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> { struct CheckVisitor<'tcx> { tcx: TyCtxt<'tcx>, - used_trait_imports: DefIdSet, + used_trait_imports: FxHashSet, } impl CheckVisitor<'tcx> { @@ -49,7 +49,7 @@ impl CheckVisitor<'tcx> { return; } - if self.used_trait_imports.contains(&def_id.to_def_id()) { + if self.used_trait_imports.contains(&def_id) { return; } From 8956a7f58194b5a3a8de944ea1dc1b3b44a070ac Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 15 Jun 2020 15:15:35 -0400 Subject: [PATCH 12/21] Only display other method receiver candidates if they actually apply Previously, we would suggest `Box` as a valid receiver, even if method resolution only succeeded due to an autoderef (e.g. to `&self`) --- src/librustc_typeck/check/expr.rs | 14 ++++++++++---- .../no-method-suggested-traits.stderr | 18 ------------------ src/test/ui/traits/trait-item-privacy.stderr | 7 ------- 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index bc3ef73d851eb..e16abed644c7b 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -913,10 +913,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr, probe::ProbeScope::AllTraits, ) { - err.span_label( - pick.item.ident.span, - &format!("the method is available for `{}` here", new_rcvr_t), - ); + debug!("try_alt_rcvr: pick candidate {:?}", pick); + // Make sure the method is defined for the *actual* receiver: + // we don't want to treat `Box` as a receiver if + // it only works because of an autoderef to `&self` + if pick.autoderefs == 0 { + err.span_label( + pick.item.ident.span, + &format!("the method is available for `{}` here", new_rcvr_t), + ); + } } } }; diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index b5135b53e1890..3cd4d0dd391af 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -49,14 +49,6 @@ LL | use foo::Bar; error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope --> $DIR/no-method-suggested-traits.rs:32:43 | -LL | fn method(&self) {} - | ------ - | | - | the method is available for `std::boxed::Box>>` here - | the method is available for `std::pin::Pin>>` here - | the method is available for `std::sync::Arc>>` here - | the method is available for `std::rc::Rc>>` here -... LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>` | @@ -83,16 +75,6 @@ error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::b | LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>` - | - ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12 - | -LL | fn method(&self) {} - | ------ - | | - | the method is available for `std::boxed::Box>>` here - | the method is available for `std::pin::Pin>>` here - | the method is available for `std::sync::Arc>>` here - | the method is available for `std::rc::Rc>>` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index 7fd5c11fcf090..3be4f11097311 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -20,13 +20,6 @@ error[E0599]: no method named `b` found for struct `S` in the current scope LL | struct S; | --------- method `b` not found for this ... -LL | fn b(&self) { } - | - - | | - | the method is available for `std::boxed::Box` here - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here -... LL | S.b(); | ^ method not found in `S` | From 792bd3b7ac7c588107cacec17a9044c0d741599e Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 12 Jun 2020 17:42:08 +0100 Subject: [PATCH 13/21] lint: normalize projections using opaque types This commit normalizes projections which contain opaque types (opaque types are otherwise linted against, which is would have previously made the test cases added in this commit fail). Signed-off-by: David Wood --- src/librustc_lint/types.rs | 27 +++++++++++------ src/test/ui/lint/lint-ctypes-73251-1.rs | 24 ++++++++++++++++ src/test/ui/lint/lint-ctypes-73251-1.stderr | 15 ++++++++++ src/test/ui/lint/lint-ctypes-73251-2.rs | 32 +++++++++++++++++++++ src/test/ui/lint/lint-ctypes-73251-2.stderr | 15 ++++++++++ src/test/ui/lint/lint-ctypes-73251.rs | 22 ++++++++++++++ 6 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/lint/lint-ctypes-73251-1.rs create mode 100644 src/test/ui/lint/lint-ctypes-73251-1.stderr create mode 100644 src/test/ui/lint/lint-ctypes-73251-2.rs create mode 100644 src/test/ui/lint/lint-ctypes-73251-2.stderr create mode 100644 src/test/ui/lint/lint-ctypes-73251.rs diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a8ecfdd0f3d45..c803e71b1f42e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -927,22 +927,33 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { use rustc_middle::ty::TypeFoldable; - struct ProhibitOpaqueTypes<'tcx> { + struct ProhibitOpaqueTypes<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, ty: Option>, }; - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> { + impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - if let ty::Opaque(..) = ty.kind { - self.ty = Some(ty); - true - } else { - ty.super_visit_with(self) + match ty.kind { + ty::Opaque(..) => { + self.ty = Some(ty); + true + } + // Consider opaque types within projections FFI-safe if they do not normalize + // to more opaque types. + ty::Projection(..) => { + let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty); + + // If `ty` is a opaque type directly then `super_visit_with` won't invoke + // this function again. + if ty.has_opaque_types() { self.visit_ty(ty) } else { false } + } + _ => ty.super_visit_with(self), } } } - let mut visitor = ProhibitOpaqueTypes { ty: None }; + let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None }; ty.visit_with(&mut visitor); if let Some(ty) = visitor.ty { self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None); diff --git a/src/test/ui/lint/lint-ctypes-73251-1.rs b/src/test/ui/lint/lint-ctypes-73251-1.rs new file mode 100644 index 0000000000000..2ce80982f5ca1 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-1.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Baz { } + +impl Baz for u32 { } + +type Qux = impl Baz; + +pub trait Foo { + type Assoc; +} + +impl Foo for u32 { + type Assoc = Qux; +} + +fn assign() -> Qux { 1 } + +extern "C" { + pub fn lint_me() -> ::Assoc; //~ ERROR: uses type `impl Baz` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73251-1.stderr b/src/test/ui/lint/lint-ctypes-73251-1.stderr new file mode 100644 index 0000000000000..0b4237bb96fb7 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-1.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl Baz`, which is not FFI-safe + --> $DIR/lint-ctypes-73251-1.rs:21:25 + | +LL | pub fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73251-1.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73251-2.rs b/src/test/ui/lint/lint-ctypes-73251-2.rs new file mode 100644 index 0000000000000..3427c657b42ac --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-2.rs @@ -0,0 +1,32 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait TraitA { + type Assoc; +} + +impl TraitA for u32 { + type Assoc = u32; +} + +pub trait TraitB { + type Assoc; +} + +impl TraitB for T where T: TraitA { + type Assoc = ::Assoc; +} + +type AliasA = impl TraitA; + +type AliasB = impl TraitB; + +fn use_of_a() -> AliasA { 3 } + +fn use_of_b() -> AliasB { 3 } + +extern "C" { + pub fn lint_me() -> ::Assoc; //~ ERROR: uses type `impl TraitA` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73251-2.stderr b/src/test/ui/lint/lint-ctypes-73251-2.stderr new file mode 100644 index 0000000000000..43f7629b043a9 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-2.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl TraitA`, which is not FFI-safe + --> $DIR/lint-ctypes-73251-2.rs:29:25 + | +LL | pub fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73251-2.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73251.rs b/src/test/ui/lint/lint-ctypes-73251.rs new file mode 100644 index 0000000000000..ebc2ca77b67a1 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251.rs @@ -0,0 +1,22 @@ +// check-pass + +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Foo { + type Assoc; +} + +impl Foo for () { + type Assoc = u32; +} + +type Bar = impl Foo; + +fn assign() -> Bar {} + +extern "C" { + pub fn lint_me() -> ::Assoc; +} + +fn main() {} From a19dfb573d18c8b937c159cda24a3bb40ca5082d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 12 Jun 2020 14:01:47 +0200 Subject: [PATCH 14/21] Create new E0763 error code for unterminated byte constant --- src/librustc_error_codes/error_codes.rs | 1 + src/librustc_error_codes/error_codes/E0763.md | 13 +++++++++++++ src/librustc_parse/lexer/mod.rs | 11 +++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/librustc_error_codes/error_codes/E0763.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 3fb5e04efc922..1d6a579bdff32 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -442,6 +442,7 @@ E0758: include_str!("./error_codes/E0758.md"), E0760: include_str!("./error_codes/E0760.md"), E0761: include_str!("./error_codes/E0761.md"), E0762: include_str!("./error_codes/E0762.md"), +E0763: include_str!("./error_codes/E0763.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0763.md b/src/librustc_error_codes/error_codes/E0763.md new file mode 100644 index 0000000000000..095b779f3e78a --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0763.md @@ -0,0 +1,13 @@ +A byte constant wasn't correctly ended. + +Erroneous code example: + +```compile_fail,E0763 +let c = b'a; // error! +``` + +To fix this error, add the missing quote: + +``` +let c = b'a'; // ok! +``` diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 84b3335a0f628..2e3cf4e746ae9 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -339,8 +339,15 @@ impl<'a> StringReader<'a> { } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { - self.fatal_span_(start + BytePos(1), suffix_start, "unterminated byte constant") - .raise() + self.sess + .span_diagnostic + .struct_span_fatal_with_code( + self.mk_sp(start + BytePos(1), suffix_start), + "unterminated byte constant", + error_code!(E0763), + ) + .emit(); + FatalError.raise(); } (token::Byte, Mode::Byte, 2, 1) // b' ' } From bad252c9faebf55565091f50bad784a0a3f1e756 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 12 Jun 2020 14:01:53 +0200 Subject: [PATCH 15/21] Update ui tests --- src/test/ui/parser/byte-literals.rs | 2 +- src/test/ui/parser/byte-literals.stderr | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/ui/parser/byte-literals.rs b/src/test/ui/parser/byte-literals.rs index dadf3971220f7..9683a83e72095 100644 --- a/src/test/ui/parser/byte-literals.rs +++ b/src/test/ui/parser/byte-literals.rs @@ -8,5 +8,5 @@ pub fn main() { b' '; //~ ERROR byte constant must be escaped b'''; //~ ERROR byte constant must be escaped b'é'; //~ ERROR byte constant must be ASCII - b'a //~ ERROR unterminated byte constant + b'a //~ ERROR unterminated byte constant [E0763] } diff --git a/src/test/ui/parser/byte-literals.stderr b/src/test/ui/parser/byte-literals.stderr index 53d50af88d33b..7bbdc07cd835f 100644 --- a/src/test/ui/parser/byte-literals.stderr +++ b/src/test/ui/parser/byte-literals.stderr @@ -34,7 +34,7 @@ error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte LL | b'é'; | ^ -error: unterminated byte constant +error[E0763]: unterminated byte constant --> $DIR/byte-literals.rs:11:6 | LL | b'a @@ -42,3 +42,4 @@ LL | b'a error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0763`. From 83e6c0e98657d8df3dd4f45fa22baadcac986402 Mon Sep 17 00:00:00 2001 From: Andrew Paverd Date: Tue, 16 Jun 2020 17:44:03 +0100 Subject: [PATCH 16/21] Update CFGuard syntax --- src/bootstrap/builder.rs | 4 +-- .../src/compiler-flags/control-flow-guard.md | 10 +++---- src/librustc_interface/tests.rs | 2 +- src/librustc_session/config.rs | 2 +- src/librustc_session/options.rs | 29 ++++++++++++++----- src/test/codegen/cfguard_checks.rs | 2 +- src/test/codegen/cfguard_disabled.rs | 2 +- src/test/codegen/cfguard_nochecks.rs | 2 +- 8 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ea5300bdfc04c..087b0da74e5e1 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1176,7 +1176,7 @@ impl<'a> Builder<'a> { ); } - // If Control Flow Guard is enabled, pass the `control_flow_guard=checks` flag to rustc + // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc // when compiling the standard library, since this might be linked into the final outputs // produced by rustc. Since this mitigation is only available on Windows, only enable it // for the standard library in case the compiler is run on a non-Windows platform. @@ -1187,7 +1187,7 @@ impl<'a> Builder<'a> { && self.config.control_flow_guard && compiler.stage >= 1 { - rustflags.arg("-Zcontrol_flow_guard=checks"); + rustflags.arg("-Zcontrol-flow-guard"); } // For `cargo doc` invocations, make rustdoc print the Rust version into the docs diff --git a/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md b/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md index 48dea213e8cee..4115825e92083 100644 --- a/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md +++ b/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md @@ -1,10 +1,10 @@ -# `control_flow_guard` +# `control-flow-guard` The tracking issue for this feature is: [#68793](https://github.com/rust-lang/rust/issues/68793). ------------------------ -The rustc flag `-Z control_flow_guard=checks` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature. +The rustc flag `-Z control-flow-guard` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature. CFG is an exploit mitigation designed to enforce control-flow integrity for software running on supported Windows platforms (Windows 8.1 onwards). Specifically, CFG uses runtime checks to validate the target address of every indirect call/jump before allowing the call to complete. @@ -29,7 +29,7 @@ The CFG checks and metadata can potentially increase binary size and runtime ove ## Testing Control Flow Guard -The rustc flag `-Z control_flow_guard=nochecks` instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement. +The rustc flag `-Z control-flow-guard=nochecks` instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement. ## Control Flow Guard in libraries @@ -44,14 +44,14 @@ For example: ```cmd rustup toolchain install --force nightly rustup component add rust-src -SET RUSTFLAGS=-Z control_flow_guard=checks +SET RUSTFLAGS=-Z control-flow-guard cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc ``` ```PowerShell rustup toolchain install --force nightly rustup component add rust-src -$Env:RUSTFLAGS = "-Z control_flow_guard=checks" +$Env:RUSTFLAGS = "-Z control-flow-guard" cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc ``` diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 87647f3b0b017..bbe2e8da12e7c 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -463,7 +463,6 @@ fn test_debugging_options_tracking_hash() { untracked!(ast_json_noexpand, true); untracked!(borrowck, String::from("other")); untracked!(borrowck_stats, true); - untracked!(control_flow_guard, CFGuard::Checks); untracked!(deduplicate_diagnostics, true); untracked!(dep_tasks, true); untracked!(dont_buffer_diagnostics, true); @@ -537,6 +536,7 @@ fn test_debugging_options_tracking_hash() { tracked!(binary_dep_depinfo, true); tracked!(chalk, true); tracked!(codegen_backend, Some("abc".to_string())); + tracked!(control_flow_guard, CFGuard::Checks); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 411a6eecbba15..562f71e8e9287 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -82,7 +82,7 @@ pub enum Strip { Symbols, } -/// The different settings that the `-Z control_flow_guard` flag can have. +/// The different settings that the `-Z control-flow-guard` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum CFGuard { /// Do not emit Control Flow Guard metadata or checks. diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index d22c6ec9d7d01..e822e79bf4fa2 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -251,7 +251,8 @@ macro_rules! options { pub const parse_sanitizer: &str = "one of: `address`, `leak`, `memory` or `thread`"; pub const parse_sanitizer_list: &str = "comma separated list of sanitizers"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; - pub const parse_cfguard: &str = "either `disabled`, `nochecks`, or `checks`"; + pub const parse_cfguard: &str = + "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; @@ -505,12 +506,24 @@ macro_rules! options { } fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool { - match v { - Some("disabled") => *slot = CFGuard::Disabled, - Some("nochecks") => *slot = CFGuard::NoChecks, - Some("checks") => *slot = CFGuard::Checks, - _ => return false, + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + CFGuard::Checks + } else { + CFGuard::Disabled + }; + return true + } } + + *slot = match v { + None => CFGuard::Checks, + Some("checks") => CFGuard::Checks, + Some("nochecks") => CFGuard::NoChecks, + Some(_) => return false, + }; true } @@ -806,8 +819,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable the experimental Chalk-based trait solving engine"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), - control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [UNTRACKED], - "use Windows Control Flow Guard (`disabled`, `nochecks` or `checks`)"), + control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED], + "use Windows Control Flow Guard (default: no)"), crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), debug_macros: bool = (false, parse_bool, [TRACKED], diff --git a/src/test/codegen/cfguard_checks.rs b/src/test/codegen/cfguard_checks.rs index 40a7353eac045..96f9158f9d394 100644 --- a/src/test/codegen/cfguard_checks.rs +++ b/src/test/codegen/cfguard_checks.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control_flow_guard=checks +// compile-flags: -Z control-flow-guard=checks #![crate_type = "lib"] diff --git a/src/test/codegen/cfguard_disabled.rs b/src/test/codegen/cfguard_disabled.rs index d1747931e15c8..1325ffc0f2595 100644 --- a/src/test/codegen/cfguard_disabled.rs +++ b/src/test/codegen/cfguard_disabled.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control_flow_guard=disabled +// compile-flags: -Z control-flow-guard=no #![crate_type = "lib"] diff --git a/src/test/codegen/cfguard_nochecks.rs b/src/test/codegen/cfguard_nochecks.rs index c5d7afbae257b..ae1de4c4d26d5 100644 --- a/src/test/codegen/cfguard_nochecks.rs +++ b/src/test/codegen/cfguard_nochecks.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control_flow_guard=nochecks +// compile-flags: -Z control-flow-guard=nochecks #![crate_type = "lib"] From 4506a358ca4be0b3f7a1f320a677168d964ca9f7 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 16 Jun 2020 17:36:04 +0000 Subject: [PATCH 17/21] add header for rust specific feature --- src/rustllvm/PassWrapper.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 7586dd91ab68b..47c03069182a5 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -424,8 +424,7 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) { printf("Available features for this target:\n"); for (auto &Feature : FeatTable) printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); - printf("\n"); - // Rust specific target features + printf("Rust-specific features:\n"); printf(" %-*s - %s.\n", MaxFeatLen, "crt-static", "Enables libraries with C Run-time Libraries(CRT) to be statically linked"); printf("\n"); From 9f50f84ef106c7f521d1322ec39562610339f74d Mon Sep 17 00:00:00 2001 From: root Date: Tue, 16 Jun 2020 18:14:32 +0000 Subject: [PATCH 18/21] break long line for formatting --- src/rustllvm/PassWrapper.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 47c03069182a5..16c2ac3322787 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -425,7 +425,11 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) { for (auto &Feature : FeatTable) printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); printf("Rust-specific features:\n"); - printf(" %-*s - %s.\n", MaxFeatLen, "crt-static", "Enables libraries with C Run-time Libraries(CRT) to be statically linked"); + printf(" %-*s - %s.\n", + MaxFeatLen, + "crt-static", + "Enables libraries with C Run-time Libraries(CRT) to be statically linked" + ); printf("\n"); printf("Use +feature to enable a feature, or -feature to disable it.\n" From 457acbd5a80153fc06bca12663405c175fd9453f Mon Sep 17 00:00:00 2001 From: root Date: Tue, 16 Jun 2020 18:53:30 +0000 Subject: [PATCH 19/21] trim whitespace --- src/rustllvm/PassWrapper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 16c2ac3322787..28caf61a0197e 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -425,9 +425,9 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) { for (auto &Feature : FeatTable) printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); printf("Rust-specific features:\n"); - printf(" %-*s - %s.\n", - MaxFeatLen, - "crt-static", + printf(" %-*s - %s.\n", + MaxFeatLen, + "crt-static", "Enables libraries with C Run-time Libraries(CRT) to be statically linked" ); printf("\n"); From caffb28ece818ce87f1c7573992cae4210544015 Mon Sep 17 00:00:00 2001 From: asrar Date: Wed, 17 Jun 2020 10:31:46 +0530 Subject: [PATCH 20/21] add blank line bw sections Separate target features from rust ones with a blank line Co-authored-by: Josh Stone --- src/rustllvm/PassWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 28caf61a0197e..323bd26c698a3 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -424,7 +424,7 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) { printf("Available features for this target:\n"); for (auto &Feature : FeatTable) printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); - printf("Rust-specific features:\n"); + printf("\nRust-specific features:\n"); printf(" %-*s - %s.\n", MaxFeatLen, "crt-static", From f633dd385f7b064b4d9eb77e77a4836dc65ca82c Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sat, 13 Jun 2020 09:58:24 +0800 Subject: [PATCH 21/21] Implement crate level only lints checking. --- src/librustc_lint/early.rs | 3 +- src/librustc_lint/levels.rs | 46 +++++++++++++- src/librustc_lint/non_ascii_idents.rs | 9 ++- src/librustc_session/lint.rs | 4 ++ src/librustc_session/lint/builtin.rs | 11 +++- src/test/ui/issues/issue-48508.rs | 2 +- src/test/ui/lint/crate_level_only_lint.rs | 22 +++++++ src/test/ui/lint/crate_level_only_lint.stderr | 62 +++++++++++++++++++ 8 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/lint/crate_level_only_lint.rs create mode 100644 src/test/ui/lint/crate_level_only_lint.stderr diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs index 06987ffa3d569..d891466611ad3 100644 --- a/src/librustc_lint/early.rs +++ b/src/librustc_lint/early.rs @@ -55,7 +55,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { where F: FnOnce(&mut Self), { - let push = self.context.builder.push(attrs, &self.context.lint_store); + let is_crate_node = id == ast::CRATE_NODE_ID; + let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node); self.check_id(id); self.enter_attrs(attrs); f(self); diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 05e7c9a0c780d..f875e2750a5c5 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -29,7 +29,7 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> LintLevelMap { let mut builder = LintLevelMapBuilder { levels, tcx, store }; let krate = tcx.hir().krate(); - let push = builder.levels.push(&krate.item.attrs, &store); + let push = builder.levels.push(&krate.item.attrs, &store, true); builder.levels.register_id(hir::CRATE_HIR_ID); for macro_def in krate.exported_macros { builder.levels.register_id(macro_def.hir_id); @@ -109,7 +109,12 @@ impl<'s> LintLevelsBuilder<'s> { /// `#[allow]` /// /// Don't forget to call `pop`! - pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush { + pub fn push( + &mut self, + attrs: &[ast::Attribute], + store: &LintStore, + is_crate_node: bool, + ) -> BuilderPush { let mut specs = FxHashMap::default(); let sess = self.sess; let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); @@ -333,6 +338,40 @@ impl<'s> LintLevelsBuilder<'s> { } } + if !is_crate_node { + for (id, &(level, ref src)) in specs.iter() { + if !id.lint.crate_level_only { + continue; + } + + let (lint_attr_name, lint_attr_span) = match *src { + LintSource::Node(name, span, _) => (name, span), + _ => continue, + }; + + let lint = builtin::UNUSED_ATTRIBUTES; + let (lint_level, lint_src) = + self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess); + struct_lint_level( + self.sess, + lint, + lint_level, + lint_src, + Some(lint_attr_span.into()), + |lint| { + let mut db = lint.build(&format!( + "{}({}) is ignored unless specified at crate level", + level.as_str(), + lint_attr_name + )); + db.emit(); + }, + ); + // don't set a separate error for every lint in the group + break; + } + } + for (id, &(level, ref src)) in specs.iter() { if level == Level::Forbid { continue; @@ -449,7 +488,8 @@ impl LintLevelMapBuilder<'_, '_> { where F: FnOnce(&mut Self), { - let push = self.levels.push(attrs, self.store); + let is_crate_hir = id == hir::CRATE_HIR_ID; + let push = self.levels.push(attrs, self.store, is_crate_hir); if push.changed { self.levels.register_id(id); } diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index ad02b2637d22f..064b0255397ce 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -8,20 +8,23 @@ use std::ops::Deref; declare_lint! { pub NON_ASCII_IDENTS, Allow, - "detects non-ASCII identifiers" + "detects non-ASCII identifiers", + crate_level_only } declare_lint! { pub UNCOMMON_CODEPOINTS, Warn, - "detects uncommon Unicode codepoints in identifiers" + "detects uncommon Unicode codepoints in identifiers", + crate_level_only } // FIXME: Change this to warn. declare_lint! { pub CONFUSABLE_IDENTS, Allow, - "detects visually confusable pairs between identifiers" + "detects visually confusable pairs between identifiers", + crate_level_only } declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]); diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index ffb4579309075..0dcbee08abea1 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -88,6 +88,8 @@ pub struct Lint { /// `Some` if this lint is feature gated, otherwise `None`. pub feature_gate: Option, + + pub crate_level_only: bool, } /// Extra information for a future incompatibility lint. @@ -111,6 +113,7 @@ impl Lint { report_in_external_macro: false, future_incompatible: None, feature_gate: None, + crate_level_only: false, } } @@ -336,6 +339,7 @@ macro_rules! declare_tool_lint { future_incompatible: None, is_plugin: true, feature_gate: None, + crate_level_only: false, }; ); } diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index bb0d6e1a47ead..e3444bb0e54ce 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -17,6 +17,7 @@ declare_lint! { reference: "issue #57571 ", edition: None, }; + crate_level_only } declare_lint! { @@ -75,7 +76,8 @@ declare_lint! { declare_lint! { pub UNUSED_CRATE_DEPENDENCIES, Allow, - "crate dependencies that are never used" + "crate dependencies that are never used", + crate_level_only } declare_lint! { @@ -166,7 +168,8 @@ declare_lint! { declare_lint! { pub UNKNOWN_CRATE_TYPES, Deny, - "unknown crate type found in `#[crate_type]` directive" + "unknown crate type found in `#[crate_type]` directive", + crate_level_only } declare_lint! { @@ -339,7 +342,8 @@ declare_lint! { declare_lint! { pub ELIDED_LIFETIMES_IN_PATHS, Allow, - "hidden lifetime parameters in types are deprecated" + "hidden lifetime parameters in types are deprecated", + crate_level_only } declare_lint! { @@ -459,6 +463,7 @@ declare_lint! { reference: "issue #52234 ", edition: None, }; + crate_level_only } declare_lint! { diff --git a/src/test/ui/issues/issue-48508.rs b/src/test/ui/issues/issue-48508.rs index 87965c204ada7..8dc9351260ebc 100644 --- a/src/test/ui/issues/issue-48508.rs +++ b/src/test/ui/issues/issue-48508.rs @@ -11,7 +11,7 @@ // ignore-asmjs wasm2js does not support source maps yet #![feature(non_ascii_idents)] -#[allow(uncommon_codepoints)] +#![allow(uncommon_codepoints)] #[path = "issue-48508-aux.rs"] mod other_file; diff --git a/src/test/ui/lint/crate_level_only_lint.rs b/src/test/ui/lint/crate_level_only_lint.rs new file mode 100644 index 0000000000000..d9673faa2142e --- /dev/null +++ b/src/test/ui/lint/crate_level_only_lint.rs @@ -0,0 +1,22 @@ +#![deny(uncommon_codepoints, unused_attributes)] + +mod foo { +#![allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] + +#[allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +const BAR: f64 = 0.000001; + +} + +#[allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +fn main() { +} diff --git a/src/test/ui/lint/crate_level_only_lint.stderr b/src/test/ui/lint/crate_level_only_lint.stderr new file mode 100644 index 0000000000000..8fb06df2a481a --- /dev/null +++ b/src/test/ui/lint/crate_level_only_lint.stderr @@ -0,0 +1,62 @@ +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/crate_level_only_lint.rs:1:30 + | +LL | #![deny(uncommon_codepoints, unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors +