From 3b92689f3d0c3b90fa01d9873cdf01543d51c000 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 13:54:33 -0500 Subject: [PATCH 001/657] Relax bounds on HashMap to match hashbrown No functional changes are made, and all APIs are moved to strictly less restrictive bounds. These APIs changed from the old bound listed to no trait bounds: K: Hash + Eq * new * with_capacity K: Eq + Hash, S: BuildHasher * with_hasher * with_capacity_and_hasher * hasher K: Eq + Hash + Debug -> K: Debug S: BuildHasher -> S K: Eq + Hash -> K S: BuildHasher + Default -> S: Default --- src/libstd/collections/hash/map.rs | 126 ++++++++++++++--------------- 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a928867d9de93..84e1cee5d66b9 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -203,7 +203,7 @@ pub struct HashMap { base: base::HashMap, } -impl HashMap { +impl HashMap { /// Creates an empty `HashMap`. /// /// The hash map is initially created with a capacity of 0, so it will not allocate until it @@ -240,6 +240,59 @@ impl HashMap { } impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_hasher(hash_builder: S) -> HashMap { + HashMap { base: base::HashMap::with_hasher(hash_builder) } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { + HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder) } + } + /// Returns the number of elements the map can hold without reallocating. /// /// This number is a lower bound; the `HashMap` might be able to hold @@ -457,65 +510,6 @@ impl HashMap { pub fn clear(&mut self) { self.base.clear(); } -} - -impl HashMap -where - K: Eq + Hash, - S: BuildHasher, -{ - /// Creates an empty `HashMap` which will use the given hash builder to hash - /// keys. - /// - /// The created map has the default initial capacity. - /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// let mut map = HashMap::with_hasher(s); - /// map.insert(1, 2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_hasher(hash_builder: S) -> HashMap { - HashMap { base: base::HashMap::with_hasher(hash_builder) } - } - - /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` - /// to hash the keys. - /// - /// The hash map will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash map will not allocate. - /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// let mut map = HashMap::with_capacity_and_hasher(10, s); - /// map.insert(1, 2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { - HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder) } - } /// Returns a reference to the map's [`BuildHasher`]. /// @@ -536,7 +530,13 @@ where pub fn hasher(&self) -> &S { self.base.hasher() } +} +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, +{ /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashMap`. The collection may reserve more space to avoid /// frequent reallocations. @@ -984,9 +984,8 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl Debug for HashMap where - K: Eq + Hash + Debug, + K: Debug, V: Debug, - S: BuildHasher, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() @@ -996,8 +995,7 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl Default for HashMap where - K: Eq + Hash, - S: BuildHasher + Default, + S: Default, { /// Creates an empty `HashMap`, with the `Default` value for the hasher. #[inline] From 48859db151b839518bdd9d44a2387c0f6b65d141 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 14:12:56 -0500 Subject: [PATCH 002/657] Relax bounds on HashSet to match hashbrown No functional changes are made, and all APIs are moved to strictly less restrictive bounds. These APIs changed from the old bound listed to the new bound: T: Hash + Eq -> T * new * with_capacity T: Eq + Hash, S: BuildHasher -> T * with_hasher * with_capacity_and_hasher * hasher T: Eq + Hash + Debug -> T: Debug S: BuildHasher -> S T: Eq + Hash -> T S: BuildHasher + Default -> S: Default --- src/libstd/collections/hash/set.rs | 20 +++++++++---------- .../core-traits-no-impls-length-33.rs | 1 - .../core-traits-no-impls-length-33.stderr | 19 +++++------------- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index fff64e9fc9008..f461f26572f01 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -110,7 +110,7 @@ pub struct HashSet { map: HashMap, } -impl HashSet { +impl HashSet { /// Creates an empty `HashSet`. /// /// The hash set is initially created with a capacity of 0, so it will not allocate until it @@ -261,13 +261,7 @@ impl HashSet { pub fn clear(&mut self) { self.map.clear() } -} -impl HashSet -where - T: Eq + Hash, - S: BuildHasher, -{ /// Creates a new empty hash set which will use the given hasher to hash /// keys. /// @@ -340,7 +334,13 @@ where pub fn hasher(&self) -> &S { self.map.hasher() } +} +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, +{ /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashSet`. The collection may reserve more space to avoid /// frequent reallocations. @@ -896,8 +896,7 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for HashSet where - T: Eq + Hash + fmt::Debug, - S: BuildHasher, + T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() @@ -945,8 +944,7 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl Default for HashSet where - T: Eq + Hash, - S: BuildHasher + Default, + S: Default, { /// Creates an empty `HashSet` with the `Default` value for the hasher. #[inline] diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs index 7fa059583f539..8397d204f35cf 100644 --- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs @@ -6,7 +6,6 @@ pub fn no_debug() { pub fn no_hash() { use std::collections::HashSet; let mut set = HashSet::new(); - //~^ ERROR arrays only have std trait implementations for lengths 0..=32 set.insert([0_usize; 33]); //~^ ERROR arrays only have std trait implementations for lengths 0..=32 } diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr index d885c98dcb287..594a0d4b5d844 100644 --- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr @@ -8,24 +8,15 @@ LL | println!("{:?}", [0_usize; 33]); = note: required by `std::fmt::Debug::fmt` error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/core-traits-no-impls-length-33.rs:10:16 + --> $DIR/core-traits-no-impls-length-33.rs:9:16 | LL | set.insert([0_usize; 33]); | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]` | = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]` -error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/core-traits-no-impls-length-33.rs:8:19 - | -LL | let mut set = HashSet::new(); - | ^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]` - | - = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]` - = note: required by `std::collections::HashSet::::new` - error[E0369]: binary operation `==` cannot be applied to type `[usize; 33]` - --> $DIR/core-traits-no-impls-length-33.rs:15:19 + --> $DIR/core-traits-no-impls-length-33.rs:14:19 | LL | [0_usize; 33] == [1_usize; 33] | ------------- ^^ ------------- [usize; 33] @@ -35,7 +26,7 @@ LL | [0_usize; 33] == [1_usize; 33] = note: an implementation of `std::cmp::PartialEq` might be missing for `[usize; 33]` error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]` - --> $DIR/core-traits-no-impls-length-33.rs:20:19 + --> $DIR/core-traits-no-impls-length-33.rs:19:19 | LL | [0_usize; 33] < [1_usize; 33] | ------------- ^ ------------- [usize; 33] @@ -45,7 +36,7 @@ LL | [0_usize; 33] < [1_usize; 33] = note: an implementation of `std::cmp::PartialOrd` might be missing for `[usize; 33]` error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied - --> $DIR/core-traits-no-impls-length-33.rs:25:14 + --> $DIR/core-traits-no-impls-length-33.rs:24:14 | LL | for _ in &[0_usize; 33] { | ^^^^^^^^^^^^^^ the trait `std::iter::IntoIterator` is not implemented for `&[usize; 33]` @@ -57,7 +48,7 @@ LL | for _ in &[0_usize; 33] { <&'a mut [T] as std::iter::IntoIterator> = note: required by `std::iter::IntoIterator::into_iter` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0277, E0369. For more information about an error, try `rustc --explain E0277`. From 51021b1d421a7d055ff44f9b6afe11377b825c5c Mon Sep 17 00:00:00 2001 From: Tobias Thiel Date: Sat, 4 Jan 2020 18:04:30 -0800 Subject: [PATCH 003/657] rustc_session: allow overriding lint level of individual lints from a group --- src/librustc_session/config.rs | 13 ++++++++++--- .../ui-fulldeps/lint-group-denied-lint-allowed.rs | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index b6b22e298ca62..fd4e47baad5d7 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -986,19 +986,26 @@ pub fn get_cmd_lint_options( matches: &getopts::Matches, error_format: ErrorOutputType, ) -> (Vec<(String, lint::Level)>, bool, Option) { - let mut lint_opts = vec![]; + let mut lint_opts_with_position = vec![]; let mut describe_lints = false; for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] { - for lint_name in matches.opt_strs(level.as_str()) { + for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) { if lint_name == "help" { describe_lints = true; } else { - lint_opts.push((lint_name.replace("-", "_"), level)); + lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level)); } } } + lint_opts_with_position.sort_by_key(|x| x.0); + let lint_opts = lint_opts_with_position + .iter() + .cloned() + .map(|(_, lint_name, level)| (lint_name, level)) + .collect(); + let lint_cap = matches.opt_str("cap-lints").map(|cap| { lint::Level::from_str(&cap) .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap))) diff --git a/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs b/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs new file mode 100644 index 0000000000000..7498745f20699 --- /dev/null +++ b/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs @@ -0,0 +1,7 @@ +// aux-build:lint-group-plugin-test.rs +// check-pass +// compile-flags: -D unused -A unused-variables + +fn main() { + let x = 1; +} From 34417792deed6f0e570e9c7b01a24f1d05b70519 Mon Sep 17 00:00:00 2001 From: Tobias Thiel Date: Sat, 4 Jan 2020 23:35:43 -0800 Subject: [PATCH 004/657] tools/compiletest: fix argument ordering for allowing unused in ui & compile-fail tests --- src/tools/compiletest/src/runtest.rs | 42 ++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 226a12c6734b7..cfa4db69a6a88 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1478,11 +1478,7 @@ impl<'test> TestCx<'test> { WillExecute::No => TargetLocation::ThisDirectory(self.output_base_dir()), }; - let mut rustc = self.make_compile_args(&self.testpaths.file, output_file, emit_metadata); - - rustc.arg("-L").arg(&self.aux_output_dir_name()); - - match self.config.mode { + let allow_unused = match self.config.mode { CompileFail | Ui => { // compile-fail and ui tests tend to have tons of unused code as // it's just testing various pieces of the compile, but we don't @@ -1495,11 +1491,18 @@ impl<'test> TestCx<'test> { // via command line flags. && local_pm != Some(PassMode::Run) { - rustc.args(&["-A", "unused"]); + AllowUnused::Yes + } else { + AllowUnused::No } } - _ => {} - } + _ => AllowUnused::No, + }; + + let mut rustc = + self.make_compile_args(&self.testpaths.file, output_file, emit_metadata, allow_unused); + + rustc.arg("-L").arg(&self.aux_output_dir_name()); self.compose_and_run_compiler(rustc, None) } @@ -1710,7 +1713,8 @@ impl<'test> TestCx<'test> { // Create the directory for the stdout/stderr files. create_dir_all(aux_cx.output_base_dir()).unwrap(); let input_file = &aux_testpaths.file; - let mut aux_rustc = aux_cx.make_compile_args(input_file, aux_output, EmitMetadata::No); + let mut aux_rustc = + aux_cx.make_compile_args(input_file, aux_output, EmitMetadata::No, AllowUnused::No); let (dylib, crate_type) = if aux_props.no_prefer_dynamic { (true, None) @@ -1819,6 +1823,7 @@ impl<'test> TestCx<'test> { input_file: &Path, output_file: TargetLocation, emit_metadata: EmitMetadata, + allow_unused: AllowUnused, ) -> Command { let is_rustdoc = self.is_rustdoc(); let mut rustc = if !is_rustdoc { @@ -1951,6 +1956,13 @@ impl<'test> TestCx<'test> { rustc.arg("-Ctarget-feature=-crt-static"); } + match allow_unused { + AllowUnused::Yes => { + rustc.args(&["-A", "unused"]); + } + AllowUnused::No => {} + } + rustc.args(&self.props.compile_flags); rustc @@ -2134,7 +2146,8 @@ impl<'test> TestCx<'test> { let output_file = TargetLocation::ThisDirectory(self.output_base_dir()); let input_file = &self.testpaths.file; - let mut rustc = self.make_compile_args(input_file, output_file, EmitMetadata::No); + let mut rustc = + self.make_compile_args(input_file, output_file, EmitMetadata::No, AllowUnused::No); rustc.arg("-L").arg(aux_dir).arg("--emit=llvm-ir"); self.compose_and_run_compiler(rustc, None) @@ -2147,7 +2160,8 @@ impl<'test> TestCx<'test> { let output_file = TargetLocation::ThisFile(output_path.clone()); let input_file = &self.testpaths.file; - let mut rustc = self.make_compile_args(input_file, output_file, EmitMetadata::No); + let mut rustc = + self.make_compile_args(input_file, output_file, EmitMetadata::No, AllowUnused::No); rustc.arg("-L").arg(self.aux_output_dir_name()); @@ -2999,6 +3013,7 @@ impl<'test> TestCx<'test> { &self.testpaths.file.with_extension(UI_FIXED), TargetLocation::ThisFile(self.make_exe_name()), emit_metadata, + AllowUnused::No, ); rustc.arg("-L").arg(&self.aux_output_dir_name()); let res = self.compose_and_run_compiler(rustc, None); @@ -3486,6 +3501,11 @@ enum ExpectedLine> { Text(T), } +enum AllowUnused { + Yes, + No, +} + impl fmt::Debug for ExpectedLine where T: AsRef + fmt::Debug, From 21edd2ae2cc4c06d8ea98051c47d24dc3c4e2238 Mon Sep 17 00:00:00 2001 From: Tobias Thiel Date: Sun, 12 Jan 2020 22:11:27 -0800 Subject: [PATCH 005/657] convert match statement to if let --- src/tools/compiletest/src/runtest.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index cfa4db69a6a88..84bae6cd27edd 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1956,11 +1956,8 @@ impl<'test> TestCx<'test> { rustc.arg("-Ctarget-feature=-crt-static"); } - match allow_unused { - AllowUnused::Yes => { - rustc.args(&["-A", "unused"]); - } - AllowUnused::No => {} + if let AllowUnused::Yes = allow_unused { + rustc.args(&["-A", "unused"]); } rustc.args(&self.props.compile_flags); From 3fc9253a5a27771c72429a738d5379c34e1cd924 Mon Sep 17 00:00:00 2001 From: Tobias Thiel Date: Mon, 13 Jan 2020 20:03:28 -0800 Subject: [PATCH 006/657] rustc: add lint level cli ordering into the documentation --- src/doc/rustc/src/command-line-arguments.md | 8 ++++++++ src/doc/rustc/src/lints/levels.md | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 577d03d1038f8..659f8f65e65d2 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -215,21 +215,29 @@ This controls which [target](targets/index.md) to produce. This flag will set which lints should be set to the [warn level](lints/levels.md#warn). +_Note:_ The order of these lint level arguments is taken into account, see [lint level via compiler flag](lints/levels.md#via-compiler-flag) for more information. + ## `-A`: set lint allowed This flag will set which lints should be set to the [allow level](lints/levels.md#allow). +_Note:_ The order of these lint level arguments is taken into account, see [lint level via compiler flag](lints/levels.md#via-compiler-flag) for more information. + ## `-D`: set lint denied This flag will set which lints should be set to the [deny level](lints/levels.md#deny). +_Note:_ The order of these lint level arguments is taken into account, see [lint level via compiler flag](lints/levels.md#via-compiler-flag) for more information. + ## `-F`: set lint forbidden This flag will set which lints should be set to the [forbid level](lints/levels.md#forbid). +_Note:_ The order of these lint level arguments is taken into account, see [lint level via compiler flag](lints/levels.md#via-compiler-flag) for more information. + ## `-Z`: set unstable options diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 2944e86566313..3cfe2f698f3e0 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -164,6 +164,18 @@ And of course, you can mix these four flags together: $ rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables ``` +The order of these command line arguments is taken into account. The following allows the `unused-variables` lint, because it is the last argument for that lint: + +```bash +$ rustc lib.rs --crate-type=lib -D unused-variables -A unused-variables +``` + +You can make use of this behavior by overriding the level of one specific lint out of a group of lints. The following example denies all the lints in the `unused` group, but explicitly allows the `unused-variables` lint in that group: + +```bash +$ rustc lib.rs --crate-type=lib -D unused -A unused-variables +``` + ### Via an attribute You can also modify the lint level with a crate-wide attribute: From a859ca5c87ddfaa635fb4cacf8a41e04fd9b02e8 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 13 Dec 2019 14:51:37 +0100 Subject: [PATCH 007/657] Fix `binary_heap::DrainSorted` drop leak on panics --- src/liballoc/collections/binary_heap.rs | 16 ++++++++++-- src/liballoc/tests/binary_heap.rs | 33 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index c527b378f7465..f38fe997b732c 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -147,7 +147,7 @@ use core::fmt; use core::iter::{FromIterator, FusedIterator, TrustedLen}; -use core::mem::{size_of, swap, ManuallyDrop}; +use core::mem::{self, size_of, swap, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::ptr; @@ -1239,7 +1239,19 @@ pub struct DrainSorted<'a, T: Ord> { impl<'a, T: Ord> Drop for DrainSorted<'a, T> { /// Removes heap elements in heap order. fn drop(&mut self) { - while let Some(_) = self.inner.pop() {} + struct DropGuard<'r, 'a, T: Ord>(&'r mut DrainSorted<'a, T>); + + impl<'r, 'a, T: Ord> Drop for DropGuard<'r, 'a, T> { + fn drop(&mut self) { + while let Some(_) = self.0.inner.pop() {} + } + } + + while let Some(item) = self.inner.pop() { + let guard = DropGuard(self); + drop(item); + mem::forget(guard); + } } } diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index f49ca7139212f..be5516f54f37b 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -1,6 +1,8 @@ use std::collections::binary_heap::{Drain, PeekMut}; use std::collections::BinaryHeap; use std::iter::TrustedLen; +use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::sync::atomic::{AtomicU32, Ordering}; #[test] fn test_iterator() { @@ -275,6 +277,37 @@ fn test_drain_sorted() { assert!(q.is_empty()); } +#[test] +fn test_drain_sorted_leak() { + static DROPS: AtomicU32 = AtomicU32::new(0); + + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] + struct D(u32, bool); + + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + + if self.1 { + panic!("panic in `drop`"); + } + } + } + + let mut q = BinaryHeap::from(vec![ + D(0, false), + D(1, false), + D(2, false), + D(3, true), + D(4, false), + D(5, false), + ]); + + catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok(); + + assert_eq!(DROPS.load(Ordering::SeqCst), 6); +} + #[test] fn test_extend_ref() { let mut a = BinaryHeap::new(); From 3e5eb2634cbb356b626e028a4be1305d4a44a023 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 13 Dec 2019 16:41:19 +0100 Subject: [PATCH 008/657] Fix `VecDeque::truncate` leak on drop panic --- src/liballoc/collections/vec_deque.rs | 17 ++++++++++++- src/liballoc/tests/vec_deque.rs | 35 ++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 2cc450bb68a20..7307aad8a9ed6 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -866,6 +866,18 @@ impl VecDeque { /// ``` #[stable(feature = "deque_extras", since = "1.16.0")] pub fn truncate(&mut self, len: usize) { + /// Runs the destructor for all items in the slice when it gets dropped (normally or + /// during unwinding). + struct Dropper<'a, T>(&'a mut [T]); + + impl<'a, T> Drop for Dropper<'a, T> { + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(self.0); + } + } + } + // Safe because: // // * Any slice passed to `drop_in_place` is valid; the second case has @@ -888,8 +900,11 @@ impl VecDeque { let drop_back = back as *mut _; let drop_front = front.get_unchecked_mut(len..) as *mut _; self.head = self.wrap_sub(self.head, num_dropped); + + // Make sure the second half is dropped even when a destructor + // in the first one panics. + let _back_dropper = Dropper(&mut *drop_back); ptr::drop_in_place(drop_front); - ptr::drop_in_place(drop_back); } } } diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 1ab3694a3ca61..2dc50d0c70e23 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -2,7 +2,7 @@ use std::collections::TryReserveError::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; use std::mem::size_of; -use std::panic::catch_unwind; +use std::panic::{AssertUnwindSafe, catch_unwind}; use std::{isize, usize}; use crate::hash; @@ -1573,3 +1573,36 @@ fn test_try_rfold_moves_iter() { assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); assert_eq!(iter.next_back(), Some(&70)); } + +#[test] +fn truncate_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let mut q = VecDeque::new(); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_front(D(true)); + q.push_front(D(false)); + q.push_front(D(false)); + + catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok(); + + assert_eq!(unsafe { DROPS }, 7); +} From 5d04790dd2e73f3faf08d528e3675e131585ec01 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 13 Dec 2019 17:54:26 +0100 Subject: [PATCH 009/657] Avoid leak in `vec::Drain` when item drop panics --- src/liballoc/tests/vec.rs | 39 +++++++++++++++++++++++++++++++++++ src/liballoc/vec.rs | 43 +++++++++++++++++++++++++++------------ 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 2a9bfefc713e7..80acba0a3a162 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; use std::mem::size_of; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::vec::{Drain, IntoIter}; use std::{isize, usize}; @@ -585,6 +586,44 @@ fn test_drain_inclusive_out_of_bounds() { v.drain(5..=5); } +#[test] +fn test_drain_leak() { + static mut DROPS: i32 = 0; + + #[derive(Debug, PartialEq)] + struct D(u32, bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.1 { + panic!("panic in `drop`"); + } + } + } + + let mut v = vec![ + D(0, false), + D(1, false), + D(2, false), + D(3, false), + D(4, true), + D(5, false), + D(6, false), + ]; + + catch_unwind(AssertUnwindSafe(|| { + v.drain(2..=5); + })) + .ok(); + + assert_eq!(unsafe { DROPS }, 4); + assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]); +} + #[test] fn test_splice() { let mut v = vec![1, 2, 3, 4, 5]; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index e9cbf627846b5..ba71e42090cbb 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2700,23 +2700,40 @@ impl DoubleEndedIterator for Drain<'_, T> { #[stable(feature = "drain", since = "1.6.0")] impl Drop for Drain<'_, T> { fn drop(&mut self) { - // exhaust self first - self.for_each(drop); + /// Continues dropping the remaining elements when a destructor unwinds. + struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>); - if self.tail_len > 0 { - unsafe { - let source_vec = self.vec.as_mut(); - // memmove back untouched tail, update to new length - let start = source_vec.len(); - let tail = self.tail_start; - if tail != start { - let src = source_vec.as_ptr().add(tail); - let dst = source_vec.as_mut_ptr().add(start); - ptr::copy(src, dst, self.tail_len); + impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> { + fn drop(&mut self) { + // Continue the same loop we do below. This only runs when a destructor has + // panicked. If another one panics this will abort. + self.0.for_each(drop); + + if self.0.tail_len > 0 { + unsafe { + let source_vec = self.0.vec.as_mut(); + // memmove back untouched tail, update to new length + let start = source_vec.len(); + let tail = self.0.tail_start; + if tail != start { + let src = source_vec.as_ptr().add(tail); + let dst = source_vec.as_mut_ptr().add(start); + ptr::copy(src, dst, self.0.tail_len); + } + source_vec.set_len(start + self.0.tail_len); + } } - source_vec.set_len(start + self.tail_len); } } + + // exhaust self first + while let Some(item) = self.next() { + let guard = DropGuard(self); + drop(item); + mem::forget(guard); + } + + DropGuard(self); } } From dc492452dae29d75b14afe3559f5fb59be7f2d3a Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 13 Dec 2019 18:36:35 +0100 Subject: [PATCH 010/657] Fix leak in btree_map::IntoIter when drop panics --- src/liballoc/collections/btree/map.rs | 17 +++++++++++++++- src/liballoc/tests/btree/map.rs | 28 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 302c2bcd5e4a3..71ddfc4ef63b6 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1381,7 +1381,22 @@ impl IntoIterator for BTreeMap { #[stable(feature = "btree_drop", since = "1.7.0")] impl Drop for IntoIter { fn drop(&mut self) { - self.for_each(drop); + struct DropGuard<'a, K, V>(&'a mut IntoIter); + + impl<'a, K, V> Drop for DropGuard<'a, K, V> { + fn drop(&mut self) { + // Continue the same loop we perform below. This only runs when unwinding, so we + // don't have to care about panics this time (they'll abort). + while let Some(_) = self.0.next() {} + } + } + + while let Some(pair) = self.next() { + let guard = DropGuard(self); + drop(pair); + mem::forget(guard); + } + unsafe { let leaf_node = ptr::read(&self.front).into_node(); if leaf_node.is_shared_root() { diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index f5be72c39b20c..0729f341d8609 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -5,7 +5,9 @@ use std::fmt::Debug; use std::iter::FromIterator; use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::ops::RangeBounds; +use std::panic::catch_unwind; use std::rc::Rc; +use std::sync::atomic::{AtomicU32, Ordering}; use super::DeterministicRng; @@ -980,3 +982,29 @@ fn test_split_off_large_random_sorted() { assert!(map.into_iter().eq(data.clone().into_iter().filter(|x| x.0 < key))); assert!(right.into_iter().eq(data.into_iter().filter(|x| x.0 >= key))); } + +#[test] +fn test_into_iter_drop_leak() { + static DROPS: AtomicU32 = AtomicU32::new(0); + + struct D; + + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == 3 { + panic!("panic in `drop`"); + } + } + } + + let mut map = BTreeMap::new(); + map.insert("a", D); + map.insert("b", D); + map.insert("c", D); + map.insert("d", D); + map.insert("e", D); + + catch_unwind(move || drop(map.into_iter())).ok(); + + assert_eq!(DROPS.load(Ordering::SeqCst), 5); +} From b04ca13873d5ef5e5b18195aaf8925562302e8e0 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 13 Dec 2019 19:32:16 +0100 Subject: [PATCH 011/657] Fix leak in VecDeque::drain when drop panics --- src/liballoc/collections/vec_deque.rs | 82 ++++++++++++++++----------- src/liballoc/tests/vec_deque.rs | 38 +++++++++++++ 2 files changed, 86 insertions(+), 34 deletions(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 7307aad8a9ed6..de92c4997e371 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -2575,47 +2575,61 @@ unsafe impl Send for Drain<'_, T> {} #[stable(feature = "drain", since = "1.6.0")] impl Drop for Drain<'_, T> { fn drop(&mut self) { - self.for_each(drop); + struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>); - let source_deque = unsafe { self.deque.as_mut() }; + impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> { + fn drop(&mut self) { + self.0.for_each(drop); - // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head - // - // T t h H - // [. . . o o x x o o . . .] - // - let orig_tail = source_deque.tail; - let drain_tail = source_deque.head; - let drain_head = self.after_tail; - let orig_head = self.after_head; + let source_deque = unsafe { self.0.deque.as_mut() }; - let tail_len = count(orig_tail, drain_tail, source_deque.cap()); - let head_len = count(drain_head, orig_head, source_deque.cap()); + // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head + // + // T t h H + // [. . . o o x x o o . . .] + // + let orig_tail = source_deque.tail; + let drain_tail = source_deque.head; + let drain_head = self.0.after_tail; + let orig_head = self.0.after_head; - // Restore the original head value - source_deque.head = orig_head; + let tail_len = count(orig_tail, drain_tail, source_deque.cap()); + let head_len = count(drain_head, orig_head, source_deque.cap()); - match (tail_len, head_len) { - (0, 0) => { - source_deque.head = 0; - source_deque.tail = 0; - } - (0, _) => { - source_deque.tail = drain_head; - } - (_, 0) => { - source_deque.head = drain_tail; - } - _ => unsafe { - if tail_len <= head_len { - source_deque.tail = source_deque.wrap_sub(drain_head, tail_len); - source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len); - } else { - source_deque.head = source_deque.wrap_add(drain_tail, head_len); - source_deque.wrap_copy(drain_tail, drain_head, head_len); + // Restore the original head value + source_deque.head = orig_head; + + match (tail_len, head_len) { + (0, 0) => { + source_deque.head = 0; + source_deque.tail = 0; + } + (0, _) => { + source_deque.tail = drain_head; + } + (_, 0) => { + source_deque.head = drain_tail; + } + _ => unsafe { + if tail_len <= head_len { + source_deque.tail = source_deque.wrap_sub(drain_head, tail_len); + source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len); + } else { + source_deque.head = source_deque.wrap_add(drain_tail, head_len); + source_deque.wrap_copy(drain_tail, drain_head, head_len); + } + }, } - }, + } } + + while let Some(item) = self.next() { + let guard = DropGuard(self); + drop(item); + mem::forget(guard); + } + + DropGuard(self); } } diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 2dc50d0c70e23..07f1f098954a9 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1606,3 +1606,41 @@ fn truncate_leak() { assert_eq!(unsafe { DROPS }, 7); } + +#[test] +fn test_drain_leak() { + static mut DROPS: i32 = 0; + + #[derive(Debug, PartialEq)] + struct D(u32, bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.1 { + panic!("panic in `drop`"); + } + } + } + + let mut v = VecDeque::new(); + v.push_back(D(4, false)); + v.push_back(D(5, false)); + v.push_back(D(6, false)); + v.push_front(D(3, false)); + v.push_front(D(2, true)); + v.push_front(D(1, false)); + v.push_front(D(0, false)); + + catch_unwind(AssertUnwindSafe(|| { + v.drain(1..=4); + })).ok(); + + assert_eq!(unsafe { DROPS }, 4); + assert_eq!(v.len(), 3); + drop(v); + assert_eq!(unsafe { DROPS }, 7); +} From 163ed23f0081d7283ccaef39141bc29879260663 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 13 Dec 2019 21:34:30 +0100 Subject: [PATCH 012/657] Fix leak in vec::IntoIter when a destructor panics --- src/liballoc/tests/vec.rs | 29 +++++++++++++++++++++++++++++ src/liballoc/vec.rs | 4 +++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 80acba0a3a162..2a027fd5d2b6e 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -765,6 +765,35 @@ fn test_into_iter_clone() { assert_eq!(it.next(), None); } +#[test] +fn test_into_iter_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let v = vec![ + D(false), + D(true), + D(false), + ]; + + catch_unwind(move || drop(v.into_iter())).ok(); + + assert_eq!(unsafe { DROPS }, 3); +} + #[test] fn test_cow_from() { let borrowed: &[_] = &["borrowed", "(slice)"]; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index ba71e42090cbb..6589cc5b1f675 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2620,7 +2620,9 @@ impl Clone for IntoIter { unsafe impl<#[may_dangle] T> Drop for IntoIter { fn drop(&mut self) { // destroy the remaining elements - for _x in self.by_ref() {} + unsafe { + ptr::drop_in_place(self.as_mut_slice()); + } // RawVec handles deallocation let _ = unsafe { RawVec::from_raw_parts(self.buf.as_ptr(), self.cap) }; From 0ae16b47ffee866ee49f909ea213a28d8068cf56 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 14 Dec 2019 00:55:06 +0100 Subject: [PATCH 013/657] Avoid leak in DrainFilter when a drop panics --- src/liballoc/collections/linked_list.rs | 16 ++++++++++- src/liballoc/tests/linked_list.rs | 36 ++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index b88ca8a0fb0d1..463ec67d66894 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -1565,7 +1565,21 @@ where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - self.for_each(drop); + struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>) + where F: FnMut(&mut T) -> bool; + + impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F> + where F: FnMut(&mut T) -> bool { + fn drop(&mut self) { + self.0.for_each(drop); + } + } + + while let Some(item) = self.next() { + let guard = DropGuard(self); + drop(item); + mem::forget(guard); + } } } diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs index b7736515b262a..aa3f582a165fb 100644 --- a/src/liballoc/tests/linked_list.rs +++ b/src/liballoc/tests/linked_list.rs @@ -1,5 +1,5 @@ use std::collections::LinkedList; -use std::panic::catch_unwind; +use std::panic::{catch_unwind, AssertUnwindSafe}; #[test] fn test_basic() { @@ -531,6 +531,40 @@ fn drain_filter_complex() { } } +#[test] +fn drain_filter_drop_panic_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let mut q = LinkedList::new(); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_front(D(false)); + q.push_front(D(true)); + q.push_front(D(false)); + + catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok(); + + assert_eq!(unsafe { DROPS }, 8); + assert!(q.is_empty()); +} + #[test] fn test_drop() { static mut DROPS: i32 = 0; From 1f373f4aeb279c6bf98976aee419db967c4f56f6 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 14 Dec 2019 01:01:28 +0100 Subject: [PATCH 014/657] Add test for panic in LL DrainFilter predicate --- src/liballoc/tests/linked_list.rs | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs index aa3f582a165fb..c40f99ee9069d 100644 --- a/src/liballoc/tests/linked_list.rs +++ b/src/liballoc/tests/linked_list.rs @@ -565,6 +565,41 @@ fn drain_filter_drop_panic_leak() { assert!(q.is_empty()); } +#[test] +fn drain_filter_pred_panic_leak() { + static mut DROPS: i32 = 0; + + #[derive(Debug)] + struct D(u32); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + + let mut q = LinkedList::new(); + q.push_back(D(3)); + q.push_back(D(4)); + q.push_back(D(5)); + q.push_back(D(6)); + q.push_back(D(7)); + q.push_front(D(2)); + q.push_front(D(1)); + q.push_front(D(0)); + + catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|item| if item.0 >= 2 { + panic!() + } else { + true + })))).ok(); + + assert_eq!(unsafe { DROPS }, 2); // 0 and 1 + assert_eq!(q.len(), 6); +} + #[test] fn test_drop() { static mut DROPS: i32 = 0; From 75f721df97fd7895b31a1d8c9ed05a368fc95d6d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 14 Dec 2019 17:06:22 +0100 Subject: [PATCH 015/657] Move VecDeque Drain iterator to new file --- src/liballoc/collections/vec_deque.rs | 126 +------------------- src/liballoc/collections/vec_deque/drain.rs | 126 ++++++++++++++++++++ 2 files changed, 131 insertions(+), 121 deletions(-) create mode 100644 src/liballoc/collections/vec_deque/drain.rs diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index de92c4997e371..85d1d98b8a9c2 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -22,6 +22,11 @@ use crate::collections::TryReserveError; use crate::raw_vec::RawVec; use crate::vec::Vec; +#[stable(feature = "drain", since = "1.6.0")] +pub use self::drain::Drain; + +mod drain; + #[cfg(test)] mod tests; @@ -2541,127 +2546,6 @@ impl ExactSizeIterator for IntoIter { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} -/// A draining iterator over the elements of a `VecDeque`. -/// -/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its -/// documentation for more. -/// -/// [`drain`]: struct.VecDeque.html#method.drain -/// [`VecDeque`]: struct.VecDeque.html -#[stable(feature = "drain", since = "1.6.0")] -pub struct Drain<'a, T: 'a> { - after_tail: usize, - after_head: usize, - iter: Iter<'a, T>, - deque: NonNull>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for Drain<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Drain") - .field(&self.after_tail) - .field(&self.after_head) - .field(&self.iter) - .finish() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -unsafe impl Sync for Drain<'_, T> {} -#[stable(feature = "drain", since = "1.6.0")] -unsafe impl Send for Drain<'_, T> {} - -#[stable(feature = "drain", since = "1.6.0")] -impl Drop for Drain<'_, T> { - fn drop(&mut self) { - struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>); - - impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> { - fn drop(&mut self) { - self.0.for_each(drop); - - let source_deque = unsafe { self.0.deque.as_mut() }; - - // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head - // - // T t h H - // [. . . o o x x o o . . .] - // - let orig_tail = source_deque.tail; - let drain_tail = source_deque.head; - let drain_head = self.0.after_tail; - let orig_head = self.0.after_head; - - let tail_len = count(orig_tail, drain_tail, source_deque.cap()); - let head_len = count(drain_head, orig_head, source_deque.cap()); - - // Restore the original head value - source_deque.head = orig_head; - - match (tail_len, head_len) { - (0, 0) => { - source_deque.head = 0; - source_deque.tail = 0; - } - (0, _) => { - source_deque.tail = drain_head; - } - (_, 0) => { - source_deque.head = drain_tail; - } - _ => unsafe { - if tail_len <= head_len { - source_deque.tail = source_deque.wrap_sub(drain_head, tail_len); - source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len); - } else { - source_deque.head = source_deque.wrap_add(drain_tail, head_len); - source_deque.wrap_copy(drain_tail, drain_head, head_len); - } - }, - } - } - } - - while let Some(item) = self.next() { - let guard = DropGuard(self); - drop(item); - mem::forget(guard); - } - - DropGuard(self); - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl Iterator for Drain<'_, T> { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt) }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl DoubleEndedIterator for Drain<'_, T> { - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(|elt| unsafe { ptr::read(elt) }) - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl ExactSizeIterator for Drain<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, T> {} - #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for VecDeque { fn eq(&self, other: &VecDeque) -> bool { diff --git a/src/liballoc/collections/vec_deque/drain.rs b/src/liballoc/collections/vec_deque/drain.rs new file mode 100644 index 0000000000000..1ae94de75adb7 --- /dev/null +++ b/src/liballoc/collections/vec_deque/drain.rs @@ -0,0 +1,126 @@ +use core::iter::FusedIterator; +use core::ptr::{self, NonNull}; +use core::{fmt, mem}; + +use super::{count, Iter, VecDeque}; + +/// A draining iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.VecDeque.html#method.drain +/// [`VecDeque`]: struct.VecDeque.html +#[stable(feature = "drain", since = "1.6.0")] +pub struct Drain<'a, T: 'a> { + pub(crate) after_tail: usize, + pub(crate) after_head: usize, + pub(crate) iter: Iter<'a, T>, + pub(crate) deque: NonNull>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for Drain<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Drain") + .field(&self.after_tail) + .field(&self.after_head) + .field(&self.iter) + .finish() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +unsafe impl Sync for Drain<'_, T> {} +#[stable(feature = "drain", since = "1.6.0")] +unsafe impl Send for Drain<'_, T> {} + +#[stable(feature = "drain", since = "1.6.0")] +impl Drop for Drain<'_, T> { + fn drop(&mut self) { + struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>); + + impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> { + fn drop(&mut self) { + self.0.for_each(drop); + + let source_deque = unsafe { self.0.deque.as_mut() }; + + // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head + // + // T t h H + // [. . . o o x x o o . . .] + // + let orig_tail = source_deque.tail; + let drain_tail = source_deque.head; + let drain_head = self.0.after_tail; + let orig_head = self.0.after_head; + + let tail_len = count(orig_tail, drain_tail, source_deque.cap()); + let head_len = count(drain_head, orig_head, source_deque.cap()); + + // Restore the original head value + source_deque.head = orig_head; + + match (tail_len, head_len) { + (0, 0) => { + source_deque.head = 0; + source_deque.tail = 0; + } + (0, _) => { + source_deque.tail = drain_head; + } + (_, 0) => { + source_deque.head = drain_tail; + } + _ => unsafe { + if tail_len <= head_len { + source_deque.tail = source_deque.wrap_sub(drain_head, tail_len); + source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len); + } else { + source_deque.head = source_deque.wrap_add(drain_tail, head_len); + source_deque.wrap_copy(drain_tail, drain_head, head_len); + } + }, + } + } + } + + while let Some(item) = self.next() { + let guard = DropGuard(self); + drop(item); + mem::forget(guard); + } + + DropGuard(self); + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl Iterator for Drain<'_, T> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|elt| unsafe { ptr::read(elt) }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl DoubleEndedIterator for Drain<'_, T> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back().map(|elt| unsafe { ptr::read(elt) }) + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl ExactSizeIterator for Drain<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Drain<'_, T> {} From 52d6c90488abdd12a24c66f5e3490ae3136bb295 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 16 Dec 2019 21:42:46 +0100 Subject: [PATCH 016/657] Update comments in `Drain`s `Drop` impl --- src/liballoc/vec.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 6589cc5b1f675..4fa60846e22a6 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2702,13 +2702,14 @@ impl DoubleEndedIterator for Drain<'_, T> { #[stable(feature = "drain", since = "1.6.0")] impl Drop for Drain<'_, T> { fn drop(&mut self) { - /// Continues dropping the remaining elements when a destructor unwinds. + /// Continues dropping the remaining elements in the `Drain`, then moves back the + /// un-`Drain`ed elements to restore the original `Vec`. struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>); impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> { fn drop(&mut self) { - // Continue the same loop we do below. This only runs when a destructor has - // panicked. If another one panics this will abort. + // Continue the same loop we have below. If the loop already finished, this does + // nothing. self.0.for_each(drop); if self.0.tail_len > 0 { @@ -2735,6 +2736,7 @@ impl Drop for Drain<'_, T> { mem::forget(guard); } + // Drop a `DropGuard` to move back the non-drained tail of `self`. DropGuard(self); } } From e5987a062f487321bdfcbbdac4b0b30548258631 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 19 Jan 2020 20:50:00 +0100 Subject: [PATCH 017/657] Format --- src/liballoc/collections/linked_list.rs | 7 +++++-- src/liballoc/tests/linked_list.rs | 11 +++++------ src/liballoc/tests/vec.rs | 6 +----- src/liballoc/tests/vec_deque.rs | 5 +++-- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 463ec67d66894..399dbe5e4bf2f 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -1566,10 +1566,13 @@ where { fn drop(&mut self) { struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>) - where F: FnMut(&mut T) -> bool; + where + F: FnMut(&mut T) -> bool; impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F> - where F: FnMut(&mut T) -> bool { + where + F: FnMut(&mut T) -> bool, + { fn drop(&mut self) { self.0.for_each(drop); } diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs index c40f99ee9069d..afcb9e03fd097 100644 --- a/src/liballoc/tests/linked_list.rs +++ b/src/liballoc/tests/linked_list.rs @@ -590,13 +590,12 @@ fn drain_filter_pred_panic_leak() { q.push_front(D(1)); q.push_front(D(0)); - catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|item| if item.0 >= 2 { - panic!() - } else { - true - })))).ok(); + catch_unwind(AssertUnwindSafe(|| { + drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true })) + })) + .ok(); - assert_eq!(unsafe { DROPS }, 2); // 0 and 1 + assert_eq!(unsafe { DROPS }, 2); // 0 and 1 assert_eq!(q.len(), 6); } diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 2a027fd5d2b6e..9c4ac52acac2a 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -783,11 +783,7 @@ fn test_into_iter_leak() { } } - let v = vec![ - D(false), - D(true), - D(false), - ]; + let v = vec![D(false), D(true), D(false)]; catch_unwind(move || drop(v.into_iter())).ok(); diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 07f1f098954a9..101dd67d97a9a 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -2,7 +2,7 @@ use std::collections::TryReserveError::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; use std::mem::size_of; -use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::{isize, usize}; use crate::hash; @@ -1637,7 +1637,8 @@ fn test_drain_leak() { catch_unwind(AssertUnwindSafe(|| { v.drain(1..=4); - })).ok(); + })) + .ok(); assert_eq!(unsafe { DROPS }, 4); assert_eq!(v.len(), 3); From 90afc0765e5e536af6307b63e1655a38df06e235 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 22 Jan 2020 19:23:37 -0500 Subject: [PATCH 018/657] Use a `ParamEnvAnd` for caching in `ObligationForest` Previously, we used a plain `Predicate` to cache results (e.g. successes and failures) in ObligationForest. However, fulfillment depends on the precise `ParamEnv` used, so this is unsound in general. This commit changes the impl of `ForestObligation` for `PendingPredicateObligation` to use `ParamEnvAnd` instead of `Predicate` for the associated type. The associated type and method are renamed from 'predicate' to 'cache_key' to reflect the fact that type is no longer just a predicate. --- src/librustc/traits/fulfill.rs | 9 ++++-- .../obligation_forest/graphviz.rs | 2 +- .../obligation_forest/mod.rs | 29 +++++++++++-------- .../obligation_forest/tests.rs | 4 +-- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 0aac6fb81e4a3..07352a3f9478a 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -18,10 +18,13 @@ use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation}; impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { - type Predicate = ty::Predicate<'tcx>; + /// Note that we include both the `ParamEnv` and the `Predicate`, + /// as the `ParamEnv` can influence whether fulfillment succeeds + /// or fails. + type CacheKey = ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>; - fn as_predicate(&self) -> &Self::Predicate { - &self.obligation.predicate + fn as_cache_key(&self) -> Self::CacheKey { + self.obligation.param_env.and(self.obligation.predicate) } } diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/src/librustc_data_structures/obligation_forest/graphviz.rs index ddf89d99621ca..96ee72d187b34 100644 --- a/src/librustc_data_structures/obligation_forest/graphviz.rs +++ b/src/librustc_data_structures/obligation_forest/graphviz.rs @@ -51,7 +51,7 @@ impl<'a, O: ForestObligation + 'a> dot::Labeller<'a> for &'a ObligationForest fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> { let node = &self.nodes[*index]; - let label = format!("{:?} ({:?})", node.obligation.as_predicate(), node.state.get()); + let label = format!("{:?} ({:?})", node.obligation.as_cache_key(), node.state.get()); dot::LabelText::LabelStr(label.into()) } diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 974d9dcfae408..500ce5c71f37a 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -86,9 +86,13 @@ mod graphviz; mod tests; pub trait ForestObligation: Clone + Debug { - type Predicate: Clone + hash::Hash + Eq + Debug; + type CacheKey: Clone + hash::Hash + Eq + Debug; - fn as_predicate(&self) -> &Self::Predicate; + /// Converts this `ForestObligation` suitable for use as a cache key. + /// If two distinct `ForestObligations`s return the same cache key, + /// then it must be sound to use the result of processing one obligation + /// (e.g. success for error) for the other obligation + fn as_cache_key(&self) -> Self::CacheKey; } pub trait ObligationProcessor { @@ -138,12 +142,12 @@ pub struct ObligationForest { nodes: Vec>, /// A cache of predicates that have been successfully completed. - done_cache: FxHashSet, + done_cache: FxHashSet, /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately, /// its contents are not guaranteed to match those of `nodes`. See the /// comments in `process_obligation` for details. - active_cache: FxHashMap, + active_cache: FxHashMap, /// A vector reused in compress(), to avoid allocating new vectors. node_rewrites: RefCell>, @@ -157,7 +161,7 @@ pub struct ObligationForest { /// See [this][details] for details. /// /// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780 - error_cache: FxHashMap>, + error_cache: FxHashMap>, } #[derive(Debug)] @@ -305,11 +309,12 @@ impl ObligationForest { // Returns Err(()) if we already know this obligation failed. fn register_obligation_at(&mut self, obligation: O, parent: Option) -> Result<(), ()> { - if self.done_cache.contains(obligation.as_predicate()) { + if self.done_cache.contains(&obligation.as_cache_key()) { + debug!("register_obligation_at: ignoring already done obligation: {:?}", obligation); return Ok(()); } - match self.active_cache.entry(obligation.as_predicate().clone()) { + match self.active_cache.entry(obligation.as_cache_key().clone()) { Entry::Occupied(o) => { let node = &mut self.nodes[*o.get()]; if let Some(parent_index) = parent { @@ -333,7 +338,7 @@ impl ObligationForest { && self .error_cache .get(&obligation_tree_id) - .map(|errors| errors.contains(obligation.as_predicate())) + .map(|errors| errors.contains(&obligation.as_cache_key())) .unwrap_or(false); if already_failed { @@ -380,7 +385,7 @@ impl ObligationForest { self.error_cache .entry(node.obligation_tree_id) .or_default() - .insert(node.obligation.as_predicate().clone()); + .insert(node.obligation.as_cache_key().clone()); } /// Performs a pass through the obligation list. This must @@ -618,11 +623,11 @@ impl ObligationForest { // `self.nodes`. See the comment in `process_obligation` // for more details. if let Some((predicate, _)) = - self.active_cache.remove_entry(node.obligation.as_predicate()) + self.active_cache.remove_entry(&node.obligation.as_cache_key()) { self.done_cache.insert(predicate); } else { - self.done_cache.insert(node.obligation.as_predicate().clone()); + self.done_cache.insert(node.obligation.as_cache_key().clone()); } if do_completed == DoCompleted::Yes { // Extract the success stories. @@ -635,7 +640,7 @@ impl ObligationForest { // We *intentionally* remove the node from the cache at this point. Otherwise // tests must come up with a different type on every type error they // check against. - self.active_cache.remove(node.obligation.as_predicate()); + self.active_cache.remove(&node.obligation.as_cache_key()); self.insert_into_error_cache(index); node_rewrites[index] = orig_nodes_len; dead_nodes += 1; diff --git a/src/librustc_data_structures/obligation_forest/tests.rs b/src/librustc_data_structures/obligation_forest/tests.rs index e29335aab2808..01652465eea2c 100644 --- a/src/librustc_data_structures/obligation_forest/tests.rs +++ b/src/librustc_data_structures/obligation_forest/tests.rs @@ -4,9 +4,9 @@ use std::fmt; use std::marker::PhantomData; impl<'a> super::ForestObligation for &'a str { - type Predicate = &'a str; + type CacheKey = &'a str; - fn as_predicate(&self) -> &Self::Predicate { + fn as_cache_key(&self) -> Self::CacheKey { self } } From ac19dffd1eaea34c3861324c2588f9cb1f1489f5 Mon Sep 17 00:00:00 2001 From: Steven Degutis Date: Thu, 23 Jan 2020 15:25:10 -0600 Subject: [PATCH 019/657] Updating str.chars docs to mention crates.io. This might spare someone else a little time searching the stdlib for unicode/grapheme support. --- src/libcore/str/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5a7cddd4041d5..89d5ba577c621 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2658,7 +2658,8 @@ impl str { /// /// It's important to remember that [`char`] represents a Unicode Scalar /// Value, and may not match your idea of what a 'character' is. Iteration - /// over grapheme clusters may be what you actually want. + /// over grapheme clusters may be what you actually want. This functionality + /// is not provided by Rust's standard library, check crates.io instead. /// /// # Examples /// From 84f3356e0dffc36f57d9be7902822db5d362e24f Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Tue, 28 Jan 2020 12:39:18 +0000 Subject: [PATCH 020/657] Simplify `Skip::nth` and `Skip::last` implementations The main improvement is to make `last` no longer recursive. --- src/libcore/iter/adapters/mod.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index 5787b9174edab..df824dd493e51 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -1801,17 +1801,15 @@ where #[inline] fn nth(&mut self, n: usize) -> Option { // Can't just add n + self.n due to overflow. - if self.n == 0 { - self.iter.nth(n) - } else { + if self.n > 0 { let to_skip = self.n; self.n = 0; // nth(n) skips n+1 if self.iter.nth(to_skip - 1).is_none() { return None; } - self.iter.nth(n) } + self.iter.nth(n) } #[inline] @@ -1827,17 +1825,13 @@ where #[inline] fn last(mut self) -> Option { - if self.n == 0 { - self.iter.last() - } else { - let next = self.next(); - if next.is_some() { - // recurse. n should be 0. - self.last().or(next) - } else { - None + if self.n > 0 { + // nth(n) skips n+1 + if self.iter.nth(self.n - 1).is_none() { + return None; } } + self.iter.last() } #[inline] From bfba6ef328bbba327cae8918e795c11b89217672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 28 Jan 2020 19:21:22 +0100 Subject: [PATCH 021/657] Add an option to use LLD to link the compiler on Windows platforms --- config.toml.example | 5 +++++ src/bootstrap/bin/rustc.rs | 5 +++++ src/bootstrap/builder.rs | 26 +++++++++++++++++++++++--- src/bootstrap/config.rs | 3 +++ src/bootstrap/lib.rs | 20 ++++++++++++++++++-- src/bootstrap/test.rs | 4 ++-- 6 files changed, 56 insertions(+), 7 deletions(-) diff --git a/config.toml.example b/config.toml.example index c9e17337ee23f..c8aff4af8ffe3 100644 --- a/config.toml.example +++ b/config.toml.example @@ -395,6 +395,11 @@ # rustc to execute. #lld = false +# Indicates whether LLD will be used to link Rust crates during bootstrap on +# supported platforms. The LLD from the bootstrap distribution will be used +# and not the LLD compiled during the bootstrap. +#use-lld = false + # Indicates whether some LLVM tools, like llvm-objdump, will be made available in the # sysroot. #llvm-tools = false diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a34ec44566bc1..46e3e4ef6d1f3 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -134,6 +134,11 @@ fn main() { cmd.arg(format!("-Clinker={}", host_linker)); } + // Override linker flavor if necessary. + if let Ok(host_linker_flavor) = env::var("RUSTC_HOST_LINKER_FLAVOR") { + cmd.arg(format!("-Clinker-flavor={}", host_linker_flavor)); + } + if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") { if s == "true" { cmd.arg("-C").arg("target-feature=+crt-static"); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d9c894aa9c6b1..008af975c33fb 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -694,7 +694,7 @@ impl<'a> Builder<'a> { cmd.env_remove("MAKEFLAGS"); cmd.env_remove("MFLAGS"); - if let Some(linker) = self.linker(compiler.host) { + if let Some(linker) = self.linker(compiler.host, true) { cmd.env("RUSTC_TARGET_LINKER", linker); } cmd @@ -949,10 +949,30 @@ impl<'a> Builder<'a> { } } - if let Some(host_linker) = self.linker(compiler.host) { + // FIXME: Don't use LLD if we're compiling libstd, since it fails to link it. + let can_use_lld = mode != Mode::Std; + + // FIXME: The beta compiler doesn't pick the `lld-link` flavor for `*-pc-windows-msvc` + // Remove `RUSTC_HOST_LINKER_FLAVOR` when this is fixed + let lld_linker_flavor = |linker: &Path, target: Interned| { + compiler.stage == 0 + && linker.file_name() == Some(OsStr::new("rust-lld")) + && target.contains("pc-windows-msvc") + }; + + if let Some(host_linker) = self.linker(compiler.host, can_use_lld) { + if lld_linker_flavor(host_linker, compiler.host) { + cargo.env("RUSTC_HOST_LINKER_FLAVOR", "lld-link"); + } + cargo.env("RUSTC_HOST_LINKER", host_linker); } - if let Some(target_linker) = self.linker(target) { + + if let Some(target_linker) = self.linker(target, can_use_lld) { + if lld_linker_flavor(target_linker, target) { + rustflags.arg("-Clinker-flavor=lld-link"); + } + let target = crate::envify(&target); cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 110c8b844d54c..8a01bee220835 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -83,6 +83,7 @@ pub struct Config { pub llvm_use_linker: Option, pub llvm_allow_old_toolchain: Option, + pub use_lld: bool, pub lld_enabled: bool, pub lldb_enabled: bool, pub llvm_tools_enabled: bool, @@ -322,6 +323,7 @@ struct Rust { save_toolstates: Option, codegen_backends: Option>, lld: Option, + use_lld: Option, llvm_tools: Option, lldb: Option, deny_warnings: Option, @@ -566,6 +568,7 @@ impl Config { if let Some(true) = rust.incremental { config.incremental = true; } + set(&mut config.use_lld, rust.use_lld); set(&mut config.lld_enabled, rust.lld); set(&mut config.lldb_enabled, rust.lldb); set(&mut config.llvm_tools_enabled, rust.llvm_tools); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1fee3fd9ac1d2..9755222410357 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -239,9 +239,10 @@ pub struct Build { hosts: Vec>, targets: Vec>, - // Stage 0 (downloaded) compiler and cargo or their local rust equivalents + // Stage 0 (downloaded) compiler, lld and cargo or their local rust equivalents initial_rustc: PathBuf, initial_cargo: PathBuf, + initial_lld: PathBuf, // Runtime state filled in later on // C/C++ compilers and archiver for all targets @@ -343,9 +344,18 @@ impl Build { // we always try to use git for LLVM builds let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project")); + let initial_sysroot = config.initial_rustc.parent().unwrap().parent().unwrap(); + let initial_lld = initial_sysroot + .join("lib") + .join("rustlib") + .join(config.build) + .join("bin") + .join("rust-lld"); + let mut build = Build { initial_rustc: config.initial_rustc.clone(), initial_cargo: config.initial_cargo.clone(), + initial_lld, local_rebuild: config.local_rebuild, fail_fast: config.cmd.fail_fast(), doc_tests: config.cmd.doc_tests(), @@ -810,7 +820,7 @@ impl Build { } /// Returns the path to the linker for the given target if it needs to be overridden. - fn linker(&self, target: Interned) -> Option<&Path> { + fn linker(&self, target: Interned, can_use_lld: bool) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref()) { Some(linker) @@ -819,6 +829,12 @@ impl Build { && !target.contains("msvc") { Some(self.cc(target)) + } else if can_use_lld + && self.config.use_lld + && target.contains("pc-windows-msvc") + && self.build == target + { + Some(&self.initial_lld) } else { None } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 6adf9ddaf3438..189f9e6ccab42 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -596,7 +596,7 @@ impl Step for RustdocTheme { .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTDOC_CRATE_VERSION", builder.rust_version()) .env("RUSTC_BOOTSTRAP", "1"); - if let Some(linker) = builder.linker(self.compiler.host) { + if let Some(linker) = builder.linker(self.compiler.host, true) { cmd.env("RUSTC_TARGET_LINKER", linker); } try_run(builder, &mut cmd); @@ -1035,7 +1035,7 @@ impl Step for Compiletest { flags.push("-Zunstable-options".to_string()); flags.push(builder.config.cmd.rustc_args().join(" ")); - if let Some(linker) = builder.linker(target) { + if let Some(linker) = builder.linker(target, false) { cmd.arg("--linker").arg(linker); } From 95318f8d859dc55cc5e06722c96f6e492529d6ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 29 Jan 2020 18:03:13 +0100 Subject: [PATCH 022/657] Link a linking issue --- src/bootstrap/builder.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 008af975c33fb..56d8944e0dd0b 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -949,7 +949,8 @@ impl<'a> Builder<'a> { } } - // FIXME: Don't use LLD if we're compiling libstd, since it fails to link it. + // FIXME: Don't use LLD if we're compiling libtest, since it fails to link it. + // See https://github.com/rust-lang/rust/issues/68647. let can_use_lld = mode != Mode::Std; // FIXME: The beta compiler doesn't pick the `lld-link` flavor for `*-pc-windows-msvc` From 2124a85260fdf0851bb4de369d311bcfc05b205f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 29 Jan 2020 18:05:26 +0100 Subject: [PATCH 023/657] Don't use a whitelist for use_lld --- src/bootstrap/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 9755222410357..5e4bedbeb28f2 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -829,11 +829,7 @@ impl Build { && !target.contains("msvc") { Some(self.cc(target)) - } else if can_use_lld - && self.config.use_lld - && target.contains("pc-windows-msvc") - && self.build == target - { + } else if can_use_lld && self.config.use_lld && self.build == target { Some(&self.initial_lld) } else { None From b60f08bd6d3fbe784eb47a57e0c41954454af3dd Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Mon, 23 Sep 2019 18:39:55 -0700 Subject: [PATCH 024/657] rustdoc: NodeId is now DefId --- src/librustdoc/html/render/cache.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index f1f83acdda59e..3acfb82fe7840 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -43,7 +43,7 @@ crate struct Cache { /// found on that implementation. pub impls: FxHashMap>, - /// Maintains a mapping of local crate `NodeId`s to the fully qualified name + /// Maintains a mapping of local crate `DefId`s to the fully qualified name /// and "short type description" of that node. This is used when generating /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information @@ -358,6 +358,7 @@ impl DocFolder for Cache { | clean::ForeignTypeItem | clean::MacroItem(..) | clean::ProcMacroItem(..) + | clean::VariantItem(..) if !self.stripped_mod => { // Re-exported items mean that the same id can show up twice @@ -373,13 +374,6 @@ impl DocFolder for Cache { } self.add_aliases(&item); } - // Link variants to their parent enum because pages aren't emitted - // for each variant. - clean::VariantItem(..) if !self.stripped_mod => { - let mut stack = self.stack.clone(); - stack.pop(); - self.paths.insert(item.def_id, (stack, ItemType::Enum)); - } clean::PrimitiveItem(..) => { self.add_aliases(&item); @@ -396,7 +390,8 @@ impl DocFolder for Cache { | clean::EnumItem(..) | clean::ForeignTypeItem | clean::StructItem(..) - | clean::UnionItem(..) => { + | clean::UnionItem(..) + | clean::VariantItem(..) => { self.parent_stack.push(item.def_id); self.parent_is_trait_impl = false; true @@ -564,7 +559,7 @@ fn extern_location( /// Builds the search index from the collected metadata fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { - let mut nodeid_to_pathid = FxHashMap::default(); + let mut defid_to_pathid = FxHashMap::default(); let mut crate_items = Vec::with_capacity(cache.search_index.len()); let mut crate_paths = vec![]; @@ -586,21 +581,21 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { } } - // Reduce `NodeId` in paths into smaller sequential numbers, + // Reduce `DefId` in paths into smaller sequential numbers, // and prune the paths that do not appear in the index. let mut lastpath = String::new(); let mut lastpathid = 0usize; for item in search_index { - item.parent_idx = item.parent.map(|nodeid| { - if nodeid_to_pathid.contains_key(&nodeid) { - *nodeid_to_pathid.get(&nodeid).expect("no pathid") + item.parent_idx = item.parent.map(|defid| { + if defid_to_pathid.contains_key(&defid) { + *defid_to_pathid.get(&defid).expect("no pathid") } else { let pathid = lastpathid; - nodeid_to_pathid.insert(nodeid, pathid); + defid_to_pathid.insert(defid, pathid); lastpathid += 1; - let &(ref fqp, short) = paths.get(&nodeid).unwrap(); + let &(ref fqp, short) = paths.get(&defid).unwrap(); crate_paths.push((short, fqp.last().unwrap().clone())); pathid } From 05c6f329e785c9b53a50217de0f21df906ae7ba0 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Mon, 23 Sep 2019 18:37:20 -0700 Subject: [PATCH 025/657] rustdoc: emit JS paths for struct-like variants On the backend, rustdoc now emits `paths` entries to a crate's search index for struct-like enum variants, and index items of type structfield which belong to such variants point to their variant parents in the `paths` table, rather than their enum grandparents. The path entry for a variant is the fully qualified module path plus the enum name. On the frontend, the search code recognizes structfields belonging to structlike variants in the `paths` table and re-constructs the URL to the field's anchor on the enum documentation page. closes #16017 --- src/librustdoc/html/static/main.js | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ec881d25dd2bf..069139ec69108 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1364,14 +1364,15 @@ function getSearchElement() { var href; var type = itemTypes[item.ty]; var name = item.name; + var path = item.path; if (type === "mod") { - displayPath = item.path + "::"; - href = rootPath + item.path.replace(/::/g, "/") + "/" + + displayPath = path + "::"; + href = rootPath + path.replace(/::/g, "/") + "/" + name + "/index.html"; } else if (type === "primitive" || type === "keyword") { displayPath = ""; - href = rootPath + item.path.replace(/::/g, "/") + + href = rootPath + path.replace(/::/g, "/") + "/" + type + "." + name + ".html"; } else if (type === "externcrate") { displayPath = ""; @@ -1380,14 +1381,27 @@ function getSearchElement() { var myparent = item.parent; var anchor = "#" + type + "." + name; var parentType = itemTypes[myparent.ty]; + var pageType = parentType; + var pageName = myparent.name; + if (parentType === "primitive") { displayPath = myparent.name + "::"; + } else if (type === "structfield" && parentType === "variant") { + // Structfields belonging to variants are special: the + // final path element is the enum name. + var splitPath = item.path.split("::"); + var enumName = splitPath.pop(); + path = splitPath.join("::"); + displayPath = path + "::" + enumName + "::" + myparent.name + "::"; + anchor = "#variant." + myparent.name + ".field." + name; + pageType = "enum"; + pageName = enumName; } else { - displayPath = item.path + "::" + myparent.name + "::"; + displayPath = path + "::" + myparent.name + "::"; } - href = rootPath + item.path.replace(/::/g, "/") + - "/" + parentType + - "." + myparent.name + + href = rootPath + path.replace(/::/g, "/") + + "/" + pageType + + "." + pageName + ".html" + anchor; } else { displayPath = item.path + "::"; @@ -1668,7 +1682,7 @@ function getSearchElement() { // (String) name] var paths = rawSearchIndex[crate].p; - // convert `paths` into an object form + // convert `rawPaths` entries into object form var len = paths.length; for (i = 0; i < len; ++i) { paths[i] = {ty: paths[i][0], name: paths[i][1]}; From 14999dd74b38ca79b80772f4f33425574faff89a Mon Sep 17 00:00:00 2001 From: Andreas Molzer Date: Wed, 29 Jan 2020 21:26:16 +0100 Subject: [PATCH 026/657] Add methods to leak RefCell borrows to references Usually, references to the interior are only created by the `Deref` and `DerefMut` impl of the guards `Ref` and `RefMut`. Note that `RefCell` already has to cope with leaks of such guards which, when it occurs, effectively makes it impossible to ever acquire a mutable guard or any guard for `Ref` and `RefMut` respectively. It is already safe to use this to create a reference to the inner of the ref cell that lives as long as the reference to the `RefCell` itself, e.g. ```rust fn leak(r: &RefCell) -> Option<&usize> { let guard = r.try_borrow().ok()?; let leaked = Box::leak(Box::new(guard)); Some(&*leaked) } ``` The newly added methods allow the same reference conversion without an indirection over a leaked allocation and composing with both borrow and try_borrow without additional method combinations. --- src/libcore/cell.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index e7eecf7540ad7..b1d799953e710 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1245,6 +1245,38 @@ impl<'b, T: ?Sized> Ref<'b, T> { let borrow = orig.borrow.clone(); (Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow }) } + + /// Convert into a reference to the underlying data. + /// + /// The underlying `RefCell` can never be mutably borrowed from again and will always appear + /// already immutably borrowed. It can still be immutably borrowed until more than `isize::MAX` + /// `Ref`s of this `RefCell` have been leaked, through this function or another leak, in total. + /// + /// This is an associated function that needs to be used as + /// `Ref::leak(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_leak)] + /// use std::cell::{RefCell, Ref}; + /// let cell = RefCell::new(0); + /// + /// let value = Ref::leak(cell.borrow()); + /// assert_eq!(*value, 0); + /// + /// assert!(cell.try_borrow().is_ok()); + /// assert!(cell.try_borrow_mut().is_err()); + /// ``` + #[unstable(feature = "cell_leak", issue = "none")] + pub fn leak(orig: Ref<'b, T>) -> &'b T { + // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never + // goes back to UNUSED again. No further references can be created from the original cell, + // making the current borrow the only reference for the remaining lifetime. + mem::forget(orig.borrow); + orig.value + } } #[unstable(feature = "coerce_unsized", issue = "27732")] @@ -1330,6 +1362,37 @@ impl<'b, T: ?Sized> RefMut<'b, T> { let borrow = orig.borrow.clone(); (RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow }) } + + /// Convert into a mutable reference to the underlying data. + /// + /// The underlying `RefCell` can not be borrowed from again and will always appear already + /// mutably borrowed, making the returned reference the only to the interior. + /// + /// This is an associated function that needs to be used as + /// `RefMut::leak(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_leak)] + /// use std::cell::{RefCell, RefMut}; + /// let cell = RefCell::new(0); + /// + /// let value = RefMut::leak(cell.borrow_mut()); + /// assert_eq!(*value, 0); + /// *value = 1; + /// + /// assert!(cell.try_borrow_mut().is_err()); + /// ``` + #[unstable(feature = "cell_leak", issue = "none")] + pub fn leak(orig: RefMut<'b, T>) -> &'b mut T { + // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never + // goes back to UNUSED again. No further references can be created from the original cell, + // making the current borrow the only reference for the remaining lifetime. + mem::forget(orig.borrow); + orig.value + } } struct BorrowRefMut<'b> { From 847d5b4d1387a30f1798a5c3c59c3e0c31e00319 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 2 Feb 2020 02:29:28 +0800 Subject: [PATCH 027/657] Derive Clone + PartialEq + Eq for std::string::FromUtf8Error --- src/liballoc/string.rs | 2 +- src/liballoc/tests/string.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 96f871d889708..8c9c95eec60c6 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -319,7 +319,7 @@ pub struct String { /// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct FromUtf8Error { bytes: Vec, error: Utf8Error, diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index dd44495845961..08859b2b24bde 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -50,7 +50,11 @@ fn test_from_utf8() { let xs = b"hello\xFF".to_vec(); let err = String::from_utf8(xs).unwrap_err(); + assert_eq!(err.as_bytes(), b"hello\xff"); + let err_clone = err.clone(); + assert_eq!(err, err_clone); assert_eq!(err.into_bytes(), b"hello\xff".to_vec()); + assert_eq!(err_clone.utf8_error().valid_up_to(), 5); } #[test] From fd2282388140ea0f370ee25c82f00be81c2f822c Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Sat, 1 Feb 2020 22:19:28 +0100 Subject: [PATCH 028/657] implement AsMut for String --- src/liballoc/string.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 96f871d889708..99725917b5d87 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2208,6 +2208,14 @@ impl AsRef for String { } } +#[stable(feature = "string_as_mut", since = "1.43.0")] +impl AsMut for String { + #[inline] + fn as_mut(&mut self) -> &mut str { + self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[u8]> for String { #[inline] From 8ee30dbc1b07ad7fc842ceee6d6729a1377f7a36 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Jan 2020 13:43:54 +0100 Subject: [PATCH 029/657] Add tests for struct variant field in search --- src/test/rustdoc-js/struct-like-variant.js | 7 +++++++ src/test/rustdoc-js/struct-like-variant.rs | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/test/rustdoc-js/struct-like-variant.js create mode 100644 src/test/rustdoc-js/struct-like-variant.rs diff --git a/src/test/rustdoc-js/struct-like-variant.js b/src/test/rustdoc-js/struct-like-variant.js new file mode 100644 index 0000000000000..f6deea51e7d4d --- /dev/null +++ b/src/test/rustdoc-js/struct-like-variant.js @@ -0,0 +1,7 @@ +const QUERY = 'name'; + +const EXPECTED = { + 'others': [ + { 'path': 'struct_like_variant::Enum::Bar', 'name': 'name', 'desc': 'This is a name.' }, + ], +}; diff --git a/src/test/rustdoc-js/struct-like-variant.rs b/src/test/rustdoc-js/struct-like-variant.rs new file mode 100644 index 0000000000000..2f52a319ab9ad --- /dev/null +++ b/src/test/rustdoc-js/struct-like-variant.rs @@ -0,0 +1,8 @@ +#![crate_name = "struct_like_variant"] + +pub enum Enum { + Bar { + /// This is a name. + name: String + } +} From 91cf0e741186a9fa3bf31b07a65dc89324c10296 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 30 Jan 2020 20:24:44 +0000 Subject: [PATCH 030/657] Don't requery the param_env of a union Union fields have the ParamEnv of the union. --- src/librustc_typeck/check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0a917a1853eb5..8d2cfd9a335d1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1545,11 +1545,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: DefId) -> bool { if let ty::Adt(def, substs) = item_type.kind { assert!(def.is_union()); let fields = &def.non_enum_variant().fields; + let param_env = tcx.param_env(item_def_id); for field in fields { let field_ty = field.ty(tcx, substs); // We are currently checking the type this field came from, so it must be local. let field_span = tcx.hir().span_if_local(field.did).unwrap(); - let param_env = tcx.param_env(field.did); if field_ty.needs_drop(tcx, param_env) { struct_span_err!( tcx.sess, From 570c1613c1225d5777af5603dcf526da9cf57e19 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 30 Jan 2020 20:25:39 +0000 Subject: [PATCH 031/657] Remove unnecessary features in rustc_ty --- src/librustc_ty/lib.rs | 2 -- src/librustc_ty/ty.rs | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_ty/lib.rs b/src/librustc_ty/lib.rs index e5ec98743e0ae..e970faef02f28 100644 --- a/src/librustc_ty/lib.rs +++ b/src/librustc_ty/lib.rs @@ -6,9 +6,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] -#![feature(in_band_lifetimes)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(slice_patterns))] #![recursion_limit = "256"] #[macro_use] diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 8f882be1a090e..a131b11b07ba3 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -9,7 +9,11 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_span::symbol::Symbol; use rustc_span::Span; -fn sized_constraint_for_ty(tcx: TyCtxt<'tcx>, adtdef: &ty::AdtDef, ty: Ty<'tcx>) -> Vec> { +fn sized_constraint_for_ty<'tcx>( + tcx: TyCtxt<'tcx>, + adtdef: &ty::AdtDef, + ty: Ty<'tcx>, +) -> Vec> { use ty::TyKind::*; let result = match ty.kind { From 39733223fc817efba52a4204dd697192bf5da185 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 30 Jan 2020 20:26:36 +0000 Subject: [PATCH 032/657] Add IS_MANUALLY_DROP to AdtFlags --- src/librustc/ty/mod.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f417b907a3811..2b272d7fe08af 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1792,19 +1792,22 @@ bitflags! { const IS_STRUCT = 1 << 2; /// Indicates whether the ADT is a struct and has a constructor. const HAS_CTOR = 1 << 3; - /// Indicates whether the type is a `PhantomData`. + /// Indicates whether the type is `PhantomData`. const IS_PHANTOM_DATA = 1 << 4; /// Indicates whether the type has a `#[fundamental]` attribute. const IS_FUNDAMENTAL = 1 << 5; - /// Indicates whether the type is a `Box`. + /// Indicates whether the type is `Box`. const IS_BOX = 1 << 6; + /// Indicates whether the type is `ManuallyDrop`. + const IS_MANUALLY_DROP = 1 << 7; + // FIXME(matthewjasper) replace these with diagnostic items /// Indicates whether the type is an `Arc`. - const IS_ARC = 1 << 7; + const IS_ARC = 1 << 8; /// Indicates whether the type is an `Rc`. - const IS_RC = 1 << 8; + const IS_RC = 1 << 9; /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. /// (i.e., this flag is never set unless this ADT is an enum). - const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 9; + const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 10; } } @@ -2180,6 +2183,9 @@ impl<'tcx> AdtDef { if Some(did) == tcx.lang_items().owned_box() { flags |= AdtFlags::IS_BOX; } + if Some(did) == tcx.lang_items().manually_drop() { + flags |= AdtFlags::IS_MANUALLY_DROP; + } if Some(did) == tcx.lang_items().arc() { flags |= AdtFlags::IS_ARC; } @@ -2280,6 +2286,12 @@ impl<'tcx> AdtDef { self.flags.contains(AdtFlags::IS_BOX) } + /// Returns `true` if this is ManuallyDrop. + #[inline] + pub fn is_manually_drop(&self) -> bool { + self.flags.contains(AdtFlags::IS_MANUALLY_DROP) + } + /// Returns `true` if this type has a destructor. pub fn has_dtor(&self, tcx: TyCtxt<'tcx>) -> bool { self.destructor(tcx).is_some() From d1965216a34dc2831cf44d2e15ad9d78403d10cc Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 30 Jan 2020 20:28:16 +0000 Subject: [PATCH 033/657] Improve needs_drop query * Handle cycles in `needs_drop` correctly * Normalize types when computing `needs_drop` * Move queries from rustc to rustc_ty --- src/librustc/query/mod.rs | 17 +- src/librustc/traits/misc.rs | 132 -------------- src/librustc/traits/mod.rs | 1 - src/librustc/ty/query/mod.rs | 2 +- src/librustc/ty/query/values.rs | 7 - src/librustc/ty/util.rs | 81 ++++++++- src/librustc_ty/common_traits.rs | 40 ++++ src/librustc_ty/lib.rs | 4 + src/librustc_ty/needs_drop.rs | 171 ++++++++++++++++++ .../ui/type-alias-impl-trait/issue-65918.rs | 2 + 10 files changed, 304 insertions(+), 153 deletions(-) create mode 100644 src/librustc_ty/common_traits.rs create mode 100644 src/librustc_ty/needs_drop.rs diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 37d5e23535b81..c705956f4540a 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -651,26 +651,27 @@ rustc_queries! { no_force desc { "computing whether `{}` is `Copy`", env.value } } + /// Query backing `TyS::is_sized`. query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { no_force desc { "computing whether `{}` is `Sized`", env.value } } + /// Query backing `TyS::is_freeze`. query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { no_force desc { "computing whether `{}` is freeze", env.value } } - - // The cycle error here should be reported as an error by `check_representable`. - // We consider the type as not needing drop in the meanwhile to avoid - // further errors (done in impl Value for NeedsDrop). - // Use `cycle_delay_bug` to delay the cycle error here to be emitted later - // in case we accidentally otherwise don't emit an error. - query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop { - cycle_delay_bug + /// Query backing `TyS::needs_drop`. + query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { no_force desc { "computing whether `{}` needs drop", env.value } } + /// A list of types where the ADT requires drop if and only if any of + /// those types require drop. If the ADT is known to always need drop + /// then `Err(AlwaysRequiresDrop)` is returned. + query adt_drop_tys(_: DefId) -> Result<&'tcx ty::List>, AlwaysRequiresDrop> {} + query layout_raw( env: ty::ParamEnvAnd<'tcx, Ty<'tcx>> ) -> Result<&'tcx ty::layout::LayoutDetails, ty::layout::LayoutError<'tcx>> { diff --git a/src/librustc/traits/misc.rs b/src/librustc/traits/misc.rs index 08c3a77bf3aca..3fd0d12c626aa 100644 --- a/src/librustc/traits/misc.rs +++ b/src/librustc/traits/misc.rs @@ -1,12 +1,9 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. -use crate::middle::lang_items; use crate::traits::{self, ObligationCause}; -use crate::ty::util::NeedsDrop; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as hir; -use rustc_span::DUMMY_SP; #[derive(Clone)] pub enum CopyImplementationError<'tcx> { @@ -71,132 +68,3 @@ pub fn can_type_implement_copy( Ok(()) }) } - -fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::CopyTraitLangItem) -} - -fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::SizedTraitLangItem) -} - -fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::FreezeTraitLangItem) -} - -fn is_item_raw<'tcx>( - tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - item: lang_items::LangItem, -) -> bool { - let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(item, None); - tcx.infer_ctxt().enter(|infcx| { - traits::type_known_to_meet_bound_modulo_regions( - &infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP, - ) - }) -} - -fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop { - let (param_env, ty) = query.into_parts(); - - let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 }; - - assert!(!ty.needs_infer()); - - NeedsDrop(match ty.kind { - // Fast-path for primitive types - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Never - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Char - | ty::GeneratorWitness(..) - | ty::RawPtr(_) - | ty::Ref(..) - | ty::Str => false, - - // Foreign types can never have destructors - ty::Foreign(..) => false, - - // `ManuallyDrop` doesn't have a destructor regardless of field types. - ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false, - - // Issue #22536: We first query `is_copy_modulo_regions`. It sees a - // normalized version of the type, and therefore will definitely - // know whether the type implements Copy (and thus needs no - // cleanup/drop/zeroing) ... - _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false, - - // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking for the structural "may drop". - - // FIXME(#22815): Note that this is a conservative heuristic; - // it may report that the type "may drop" when actual type does - // not actually have a destructor associated with it. But since - // the type absolutely did not have the `Copy` bound attached - // (see above), it is sound to treat it as having a destructor. - - // User destructors are the only way to have concrete drop types. - ty::Adt(def, _) if def.has_dtor(tcx) => true, - - // Can refer to a type which may drop. - // FIXME(eddyb) check this against a ParamEnv. - ty::Dynamic(..) - | ty::Projection(..) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Opaque(..) - | ty::Infer(_) - | ty::Error => true, - - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - - // Zero-length arrays never contain anything to drop. - ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false, - - // Structural recursion. - ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty), - - ty::Closure(def_id, ref substs) => { - substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop) - } - - // Pessimistically assume that all generators will require destructors - // as we don't know if a destructor is a noop or not until after the MIR - // state transformation pass - ty::Generator(..) => true, - - ty::Tuple(..) => ty.tuple_fields().any(needs_drop), - - // unions don't have destructors because of the child types, - // only if they manually implement `Drop` (handled above). - ty::Adt(def, _) if def.is_union() => false, - - ty::Adt(def, substs) => def - .variants - .iter() - .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))), - }) -} - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { - is_copy_raw, - is_sized_raw, - is_freeze_raw, - needs_drop_raw, - ..*providers - }; -} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index daaba95cf6b13..f6c939c1ce5a2 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -1255,7 +1255,6 @@ impl<'tcx> TraitObligation<'tcx> { } pub fn provide(providers: &mut ty::query::Providers<'_>) { - misc::provide(providers); *providers = ty::query::Providers { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 973cd81014616..4126b161a821b 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -33,7 +33,7 @@ use crate::traits::Clauses; use crate::traits::{self, Vtable}; use crate::ty::steal::Steal; use crate::ty::subst::SubstsRef; -use crate::ty::util::NeedsDrop; +use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use crate::util::common::ErrorReported; use rustc_data_structures::fingerprint::Fingerprint; diff --git a/src/librustc/ty/query/values.rs b/src/librustc/ty/query/values.rs index 900a91fe5cf59..b01d15c29b2db 100644 --- a/src/librustc/ty/query/values.rs +++ b/src/librustc/ty/query/values.rs @@ -1,4 +1,3 @@ -use crate::ty::util::NeedsDrop; use crate::ty::{self, AdtSizedConstraint, Ty, TyCtxt}; use rustc_span::symbol::Symbol; @@ -26,12 +25,6 @@ impl<'tcx> Value<'tcx> for ty::SymbolName { } } -impl<'tcx> Value<'tcx> for NeedsDrop { - fn from_cycle_error(_: TyCtxt<'tcx>) -> Self { - NeedsDrop(false) - } -} - impl<'tcx> Value<'tcx> for AdtSizedConstraint<'tcx> { fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 4dfff85d53147..eaa7a43b09174 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -18,6 +18,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_span::Span; +use smallvec::SmallVec; use std::{cmp, fmt}; use syntax::ast; @@ -724,7 +725,23 @@ impl<'tcx> ty::TyS<'tcx> { /// Note that this method is used to check eligible types in unions. #[inline] pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - tcx.needs_drop_raw(param_env.and(self)).0 + // Avoid querying in simple cases. + match needs_drop_components(self) { + Err(AlwaysRequiresDrop) => true, + Ok(components) => { + let query_ty = match *components { + [] => return false, + // If we've got a single component, call the query with that + // to increase the chance that we hit the query cache. + [component_ty] => component_ty, + _ => self, + }; + // This doesn't depend on regions, so try to minimize distinct. + // query keys used. + let erased = tcx.normalize_erasing_regions(param_env, query_ty); + tcx.needs_drop_raw(param_env.and(erased)) + } + } } pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { @@ -923,9 +940,6 @@ impl<'tcx> ty::TyS<'tcx> { } } -#[derive(Clone, HashStable)] -pub struct NeedsDrop(pub bool); - pub enum ExplicitSelf<'tcx> { ByValue, ByReference(ty::Region<'tcx>, hir::Mutability), @@ -974,3 +988,62 @@ impl<'tcx> ExplicitSelf<'tcx> { } } } + +/// Returns a list of types such that the given type needs drop if and only if +/// *any* of the returned types need drop. Returns `Err(AlwaysRequiresDrop)` if +/// this type always needs drop. +pub fn needs_drop_components(ty: Ty<'tcx>) -> Result; 4]>, AlwaysRequiresDrop> { + match ty.kind { + ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) + | ty::Bool + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Never + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Char + | ty::GeneratorWitness(..) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::Str => Ok(SmallVec::new()), + + // Foreign types can never have destructors + ty::Foreign(..) => Ok(SmallVec::new()), + + // Pessimistically assume that all generators will require destructors + // as we don't know if a destructor is a noop or not until after the MIR + // state transformation pass + ty::Generator(..) | ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop), + + ty::Slice(ty) => needs_drop_components(ty), + ty::Array(elem_ty, ..) => { + match needs_drop_components(elem_ty) { + Ok(v) if v.is_empty() => Ok(v), + // Arrays of size zero don't need drop, even if their element + // type does. + _ => Ok(smallvec![ty]), + } + } + // If any field needs drop, then the whole tuple does. + ty::Tuple(..) => ty.tuple_fields().try_fold(SmallVec::new(), |mut acc, elem| { + acc.extend(needs_drop_components(elem)?); + Ok(acc) + }), + + // These require checking for `Copy` bounds or `Adt` destructors. + ty::Adt(..) + | ty::Projection(..) + | ty::UnnormalizedProjection(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Opaque(..) + | ty::Infer(_) + | ty::Closure(..) => Ok(smallvec![ty]), + } +} + +#[derive(Copy, Clone, Debug, HashStable)] +pub struct AlwaysRequiresDrop; diff --git a/src/librustc_ty/common_traits.rs b/src/librustc_ty/common_traits.rs new file mode 100644 index 0000000000000..9fe8a19311fb6 --- /dev/null +++ b/src/librustc_ty/common_traits.rs @@ -0,0 +1,40 @@ +//! Queries for checking whether a type implements one of a few common traits. + +use rustc::middle::lang_items; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc_span::DUMMY_SP; + +fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, lang_items::CopyTraitLangItem) +} + +fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, lang_items::SizedTraitLangItem) +} + +fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, lang_items::FreezeTraitLangItem) +} + +fn is_item_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + item: lang_items::LangItem, +) -> bool { + let (param_env, ty) = query.into_parts(); + let trait_def_id = tcx.require_lang_item(item, None); + tcx.infer_ctxt().enter(|infcx| { + traits::type_known_to_meet_bound_modulo_regions( + &infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP, + ) + }) +} + +pub(crate) fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { is_copy_raw, is_sized_raw, is_freeze_raw, ..*providers }; +} diff --git a/src/librustc_ty/lib.rs b/src/librustc_ty/lib.rs index e970faef02f28..7eef19b94e401 100644 --- a/src/librustc_ty/lib.rs +++ b/src/librustc_ty/lib.rs @@ -16,8 +16,12 @@ extern crate log; use rustc::ty::query::Providers; +mod common_traits; +mod needs_drop; mod ty; pub fn provide(providers: &mut Providers<'_>) { + common_traits::provide(providers); + needs_drop::provide(providers); ty::provide(providers); } diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs new file mode 100644 index 0000000000000..1a65acb1f984b --- /dev/null +++ b/src/librustc_ty/needs_drop.rs @@ -0,0 +1,171 @@ +//! Check whether a type has (potentially) non-trivial drop glue. + +use rustc::ty::subst::Subst; +use rustc::ty::util::{needs_drop_components, AlwaysRequiresDrop}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def_id::DefId; +use rustc_span::DUMMY_SP; + +type NeedsDropResult = Result; + +fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + let adt_fields = + move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter().copied()); + // If we don't know a type doesn't need drop, say it's a type parameter + // without a `Copy` bound, then we conservatively return that it needs + // drop. + let res = NeedsDropTypes::new(tcx, query.param_env, query.value, adt_fields).next().is_some(); + debug!("needs_drop_raw({:?}) = {:?}", query, res); + res +} + +struct NeedsDropTypes<'tcx, F> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + query_ty: Ty<'tcx>, + seen_tys: FxHashSet>, + /// A stack of types left to process. Each round, we pop something from the + /// stack and check if it needs drop. If the result depends on whether some + /// other types need drop we push them onto the stack. + unchecked_tys: Vec<(Ty<'tcx>, usize)>, + recursion_limit: usize, + adt_components: F, +} + +impl<'tcx, F> NeedsDropTypes<'tcx, F> { + fn new( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + adt_components: F, + ) -> Self { + let mut seen_tys = FxHashSet::default(); + seen_tys.insert(ty); + let recursion_limit = *tcx.sess.recursion_limit.get(); + Self { + tcx, + param_env, + seen_tys, + query_ty: ty, + unchecked_tys: vec![(ty, 0)], + recursion_limit, + adt_components, + } + } +} + +impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> +where + F: Fn(&ty::AdtDef) -> NeedsDropResult, + I: Iterator>, +{ + type Item = NeedsDropResult>; + + fn next(&mut self) -> Option>> { + let tcx = self.tcx; + + while let Some((ty, level)) = self.unchecked_tys.pop() { + if level > self.recursion_limit { + // Not having a `Span` isn't great. But there's hopefully some other + // recursion limit error as well. + tcx.sess.span_err( + DUMMY_SP, + &format!("overflow while checking whether `{}` requires drop", self.query_ty), + ); + return Some(Err(AlwaysRequiresDrop)); + } + + let components = match needs_drop_components(ty) { + Err(e) => return Some(Err(e)), + Ok(components) => components, + }; + debug!("needs_drop_components({:?}) = {:?}", ty, components); + + for component in components { + match component.kind { + _ if component.is_copy_modulo_regions(tcx, self.param_env, DUMMY_SP) => (), + + ty::Array(elem_ty, len) => { + // Zero-length arrays never contain anything to drop. + if len.try_eval_usize(tcx, self.param_env) != Some(0) { + if self.seen_tys.insert(elem_ty) { + self.unchecked_tys.push((elem_ty, level + 1)); + } + } + } + + ty::Closure(def_id, substs) => { + for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) { + if self.seen_tys.insert(upvar_ty) { + self.unchecked_tys.push((upvar_ty, level + 1)); + } + } + } + + // Check for a `Drop` impl and whether this is a union or + // `ManuallyDrop`. If it's a struct or enum without a `Drop` + // impl then check whether the field types need `Drop`. + ty::Adt(adt_def, substs) => { + let tys = match (self.adt_components)(adt_def) { + Err(e) => return Some(Err(e)), + Ok(tys) => tys, + }; + for required_ty in tys { + let subst_ty = tcx.normalize_erasing_regions( + self.param_env, + required_ty.subst(tcx, substs), + ); + if self.seen_tys.insert(subst_ty) { + self.unchecked_tys.push((subst_ty, level + 1)); + } + } + } + ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => { + if ty == component { + // Return the type to the caller so they can decide + // what to do with it. + return Some(Ok(component)); + } else if self.seen_tys.insert(component) { + // Store the type for later. We can't return here + // because we would then lose any other components + // of the type. + self.unchecked_tys.push((component, level + 1)); + } + } + _ => return Some(Err(AlwaysRequiresDrop)), + } + } + } + + return None; + } +} + +fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List>, AlwaysRequiresDrop> { + let adt_components = move |adt_def: &ty::AdtDef| { + if adt_def.is_manually_drop() { + debug!("adt_drop_tys: `{:?}` is manually drop", adt_def); + return Ok(Vec::new().into_iter()); + } else if adt_def.destructor(tcx).is_some() { + debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); + return Err(AlwaysRequiresDrop); + } else if adt_def.is_union() { + debug!("adt_drop_tys: `{:?}` is a union", adt_def); + return Ok(Vec::new().into_iter()); + } + Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::>().into_iter()) + }; + + let adt_ty = tcx.type_of(def_id); + let param_env = tcx.param_env(def_id); + let res: Result, _> = + NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect(); + + debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res); + res.map(|components| tcx.intern_type_list(&components)) +} + +pub(crate) fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { needs_drop_raw, adt_drop_tys, ..*providers }; +} diff --git a/src/test/ui/type-alias-impl-trait/issue-65918.rs b/src/test/ui/type-alias-impl-trait/issue-65918.rs index 97efb85ef64c7..4ba778d53ac08 100644 --- a/src/test/ui/type-alias-impl-trait/issue-65918.rs +++ b/src/test/ui/type-alias-impl-trait/issue-65918.rs @@ -1,3 +1,5 @@ +// ignore-test: This now ICEs again. + // build-pass #![feature(type_alias_impl_trait)] From d20646b2d8033f31423b5bda3e56776df115e144 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 31 Jan 2020 22:22:30 +0000 Subject: [PATCH 034/657] Address review comments * Handle arrays with const-generic lengths * Use closure for repeated code. --- src/librustc/ty/util.rs | 33 ++++++++++++++++++++++----------- src/librustc_ty/needs_drop.rs | 35 ++++++++++++++--------------------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index eaa7a43b09174..6191d304719cb 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -18,6 +18,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_span::Span; +use rustc_target::abi::TargetDataLayout; use smallvec::SmallVec; use std::{cmp, fmt}; use syntax::ast; @@ -726,7 +727,7 @@ impl<'tcx> ty::TyS<'tcx> { #[inline] pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { // Avoid querying in simple cases. - match needs_drop_components(self) { + match needs_drop_components(self, &tcx.data_layout) { Err(AlwaysRequiresDrop) => true, Ok(components) => { let query_ty = match *components { @@ -736,7 +737,7 @@ impl<'tcx> ty::TyS<'tcx> { [component_ty] => component_ty, _ => self, }; - // This doesn't depend on regions, so try to minimize distinct. + // This doesn't depend on regions, so try to minimize distinct // query keys used. let erased = tcx.normalize_erasing_regions(param_env, query_ty); tcx.needs_drop_raw(param_env.and(erased)) @@ -992,7 +993,10 @@ impl<'tcx> ExplicitSelf<'tcx> { /// Returns a list of types such that the given type needs drop if and only if /// *any* of the returned types need drop. Returns `Err(AlwaysRequiresDrop)` if /// this type always needs drop. -pub fn needs_drop_components(ty: Ty<'tcx>) -> Result; 4]>, AlwaysRequiresDrop> { +pub fn needs_drop_components( + ty: Ty<'tcx>, + target_layout: &TargetDataLayout, +) -> Result; 2]>, AlwaysRequiresDrop> { match ty.kind { ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) @@ -1017,18 +1021,25 @@ pub fn needs_drop_components(ty: Ty<'tcx>) -> Result; 4]>, Al // state transformation pass ty::Generator(..) | ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop), - ty::Slice(ty) => needs_drop_components(ty), - ty::Array(elem_ty, ..) => { - match needs_drop_components(elem_ty) { + ty::Slice(ty) => needs_drop_components(ty, target_layout), + ty::Array(elem_ty, size) => { + match needs_drop_components(elem_ty, target_layout) { Ok(v) if v.is_empty() => Ok(v), - // Arrays of size zero don't need drop, even if their element - // type does. - _ => Ok(smallvec![ty]), + res => match size.val.try_to_bits(target_layout.pointer_size) { + // Arrays of size zero don't need drop, even if their element + // type does. + Some(0) => Ok(SmallVec::new()), + Some(_) => res, + // We don't know which of the cases above we are in, so + // return the whole type and let the caller decide what to + // do. + None => Ok(smallvec![ty]), + }, } } // If any field needs drop, then the whole tuple does. - ty::Tuple(..) => ty.tuple_fields().try_fold(SmallVec::new(), |mut acc, elem| { - acc.extend(needs_drop_components(elem)?); + ty::Tuple(..) => ty.tuple_fields().try_fold(SmallVec::new(), move |mut acc, elem| { + acc.extend(needs_drop_components(elem, target_layout)?); Ok(acc) }), diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs index 1a65acb1f984b..c01b3e384aec5 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/src/librustc_ty/needs_drop.rs @@ -76,30 +76,25 @@ where return Some(Err(AlwaysRequiresDrop)); } - let components = match needs_drop_components(ty) { + let components = match needs_drop_components(ty, &tcx.data_layout) { Err(e) => return Some(Err(e)), Ok(components) => components, }; debug!("needs_drop_components({:?}) = {:?}", ty, components); + let queue_type = move |this: &mut Self, component: Ty<'tcx>| { + if this.seen_tys.insert(component) { + this.unchecked_tys.push((component, level + 1)); + } + }; + for component in components { match component.kind { _ if component.is_copy_modulo_regions(tcx, self.param_env, DUMMY_SP) => (), - ty::Array(elem_ty, len) => { - // Zero-length arrays never contain anything to drop. - if len.try_eval_usize(tcx, self.param_env) != Some(0) { - if self.seen_tys.insert(elem_ty) { - self.unchecked_tys.push((elem_ty, level + 1)); - } - } - } - ty::Closure(def_id, substs) => { for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) { - if self.seen_tys.insert(upvar_ty) { - self.unchecked_tys.push((upvar_ty, level + 1)); - } + queue_type(self, upvar_ty); } } @@ -116,21 +111,19 @@ where self.param_env, required_ty.subst(tcx, substs), ); - if self.seen_tys.insert(subst_ty) { - self.unchecked_tys.push((subst_ty, level + 1)); - } + queue_type(self, subst_ty); } } - ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => { + ty::Array(..) | ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => { if ty == component { - // Return the type to the caller so they can decide - // what to do with it. + // Return the type to the caller: they may be able + // to normalize further than we can. return Some(Ok(component)); - } else if self.seen_tys.insert(component) { + } else { // Store the type for later. We can't return here // because we would then lose any other components // of the type. - self.unchecked_tys.push((component, level + 1)); + queue_type(self, component); } } _ => return Some(Err(AlwaysRequiresDrop)), From 465b86253ce828e215d564fde53adf8742f0e3f6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 1 Feb 2020 11:41:58 +0000 Subject: [PATCH 035/657] Use correct `ParamEnv` in `Instance::resolve` --- src/librustc/ty/instance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 51a18f8eae274..f73e069df36c7 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -285,7 +285,7 @@ impl<'tcx> Instance<'tcx> { _ => { if Some(def_id) == tcx.lang_items().drop_in_place_fn() { let ty = substs.type_at(0); - if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) { + if ty.needs_drop(tcx, param_env.with_reveal_all()) { debug!(" => nontrivial drop glue"); ty::InstanceDef::DropGlue(def_id, Some(ty)) } else { From 109d5c189f4b5c3405a7d6cfb312e04d866c0c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 3 Feb 2020 16:08:45 -0800 Subject: [PATCH 036/657] Tweak borrow error on `FnMut` when `Fn` is expected --- .../diagnostics/mutability_errors.rs | 102 +++++++++++++- .../borrow-immutable-upvar-mutation.rs | 21 ++- .../borrow-immutable-upvar-mutation.stderr | 123 ++++++++++------- .../borrow-raw-address-of-mutability.stderr | 32 ++--- src/test/ui/borrowck/mutability-errors.stderr | 128 +++++++++--------- src/test/ui/fn/fn-closure-mutable-capture.rs | 4 +- .../ui/fn/fn-closure-mutable-capture.stderr | 13 +- src/test/ui/issues/issue-21600.stderr | 33 +++-- src/test/ui/nll/closure-captures.stderr | 120 ++++++++-------- .../unboxed-closures-mutate-upvar.stderr | 16 +-- ...sures-mutated-upvar-from-fn-closure.stderr | 16 +-- 11 files changed, 370 insertions(+), 238 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index 563ff1112c3a6..4fc31b3a41262 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -10,7 +10,7 @@ use rustc_span::Span; use crate::borrow_check::diagnostics::BorrowedContentSource; use crate::borrow_check::MirBorrowckCtxt; use crate::util::collect_writes::FindAssignments; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, DiagnosticBuilder}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { @@ -412,11 +412,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { projection: [ProjectionElem::Deref], // FIXME document what is this 1 magic number about } if local == Local::new(1) && !self.upvars.is_empty() => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); - err.span_help( - self.body.span, - "consider changing this to accept closures that implement `FnMut`", - ); + self.expected_fn_found_fn_mut_call(&mut err, span, act); } PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => { @@ -448,6 +444,100 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.buffer(&mut self.errors_buffer); } + + /// Targetted error when encountering an `FnMut` closure where an `Fn` closure was expected. + fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) { + err.span_label(sp, format!("cannot {ACT}", ACT = act)); + + let hir = self.infcx.tcx.hir(); + let closure_id = hir.as_local_hir_id(self.mir_def_id).unwrap(); + let fn_call_id = hir.get_parent_node(closure_id); + let node = hir.get(fn_call_id); + let item_id = hir.get_parent_item(fn_call_id); + let mut look_at_return = true; + // If we can detect the expression to be an `fn` call where the closure was an argument, + // we point at the `fn` definition argument... + match node { + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Call(func, args), .. }) => { + let arg_pos = args + .iter() + .enumerate() + .filter(|(_, arg)| arg.span == self.body.span) + .map(|(pos, _)| pos) + .next(); + let def_id = hir.local_def_id(item_id); + let tables = self.infcx.tcx.typeck_tables_of(def_id); + if let Some(ty::FnDef(def_id, _)) = + tables.node_type_opt(func.hir_id).as_ref().map(|ty| &ty.kind) + { + let arg = match hir.get_if_local(*def_id) { + Some(hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::Fn(sig, ..), + .. + })) + | Some(hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Method(sig, _), + .. + })) + | Some(hir::Node::ImplItem(hir::ImplItem { + ident, + kind: hir::ImplItemKind::Method(sig, _), + .. + })) => Some( + arg_pos + .and_then(|pos| { + sig.decl.inputs.get( + pos + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ) + }) + .map(|arg| arg.span) + .unwrap_or(ident.span), + ), + _ => None, + }; + if let Some(span) = arg { + err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); + err.span_label(func.span, "expects `Fn` instead of `FnMut`"); + if self.infcx.tcx.sess.source_map().is_multiline(self.body.span) { + err.span_label(self.body.span, "in this closure"); + } + look_at_return = false; + } + } + } + _ => {} + } + if look_at_return && hir.get_return_block(closure_id).is_some() { + // ...otherwise we are probably in the tail expression of the function, point at the + // return type. + match hir.get(hir.get_parent_item(fn_call_id)) { + hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) + | hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Method(sig, _), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + ident, + kind: hir::ImplItemKind::Method(sig, _), + .. + }) => { + err.span_label(ident.span, "you might have to change this..."); + err.span_label(sig.decl.output.span(), "...to return `FnMut` instead of `Fn`"); + err.span_label(self.body.span, "in this closure"); + } + parent => { + err.note(&format!("parent {:?}", parent)); + } + } + } + } } fn suggest_ampmut_self<'tcx>( diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs index fed8bc95b6b86..62e27bcf1643f 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs @@ -18,7 +18,10 @@ fn main() { let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow let mut z = 0; - let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign + let _h = to_fn_mut(|| { + set(&mut z); + to_fn(|| z = 42); //~ ERROR cannot assign + }); } // By-value captures @@ -33,3 +36,19 @@ fn main() { let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign } } + +fn foo() -> Box usize> { + let mut x = 0; + Box::new(move || { + x += 1; //~ ERROR cannot assign + x + }) +} + +fn bar() -> impl Fn() -> usize { + let mut x = 0; + move || { + x += 1; //~ ERROR cannot assign + x + } +} diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr index 097e4c75065c9..a97d694685d76 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr @@ -1,76 +1,101 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/borrow-immutable-upvar-mutation.rs:15:27 | +LL | fn to_fn>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | let _f = to_fn(|| x = 42); - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:15:24 - | -LL | let _f = to_fn(|| x = 42); - | ^^^^^^^^^ + | ----- ^^^^^^ cannot assign + | | + | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/borrow-immutable-upvar-mutation.rs:18:31 | +LL | fn to_fn>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | let _g = to_fn(|| set(&mut y)); - | ^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:18:24 - | -LL | let _g = to_fn(|| set(&mut y)); - | ^^^^^^^^^^^^^^ + | ----- ^^^^^^ cannot borrow as mutable + | | + | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:21:55 - | -LL | let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:21:52 - | -LL | let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); - | ^^^^^^^^^ + --> $DIR/borrow-immutable-upvar-mutation.rs:23:22 + | +LL | fn to_fn>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | to_fn(|| z = 42); + | ----- ^^^^^^ cannot assign + | | + | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:27:32 - | -LL | let _f = to_fn(move || x = 42); - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:27:24 + --> $DIR/borrow-immutable-upvar-mutation.rs:30:32 | +LL | fn to_fn>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | let _f = to_fn(move || x = 42); - | ^^^^^^^^^^^^^^ + | ----- ^^^^^^ cannot assign + | | + | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:30:36 - | -LL | let _g = to_fn(move || set(&mut y)); - | ^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:30:24 + --> $DIR/borrow-immutable-upvar-mutation.rs:33:36 | +LL | fn to_fn>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | let _g = to_fn(move || set(&mut y)); - | ^^^^^^^^^^^^^^^^^^^ + | ----- ^^^^^^ cannot borrow as mutable + | | + | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:33:65 + --> $DIR/borrow-immutable-upvar-mutation.rs:36:65 | +LL | fn to_fn>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:33:57 - | -LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); - | ^^^^^^^^^^^^^^ + | ----- ^^^^^^ cannot assign + | | + | expects `Fn` instead of `FnMut` + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:43:9 + | +LL | fn foo() -> Box usize> { + | --- ---------------------- ...to return `FnMut` instead of `Fn` + | | + | you might have to change this... +LL | let mut x = 0; +LL | Box::new(move || { + | ______________- +LL | | x += 1; + | | ^^^^^^ cannot assign +LL | | x +LL | | }) + | |_____- in this closure + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:51:9 + | +LL | fn bar() -> impl Fn() -> usize { + | --- ------------------ ...to return `FnMut` instead of `Fn` + | | + | you might have to change this... +LL | let mut x = 0; +LL | / move || { +LL | | x += 1; + | | ^^^^^^ cannot assign +LL | | x +LL | | } + | |_____- in this closure -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors Some errors have detailed explanations: E0594, E0596. For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr index cf01c362d50bc..44dde0fd80b0d 100644 --- a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr +++ b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr @@ -27,32 +27,32 @@ LL | f(); error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/borrow-raw-address-of-mutability.rs:29:17 | -LL | let y = &raw mut x; - | ^^^^^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-raw-address-of-mutability.rs:28:21 - | +LL | fn make_fn(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | let f = make_fn(|| { - | _____________________^ + | _____________-------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | let y = &raw mut x; + | | ^^^^^^^^^^ cannot borrow as mutable LL | | }); - | |_____^ + | |_____- in this closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/borrow-raw-address-of-mutability.rs:37:17 | -LL | let y = &raw mut x; - | ^^^^^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-raw-address-of-mutability.rs:36:21 - | +LL | fn make_fn(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | let f = make_fn(move || { - | _____________________^ + | _____________-------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | let y = &raw mut x; + | | ^^^^^^^^^^ cannot borrow as mutable LL | | }); - | |_____^ + | |_____- in this closure error: aborting due to 5 previous errors diff --git a/src/test/ui/borrowck/mutability-errors.stderr b/src/test/ui/borrowck/mutability-errors.stderr index 72547a40352c9..5361ebe3916d7 100644 --- a/src/test/ui/borrowck/mutability-errors.stderr +++ b/src/test/ui/borrowck/mutability-errors.stderr @@ -119,146 +119,146 @@ LL | &mut (*f()).0; error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:40:9 | -LL | x = (1,); - | ^^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:39:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(|| { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | x = (1,); + | | ^^^^^^^^ cannot assign LL | | x.0 = 1; LL | | &mut x; LL | | &mut x.0; LL | | }); - | |_____^ + | |_____- in this closure error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:41:9 | -LL | x.0 = 1; - | ^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:39:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(|| { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | x = (1,); LL | | x.0 = 1; + | | ^^^^^^^ cannot assign LL | | &mut x; LL | | &mut x.0; LL | | }); - | |_____^ + | |_____- in this closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:42:9 | -LL | &mut x; - | ^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:39:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(|| { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | x = (1,); LL | | x.0 = 1; LL | | &mut x; + | | ^^^^^^ cannot borrow as mutable LL | | &mut x.0; LL | | }); - | |_____^ + | |_____- in this closure error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:43:9 | -LL | &mut x.0; - | ^^^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:39:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(|| { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | x = (1,); LL | | x.0 = 1; LL | | &mut x; LL | | &mut x.0; + | | ^^^^^^^^ cannot borrow as mutable LL | | }); - | |_____^ + | |_____- in this closure error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:46:9 | -LL | x = (1,); - | ^^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:45:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(move || { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | x = (1,); + | | ^^^^^^^^ cannot assign LL | | x.0 = 1; LL | | &mut x; LL | | &mut x.0; LL | | }); - | |_____^ + | |_____- in this closure error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:47:9 | -LL | x.0 = 1; - | ^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:45:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(move || { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | x = (1,); LL | | x.0 = 1; + | | ^^^^^^^ cannot assign LL | | &mut x; LL | | &mut x.0; LL | | }); - | |_____^ + | |_____- in this closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:48:9 | -LL | &mut x; - | ^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:45:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(move || { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | x = (1,); LL | | x.0 = 1; LL | | &mut x; + | | ^^^^^^ cannot borrow as mutable LL | | &mut x.0; LL | | }); - | |_____^ + | |_____- in this closure error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:49:9 | -LL | &mut x.0; - | ^^^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:45:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(move || { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | x = (1,); LL | | x.0 = 1; LL | | &mut x; LL | | &mut x.0; + | | ^^^^^^^^ cannot borrow as mutable LL | | }); - | |_____^ + | |_____- in this closure error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/mutability-errors.rs:54:5 diff --git a/src/test/ui/fn/fn-closure-mutable-capture.rs b/src/test/ui/fn/fn-closure-mutable-capture.rs index 81376af091b45..0e427b9cf318f 100644 --- a/src/test/ui/fn/fn-closure-mutable-capture.rs +++ b/src/test/ui/fn/fn-closure-mutable-capture.rs @@ -1,11 +1,11 @@ -pub fn bar(_f: F) {} +pub fn bar(_f: F) {} //~ NOTE change this to accept `FnMut` instead of `Fn` pub fn foo() { let mut x = 0; bar(move || x = 1); //~^ ERROR cannot assign to `x`, as it is a captured variable in a `Fn` closure //~| NOTE cannot assign - //~| HELP consider changing this to accept closures that implement `FnMut` + //~| NOTE expects `Fn` instead of `FnMut` } fn main() {} diff --git a/src/test/ui/fn/fn-closure-mutable-capture.stderr b/src/test/ui/fn/fn-closure-mutable-capture.stderr index f7ab56da8de97..d23c363ae1582 100644 --- a/src/test/ui/fn/fn-closure-mutable-capture.stderr +++ b/src/test/ui/fn/fn-closure-mutable-capture.stderr @@ -1,14 +1,13 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/fn-closure-mutable-capture.rs:5:17 | +LL | pub fn bar(_f: F) {} + | - change this to accept `FnMut` instead of `Fn` +... LL | bar(move || x = 1); - | ^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/fn-closure-mutable-capture.rs:5:9 - | -LL | bar(move || x = 1); - | ^^^^^^^^^^^^^ + | --- ^^^^^ cannot assign + | | + | expects `Fn` instead of `FnMut` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21600.stderr b/src/test/ui/issues/issue-21600.stderr index 9c534809dbee3..84c7106e89016 100644 --- a/src/test/ui/issues/issue-21600.stderr +++ b/src/test/ui/issues/issue-21600.stderr @@ -1,34 +1,33 @@ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/issue-21600.rs:14:20 | +LL | fn call_it(f: F) where F: Fn() { f(); } + | - change this to accept `FnMut` instead of `Fn` +... LL | call_it(|| x.gen_mut()); - | ^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/issue-21600.rs:14:17 - | -LL | call_it(|| x.gen_mut()); - | ^^^^^^^^^^^^^^ + | ------- ^ cannot borrow as mutable + | | + | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/issue-21600.rs:14:17 | -LL | call_it(|| x.gen_mut()); - | ^^ - mutable borrow occurs due to use of `x` in closure - | | - | cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/issue-21600.rs:12:13 - | +LL | fn call_it(f: F) where F: Fn() { f(); } + | - change this to accept `FnMut` instead of `Fn` +... LL | call_it(|| { - | _____________^ + | _____-------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | call_it(|| x.gen()); LL | | call_it(|| x.gen_mut()); + | | ^^ - mutable borrow occurs due to use of `x` in closure + | | | + | | cannot borrow as mutable LL | | LL | | LL | | }); - | |_____^ + | |_____- in this closure error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr index b8f5cc86500c5..dd5f32ef4f581 100644 --- a/src/test/ui/nll/closure-captures.stderr +++ b/src/test/ui/nll/closure-captures.stderr @@ -37,36 +37,36 @@ LL | x = 1; error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:27:9 | -LL | || - | ^^ cannot borrow as mutable -LL | x = 1;} - | - mutable borrow occurs due to use of `x` in closure - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:26:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(|| { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | || + | | ^^ cannot borrow as mutable LL | | x = 1;} - | |________________^ + | |__________-_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:31:9 | -LL | || - | ^^ cannot borrow as mutable -LL | x = 1;}); - | - mutable borrow occurs due to use of `x` in closure - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:30:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(move || { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | || + | | ^^ cannot borrow as mutable LL | | x = 1;}); - | |___________^ + | |_____-_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:39:10 @@ -80,19 +80,19 @@ LL | x = 1;} error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:38:9 | -LL | || - | ^^ cannot borrow as mutable -LL | x = 1;} - | - mutable borrow occurs due to use of `x` in closure - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:37:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(|| { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | || + | | ^^ cannot borrow as mutable LL | | x = 1;} - | |________________^ + | |__________-_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:43:5 @@ -106,53 +106,53 @@ LL | x = 1;}); error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:42:9 | -LL | || - | ^^ cannot borrow as mutable -LL | x = 1;}); - | - mutable borrow occurs due to use of `x` in closure - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:41:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(move || { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | || + | | ^^ cannot borrow as mutable LL | | x = 1;}); - | |___________^ + | |_____-_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:48:9 | -LL | || - | ^^ cannot borrow as mutable -LL | *x = 1;}); - | - mutable borrow occurs due to use of `x` in closure - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:47:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(|| { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | || + | | ^^ cannot borrow as mutable LL | | *x = 1;}); - | |________________^ + | |__________-_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:51:9 | -LL | || - | ^^ cannot borrow as mutable -LL | *x = 1;}); - | - mutable borrow occurs due to use of `x` in closure - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:50:12 - | +LL | fn fn_ref(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | fn_ref(move || { - | ____________^ + | _____------_- + | | | + | | expects `Fn` instead of `FnMut` LL | | || + | | ^^ cannot borrow as mutable LL | | *x = 1;}); - | |________________^ + | |__________-_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error: aborting due to 12 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr index 6bba38510b676..48ec620d92ea7 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr @@ -28,17 +28,17 @@ LL | n += 1; error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure --> $DIR/unboxed-closures-mutate-upvar.rs:53:9 | -LL | n += 1; - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/unboxed-closures-mutate-upvar.rs:52:23 - | +LL | fn to_fn>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... LL | let mut f = to_fn(move || { - | _______________________^ + | _________________-----_- + | | | + | | expects `Fn` instead of `FnMut` LL | | n += 1; + | | ^^^^^^ cannot assign LL | | }); - | |_____^ + | |_____- in this closure error: aborting due to 4 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr index a38c612e1dea9..80e84fb7cad3f 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr @@ -1,18 +1,18 @@ error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:11:9 | -LL | counter += 1; - | ^^^^^^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:10:10 - | +LL | fn call(f: F) where F : Fn() { + | - change this to accept `FnMut` instead of `Fn` +... LL | call(|| { - | __________^ + | _____----_- + | | | + | | expects `Fn` instead of `FnMut` LL | | counter += 1; + | | ^^^^^^^^^^^^ cannot assign LL | | LL | | }); - | |_____^ + | |_____- in this closure error: aborting due to previous error From 60274a95fef57a18113f7c48be68be31ece860eb Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Sun, 1 Sep 2019 17:23:20 +0200 Subject: [PATCH 037/657] Added From> for CString Updated tracking issue number Added safeguards for transmute_vec potentially being factored out elsewhere Clarified comment about avoiding mem::forget Removed unneeded unstable guard Added back a stability annotation for CI Minor documentation improvements Thanks to @Centril's code review Co-Authored-By: Mazdak Farrokhzad Improved layout checks, type annotations and removed unaccurate comment Removed unnecessary check on array layout Adapt the stability annotation to the new 1.41 milestone Co-Authored-By: Mazdak Farrokhzad Simplify the implementation. Use `Vec::into_raw_parts` instead of a manual implementation of `Vec::transmute`. If `Vec::into_raw_parts` uses `NonNull` instead, then the code here will need to be adjusted to take it into account (issue #65816) Reduce the whitespace of safety comments --- src/libstd/ffi/c_str.rs | 27 +++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + 2 files changed, 28 insertions(+) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index d2ee65f0a74eb..217672ea292fc 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -6,6 +6,7 @@ use crate::fmt::{self, Write}; use crate::io; use crate::mem; use crate::memchr; +use crate::num::NonZeroU8; use crate::ops; use crate::os::raw::c_char; use crate::ptr; @@ -741,6 +742,32 @@ impl From> for CString { } } +#[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")] +impl From> for CString { + /// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without + /// copying nor checking for inner null bytes. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`NonZeroU8`]: ../num/struct.NonZeroU8.html + /// [`Vec`]: ../vec/struct.Vec.html + #[inline] + fn from(v: Vec) -> CString { + unsafe { + // Transmute `Vec` to `Vec`. + let v: Vec = { + // Safety: + // - transmuting between `NonZeroU8` and `u8` is sound; + // - `alloc::Layout == alloc::Layout`. + let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v); + Vec::from_raw_parts(ptr.cast::(), len, cap) + }; + // Safety: `v` cannot contain null bytes, given the type-level + // invariant of `NonZeroU8`. + CString::from_vec_unchecked(v) + } + } +} + #[stable(feature = "more_box_slice_clone", since = "1.29.0")] impl Clone for Box { #[inline] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9e9df5ab9b6ce..c05ebc7349d71 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -310,6 +310,7 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(vec_into_raw_parts)] // NB: the above list is sorted to minimize merge conflicts. #![default_lib_allocator] From bdacdf49e532ce869d1eb96e967fd77991566a7f Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 16:34:03 +0100 Subject: [PATCH 038/657] Remove unused core_intrinsics feature gate from bootstrap --- src/bootstrap/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 637323331f582..042e3b55cc994 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -103,7 +103,6 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![feature(core_intrinsics)] #![feature(drain_filter)] use std::cell::{Cell, RefCell}; From 095963f91d525951cb0183648c47c427fb69f16d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 18:49:26 +0100 Subject: [PATCH 039/657] Remove unused feature gates from librustc --- src/librustc/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 744ee1a65e154..33552ffb03e6d 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -27,7 +27,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(arbitrary_self_types)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -39,21 +38,15 @@ #![feature(overlapping_marker_traits)] #![feature(extern_types)] #![feature(nll)] -#![feature(optin_builtin_traits)] #![feature(option_expect_none)] #![feature(range_is_empty)] #![feature(specialization)] -#![feature(unboxed_closures)] -#![feature(thread_local)] -#![feature(trace_macros)] #![feature(trusted_len)] #![feature(vec_remove_item)] #![feature(stmt_expr_attributes)] -#![feature(integer_atomics)] #![feature(test)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] -#![feature(log_syntax)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(hash_raw_entry)] From f9971c5cba0a141d3f00737292a40e3cacf44ac0 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 18:54:13 +0100 Subject: [PATCH 040/657] Remove unused feature gates from cg_llvm Also turns a few `box` into `Box::new` --- src/librustc_codegen_llvm/lib.rs | 15 ++++----------- src/librustc_codegen_llvm/metadata.rs | 4 ++-- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 8091a74854070..98a3e695fa079 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -6,18 +6,11 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] -#![feature(box_patterns)] -#![feature(box_syntax)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] #![feature(extern_types)] #![feature(in_band_lifetimes)] -#![feature(libc)] #![feature(nll)] -#![feature(optin_builtin_traits)] -#![feature(concat_idents)] -#![feature(link_args)] -#![feature(static_nobundle)] #![feature(trusted_len)] #![recursion_limit = "256"] @@ -196,7 +189,7 @@ unsafe impl Sync for LlvmCodegenBackend {} impl LlvmCodegenBackend { pub fn new() -> Box { - box LlvmCodegenBackend(()) + Box::new(LlvmCodegenBackend(())) } } @@ -245,7 +238,7 @@ impl CodegenBackend for LlvmCodegenBackend { } fn metadata_loader(&self) -> Box { - box metadata::LlvmMetadataLoader + Box::new(metadata::LlvmMetadataLoader) } fn provide(&self, providers: &mut ty::query::Providers<'_>) { @@ -262,12 +255,12 @@ impl CodegenBackend for LlvmCodegenBackend { metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box { - box rustc_codegen_ssa::base::codegen_crate( + Box::new(rustc_codegen_ssa::base::codegen_crate( LlvmCodegenBackend(()), tcx, metadata, need_metadata_module, - ) + )) } fn join_codegen( diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs index abe34bb148ce5..36b12f1a7b184 100644 --- a/src/librustc_codegen_llvm/metadata.rs +++ b/src/librustc_codegen_llvm/metadata.rs @@ -22,7 +22,7 @@ impl MetadataLoader for LlvmMetadataLoader { // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap // internally to read the file. We also avoid even using a memcpy by // just keeping the archive along while the metadata is in use. - let archive = ArchiveRO::open(filename).map(|ar| OwningRef::new(box ar)).map_err(|e| { + let archive = ArchiveRO::open(filename).map(|ar| OwningRef::new(Box::new(ar))).map_err(|e| { debug!("llvm didn't like `{}`: {}", filename.display(), e); format!("failed to read rlib metadata in '{}': {}", filename.display(), e) })?; @@ -44,7 +44,7 @@ impl MetadataLoader for LlvmMetadataLoader { let buf = path_to_c_string(filename); let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()) .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?; - let of = ObjectFile::new(mb).map(|of| OwningRef::new(box of)).ok_or_else(|| { + let of = ObjectFile::new(mb).map(|of| OwningRef::new(Box::new(of))).ok_or_else(|| { format!("provided path not an object file: '{}'", filename.display()) })?; let buf = of.try_map(|of| search_meta_section(of, target, filename))?; From c2da8b3f0d669cb5d6e7d1338aed91fd1c76b8a3 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 19:04:56 +0100 Subject: [PATCH 041/657] Remove unused feature gates from cg_ssa and cg_utils --- src/librustc_codegen_ssa/lib.rs | 4 ---- src/librustc_codegen_utils/lib.rs | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index f39587122c56d..a2bb39b9e4019 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -1,10 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] #![feature(box_patterns)] -#![feature(box_syntax)] -#![feature(core_intrinsics)] -#![feature(libc)] -#![feature(stmt_expr_attributes)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] #![feature(nll)] diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index 6b802bf530e86..38906bbaef810 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -3,10 +3,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(arbitrary_self_types)] -#![feature(box_patterns)] -#![feature(box_syntax)] -#![feature(core_intrinsics)] #![feature(never_type)] #![feature(nll)] #![feature(in_band_lifetimes)] From 2a4596abfb4449371982c824c330e30f4ae0d1ee Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 19:08:28 +0100 Subject: [PATCH 042/657] Remove unused feature gates from librustc_data_structures --- src/librustc_data_structures/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index aaac7fb4460cd..13792a0c890c4 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -12,7 +12,6 @@ #![feature(generators)] #![feature(generator_trait)] #![feature(fn_traits)] -#![feature(unsize)] #![feature(specialization)] #![feature(optin_builtin_traits)] #![feature(nll)] @@ -20,11 +19,9 @@ #![feature(hash_raw_entry)] #![feature(stmt_expr_attributes)] #![feature(core_intrinsics)] -#![feature(integer_atomics)] #![feature(test)] #![feature(associated_type_bounds)] #![feature(thread_id_value)] -#![cfg_attr(unix, feature(libc))] #![allow(rustc::default_hash_types)] #[macro_use] From cf862df494438923295ae4ca78b40787c6b89d53 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 19:10:39 +0100 Subject: [PATCH 043/657] Remove unused feature gates from librustc_driver --- src/librustc_driver/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 019ff431bcb97..52c6399498534 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -5,12 +5,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(box_syntax)] -#![cfg_attr(unix, feature(libc))] #![feature(nll)] -#![feature(set_stdio)] -#![feature(no_debug)] -#![feature(integer_atomics)] #![recursion_limit = "256"] pub extern crate getopts; From 3e61d52784bd20140a8124d41a9661378b65f40e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 19:11:41 +0100 Subject: [PATCH 044/657] Remove unused feature gates from librustc_errors --- src/librustc_errors/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 17b293401f89e..109b151e4140b 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -4,9 +4,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(crate_visibility_modifier)] -#![cfg_attr(unix, feature(libc))] #![feature(nll)] -#![feature(optin_builtin_traits)] pub use emitter::ColorConfig; From fa9bfebfc9256369c03cbe8bba2e737de3cb38fc Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 4 Feb 2020 22:19:05 +0100 Subject: [PATCH 045/657] Fix and test implementation of BTreeMap's first_entry, last_entry, pop_first, pop_last --- src/liballoc/collections/btree/map.rs | 24 ++++++++++++++---------- src/liballoc/tests/btree/map.rs | 5 +++++ src/liballoc/tests/btree/set.rs | 27 ++++++++++++++++----------- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 8eabc1773042f..c1778f2065d40 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -675,13 +675,15 @@ impl BTreeMap { T: Ord, K: Borrow, { - match self.length { - 0 => None, - _ => Some(OccupiedEntry { - handle: self.root.as_mut().first_kv(), + let front = self.root.as_mut().first_leaf_edge(); + if let Ok(kv) = front.right_kv() { + Some(OccupiedEntry { + handle: kv.forget_node_type(), length: &mut self.length, _marker: PhantomData, - }), + }) + } else { + None } } @@ -736,13 +738,15 @@ impl BTreeMap { T: Ord, K: Borrow, { - match self.length { - 0 => None, - _ => Some(OccupiedEntry { - handle: self.root.as_mut().last_kv(), + let back = self.root.as_mut().last_leaf_edge(); + if let Ok(kv) = back.left_kv() { + Some(OccupiedEntry { + handle: kv.forget_node_type(), length: &mut self.length, _marker: PhantomData, - }), + }) + } else { + None } } diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 0d009507fc7aa..0a26d7bf427ab 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -23,6 +23,11 @@ fn test_basic_large() { assert_eq!(map.len(), i + 1); } + assert_eq!(map.first_key_value(), Some((&0, &0))); + assert_eq!(map.last_key_value(), Some((&(size - 1), &(10 * (size - 1))))); + assert_eq!(map.first_entry().unwrap().key(), &0); + assert_eq!(map.last_entry().unwrap().key(), &(size - 1)); + for i in 0..size { assert_eq!(map.get(&i).unwrap(), &(i * 10)); } diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 265ef758cc5bc..1a2b62d026b2e 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -487,21 +487,26 @@ fn test_first_last() { a.insert(2); assert_eq!(a.first(), Some(&1)); assert_eq!(a.last(), Some(&2)); - a.insert(3); + for i in 3..=12 { + a.insert(i); + } assert_eq!(a.first(), Some(&1)); - assert_eq!(a.last(), Some(&3)); - - assert_eq!(a.len(), 3); + assert_eq!(a.last(), Some(&12)); assert_eq!(a.pop_first(), Some(1)); - assert_eq!(a.len(), 2); - assert_eq!(a.pop_last(), Some(3)); - assert_eq!(a.len(), 1); + assert_eq!(a.pop_last(), Some(12)); assert_eq!(a.pop_first(), Some(2)); - assert_eq!(a.len(), 0); - assert_eq!(a.pop_last(), None); - assert_eq!(a.len(), 0); + assert_eq!(a.pop_last(), Some(11)); + assert_eq!(a.pop_first(), Some(3)); + assert_eq!(a.pop_last(), Some(10)); + assert_eq!(a.pop_first(), Some(4)); + assert_eq!(a.pop_first(), Some(5)); + assert_eq!(a.pop_first(), Some(6)); + assert_eq!(a.pop_first(), Some(7)); + assert_eq!(a.pop_first(), Some(8)); + assert_eq!(a.clone().pop_last(), Some(9)); + assert_eq!(a.pop_first(), Some(9)); assert_eq!(a.pop_first(), None); - assert_eq!(a.len(), 0); + assert_eq!(a.pop_last(), None); } fn rand_data(len: usize) -> Vec { From 319dd6f139377259ceca7db35069b382446ee3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 30 Jan 2020 19:01:31 -0800 Subject: [PATCH 046/657] When suggesting associated fn with type parameters, include in the structured suggestion --- src/librustc_typeck/check/mod.rs | 85 ++++++++++++++++++- ...sing-assoc-fn-applicable-suggestions.fixed | 21 +++++ ...missing-assoc-fn-applicable-suggestions.rs | 18 ++++ ...ing-assoc-fn-applicable-suggestions.stderr | 16 ++++ src/test/ui/suggestions/missing-assoc-fn.rs | 22 +++++ .../ui/suggestions/missing-assoc-fn.stderr | 36 ++++++++ 6 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed create mode 100644 src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs create mode 100644 src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr create mode 100644 src/test/ui/suggestions/missing-assoc-fn.rs create mode 100644 src/test/ui/suggestions/missing-assoc-fn.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d0275429747b6..678f837db96fd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2157,8 +2157,77 @@ fn missing_items_err( err.emit(); } +/// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. +fn bounds_from_generic_predicates( + tcx: TyCtxt<'_>, + predicates: ty::GenericPredicates<'_>, +) -> (String, String) { + let mut types: FxHashMap, Vec> = FxHashMap::default(); + let mut projections = vec![]; + for (predicate, _) in predicates.predicates { + debug!("predicate {:?}", predicate); + match predicate { + ty::Predicate::Trait(trait_predicate, _) => { + let entry = types.entry(trait_predicate.skip_binder().self_ty()).or_default(); + let def_id = trait_predicate.skip_binder().def_id(); + if Some(def_id) != tcx.lang_items().sized_trait() { + // Type params are `Sized` by default, do not add that restriction to the list + // if it is a positive requirement. + entry.push(trait_predicate.skip_binder().def_id()); + } + } + ty::Predicate::Projection(projection_pred) => { + projections.push(projection_pred); + } + _ => {} + } + } + let generics = if types.is_empty() { + "".to_string() + } else { + format!( + "<{}>", + types + .keys() + .filter_map(|t| match t.kind { + ty::Param(_) => Some(t.to_string()), + // Avoid suggesting the following: + // fn foo::Bar>(_: T) where T: Trait, ::Bar: Other {} + _ => None, + }) + .collect::>() + .join(", ") + ) + }; + let mut where_clauses = vec![]; + for (ty, bounds) in types { + for bound in &bounds { + where_clauses.push(format!("{}: {}", ty, tcx.def_path_str(*bound))); + } + } + for projection in &projections { + let p = projection.skip_binder(); + // FIXME: this is not currently supported syntax, we should be looking at the `types` and + // insert the associated types where they correspond, but for now lets be "lazy" and + // propose this instead of the following valid resugaring: + // `T: Trait, Trait::Assoc = K` → `T: Trait` + where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty)); + } + let where_clauses = if where_clauses.is_empty() { + String::new() + } else { + format!(" where {}", where_clauses.join(", ")) + }; + (generics, where_clauses) +} + /// Return placeholder code for the given function. -fn fn_sig_suggestion(sig: &ty::FnSig<'_>, ident: Ident) -> String { +fn fn_sig_suggestion( + tcx: TyCtxt<'_>, + sig: &ty::FnSig<'_>, + ident: Ident, + predicates: ty::GenericPredicates<'_>, +) -> String { let args = sig .inputs() .iter() @@ -2188,12 +2257,17 @@ fn fn_sig_suggestion(sig: &ty::FnSig<'_>, ident: Ident) -> String { let output = if !output.is_unit() { format!(" -> {:?}", output) } else { String::new() }; let unsafety = sig.unsafety.prefix_str(); + let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); + // FIXME: this is not entirely correct, as the lifetimes from borrowed params will // not be present in the `fn` definition, not will we account for renamed // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. - format!("{}fn {}({}){} {{ unimplemented!() }}", unsafety, ident, args, output) + format!( + "{}fn {}{}({}){}{} {{ unimplemented!() }}", + unsafety, ident, generics, args, output, where_clauses + ) } /// Return placeholder code for the given associated item. @@ -2206,7 +2280,12 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { // late-bound regions, and we don't want method signatures to show up // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound // regions just fine, showing `fn(&MyType)`. - fn_sig_suggestion(tcx.fn_sig(assoc.def_id).skip_binder(), assoc.ident) + fn_sig_suggestion( + tcx, + tcx.fn_sig(assoc.def_id).skip_binder(), + assoc.ident, + tcx.predicates_of(assoc.def_id), + ) } ty::AssocKind::Type => format!("type {} = Type;", assoc.ident), // FIXME(type_alias_impl_trait): we should print bounds here too. diff --git a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed new file mode 100644 index 0000000000000..00a712e5722a7 --- /dev/null +++ b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed @@ -0,0 +1,21 @@ +// run-rustfix +trait TraitB { + type Item; +} + +trait TraitA { + type Type; + fn bar(_: T) -> Self; + fn baz(_: T) -> Self where T: TraitB, ::Item: Copy; +} + +struct S; +struct Type; + +impl TraitA<()> for S { //~ ERROR not all trait items implemented +fn baz(_: T) -> Self where T: TraitB, ::Item: std::marker::Copy { unimplemented!() } +fn bar(_: T) -> Self { unimplemented!() } +type Type = Type; +} + +fn main() {} diff --git a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs new file mode 100644 index 0000000000000..c80ede1b2be23 --- /dev/null +++ b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs @@ -0,0 +1,18 @@ +// run-rustfix +trait TraitB { + type Item; +} + +trait TraitA { + type Type; + fn bar(_: T) -> Self; + fn baz(_: T) -> Self where T: TraitB, ::Item: Copy; +} + +struct S; +struct Type; + +impl TraitA<()> for S { //~ ERROR not all trait items implemented +} + +fn main() {} diff --git a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr new file mode 100644 index 0000000000000..ee29a56f3f8c5 --- /dev/null +++ b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr @@ -0,0 +1,16 @@ +error[E0046]: not all trait items implemented, missing: `Type`, `bar`, `baz` + --> $DIR/missing-assoc-fn-applicable-suggestions.rs:15:1 + | +LL | type Type; + | ---------- `Type` from trait +LL | fn bar(_: T) -> Self; + | ------------------------ `bar` from trait +LL | fn baz(_: T) -> Self where T: TraitB, ::Item: Copy; + | ------------------------------------------------------------------- `baz` from trait +... +LL | impl TraitA<()> for S { + | ^^^^^^^^^^^^^^^^^^^^^ missing `Type`, `bar`, `baz` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/src/test/ui/suggestions/missing-assoc-fn.rs b/src/test/ui/suggestions/missing-assoc-fn.rs new file mode 100644 index 0000000000000..9af8e5a939d65 --- /dev/null +++ b/src/test/ui/suggestions/missing-assoc-fn.rs @@ -0,0 +1,22 @@ +trait TraitB { + type Item; +} + +trait TraitA { + fn foo>(_: T) -> Self; + fn bar(_: T) -> Self; + fn baz(_: T) -> Self where T: TraitB, ::Item: Copy; + fn bat>(_: T) -> Self; //~ ERROR associated type bounds are unstable +} + +struct S; + +impl TraitA<()> for S { //~ ERROR not all trait items implemented +} + +use std::iter::FromIterator; +struct X; +impl FromIterator<()> for X { //~ ERROR not all trait items implemented +} + +fn main() {} diff --git a/src/test/ui/suggestions/missing-assoc-fn.stderr b/src/test/ui/suggestions/missing-assoc-fn.stderr new file mode 100644 index 0000000000000..bed8bffe38d73 --- /dev/null +++ b/src/test/ui/suggestions/missing-assoc-fn.stderr @@ -0,0 +1,36 @@ +error[E0658]: associated type bounds are unstable + --> $DIR/missing-assoc-fn.rs:9:22 + | +LL | fn bat>(_: T) -> Self; + | ^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + +error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `baz`, `bat` + --> $DIR/missing-assoc-fn.rs:14:1 + | +LL | fn foo>(_: T) -> Self; + | ------------------------------------------ `foo` from trait +LL | fn bar(_: T) -> Self; + | ------------------------ `bar` from trait +LL | fn baz(_: T) -> Self where T: TraitB, ::Item: Copy; + | ------------------------------------------------------------------- `baz` from trait +LL | fn bat>(_: T) -> Self; + | -------------------------------------------- `bat` from trait +... +LL | impl TraitA<()> for S { + | ^^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `baz`, `bat` in implementation + +error[E0046]: not all trait items implemented, missing: `from_iter` + --> $DIR/missing-assoc-fn.rs:19:1 + | +LL | impl FromIterator<()> for X { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_iter` in implementation + | + = help: implement the missing item: `fn from_iter(_: T) -> Self where T: std::iter::IntoIterator, std::iter::IntoIterator::Item = A { unimplemented!() }` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0046, E0658. +For more information about an error, try `rustc --explain E0046`. From 6509db844315882db7ec0b624ca1e7b04d72568d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 5 Feb 2020 05:03:37 +0100 Subject: [PATCH 047/657] or_patterns: harden bindings test --- .../ui/or-patterns/or-pattern-mismatch.rs | 70 ++++++- .../ui/or-patterns/or-pattern-mismatch.stderr | 182 +++++++++++++++++- 2 files changed, 245 insertions(+), 7 deletions(-) diff --git a/src/test/ui/or-patterns/or-pattern-mismatch.rs b/src/test/ui/or-patterns/or-pattern-mismatch.rs index 973954bca5a5e..5ec7dc6962c18 100644 --- a/src/test/ui/or-patterns/or-pattern-mismatch.rs +++ b/src/test/ui/or-patterns/or-pattern-mismatch.rs @@ -1,4 +1,68 @@ -enum Blah { A(isize, isize, usize), B(isize, isize) } +// Here we test type checking of bindings when combined with or-patterns. +// Specifically, we ensure that introducing bindings of different types result in type errors. -fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } } -//~^ ERROR mismatched types +#![feature(or_patterns)] + +fn main() { + enum Blah { + A(isize, isize, usize), + B(isize, isize), + } + + match Blah::A(1, 1, 2) { + Blah::A(_, x, y) | Blah::B(x, y) => {} //~ ERROR mismatched types + } + + match Some(Blah::A(1, 1, 2)) { + Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} //~ ERROR mismatched types + } + + match (0u8, 1u16) { + (x, y) | (y, x) => {} //~ ERROR mismatched types + //~^ ERROR mismatched types + } + + match Some((0u8, Some((1u16, 2u32)))) { + Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + _ => {} + } + + if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { + //~^ ERROR mismatched types + } + + if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) { + //~^ ERROR mismatched types + } + + if let (x, y) | (y, x) = (0u8, 1u16) { + //~^ ERROR mismatched types + //~| ERROR mismatched types + } + + if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + = Some((0u8, Some((1u16, 2u32)))) + {} + + let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); + //~^ ERROR mismatched types + + let (x, y) | (y, x) = (0u8, 1u16); + //~^ ERROR mismatched types + //~| ERROR mismatched types + + fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {} + //~^ ERROR mismatched types + + fn f2(((x, y) | (y, x)): (u8, u16)) {} + //~^ ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/or-patterns/or-pattern-mismatch.stderr b/src/test/ui/or-patterns/or-pattern-mismatch.stderr index bc288e0625075..84c38e3be9019 100644 --- a/src/test/ui/or-patterns/or-pattern-mismatch.stderr +++ b/src/test/ui/or-patterns/or-pattern-mismatch.stderr @@ -1,9 +1,183 @@ error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:3:68 + --> $DIR/or-pattern-mismatch.rs:13:39 | -LL | fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } } - | ---------------- this expression has type `Blah` ^ expected `usize`, found `isize` +LL | match Blah::A(1, 1, 2) { + | ---------------- this expression has type `main::Blah` +LL | Blah::A(_, x, y) | Blah::B(x, y) => {} + | ^ expected `usize`, found `isize` -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:17:44 + | +LL | match Some(Blah::A(1, 1, 2)) { + | ---------------------- this expression has type `std::option::Option` +LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} + | ^ expected `usize`, found `isize` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:21:19 + | +LL | match (0u8, 1u16) { + | ----------- this expression has type `(u8, u16)` +LL | (x, y) | (y, x) => {} + | ^ expected `u16`, found `u8` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:21:22 + | +LL | match (0u8, 1u16) { + | ----------- this expression has type `(u8, u16)` +LL | (x, y) | (y, x) => {} + | ^ expected `u8`, found `u16` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:26:41 + | +LL | match Some((0u8, Some((1u16, 2u32)))) { + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` +LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + | ^ expected `u16`, found `u8` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:26:50 + | +LL | match Some((0u8, Some((1u16, 2u32)))) { + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` +LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + | ^ expected `u8`, found `u16` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:26:59 + | +LL | match Some((0u8, Some((1u16, 2u32)))) { + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` +LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + | ^ expected `u32`, found `u16` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:26:62 + | +LL | match Some((0u8, Some((1u16, 2u32)))) { + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` +LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + | ^ expected `u8`, found `u32` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:34:42 + | +LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { + | ^ ---------------- this expression has type `main::Blah` + | | + | expected `usize`, found `isize` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:38:47 + | +LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) { + | ^ ---------------------- this expression has type `std::option::Option` + | | + | expected `usize`, found `isize` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:42:22 + | +LL | if let (x, y) | (y, x) = (0u8, 1u16) { + | ^ ----------- this expression has type `(u8, u16)` + | | + | expected `u16`, found `u8` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:42:25 + | +LL | if let (x, y) | (y, x) = (0u8, 1u16) { + | ^ ----------- this expression has type `(u8, u16)` + | | + | expected `u8`, found `u16` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:47:44 + | +LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + | ^ expected `u16`, found `u8` +... +LL | = Some((0u8, Some((1u16, 2u32)))) + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:47:53 + | +LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + | ^ expected `u8`, found `u16` +... +LL | = Some((0u8, Some((1u16, 2u32)))) + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:47:62 + | +LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + | ^ expected `u32`, found `u16` +... +LL | = Some((0u8, Some((1u16, 2u32)))) + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:47:65 + | +LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + | ^ expected `u8`, found `u32` +... +LL | = Some((0u8, Some((1u16, 2u32)))) + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:55:39 + | +LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); + | ^ ---------------- this expression has type `main::Blah` + | | + | expected `usize`, found `isize` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:58:19 + | +LL | let (x, y) | (y, x) = (0u8, 1u16); + | ^ ----------- this expression has type `(u8, u16)` + | | + | expected `u16`, found `u8` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:58:22 + | +LL | let (x, y) | (y, x) = (0u8, 1u16); + | ^ ----------- this expression has type `(u8, u16)` + | | + | expected `u8`, found `u16` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:62:42 + | +LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {} + | ^ ---- expected due to this + | | + | expected `usize`, found `isize` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:65:22 + | +LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} + | ^ --------- expected due to this + | | + | expected `u16`, found `u8` + +error[E0308]: mismatched types + --> $DIR/or-pattern-mismatch.rs:65:25 + | +LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} + | ^ --------- expected due to this + | | + | expected `u8`, found `u16` + +error: aborting due to 22 previous errors For more information about this error, try `rustc --explain E0308`. From 29437e55a56c1c1251ae5f7276f3e95dac4b609a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 5 Feb 2020 05:05:29 +0100 Subject: [PATCH 048/657] or_patterns: rename previous test --- ...s => or-patterns-binding-type-mismatch.rs} | 0 ... or-patterns-binding-type-mismatch.stderr} | 44 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) rename src/test/ui/or-patterns/{or-pattern-mismatch.rs => or-patterns-binding-type-mismatch.rs} (100%) rename src/test/ui/or-patterns/{or-pattern-mismatch.stderr => or-patterns-binding-type-mismatch.stderr} (85%) diff --git a/src/test/ui/or-patterns/or-pattern-mismatch.rs b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs similarity index 100% rename from src/test/ui/or-patterns/or-pattern-mismatch.rs rename to src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs diff --git a/src/test/ui/or-patterns/or-pattern-mismatch.stderr b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr similarity index 85% rename from src/test/ui/or-patterns/or-pattern-mismatch.stderr rename to src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr index 84c38e3be9019..5094f04b9204f 100644 --- a/src/test/ui/or-patterns/or-pattern-mismatch.stderr +++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:13:39 + --> $DIR/or-patterns-binding-type-mismatch.rs:13:39 | LL | match Blah::A(1, 1, 2) { | ---------------- this expression has type `main::Blah` @@ -7,7 +7,7 @@ LL | Blah::A(_, x, y) | Blah::B(x, y) => {} | ^ expected `usize`, found `isize` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:17:44 + --> $DIR/or-patterns-binding-type-mismatch.rs:17:44 | LL | match Some(Blah::A(1, 1, 2)) { | ---------------------- this expression has type `std::option::Option` @@ -15,7 +15,7 @@ LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} | ^ expected `usize`, found `isize` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:21:19 + --> $DIR/or-patterns-binding-type-mismatch.rs:21:19 | LL | match (0u8, 1u16) { | ----------- this expression has type `(u8, u16)` @@ -23,7 +23,7 @@ LL | (x, y) | (y, x) => {} | ^ expected `u16`, found `u8` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:21:22 + --> $DIR/or-patterns-binding-type-mismatch.rs:21:22 | LL | match (0u8, 1u16) { | ----------- this expression has type `(u8, u16)` @@ -31,7 +31,7 @@ LL | (x, y) | (y, x) => {} | ^ expected `u8`, found `u16` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:26:41 + --> $DIR/or-patterns-binding-type-mismatch.rs:26:41 | LL | match Some((0u8, Some((1u16, 2u32)))) { | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` @@ -39,7 +39,7 @@ LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | ^ expected `u16`, found `u8` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:26:50 + --> $DIR/or-patterns-binding-type-mismatch.rs:26:50 | LL | match Some((0u8, Some((1u16, 2u32)))) { | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` @@ -47,7 +47,7 @@ LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | ^ expected `u8`, found `u16` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:26:59 + --> $DIR/or-patterns-binding-type-mismatch.rs:26:59 | LL | match Some((0u8, Some((1u16, 2u32)))) { | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` @@ -55,7 +55,7 @@ LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | ^ expected `u32`, found `u16` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:26:62 + --> $DIR/or-patterns-binding-type-mismatch.rs:26:62 | LL | match Some((0u8, Some((1u16, 2u32)))) { | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` @@ -63,7 +63,7 @@ LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | ^ expected `u8`, found `u32` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:34:42 + --> $DIR/or-patterns-binding-type-mismatch.rs:34:42 | LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { | ^ ---------------- this expression has type `main::Blah` @@ -71,7 +71,7 @@ LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { | expected `usize`, found `isize` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:38:47 + --> $DIR/or-patterns-binding-type-mismatch.rs:38:47 | LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) { | ^ ---------------------- this expression has type `std::option::Option` @@ -79,7 +79,7 @@ LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) | expected `usize`, found `isize` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:42:22 + --> $DIR/or-patterns-binding-type-mismatch.rs:42:22 | LL | if let (x, y) | (y, x) = (0u8, 1u16) { | ^ ----------- this expression has type `(u8, u16)` @@ -87,7 +87,7 @@ LL | if let (x, y) | (y, x) = (0u8, 1u16) { | expected `u16`, found `u8` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:42:25 + --> $DIR/or-patterns-binding-type-mismatch.rs:42:25 | LL | if let (x, y) | (y, x) = (0u8, 1u16) { | ^ ----------- this expression has type `(u8, u16)` @@ -95,7 +95,7 @@ LL | if let (x, y) | (y, x) = (0u8, 1u16) { | expected `u8`, found `u16` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:47:44 + --> $DIR/or-patterns-binding-type-mismatch.rs:47:44 | LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | ^ expected `u16`, found `u8` @@ -104,7 +104,7 @@ LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:47:53 + --> $DIR/or-patterns-binding-type-mismatch.rs:47:53 | LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | ^ expected `u8`, found `u16` @@ -113,7 +113,7 @@ LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:47:62 + --> $DIR/or-patterns-binding-type-mismatch.rs:47:62 | LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | ^ expected `u32`, found `u16` @@ -122,7 +122,7 @@ LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:47:65 + --> $DIR/or-patterns-binding-type-mismatch.rs:47:65 | LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | ^ expected `u8`, found `u32` @@ -131,7 +131,7 @@ LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:55:39 + --> $DIR/or-patterns-binding-type-mismatch.rs:55:39 | LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); | ^ ---------------- this expression has type `main::Blah` @@ -139,7 +139,7 @@ LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); | expected `usize`, found `isize` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:58:19 + --> $DIR/or-patterns-binding-type-mismatch.rs:58:19 | LL | let (x, y) | (y, x) = (0u8, 1u16); | ^ ----------- this expression has type `(u8, u16)` @@ -147,7 +147,7 @@ LL | let (x, y) | (y, x) = (0u8, 1u16); | expected `u16`, found `u8` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:58:22 + --> $DIR/or-patterns-binding-type-mismatch.rs:58:22 | LL | let (x, y) | (y, x) = (0u8, 1u16); | ^ ----------- this expression has type `(u8, u16)` @@ -155,7 +155,7 @@ LL | let (x, y) | (y, x) = (0u8, 1u16); | expected `u8`, found `u16` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:62:42 + --> $DIR/or-patterns-binding-type-mismatch.rs:62:42 | LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {} | ^ ---- expected due to this @@ -163,7 +163,7 @@ LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {} | expected `usize`, found `isize` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:65:22 + --> $DIR/or-patterns-binding-type-mismatch.rs:65:22 | LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} | ^ --------- expected due to this @@ -171,7 +171,7 @@ LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} | expected `u16`, found `u8` error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:65:25 + --> $DIR/or-patterns-binding-type-mismatch.rs:65:25 | LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} | ^ --------- expected due to this From c00d8aa5179ef38f7d83067a8d010bcc26fa0cc3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 5 Feb 2020 16:28:13 +0800 Subject: [PATCH 049/657] Reorder declarations of Result::export/unwrap to match Option --- src/libcore/result.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index bc70dbd62eb52..3361ab6c97d80 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -935,8 +935,8 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an [`Err`], with a panic message provided by the - /// [`Err`]'s value. + /// Panics if the value is an [`Err`], with a panic message including the + /// passed message, and the content of the [`Err`]. /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err @@ -945,22 +945,17 @@ impl Result { /// /// Basic usage: /// - /// ``` - /// let x: Result = Ok(2); - /// assert_eq!(x.unwrap(), 2); - /// ``` - /// /// ```{.should_panic} /// let x: Result = Err("emergency failure"); - /// x.unwrap(); // panics with `emergency failure` + /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure` /// ``` #[inline] #[track_caller] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap(self) -> T { + #[stable(feature = "result_expect", since = "1.4.0")] + pub fn expect(self, msg: &str) -> T { match self { Ok(t) => t, - Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e), + Err(e) => unwrap_failed(msg, &e), } } @@ -968,8 +963,8 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an [`Err`], with a panic message including the - /// passed message, and the content of the [`Err`]. + /// Panics if the value is an [`Err`], with a panic message provided by the + /// [`Err`]'s value. /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err @@ -978,17 +973,22 @@ impl Result { /// /// Basic usage: /// + /// ``` + /// let x: Result = Ok(2); + /// assert_eq!(x.unwrap(), 2); + /// ``` + /// /// ```{.should_panic} /// let x: Result = Err("emergency failure"); - /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure` + /// x.unwrap(); // panics with `emergency failure` /// ``` #[inline] #[track_caller] - #[stable(feature = "result_expect", since = "1.4.0")] - pub fn expect(self, msg: &str) -> T { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn unwrap(self) -> T { match self { Ok(t) => t, - Err(e) => unwrap_failed(msg, &e), + Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e), } } } From db9b578b71190540cfd84f16f5d310d6ce4cb659 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 5 Feb 2020 16:31:12 +0800 Subject: [PATCH 050/657] Reorder declarations of Result::expect_err/unwrap_err to match Option --- src/libcore/result.rs | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 3361ab6c97d80..ee28946f0da7a 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -998,30 +998,26 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an [`Ok`], with a custom panic message provided - /// by the [`Ok`]'s value. + /// Panics if the value is an [`Ok`], with a panic message including the + /// passed message, and the content of the [`Ok`]. /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err /// - /// /// # Examples /// - /// ```{.should_panic} - /// let x: Result = Ok(2); - /// x.unwrap_err(); // panics with `2` - /// ``` + /// Basic usage: /// - /// ``` - /// let x: Result = Err("emergency failure"); - /// assert_eq!(x.unwrap_err(), "emergency failure"); + /// ```{.should_panic} + /// let x: Result = Ok(10); + /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` /// ``` #[inline] #[track_caller] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_err(self) -> E { + #[stable(feature = "result_expect_err", since = "1.17.0")] + pub fn expect_err(self, msg: &str) -> E { match self { - Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t), + Ok(t) => unwrap_failed(msg, &t), Err(e) => e, } } @@ -1030,26 +1026,30 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an [`Ok`], with a panic message including the - /// passed message, and the content of the [`Ok`]. + /// Panics if the value is an [`Ok`], with a custom panic message provided + /// by the [`Ok`]'s value. /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err /// - /// # Examples /// - /// Basic usage: + /// # Examples /// /// ```{.should_panic} - /// let x: Result = Ok(10); - /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` + /// let x: Result = Ok(2); + /// x.unwrap_err(); // panics with `2` + /// ``` + /// + /// ``` + /// let x: Result = Err("emergency failure"); + /// assert_eq!(x.unwrap_err(), "emergency failure"); /// ``` #[inline] #[track_caller] - #[stable(feature = "result_expect_err", since = "1.17.0")] - pub fn expect_err(self, msg: &str) -> E { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn unwrap_err(self) -> E { match self { - Ok(t) => unwrap_failed(msg, &t), + Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t), Err(e) => e, } } From 17e632d382dfae46e9dfa684db9bddec3e8951a7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 5 Feb 2020 10:32:54 +0100 Subject: [PATCH 051/657] or_patterns: test default binding modes --- .../or-patterns-default-binding-modes.rs | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/test/ui/or-patterns/or-patterns-default-binding-modes.rs diff --git a/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs b/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs new file mode 100644 index 0000000000000..3b6047c7be47d --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs @@ -0,0 +1,132 @@ +// Test that or-patterns are pass-through with respect to default binding modes. + +// check-pass + +#![feature(or_patterns)] +#![allow(irrefutable_let_patterns)] + +fn main() { + // A regression test for a mistake we made at one point: + match &1 { + e @ &(1..=2) | e @ &(3..=4) => {} + _ => {} + } + + match &0 { + 0 | &1 => {} + _ => {} + } + + type R<'a> = &'a Result; + + let res: R<'_> = &Ok(0); + + match res { + // Alternatives propagate expected type / binding mode independently. + Ok(mut x) | &Err(mut x) => drop::(x), + } + match res { + &(Ok(x) | Err(x)) => drop::(x), + } + match res { + Ok(x) | Err(x) => drop::<&u8>(x), + } + if let Ok(mut x) | &Err(mut x) = res { + drop::(x); + } + if let &(Ok(x) | Err(x)) = res { + drop::(x); + } + let Ok(mut x) | &Err(mut x) = res; + drop::(x); + let &(Ok(x) | Err(x)) = res; + drop::(x); + let Ok(x) | Err(x) = res; + drop::<&u8>(x); + for Ok(mut x) | &Err(mut x) in std::iter::once(res) { + drop::(x); + } + for &(Ok(x) | Err(x)) in std::iter::once(res) { + drop::(x); + } + for Ok(x) | Err(x) in std::iter::once(res) { + drop::<&u8>(x); + } + fn f1((Ok(mut x) | &Err(mut x)): R<'_>) { + drop::(x); + } + fn f2(&(Ok(x) | Err(x)): R<'_>) { + drop::(x); + } + fn f3((Ok(x) | Err(x)): R<'_>) { + drop::<&u8>(x); + } + + // Wrap inside another type (a product for a simplity with irrefutable contexts). + #[derive(Copy, Clone)] + struct Wrap(T); + let wres = Wrap(res); + + match wres { + Wrap(Ok(mut x) | &Err(mut x)) => drop::(x), + } + match wres { + Wrap(&(Ok(x) | Err(x))) => drop::(x), + } + match wres { + Wrap(Ok(x) | Err(x)) => drop::<&u8>(x), + } + if let Wrap(Ok(mut x) | &Err(mut x)) = wres { + drop::(x); + } + if let Wrap(&(Ok(x) | Err(x))) = wres { + drop::(x); + } + if let Wrap(Ok(x) | Err(x)) = wres { + drop::<&u8>(x); + } + let Wrap(Ok(mut x) | &Err(mut x)) = wres; + drop::(x); + let Wrap(&(Ok(x) | Err(x))) = wres; + drop::(x); + let Wrap(Ok(x) | Err(x)) = wres; + drop::<&u8>(x); + for Wrap(Ok(mut x) | &Err(mut x)) in std::iter::once(wres) { + drop::(x); + } + for Wrap(&(Ok(x) | Err(x))) in std::iter::once(wres) { + drop::(x); + } + for Wrap(Ok(x) | Err(x)) in std::iter::once(wres) { + drop::<&u8>(x); + } + fn fw1(Wrap(Ok(mut x) | &Err(mut x)): Wrap>) { + drop::(x); + } + fn fw2(Wrap(&(Ok(x) | Err(x))): Wrap>) { + drop::(x); + } + fn fw3(Wrap(Ok(x) | Err(x)): Wrap>) { + drop::<&u8>(x); + } + + // Nest some more: + + enum Tri

{ + A(P), + B(P), + C(P), + } + + let tri = &Tri::A(&Ok(0)); + let Tri::A(Ok(mut x) | Err(mut x)) + | Tri::B(&Ok(mut x) | Err(mut x)) + | &Tri::C(Ok(mut x) | Err(mut x)) = tri; + drop::(x); + + match tri { + Tri::A(Ok(mut x) | Err(mut x)) + | Tri::B(&Ok(mut x) | Err(mut x)) + | &Tri::C(Ok(mut x) | Err(mut x)) => drop::(x), + } +} From b5aca3128d5c0ee2441ec9ca9a9c3ae4f391ef16 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 5 Feb 2020 04:45:13 +0100 Subject: [PATCH 052/657] typeck: refactor default binding mode logic & improve docs --- src/librustc_typeck/check/pat.rs | 113 +++++++++++++++++-------------- 1 file changed, 64 insertions(+), 49 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index f9dee0e477f79..81e10e7a54010 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -89,6 +89,18 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } +const INITIAL_BM: BindingMode = BindingMode::BindByValue(hir::Mutability::Not); + +/// Mode for adjusting the expected type and binding mode. +enum AdjustMode { + /// Peel off all immediate reference types. + Peel, + /// Reset binding mode to the inital mode. + Reset, + /// Pass on the input binding mode and expected type. + Pass, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check the given top level pattern against the `expected` type. /// @@ -105,8 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Option, origin_expr: bool, ) { - let def_bm = BindingMode::BindByValue(hir::Mutability::Not); - self.check_pat(pat, expected, def_bm, TopInfo { expected, origin_expr, span }); + self.check_pat(pat, expected, INITIAL_BM, TopInfo { expected, origin_expr, span }); } /// Type check the given `pat` against the `expected` type @@ -123,12 +134,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); - let path_resolution = match &pat.kind { + let path_res = match &pat.kind { PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)), _ => None, }; - let is_nrp = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res)); - let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, is_nrp); + let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); + let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); let ty = match pat.kind { PatKind::Wild => expected, @@ -141,7 +152,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) } PatKind::Path(ref qpath) => { - self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected) + self.check_pat_path(pat, path_res.unwrap(), qpath, expected) } PatKind::Struct(ref qpath, fields, etc) => { self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti) @@ -223,64 +234,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingMode, - is_non_ref_pat: bool, + adjust_mode: AdjustMode, ) -> (Ty<'tcx>, BindingMode) { - if is_non_ref_pat { - debug!("pattern is non reference pattern"); - self.peel_off_references(pat, expected, def_bm) - } else { - // When you encounter a `&pat` pattern, reset to "by - // value". This is so that `x` and `y` here are by value, - // as they appear to be: - // - // ``` - // match &(&22, &44) { - // (&x, &y) => ... - // } - // ``` - // - // See issue #46688. - let def_bm = match pat.kind { - PatKind::Ref(..) => ty::BindByValue(hir::Mutability::Not), - _ => def_bm, - }; - (expected, def_bm) + match adjust_mode { + AdjustMode::Pass => (expected, def_bm), + AdjustMode::Reset => (expected, INITIAL_BM), + AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm), } } - /// Is the pattern a "non reference pattern"? + /// How should the binding mode and expected type be adjusted? + /// /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`. - fn is_non_ref_pat(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option) -> bool { - match pat.kind { + fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option) -> AdjustMode { + match &pat.kind { + // Type checking these product-like types successfully always require + // that the expected type be of those types and not reference types. PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Tuple(..) | PatKind::Box(_) | PatKind::Range(..) - | PatKind::Slice(..) => true, - PatKind::Lit(ref lt) => { - let ty = self.check_expr(lt); - match ty.kind { - ty::Ref(..) => false, - _ => true, - } - } + | PatKind::Slice(..) => AdjustMode::Peel, + // String and byte-string literals result in types `&str` and `&[u8]` respectively. + // All other literals result in non-reference types. + // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. + PatKind::Lit(lt) => match self.check_expr(lt).kind { + ty::Ref(..) => AdjustMode::Pass, + _ => AdjustMode::Peel, + }, PatKind::Path(_) => match opt_path_res.unwrap() { - Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => false, - _ => true, + // These constants can be of a reference type, e.g. `const X: &u8 = &0;`. + // Peeling the reference types too early will cause type checking failures. + // Although it would be possible to *also* peel the types of the constants too. + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => AdjustMode::Pass, + // In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which + // could successfully compile. The former being `Self` requires a unit struct. + // In either case, and unlike constants, the pattern itself cannot be + // a reference type wherefore peeling doesn't give up any expressivity. + _ => AdjustMode::Peel, }, - // FIXME(or_patterns; Centril | dlrobertson): To keep things compiling - // for or-patterns at the top level, we need to make `p_0 | ... | p_n` - // a "non reference pattern". For example the following currently compiles: + // When encountering a `& mut? pat` pattern, reset to "by value". + // This is so that `x` and `y` here are by value, as they appear to be: + // // ``` - // match &1 { - // e @ &(1...2) | e @ &(3...4) => {} - // _ => {} + // match &(&22, &44) { + // (&x, &y) => ... // } // ``` // - // We should consider whether we should do something special in nested or-patterns. - PatKind::Or(_) | PatKind::Wild | PatKind::Binding(..) | PatKind::Ref(..) => false, + // See issue #46688. + PatKind::Ref(..) => AdjustMode::Reset, + // A `_` pattern works with any expected type, so there's no need to do anything. + PatKind::Wild + // Bindings also work with whatever the expected type is, + // and moreover if we peel references off, that will give us the wrong binding type. + // Also, we can have a subpattern `binding @ pat`. + // Each side of the `@` should be treated independently (like with OR-patterns). + | PatKind::Binding(..) + // An OR-pattern just propagates to each individual alternative. + // This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`. + // In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`. + | PatKind::Or(_) => AdjustMode::Pass, } } @@ -508,7 +523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty; let eq_ty = match bm { ty::BindByReference(mutbl) => { - // If the binding is like `ref x | ref const x | ref mut x` + // If the binding is like `ref x | ref mut x`, // then `x` is assigned a value of type `&M T` where M is the // mutability and T is the expected type. // From 82684ad30a0929afba9463b89232730a9c6dadf4 Mon Sep 17 00:00:00 2001 From: Josh White Date: Wed, 5 Feb 2020 06:28:31 -0500 Subject: [PATCH 053/657] Added long error description & modifed error_codes.rs --- src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_error_codes/error_codes/E0637.md | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/librustc_error_codes/error_codes/E0637.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index c3d9ed088981d..ba43b29538d50 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -353,6 +353,7 @@ E0631: include_str!("./error_codes/E0631.md"), E0633: include_str!("./error_codes/E0633.md"), E0635: include_str!("./error_codes/E0635.md"), E0636: include_str!("./error_codes/E0636.md"), +E0637: include_str!("./error_codes/E0637.md"), E0638: include_str!("./error_codes/E0638.md"), E0639: include_str!("./error_codes/E0639.md"), E0641: include_str!("./error_codes/E0641.md"), @@ -584,7 +585,6 @@ E0746: include_str!("./error_codes/E0746.md"), E0632, // cannot provide explicit generic arguments when `impl Trait` is // used in argument position E0634, // type has conflicting packed representaton hints - E0637, // "'_" is not a valid lifetime bound E0640, // infer outlives requirements // E0645, // trait aliases not finished E0657, // `impl Trait` can only capture lifetimes bound at the fn level diff --git a/src/librustc_error_codes/error_codes/E0637.md b/src/librustc_error_codes/error_codes/E0637.md new file mode 100644 index 0000000000000..4f139b0ec49d6 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0637.md @@ -0,0 +1,22 @@ +The underscore `_` character has been used as the identifier for a lifetime. + +Erroneous code example: +``` +fn some_function<'_>(x: &'_ str, y: &'_ str) -> &'_ str { + //Some code +} +``` + +Lifetimes are named with 'ident, where ident is the name of the +lifetime or loop. The `_` character, which represents the ignore pattern, +cannot be used because it is a reserved lifetime name. +To fix this, use a single lowercase letter as the +lifetime identifier, such as `'a`. For more information, see [The Rust Book](https://doc.rust-lang.org/stable/book/appendix-02-operators.html#non-operator-symbols). + +Corrected code example: +``` +fn some_function<'a>(x: &'a str, y: &'a str) -> &'a str { + //Some code +} +``` + From 6bf2cc2229768faa8e86e0e8a9f5bd8ebfc817a2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 5 Feb 2020 09:44:03 +1100 Subject: [PATCH 054/657] Avoid instantiating many `Parser` structs in `generic_extension`. Currently, every iteration of the main loop in `generic_extension` instantiates a `Parser`, which is expensive because `Parser` is a large type. Many of those instantiations are only used immutably, particularly for simple-but-repetitive macros of the sort seen in `html5ever` and PR 68836. This commit initializes a single "base" parser outside the loop, and then uses `Cow` to avoid cloning it except for the mutating iterations. This speeds up `html5ever` runs by up to 15%. --- src/librustc_expand/lib.rs | 1 + src/librustc_expand/mbe/macro_parser.rs | 38 ++++----------- src/librustc_expand/mbe/macro_rules.rs | 62 ++++++++++++++++++------- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/src/librustc_expand/lib.rs b/src/librustc_expand/lib.rs index 4fe7c268c4f0b..f119c956ced04 100644 --- a/src/librustc_expand/lib.rs +++ b/src/librustc_expand/lib.rs @@ -1,3 +1,4 @@ +#![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(proc_macro_diagnostic)] diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index b14725fd731b1..78f22f3e443b1 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -78,13 +78,11 @@ use crate::mbe::{self, TokenTree}; use rustc_ast_pretty::pprust; use rustc_parse::parser::{FollowedByType, Parser, PathStyle}; -use rustc_parse::Directory; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, sym, Symbol}; use syntax::ast::{Ident, Name}; use syntax::ptr::P; use syntax::token::{self, DocComment, Nonterminal, Token}; -use syntax::tokenstream::TokenStream; use rustc_errors::{FatalError, PResult}; use rustc_span::Span; @@ -92,6 +90,7 @@ use smallvec::{smallvec, SmallVec}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use std::borrow::Cow; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::mem; use std::ops::{Deref, DerefMut}; @@ -613,28 +612,9 @@ fn inner_parse_loop<'root, 'tt>( Success(()) } -/// Use the given sequence of token trees (`ms`) as a matcher. Match the given token stream `tts` -/// against it and return the match. -/// -/// # Parameters -/// -/// - `sess`: The session into which errors are emitted -/// - `tts`: The tokenstream we are matching against the pattern `ms` -/// - `ms`: A sequence of token trees representing a pattern against which we are matching -/// - `directory`: Information about the file locations (needed for the black-box parser) -/// - `recurse_into_modules`: Whether or not to recurse into modules (needed for the black-box -/// parser) -pub(super) fn parse( - sess: &ParseSess, - tts: TokenStream, - ms: &[TokenTree], - directory: Option>, - recurse_into_modules: bool, -) -> NamedParseResult { - // Create a parser that can be used for the "black box" parts. - let mut parser = - Parser::new(sess, tts, directory, recurse_into_modules, true, rustc_parse::MACRO_ARGUMENTS); - +/// Use the given sequence of token trees (`ms`) as a matcher. Match the token +/// stream from the given `parser` against it and return the match. +pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> NamedParseResult { // A queue of possible matcher positions. We initialize it with the matcher position in which // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then // processes all of these possible matcher positions and produces possible next positions into @@ -659,7 +639,7 @@ pub(super) fn parse( // parsing from the black-box parser done. The result is that `next_items` will contain a // bunch of possible next matcher positions in `next_items`. match inner_parse_loop( - sess, + parser.sess, &mut cur_items, &mut next_items, &mut eof_items, @@ -684,7 +664,7 @@ pub(super) fn parse( if eof_items.len() == 1 { let matches = eof_items[0].matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap()); - return nameize(sess, ms, matches); + return nameize(parser.sess, ms, matches); } else if eof_items.len() > 1 { return Error( parser.token.span, @@ -736,13 +716,13 @@ pub(super) fn parse( // If there are no possible next positions AND we aren't waiting for the black-box parser, // then there is a syntax error. else if bb_items.is_empty() && next_items.is_empty() { - return Failure(parser.token.take(), "no rules expected this token in macro call"); + return Failure(parser.token.clone(), "no rules expected this token in macro call"); } // Dump all possible `next_items` into `cur_items` for the next iteration. else if !next_items.is_empty() { // Now process the next token cur_items.extend(next_items.drain(..)); - parser.bump(); + parser.to_mut().bump(); } // Finally, we have the case where we need to call the black-box parser to get some // nonterminal. @@ -754,7 +734,7 @@ pub(super) fn parse( let match_cur = item.match_cur; item.push_match( match_cur, - MatchedNonterminal(Lrc::new(parse_nt(&mut parser, span, ident.name))), + MatchedNonterminal(Lrc::new(parse_nt(parser.to_mut(), span, ident.name))), ); item.idx += 1; item.match_cur += 1; diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 29d41543fbf8c..9432790e78ced 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -1,11 +1,11 @@ -use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; +use crate::base::{DummyResult, ExpansionData, ExtCtxt, MacResult, TTMacroExpander}; use crate::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind}; use crate::mbe; use crate::mbe::macro_check; -use crate::mbe::macro_parser::parse; +use crate::mbe::macro_parser::parse_tt; use crate::mbe::macro_parser::{Error, Failure, Success}; -use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult}; +use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq}; use crate::mbe::transcribe::transcribe; use rustc_ast_pretty::pprust; @@ -166,9 +166,9 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } -fn trace_macros_note(cx: &mut ExtCtxt<'_>, sp: Span, message: String) { +fn trace_macros_note(cx_expansions: &mut FxHashMap>, sp: Span, message: String) { let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); - cx.expansions.entry(sp).or_default().push(message); + cx_expansions.entry(sp).or_default().push(message); } /// Given `lhses` and `rhses`, this is the new macro we create @@ -184,12 +184,36 @@ fn generic_extension<'cx>( ) -> Box { if cx.trace_macros() { let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone())); - trace_macros_note(cx, sp, msg); + trace_macros_note(&mut cx.expansions, sp, msg); } // Which arm's failure should we report? (the one furthest along) let mut best_failure: Option<(Token, &str)> = None; + + // We create a base parser that can be used for the "black box" parts. + // Every iteration needs a fresh copy of that base parser. However, the + // parser is not mutated on many of the iterations, particularly when + // dealing with macros like this: + // + // macro_rules! foo { + // ("a") => (A); + // ("b") => (B); + // ("c") => (C); + // // ... etc. (maybe hundreds more) + // } + // + // as seen in the `html5ever` benchmark. We use a `Cow` so that the base + // parser is only cloned when necessary (upon mutation). Furthermore, we + // reinitialize the `Cow` with the base parser at the start of every + // iteration, so that any mutated parsers are not reused. This is all quite + // hacky, but speeds up the `html5ever` benchmark significantly. (Issue + // 68836 suggests a more comprehensive but more complex change to deal with + // this situation.) + let base_parser = base_parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); + for (i, lhs) in lhses.iter().enumerate() { + let mut parser = Cow::Borrowed(&base_parser); + // try each arm's matchers let lhs_tt = match *lhs { mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], @@ -202,7 +226,7 @@ fn generic_extension<'cx>( // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. let mut gated_spans_snaphot = mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut()); - match parse_tt(cx, lhs_tt, arg.clone()) { + match parse_tt(&mut parser, lhs_tt) { Success(named_matches) => { // The matcher was `Success(..)`ful. // Merge the gated spans from parsing the matcher with the pre-existing ones. @@ -232,7 +256,7 @@ fn generic_extension<'cx>( if cx.trace_macros() { let msg = format!("to `{}`", pprust::tts_to_string(tts.clone())); - trace_macros_note(cx, sp, msg); + trace_macros_note(&mut cx.expansions, sp, msg); } let directory = Directory { @@ -269,6 +293,7 @@ fn generic_extension<'cx>( // Restore to the state before snapshotting and maybe try again. mem::swap(&mut gated_spans_snaphot, &mut cx.parse_sess.gated_spans.spans.borrow_mut()); } + drop(base_parser); let (token, label) = best_failure.expect("ran no matchers"); let span = token.span.substitute_dummy(sp); @@ -286,7 +311,9 @@ fn generic_extension<'cx>( mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => continue, }; - match parse_tt(cx, lhs_tt, arg.clone()) { + let base_parser = + base_parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); + match parse_tt(&mut Cow::Borrowed(&base_parser), lhs_tt) { Success(_) => { if comma_span.is_dummy() { err.note("you might be missing a comma"); @@ -368,7 +395,8 @@ pub fn compile_declarative_macro( ), ]; - let argument_map = match parse(sess, body, &argument_gram, None, true) { + let base_parser = Parser::new(sess, body, None, true, true, rustc_parse::MACRO_ARGUMENTS); + let argument_map = match parse_tt(&mut Cow::Borrowed(&base_parser), &argument_gram) { Success(m) => m, Failure(token, msg) => { let s = parse_failure_msg(&token); @@ -1184,14 +1212,16 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { } } -/// Use this token tree as a matcher to parse given tts. -fn parse_tt(cx: &ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream) -> NamedParseResult { - // `None` is because we're not interpolating +fn base_parser_from_cx<'cx>( + current_expansion: &'cx ExpansionData, + sess: &'cx ParseSess, + tts: TokenStream, +) -> Parser<'cx> { let directory = Directory { - path: Cow::from(cx.current_expansion.module.directory.as_path()), - ownership: cx.current_expansion.directory_ownership, + path: Cow::from(current_expansion.module.directory.as_path()), + ownership: current_expansion.directory_ownership, }; - parse(cx.parse_sess(), tts, mtch, Some(directory), true) + Parser::new(sess, tts, Some(directory), true, true, rustc_parse::MACRO_ARGUMENTS) } /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For From f840a955bd449810e75d8320b4c46482d6dbdec1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 5 Feb 2020 14:33:08 +1100 Subject: [PATCH 055/657] Remove the `Cow` from `Directory`. The previous commit wrapped `Parser` within a `Cow` for the hot macro parsing path. As a result, there's no need for the `Cow` within `Directory`, because it lies within `Parser`. --- src/librustc_expand/mbe/macro_rules.rs | 4 ++-- src/librustc_parse/lib.rs | 9 ++++----- src/librustc_parse/parser/mod.rs | 9 ++++----- src/librustc_parse/parser/module.rs | 6 +++--- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 9432790e78ced..9e6edee265c98 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -260,7 +260,7 @@ fn generic_extension<'cx>( } let directory = Directory { - path: Cow::from(cx.current_expansion.module.directory.as_path()), + path: cx.current_expansion.module.directory.clone(), ownership: cx.current_expansion.directory_ownership, }; let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None); @@ -1218,7 +1218,7 @@ fn base_parser_from_cx<'cx>( tts: TokenStream, ) -> Parser<'cx> { let directory = Directory { - path: Cow::from(current_expansion.module.directory.as_path()), + path: current_expansion.module.directory.clone(), ownership: current_expansion.directory_ownership, }; Parser::new(sess, tts, Some(directory), true, true, rustc_parse::MACRO_ARGUMENTS) diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index cd674e3c5ebef..4aad2c0f68a29 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -12,8 +12,7 @@ use syntax::ast; use syntax::token::{self, Nonterminal}; use syntax::tokenstream::{self, TokenStream, TokenTree}; -use std::borrow::Cow; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str; use log::info; @@ -29,8 +28,8 @@ pub mod validate_attr; pub mod config; #[derive(Clone)] -pub struct Directory<'a> { - pub path: Cow<'a, Path>, +pub struct Directory { + pub path: PathBuf, pub ownership: DirectoryOwnership, } @@ -274,7 +273,7 @@ pub fn stream_to_parser<'a>( pub fn stream_to_parser_with_base_dir<'a>( sess: &'a ParseSess, stream: TokenStream, - base_dir: Directory<'a>, + base_dir: Directory, ) -> Parser<'a> { Parser::new(sess, stream, Some(base_dir), true, false, None) } diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 8c1839da1cb8f..cb95750d984e9 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -29,7 +29,6 @@ use syntax::token::{self, DelimToken, Token, TokenKind}; use syntax::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use syntax::util::comments::{doc_comment_style, strip_doc_comment_decoration}; -use std::borrow::Cow; use std::path::PathBuf; use std::{cmp, mem, slice}; @@ -114,7 +113,7 @@ pub struct Parser<'a> { prev_token_kind: PrevTokenKind, restrictions: Restrictions, /// Used to determine the path to externally loaded source files. - pub(super) directory: Directory<'a>, + pub(super) directory: Directory, /// `true` to parse sub-modules in other files. // Public for rustfmt usage. pub recurse_into_file_modules: bool, @@ -376,7 +375,7 @@ impl<'a> Parser<'a> { pub fn new( sess: &'a ParseSess, tokens: TokenStream, - directory: Option>, + directory: Option, recurse_into_file_modules: bool, desugar_doc_comments: bool, subparser_name: Option<&'static str>, @@ -390,7 +389,7 @@ impl<'a> Parser<'a> { restrictions: Restrictions::empty(), recurse_into_file_modules, directory: Directory { - path: Cow::from(PathBuf::new()), + path: PathBuf::new(), ownership: DirectoryOwnership::Owned { relative: None }, }, root_module_name: None, @@ -418,7 +417,7 @@ impl<'a> Parser<'a> { &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path { if let Some(directory_path) = path.parent() { - parser.directory.path = Cow::from(directory_path.to_path_buf()); + parser.directory.path = directory_path.to_path_buf(); } } } diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 6ce94d3c6793c..0c8fad03d8690 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -285,7 +285,7 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { - self.directory.path.to_mut().push(&*path.as_str()); + self.directory.path.push(&*path.as_str()); self.directory.ownership = DirectoryOwnership::Owned { relative: None }; } else { // We have to push on the current module name in the case of relative @@ -297,10 +297,10 @@ impl<'a> Parser<'a> { if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership { if let Some(ident) = relative.take() { // remove the relative offset - self.directory.path.to_mut().push(&*ident.as_str()); + self.directory.path.push(&*ident.as_str()); } } - self.directory.path.to_mut().push(&*id.as_str()); + self.directory.path.push(&*id.as_str()); } } } From 2a13b24d369b8619f0197993cd5dc60f7217ed72 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 5 Feb 2020 15:09:24 +1100 Subject: [PATCH 056/657] Change condition ordering in `parse_tt`. This is a small win, because `Failure` is much more common than `Success`. --- src/librustc_expand/mbe/macro_parser.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index 78f22f3e443b1..5bf7602ea6e8f 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -689,9 +689,14 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na // unnecessary implicit clone later in Rc::make_mut. drop(eof_items); + // If there are no possible next positions AND we aren't waiting for the black-box parser, + // then there is a syntax error. + if bb_items.is_empty() && next_items.is_empty() { + return Failure(parser.token.clone(), "no rules expected this token in macro call"); + } // Another possibility is that we need to call out to parse some rust nonterminal // (black-box) parser. However, if there is not EXACTLY ONE of these, something is wrong. - if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 { + else if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 { let nts = bb_items .iter() .map(|item| match item.top_elts.get_tt(item.idx) { @@ -713,11 +718,6 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na ), ); } - // If there are no possible next positions AND we aren't waiting for the black-box parser, - // then there is a syntax error. - else if bb_items.is_empty() && next_items.is_empty() { - return Failure(parser.token.clone(), "no rules expected this token in macro call"); - } // Dump all possible `next_items` into `cur_items` for the next iteration. else if !next_items.is_empty() { // Now process the next token From b82f6c575e53f06c3645f66a9d480b4f025ee39e Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 6 Feb 2020 11:04:46 +0200 Subject: [PATCH 057/657] rustc_codegen_llvm: always set AlwaysPreserve on all debuginfo variables. --- src/librustc_codegen_llvm/debuginfo/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index c4a52a73e25d9..eb22d74ba3e47 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -569,7 +569,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { file_metadata, loc.line as c_uint, type_metadata, - self.sess().opts.optimize != config::OptLevel::No, + true, DIFlags::FlagZero, argument_index, align.bytes() as u32, From 4a1c6ce23547346757fa8b61207aea7eb6997aa3 Mon Sep 17 00:00:00 2001 From: Josh White Date: Wed, 5 Feb 2020 06:28:31 -0500 Subject: [PATCH 058/657] Added long error description & modifed error_codes.rs --- src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_error_codes/error_codes/E0637.md | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/librustc_error_codes/error_codes/E0637.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index c3d9ed088981d..ba43b29538d50 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -353,6 +353,7 @@ E0631: include_str!("./error_codes/E0631.md"), E0633: include_str!("./error_codes/E0633.md"), E0635: include_str!("./error_codes/E0635.md"), E0636: include_str!("./error_codes/E0636.md"), +E0637: include_str!("./error_codes/E0637.md"), E0638: include_str!("./error_codes/E0638.md"), E0639: include_str!("./error_codes/E0639.md"), E0641: include_str!("./error_codes/E0641.md"), @@ -584,7 +585,6 @@ E0746: include_str!("./error_codes/E0746.md"), E0632, // cannot provide explicit generic arguments when `impl Trait` is // used in argument position E0634, // type has conflicting packed representaton hints - E0637, // "'_" is not a valid lifetime bound E0640, // infer outlives requirements // E0645, // trait aliases not finished E0657, // `impl Trait` can only capture lifetimes bound at the fn level diff --git a/src/librustc_error_codes/error_codes/E0637.md b/src/librustc_error_codes/error_codes/E0637.md new file mode 100644 index 0000000000000..4f139b0ec49d6 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0637.md @@ -0,0 +1,22 @@ +The underscore `_` character has been used as the identifier for a lifetime. + +Erroneous code example: +``` +fn some_function<'_>(x: &'_ str, y: &'_ str) -> &'_ str { + //Some code +} +``` + +Lifetimes are named with 'ident, where ident is the name of the +lifetime or loop. The `_` character, which represents the ignore pattern, +cannot be used because it is a reserved lifetime name. +To fix this, use a single lowercase letter as the +lifetime identifier, such as `'a`. For more information, see [The Rust Book](https://doc.rust-lang.org/stable/book/appendix-02-operators.html#non-operator-symbols). + +Corrected code example: +``` +fn some_function<'a>(x: &'a str, y: &'a str) -> &'a str { + //Some code +} +``` + From 201a262ac4a9cb61e4e94d8e841a973fee0edc86 Mon Sep 17 00:00:00 2001 From: Josh White Date: Thu, 6 Feb 2020 16:07:35 -0500 Subject: [PATCH 059/657] Revised error long description --- src/librustc_error_codes/error_codes/E0637.md | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0637.md b/src/librustc_error_codes/error_codes/E0637.md index 4f139b0ec49d6..f5da357534e26 100644 --- a/src/librustc_error_codes/error_codes/E0637.md +++ b/src/librustc_error_codes/error_codes/E0637.md @@ -1,22 +1,34 @@ -The underscore `_` character has been used as the identifier for a lifetime. + +An underscore `_` character or a numeric literal `u8`, `i32`, `f64`, etc has +been used as the identifier for a lifetime. Erroneous code example: ``` -fn some_function<'_>(x: &'_ str, y: &'_ str) -> &'_ str { +fn some_function<'_>(string1: &'_ str, string2: &'_ str) -> &'_ str { + //Some code +} +``` +or Erroneous code example 2: +``` +fn some_function<'u8>(string1: &'u8 str, string2: &'u8 str) -> &'u8 str { //Some code } ``` -Lifetimes are named with 'ident, where ident is the name of the -lifetime or loop. The `_` character, which represents the ignore pattern, -cannot be used because it is a reserved lifetime name. -To fix this, use a single lowercase letter as the -lifetime identifier, such as `'a`. For more information, see [The Rust Book](https://doc.rust-lang.org/stable/book/appendix-02-operators.html#non-operator-symbols). +Lifetimes are named with `'ident`, where ident is the name of the lifetime or +loop. The `_` character, which represents the ignore pattern, cannot be used +as the identifier because it is a reserved lifetime name. Numeric literals are +also invalid lifetime identifiers and will cause this error to be thrown. To fix +this, use a series of lowercase letters as the lifetime identifier. Often a +single lowercase letter, such as `'a`, is sufficient. For more information, see +[the book][bk-no]. Corrected code example: ``` -fn some_function<'a>(x: &'a str, y: &'a str) -> &'a str { +fn some_function<'a>(string1: &'a str, string2: &'a str) -> &'a str { //Some code } ``` +[bk-no]: https://doc.rust-lang.org/book/appendix-02-operators.html#non-operator-symbols + From 178de46116b4fc8c1d9b30007f5e5ed24c809881 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 12:55:13 -0500 Subject: [PATCH 060/657] Add primitive module to libcore/std This re-exports the primitive types from libcore at `core::primitive` to allow macro authors to have a reliable location to use them from. --- src/libcore/lib.rs | 3 + src/libcore/primitive.rs | 67 +++++++++++++++++++ src/libstd/lib.rs | 5 +- .../resolve/resolve-primitive-fallback.stderr | 5 ++ src/test/ui/shadow-bool.rs | 18 +++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/libcore/primitive.rs create mode 100644 src/test/ui/shadow-bool.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1fd70e1a1b049..257a6d371b730 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -262,6 +262,9 @@ mod bool; mod tuple; mod unit; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub mod primitive; + // Pull in the `core_arch` crate directly into libcore. The contents of // `core_arch` are in a different repository: rust-lang/stdarch. // diff --git a/src/libcore/primitive.rs b/src/libcore/primitive.rs new file mode 100644 index 0000000000000..d37bbfaf5dfd4 --- /dev/null +++ b/src/libcore/primitive.rs @@ -0,0 +1,67 @@ +//! This module reexports the primitive types to allow usage that is not +//! possibly shadowed by other declared types. +//! +//! This is normally only useful in macro generated code. +//! +//! An example of this is when generating a new struct and an impl for it: +//! +//! ```rust,compile_fail +//! pub struct bool; +//! +//! impl QueryId for bool { +//! const SOME_PROPERTY: bool = true; +//! } +//! +//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; } +//! ``` +//! +//! Note that the `SOME_PROPERTY` associated constant would not compile, as its +//! type `bool` refers to the struct, rather than to the primitive bool type. +//! +//! A correct implementation could look like: +//! +//! ```rust +//! # #[allow(non_camel_case_types)] +//! pub struct bool; +//! +//! impl QueryId for bool { +//! const SOME_PROPERTY: core::primitive::bool = true; +//! } +//! +//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; } +//! ``` + +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use bool; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use char; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use f32; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use f64; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i128; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i16; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i32; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i64; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use i8; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use isize; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use str; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u128; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u16; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u32; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u64; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use u8; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use usize; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f9c9f224730da..2b54481ab5670 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -233,12 +233,12 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(atomic_mut_ptr)] #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] #![feature(assoc_int_consts)] #![feature(associated_type_bounds)] +#![feature(atomic_mut_ptr)] #![feature(box_syntax)] #![feature(c_variadic)] #![feature(cfg_target_has_atomic)] @@ -550,6 +550,9 @@ pub use core::{ trace_macros, }; +#[stable(feature = "core_primitive", since = "1.42.0")] +pub use core::primitive; + // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/test/ui/resolve/resolve-primitive-fallback.stderr b/src/test/ui/resolve/resolve-primitive-fallback.stderr index 92c2a03298381..72a854346fad0 100644 --- a/src/test/ui/resolve/resolve-primitive-fallback.stderr +++ b/src/test/ui/resolve/resolve-primitive-fallback.stderr @@ -9,6 +9,11 @@ error[E0412]: cannot find type `u8` in the crate root | LL | let _: ::u8; | ^^ not found in the crate root + | +help: possible candidate is found in another module, you can import it into scope + | +LL | use std::primitive::u8; + | error[E0061]: this function takes 0 parameters but 1 parameter was supplied --> $DIR/resolve-primitive-fallback.rs:3:5 diff --git a/src/test/ui/shadow-bool.rs b/src/test/ui/shadow-bool.rs new file mode 100644 index 0000000000000..f290a329eaac2 --- /dev/null +++ b/src/test/ui/shadow-bool.rs @@ -0,0 +1,18 @@ +// check-pass + +mod bar { + pub trait QueryId { + const SOME_PROPERTY: bool; + } +} + +use bar::QueryId; + +#[allow(non_camel_case_types)] +pub struct bool; + +impl QueryId for bool { + const SOME_PROPERTY: core::primitive::bool = true; +} + +fn main() {} From 1923586286dea1a0f8ece43056126fc2ecc89337 Mon Sep 17 00:00:00 2001 From: Josh White Date: Thu, 6 Feb 2020 16:54:24 -0500 Subject: [PATCH 061/657] Edited error description --- src/librustc_error_codes/error_codes/E0637.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0637.md b/src/librustc_error_codes/error_codes/E0637.md index f5da357534e26..44a365be7e0f7 100644 --- a/src/librustc_error_codes/error_codes/E0637.md +++ b/src/librustc_error_codes/error_codes/E0637.md @@ -2,15 +2,15 @@ An underscore `_` character or a numeric literal `u8`, `i32`, `f64`, etc has been used as the identifier for a lifetime. -Erroneous code example: +Erroneous code example 1: ``` -fn some_function<'_>(string1: &'_ str, string2: &'_ str) -> &'_ str { +fn some_function<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { //Some code } ``` or Erroneous code example 2: ``` -fn some_function<'u8>(string1: &'u8 str, string2: &'u8 str) -> &'u8 str { +fn some_function<'u8>(str1: &'u8 str, str2: &'u8 str) -> &'u8 str { //Some code } ``` @@ -25,7 +25,7 @@ single lowercase letter, such as `'a`, is sufficient. For more information, see Corrected code example: ``` -fn some_function<'a>(string1: &'a str, string2: &'a str) -> &'a str { +fn some_function<'a>(str1: &'a str, str2: &'a str) -> &'a str { //Some code } ``` From 78df44655aa8547baa25ee9ca49699ad82c7f76d Mon Sep 17 00:00:00 2001 From: Josh White Date: Thu, 6 Feb 2020 17:28:03 -0500 Subject: [PATCH 062/657] Tidied up the long error description --- src/librustc_error_codes/error_codes/E0637.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0637.md b/src/librustc_error_codes/error_codes/E0637.md index 44a365be7e0f7..978cf273c94d3 100644 --- a/src/librustc_error_codes/error_codes/E0637.md +++ b/src/librustc_error_codes/error_codes/E0637.md @@ -1,6 +1,5 @@ - An underscore `_` character or a numeric literal `u8`, `i32`, `f64`, etc has -been used as the identifier for a lifetime. +been used as the identifier for a lifetime. Erroneous code example 1: ``` @@ -29,6 +28,4 @@ fn some_function<'a>(str1: &'a str, str2: &'a str) -> &'a str { //Some code } ``` - [bk-no]: https://doc.rust-lang.org/book/appendix-02-operators.html#non-operator-symbols - From 8251e12950159c5802dd3995b14be7cf4fa99acd Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 7 Feb 2020 13:59:43 +0800 Subject: [PATCH 063/657] Don't use the word 'unwrap' to describe core unwrapping functions It's tautological, and Rust-specific Jargon. This changes various Option/Result methods to consistently describe unwrapping behavior using the words "return", "contain", "consume". It also renames the closure argument of `Return::unwrap_or_else` to `default` to be consistent with `Option`. --- src/libcore/option.rs | 26 ++++++++++++++++---------- src/libcore/result.rs | 38 ++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index ad0491f888cc7..c7b36d8ad6362 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -317,7 +317,7 @@ impl Option { // Getting to contained values ///////////////////////////////////////////////////////////////////////// - /// Unwraps an option, yielding the content of a [`Some`]. + /// Returns the contained [`Some`] value, consuming the `self` value. /// /// # Panics /// @@ -348,17 +348,22 @@ impl Option { } } - /// Moves the value `v` out of the `Option` if it is [`Some(v)`]. + /// Returns the contained [`Some`] value, consuming the `self` value. /// - /// In general, because this function may panic, its use is discouraged. + /// Because this function may panic, its use is generally discouraged. /// Instead, prefer to use pattern matching and handle the [`None`] - /// case explicitly. + /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or + /// [`unwrap_or_default`]. + /// + /// [`unwrap_or`]: #method.unwrap_or + /// [`unwrap_or_else`]: #method.unwrap_or_else + /// [`unwrap_or_default`]: #method.unwrap_or_default /// /// # Panics /// /// Panics if the self value equals [`None`]. /// - /// [`Some(v)`]: #variant.Some + /// [`Some`]: #variant.Some /// [`None`]: #variant.None /// /// # Examples @@ -382,12 +387,13 @@ impl Option { } } - /// Returns the contained value or a default. + /// Returns the contained [`Some`] value or a provided default. /// /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`unwrap_or_else`], /// which is lazily evaluated. /// + /// [`Some`]: #variant.Some /// [`unwrap_or_else`]: #method.unwrap_or_else /// /// # Examples @@ -405,7 +411,7 @@ impl Option { } } - /// Returns the contained value or computes it from a closure. + /// Returns the contained [`Some`] value or computes it from a closure. /// /// # Examples /// @@ -980,7 +986,7 @@ impl Option<&mut T> { } impl Option { - /// Unwraps an option, expecting [`None`] and returning nothing. + /// Consumes `self` while expecting [`None`] and returning nothing. /// /// # Panics /// @@ -1023,7 +1029,7 @@ impl Option { } } - /// Unwraps an option, expecting [`None`] and returning nothing. + /// Consumes `self` while expecting [`None`] and returning nothing. /// /// # Panics /// @@ -1068,7 +1074,7 @@ impl Option { } impl Option { - /// Returns the contained value or a default + /// Returns the contained [`Some`] value or a default /// /// Consumes the `self` argument then, if [`Some`], returns the contained /// value, otherwise if [`None`], returns the [default value] for that diff --git a/src/libcore/result.rs b/src/libcore/result.rs index ee28946f0da7a..022701c949815 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -792,8 +792,7 @@ impl Result { } } - /// Unwraps a result, yielding the content of an [`Ok`]. - /// Else, it returns `optb`. + /// Returns the contained [`Ok`] value or a provided default. /// /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`unwrap_or_else`], @@ -808,27 +807,25 @@ impl Result { /// Basic usage: /// /// ``` - /// let optb = 2; + /// let default = 2; /// let x: Result = Ok(9); - /// assert_eq!(x.unwrap_or(optb), 9); + /// assert_eq!(x.unwrap_or(default), 9); /// /// let x: Result = Err("error"); - /// assert_eq!(x.unwrap_or(optb), optb); + /// assert_eq!(x.unwrap_or(default), default); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or(self, optb: T) -> T { + pub fn unwrap_or(self, default: T) -> T { match self { Ok(t) => t, - Err(_) => optb, + Err(_) => default, } } - /// Unwraps a result, yielding the content of an [`Ok`]. - /// If the value is an [`Err`] then it calls `op` with its value. + /// Returns the contained [`Ok`] value or computes it from a closure. /// /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -931,7 +928,7 @@ impl Result<&mut T, E> { } impl Result { - /// Unwraps a result, yielding the content of an [`Ok`]. + /// Returns the contained [`Ok`] value, consuming the `self` value. /// /// # Panics /// @@ -959,7 +956,16 @@ impl Result { } } - /// Unwraps a result, yielding the content of an [`Ok`]. + /// Returns the contained [`Ok`] value, consuming the `self` value. + /// + /// Because this function may panic, its use is generally discouraged. + /// Instead, prefer to use pattern matching and handle the [`Err`] + /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or + /// [`unwrap_or_default`]. + /// + /// [`unwrap_or`]: #method.unwrap_or + /// [`unwrap_or_else`]: #method.unwrap_or_else + /// [`unwrap_or_default`]: #method.unwrap_or_default /// /// # Panics /// @@ -994,7 +1000,7 @@ impl Result { } impl Result { - /// Unwraps a result, yielding the content of an [`Err`]. + /// Returns the contained [`Err`] value, consuming the `self` value. /// /// # Panics /// @@ -1022,7 +1028,7 @@ impl Result { } } - /// Unwraps a result, yielding the content of an [`Err`]. + /// Returns the contained [`Err`] value, consuming the `self` value. /// /// # Panics /// @@ -1056,7 +1062,7 @@ impl Result { } impl Result { - /// Returns the contained value or a default + /// Returns the contained [`Ok`] value or a default /// /// Consumes the `self` argument then, if [`Ok`], returns the contained /// value, otherwise if [`Err`], returns the default value for that @@ -1095,7 +1101,7 @@ impl Result { #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] impl> Result { - /// Unwraps a result that can never be an [`Err`], yielding the content of the [`Ok`]. + /// Returns the contained [`Ok`] value, but never panics. /// /// Unlike [`unwrap`], this method is known to never panic on the /// result types it is implemented for. Therefore, it can be used From d252791a93b7ad26c9af63b68d223164a3678e8e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 19:14:21 +0100 Subject: [PATCH 064/657] Remove unused feature gate from librustc_incremental --- src/librustc_incremental/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 7ce4def2886b8..ca824fde7efc1 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -3,7 +3,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(specialization)] #![recursion_limit = "256"] #[macro_use] From 6638b867022fb1d2a56b6ed5f899e9fd00183396 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 19:18:04 +0100 Subject: [PATCH 065/657] Remove unused feature gates from librustc_interface --- src/librustc_interface/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index e4e6849ab8e59..ba1e2216ca805 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -2,10 +2,8 @@ #![feature(box_syntax)] #![feature(set_stdio)] #![feature(nll)] -#![feature(arbitrary_self_types)] #![feature(generator_trait)] #![feature(generators)] -#![cfg_attr(unix, feature(libc))] #![recursion_limit = "256"] #[cfg(unix)] From 74994af266a83edb9f82f8175de0c5c84bd849a0 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 19:19:03 +0100 Subject: [PATCH 066/657] Remove unused feature gate from librustc_lint --- src/librustc_lint/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 78e9d0f14f2de..6e2db65c84005 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -28,7 +28,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(test, feature(test))] #![feature(bool_to_option)] -#![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] #![feature(never_type)] From 6305c683cb63a3a83641aaf4ec763c290fc52b0c Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 19:51:00 +0100 Subject: [PATCH 067/657] Remove unused feature gates from librustc_metadata --- src/librustc_metadata/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index d94f23ff8bc6a..d4cc3c32616ac 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -1,15 +1,11 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] -#![feature(box_patterns)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] -#![feature(libc)] #![feature(nll)] #![feature(proc_macro_internals)] -#![feature(proc_macro_quote)] -#![feature(rustc_private)] #![feature(specialization)] #![feature(stmt_expr_attributes)] #![recursion_limit = "256"] From 341594e1969795e4d48840ec48f0d6309ea0fa3a Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 20:04:44 +0100 Subject: [PATCH 068/657] Remove unused feature gates from librustc_mir --- src/librustc_mir/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f064869d66471..4f1b90e34cf00 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -6,21 +6,15 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(nll)] #![feature(in_band_lifetimes)] -#![feature(inner_deref)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] -#![feature(core_intrinsics)] -#![feature(decl_macro)] #![feature(drain_filter)] #![feature(exhaustive_patterns)] #![feature(iter_order_by)] #![feature(never_type)] #![feature(specialization)] -#![feature(try_trait)] -#![feature(unicode_internals)] -#![feature(slice_concat_ext)] #![feature(trusted_len)] #![feature(try_blocks)] #![feature(associated_type_bounds)] From 1bfba4fbce25ac02a8023a817eee2c539c47c37e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 20:08:15 +0100 Subject: [PATCH 069/657] Remove unused feature gate from librustc_resolve --- src/librustc_resolve/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index af4ba4c0eb20e..2e63c3e170605 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -9,7 +9,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] -#![feature(label_break_value)] #![feature(nll)] #![recursion_limit = "256"] From 1a26c1c67acd9360bed7121b917581c9d69fc214 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 20:09:43 +0100 Subject: [PATCH 070/657] Remove unused feature gate from librustc_target --- src/librustc_target/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index a9db0254a7d11..71150e74f70d4 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -8,7 +8,6 @@ //! LLVM. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(box_syntax)] #![feature(bool_to_option)] #![feature(nll)] From 8f672cd7dd9139947feb6b04f8b20dc27735dcc9 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 20:12:28 +0100 Subject: [PATCH 071/657] Remove unused feature gates from librustc_typeck --- src/librustc_typeck/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 05ea9b1ac56dc..474868f0dd6c4 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -58,10 +58,8 @@ This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(non_camel_case_types)] #![feature(bool_to_option)] -#![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] -#![feature(exhaustive_patterns)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(try_blocks)] From b7599990d492e2650f343ab61e1ce5d390996284 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 20:14:27 +0100 Subject: [PATCH 072/657] Remove unused feature gates from librustdoc --- src/librustdoc/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ed3f0f94e0ed8..4e0a2d9427431 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -3,19 +3,15 @@ html_playground_url = "https://play.rust-lang.org/" )] #![feature(rustc_private)] -#![feature(arbitrary_self_types)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(set_stdio)] #![feature(test)] #![feature(vec_remove_item)] #![feature(ptr_offset_from)] #![feature(crate_visibility_modifier)] -#![feature(drain_filter)] #![feature(never_type)] -#![feature(unicode_internals)] #![recursion_limit = "256"] extern crate env_logger; From 9d6bdccd9e835c46de1f703a31cb00ccfeab9e84 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 20:15:15 +0100 Subject: [PATCH 073/657] Remove unused feature gate from libserialize --- src/libserialize/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 280fb078f7de4..b990e71bef0dd 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -10,7 +10,6 @@ Core encoding and decoding interfaces. test(attr(allow(unused_variables), deny(warnings))) )] #![feature(box_syntax)] -#![feature(core_intrinsics)] #![feature(specialization)] #![feature(never_type)] #![feature(nll)] From 91d01e7c6b3c646a183f9f0caab53b696b3feea8 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 17 Nov 2019 20:17:38 +0100 Subject: [PATCH 074/657] Remove unused feature gates from libsyntax_pos --- src/librustc_span/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 413bd77daae24..ac9c3360b860d 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -8,9 +8,6 @@ #![feature(crate_visibility_modifier)] #![feature(nll)] #![feature(optin_builtin_traits)] -#![feature(rustc_attrs)] -#![feature(specialization)] -#![feature(step_trait)] use rustc_data_structures::AtomicRef; use rustc_macros::HashStable_Generic; From e38665676b291eeacf1b9ba54a476588da1230c1 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 23 Dec 2019 16:26:53 +0100 Subject: [PATCH 075/657] Rustfmt --- src/librustc_codegen_llvm/metadata.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs index 36b12f1a7b184..0f30c2c020de7 100644 --- a/src/librustc_codegen_llvm/metadata.rs +++ b/src/librustc_codegen_llvm/metadata.rs @@ -22,10 +22,11 @@ impl MetadataLoader for LlvmMetadataLoader { // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap // internally to read the file. We also avoid even using a memcpy by // just keeping the archive along while the metadata is in use. - let archive = ArchiveRO::open(filename).map(|ar| OwningRef::new(Box::new(ar))).map_err(|e| { - debug!("llvm didn't like `{}`: {}", filename.display(), e); - format!("failed to read rlib metadata in '{}': {}", filename.display(), e) - })?; + let archive = + ArchiveRO::open(filename).map(|ar| OwningRef::new(Box::new(ar))).map_err(|e| { + debug!("llvm didn't like `{}`: {}", filename.display(), e); + format!("failed to read rlib metadata in '{}': {}", filename.display(), e) + })?; let buf: OwningRef<_, [u8]> = archive.try_map(|ar| { ar.iter() .filter_map(|s| s.ok()) @@ -44,9 +45,10 @@ impl MetadataLoader for LlvmMetadataLoader { let buf = path_to_c_string(filename); let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()) .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?; - let of = ObjectFile::new(mb).map(|of| OwningRef::new(Box::new(of))).ok_or_else(|| { - format!("provided path not an object file: '{}'", filename.display()) - })?; + let of = + ObjectFile::new(mb).map(|of| OwningRef::new(Box::new(of))).ok_or_else(|| { + format!("provided path not an object file: '{}'", filename.display()) + })?; let buf = of.try_map(|of| search_meta_section(of, target, filename))?; Ok(rustc_erase_owner!(buf)) } From 5827d78f18ce688a96ecd5a20defda07c8834936 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 25 Jan 2020 12:13:14 +0100 Subject: [PATCH 076/657] Fix test --- src/test/ui/consts/miri_unleashed/mutable_const2.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/miri_unleashed/mutable_const2.stderr b/src/test/ui/consts/miri_unleashed/mutable_const2.stderr index a316d8f1698ac..3eb8e0ec18288 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const2.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_const2.stderr @@ -10,7 +10,7 @@ error: internal compiler error: mutable allocation in constant LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:357:17 +thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:355:17 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: internal compiler error: unexpected panic From 73936ab57ad567802a613157ae9db0cccf31eda3 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko Date: Fri, 7 Feb 2020 04:03:54 +0300 Subject: [PATCH 077/657] print generic bounds on associated types --- src/librustc_ast_pretty/pprust.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index d9077d1606f3a..78bf149f0e01a 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1074,12 +1074,15 @@ impl<'a> State<'a> { fn print_associated_type( &mut self, ident: ast::Ident, + generics: &ast::Generics, bounds: &ast::GenericBounds, ty: Option<&ast::Ty>, ) { self.word_space("type"); self.print_ident(ident); + self.print_generic_params(&generics.params); self.print_type_bounds(":", bounds); + self.print_where_clause(&generics.where_clause); if let Some(ty) = ty { self.s.space(); self.word_space("="); @@ -1474,7 +1477,7 @@ impl<'a> State<'a> { self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs); } ast::AssocItemKind::TyAlias(bounds, ty) => { - self.print_associated_type(item.ident, bounds, ty.as_deref()); + self.print_associated_type(item.ident, &item.generics, bounds, ty.as_deref()); } ast::AssocItemKind::Macro(mac) => { self.print_mac(mac); From ab6ea2bba771836ebbf8759e718fedd2c6d229d2 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko Date: Fri, 7 Feb 2020 05:17:38 +0300 Subject: [PATCH 078/657] add regression test --- src/test/pretty/gat-bounds.pp | 25 +++++++++++++++++++++++++ src/test/pretty/gat-bounds.rs | 17 +++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/test/pretty/gat-bounds.pp create mode 100644 src/test/pretty/gat-bounds.rs diff --git a/src/test/pretty/gat-bounds.pp b/src/test/pretty/gat-bounds.pp new file mode 100644 index 0000000000000..0c95add490110 --- /dev/null +++ b/src/test/pretty/gat-bounds.pp @@ -0,0 +1,25 @@ +// Check that associated types print generic parameters and where clauses. +// See issue #67509. + +// pretty-compare-only +// pp-exact:gat-bounds.pp + +#![feature(generic_associated_types)] + +trait X { + type + Y: Trait + where + Self: Sized; +} + +impl X for () { + type + Y + where + Self: Sized + = + u32; +} + +fn main() { } diff --git a/src/test/pretty/gat-bounds.rs b/src/test/pretty/gat-bounds.rs new file mode 100644 index 0000000000000..1275f432a3c50 --- /dev/null +++ b/src/test/pretty/gat-bounds.rs @@ -0,0 +1,17 @@ +// Check that associated types print generic parameters and where clauses. +// See issue #67509. + +// pretty-compare-only +// pp-exact:gat-bounds.pp + +#![feature(generic_associated_types)] + +trait X { + type Y: Trait where Self: Sized; +} + +impl X for () { + type Y where Self: Sized = u32; +} + +fn main() { } From bf82582d6f8de744df5c34e80a04ad72f40afed7 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko Date: Fri, 7 Feb 2020 18:27:12 +0300 Subject: [PATCH 079/657] add hir printing --- src/librustc_hir/print.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index b0d2f96c71a03..071c3de4b1c2c 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -454,14 +454,17 @@ impl<'a> State<'a> { fn print_associated_type( &mut self, ident: ast::Ident, + generics: &hir::Generics<'_>, bounds: Option>, ty: Option<&hir::Ty<'_>>, ) { self.word_space("type"); self.print_ident(ident); + self.print_generic_params(&generics.params); if let Some(bounds) = bounds { self.print_bounds(":", bounds); } + self.print_where_clause(&generics.where_clause); if let Some(ty) = ty { self.s.space(); self.word_space("="); @@ -902,6 +905,7 @@ impl<'a> State<'a> { hir::TraitItemKind::Type(ref bounds, ref default) => { self.print_associated_type( ti.ident, + &ti.generics, Some(bounds), default.as_ref().map(|ty| &**ty), ); @@ -930,7 +934,7 @@ impl<'a> State<'a> { self.ann.nested(self, Nested::Body(body)); } hir::ImplItemKind::TyAlias(ref ty) => { - self.print_associated_type(ii.ident, None, Some(ty)); + self.print_associated_type(ii.ident, &ii.generics, None, Some(ty)); } hir::ImplItemKind::OpaqueTy(bounds) => { self.word_space("type"); From 8b77f8688e9436c6b35d5746e3bb79e20c67567d Mon Sep 17 00:00:00 2001 From: Josh White Date: Fri, 7 Feb 2020 12:44:31 -0500 Subject: [PATCH 080/657] performed --bless of 15 ui tests affected --- src/librustc_error_codes/error_codes/E0637.md | 69 ++++++++++++++----- .../const-param-elided-lifetime.stderr | 1 + src/test/ui/error-codes/E0637.stderr | 1 + ...rrect-explicit-lifetime-name-needed.stderr | 3 +- .../ui/underscore-lifetime/in-binder.stderr | 1 + .../underscore-lifetime-binders.stderr | 3 +- .../underscore-outlives-bounds.stderr | 1 + ...se-inherent-impl-ampersand.rust2015.stderr | 1 + ...se-inherent-impl-ampersand.rust2018.stderr | 1 + ...e-inherent-impl-underscore.rust2015.stderr | 1 + ...e-inherent-impl-underscore.rust2018.stderr | 1 + ...e-clause-trait-impl-region.rust2015.stderr | 1 + ...e-clause-trait-impl-region.rust2018.stderr | 1 + ...ause-trait-impl-underscore.rust2015.stderr | 1 + ...ause-trait-impl-underscore.rust2018.stderr | 1 + .../underscore-lifetime/where-clauses.stderr | 1 + 16 files changed, 67 insertions(+), 21 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0637.md b/src/librustc_error_codes/error_codes/E0637.md index 978cf273c94d3..ba81e42ce0850 100644 --- a/src/librustc_error_codes/error_codes/E0637.md +++ b/src/librustc_error_codes/error_codes/E0637.md @@ -1,31 +1,62 @@ -An underscore `_` character or a numeric literal `u8`, `i32`, `f64`, etc has -been used as the identifier for a lifetime. +An underscore `_` character has been used as the identifier for a lifetime, +or a const generic has been borrowed without an explicit lifetime. -Erroneous code example 1: +Erroneous example with an underscore: ``` -fn some_function<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { - //Some code -} +fn foo<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {} + // ^^ `'_` is a reserved lifetime name +``` +Lifetimes are named with `'ident`, where ident is the name of the lifetime or +loop. The `_` character, which represents the ignore pattern, cannot be used +as the identifier because it is a reserved lifetime name. To fix +this, use a lowercase letter, or a series of lowercase letters as the lifetime +identifier. Often a single lowercase letter, such as `'a`, is sufficient. For +more information, see +[the book][bk-no]. + +Corrected underscore example: +``` +fn <'a>(str1: &'a str, str2: &'a str) -> &'a str {} ``` -or Erroneous code example 2: + +Erroneous example with const generic: ``` -fn some_function<'u8>(str1: &'u8 str, str2: &'u8 str) -> &'u8 str { - //Some code +struct A; +//~^ ERROR `&` without an explicit lifetime name cannot be used here +trait B {} + +impl A { +//~^ ERROR `&` without an explicit lifetime name cannot be used here + fn foo(&self) {} + //~^ ERROR `&` without an explicit lifetime name cannot be used here +} + +impl B for A {} +//~^ ERROR `&` without an explicit lifetime name cannot be used here + +fn bar() {} +//~^ ERROR `&` without an explicit lifetime name cannot be used here } ``` -Lifetimes are named with `'ident`, where ident is the name of the lifetime or -loop. The `_` character, which represents the ignore pattern, cannot be used -as the identifier because it is a reserved lifetime name. Numeric literals are -also invalid lifetime identifiers and will cause this error to be thrown. To fix -this, use a series of lowercase letters as the lifetime identifier. Often a -single lowercase letter, such as `'a`, is sufficient. For more information, see -[the book][bk-no]. +Const generics cannot be borrowed without specifying a lifetime.The +compiler handles memory allocation of constants differently than that of +variables and it cannot infer the lifetime of the borrowed constant. +To fix this, explicitly specify a lifetime for the const generic. -Corrected code example: +Corrected const generic example: ``` -fn some_function<'a>(str1: &'a str, str2: &'a str) -> &'a str { - //Some code +struct A; + +trait B {} + +impl A { + fn foo(&self) {} +} + +impl B for A {} + +fn bar() {} } ``` [bk-no]: https://doc.rust-lang.org/book/appendix-02-operators.html#non-operator-symbols diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.stderr b/src/test/ui/const-generics/const-param-elided-lifetime.stderr index 93133c507fe40..6841d1fdf360b 100644 --- a/src/test/ui/const-generics/const-param-elided-lifetime.stderr +++ b/src/test/ui/const-generics/const-param-elided-lifetime.stderr @@ -38,3 +38,4 @@ LL | #![feature(const_generics)] error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/error-codes/E0637.stderr b/src/test/ui/error-codes/E0637.stderr index 9c3ca87ed7e64..d19ebfd15a52c 100644 --- a/src/test/ui/error-codes/E0637.stderr +++ b/src/test/ui/error-codes/E0637.stderr @@ -18,3 +18,4 @@ LL | impl<'a: '_> Bar<'a> { error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr index 8720288b53e58..9f410c0dbbbd2 100644 --- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr @@ -18,4 +18,5 @@ LL | fn bar<'b, L: X<&'b Nested>>(){} error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0106, E0637. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/in-binder.stderr b/src/test/ui/underscore-lifetime/in-binder.stderr index 1b936dd9aec2f..fcd7eddb57605 100644 --- a/src/test/ui/underscore-lifetime/in-binder.stderr +++ b/src/test/ui/underscore-lifetime/in-binder.stderr @@ -36,3 +36,4 @@ LL | fn foo<'_>() { error: aborting due to 6 previous errors +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index c7cda38e47691..ada4551baefff 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -38,4 +38,5 @@ LL | fn foo2<'a>(_: &'a u8, y: &'a u8) -> &'a u8 { y } error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0106, E0637. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr b/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr index 6fa74d4e31034..4b38a26f957f9 100644 --- a/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr +++ b/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr @@ -6,3 +6,4 @@ LL | impl<'b: '_> Foo<'b> for i32 {} error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr index eec8e4b846886..fe726cb49c737 100644 --- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr @@ -6,3 +6,4 @@ LL | T: WithType<&u32> error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr index eec8e4b846886..fe726cb49c737 100644 --- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr @@ -6,3 +6,4 @@ LL | T: WithType<&u32> error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr index d2c3e352045b6..95939fd6b7e03 100644 --- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr @@ -6,3 +6,4 @@ LL | T: WithRegion<'_> error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr index d2c3e352045b6..95939fd6b7e03 100644 --- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr @@ -6,3 +6,4 @@ LL | T: WithRegion<'_> error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr index 586b2b6aeaf28..fbd14de21078b 100644 --- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr @@ -6,3 +6,4 @@ LL | T: WithType<&u32> error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr index 586b2b6aeaf28..fbd14de21078b 100644 --- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr @@ -6,3 +6,4 @@ LL | T: WithType<&u32> error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr index faabf57a7df40..92caff0dcde99 100644 --- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr @@ -6,3 +6,4 @@ LL | T: WithRegion<'_> error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr index faabf57a7df40..92caff0dcde99 100644 --- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr @@ -6,3 +6,4 @@ LL | T: WithRegion<'_> error: aborting due to previous error +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clauses.stderr b/src/test/ui/underscore-lifetime/where-clauses.stderr index 8674a925c110d..1a3ea4af7e12e 100644 --- a/src/test/ui/underscore-lifetime/where-clauses.stderr +++ b/src/test/ui/underscore-lifetime/where-clauses.stderr @@ -12,3 +12,4 @@ LL | impl Foo<'static> for Vec {} error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0637`. From 953f6ecb6adc37b4f8e52102c1e7ca86cc5bc92c Mon Sep 17 00:00:00 2001 From: Mikhail Babenko Date: Fri, 7 Feb 2020 23:38:13 +0300 Subject: [PATCH 081/657] fix lifetime shadowing check in GATs --- src/librustc_resolve/lifetimes.rs | 6 ++++-- .../ui/generic-associated-types/shadowing.rs | 4 ++-- .../generic-associated-types/shadowing.stderr | 21 +++++++++++++++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 0ba9b4f17068e..c527d6050cabc 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -747,7 +747,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { track_lifetime_uses: true, opaque_type_parent: true, }; - self.with(scope, |_old_scope, this| { + self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &generics.params); this.visit_generics(generics); for bound in bounds { this.visit_param_bound(bound); @@ -804,7 +805,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { track_lifetime_uses: true, opaque_type_parent: true, }; - self.with(scope, |_old_scope, this| { + self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &generics.params); this.visit_generics(generics); this.visit_ty(ty); }); diff --git a/src/test/ui/generic-associated-types/shadowing.rs b/src/test/ui/generic-associated-types/shadowing.rs index 7277c0d87c6ff..5c308948bd3f8 100644 --- a/src/test/ui/generic-associated-types/shadowing.rs +++ b/src/test/ui/generic-associated-types/shadowing.rs @@ -2,8 +2,8 @@ #![feature(generic_associated_types)] trait Shadow<'a> { - //FIXME(#44265): The lifetime parameter shadowing should cause an error. type Bar<'a>; + //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope } trait NoShadow<'a> { @@ -11,8 +11,8 @@ trait NoShadow<'a> { } impl<'a> NoShadow<'a> for &'a u32 { - //FIXME(#44265): The lifetime parameter shadowing should cause an error. type Bar<'a> = i32; + //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope } trait ShadowT { diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index 50c12e822e7db..1cb6f071f3a19 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -14,6 +14,22 @@ LL | impl NoShadowT for Option { LL | type Bar = i32; | ^ already used +error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope + --> $DIR/shadowing.rs:5:14 + | +LL | trait Shadow<'a> { + | -- first declared here +LL | type Bar<'a>; + | ^^ lifetime 'a already in scope + +error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope + --> $DIR/shadowing.rs:14:14 + | +LL | impl<'a> NoShadow<'a> for &'a u32 { + | -- first declared here +LL | type Bar<'a> = i32; + | ^^ lifetime 'a already in scope + error: type-generic associated types are not yet implemented --> $DIR/shadowing.rs:19:5 | @@ -30,6 +46,7 @@ LL | type Bar; // OK | = note: for more information, see https://github.com/rust-lang/rust/issues/44265 -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0403`. +Some errors have detailed explanations: E0403, E0496. +For more information about an error, try `rustc --explain E0403`. From 3998249ae77f3a6e1c6e44de944e9d5928963594 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Fri, 7 Feb 2020 22:00:25 -0500 Subject: [PATCH 082/657] remove unnecessary local variable assignment in context manager --- src/bootstrap/bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 1935759a5628e..563f12e7bacbd 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -351,7 +351,7 @@ def support_xz(): try: with tempfile.NamedTemporaryFile(delete=False) as temp_file: temp_path = temp_file.name - with tarfile.open(temp_path, "w:xz") as tar: + with tarfile.open(temp_path, "w:xz"): pass return True except tarfile.CompressionError: From 19aaf639459705e2b397f2b8a12f3d73ef0748b2 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Fri, 7 Feb 2020 22:04:44 -0500 Subject: [PATCH 083/657] PEP8 format spacing --- src/bootstrap/bootstrap.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 563f12e7bacbd..50e1726240fff 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -80,7 +80,7 @@ def _download(path, url, probably_big, verbose, exception): option = "-s" run(["curl", option, "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds - "--connect-timeout", "30", # timeout if cannot connect within 30 seconds + "--connect-timeout", "30", # timeout if cannot connect within 30 seconds "--retry", "3", "-Sf", "-o", path, url], verbose=verbose, exception=exception) @@ -332,7 +332,6 @@ def __init__(self): self.use_vendored_sources = '' self.verbose = False - def download_stage0(self): """Fetch the build system for Rust, written in Rust @@ -825,7 +824,7 @@ def check_vendored_status(self): if not os.path.exists(vendor_dir): print('error: vendoring required, but vendor directory does not exist.') print(' Run `cargo vendor` without sudo to initialize the ' - 'vendor directory.') + 'vendor directory.') raise Exception("{} not found".format(vendor_dir)) if self.use_vendored_sources: @@ -839,7 +838,7 @@ def check_vendored_status(self): "\n" "[source.vendored-sources]\n" "directory = '{}/vendor'\n" - .format(self.rust_root)) + .format(self.rust_root)) else: if os.path.exists('.cargo'): shutil.rmtree('.cargo') From 6ce8d2b00005143d5f0fb0c9b712ece7709b3ecf Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Fri, 7 Feb 2020 22:09:55 -0500 Subject: [PATCH 084/657] PEP8 format spacing --- src/bootstrap/configure.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 7cfc5385e2104..27bd6d028cd32 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -392,11 +392,12 @@ def set(key, value): def is_number(value): - try: - float(value) - return True - except ValueError: - return False + try: + float(value) + return True + except ValueError: + return False + # Here we walk through the constructed configuration we have from the parsed # command line arguments. We then apply each piece of configuration by From adde3d443d042cd53f7448ce1d6f32e1634fcf28 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Fri, 7 Feb 2020 22:30:11 -0500 Subject: [PATCH 085/657] PEP8 format spacing --- src/tools/publish_toolstate.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 61762ae1d9b04..967333c1ace4f 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -1,11 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -## This script publishes the new "current" toolstate in the toolstate repo (not to be -## confused with publishing the test results, which happens in -## `src/ci/docker/x86_64-gnu-tools/checktools.sh`). -## It is set as callback for `src/ci/docker/x86_64-gnu-tools/repo.sh` by the CI scripts -## when a new commit lands on `master` (i.e., after it passed all checks on `auto`). +# This script publishes the new "current" toolstate in the toolstate repo (not to be +# confused with publishing the test results, which happens in +# `src/ci/docker/x86_64-gnu-tools/checktools.sh`). +# It is set as callback for `src/ci/docker/x86_64-gnu-tools/repo.sh` by the CI scripts +# when a new commit lands on `master` (i.e., after it passed all checks on `auto`). from __future__ import print_function @@ -103,6 +103,7 @@ def validate_maintainers(repo, github_token): print("The build will fail due to this.") exit(1) + def read_current_status(current_commit, path): '''Reads build status of `current_commit` from content of `history/*.tsv` ''' @@ -113,14 +114,17 @@ def read_current_status(current_commit, path): return json.loads(status) return {} + def gh_url(): return os.environ['TOOLSTATE_ISSUES_API_URL'] + def maybe_delink(message): if os.environ.get('TOOLSTATE_SKIP_MENTIONS') is not None: return message.replace("@", "") return message + def issue( tool, status, @@ -164,6 +168,7 @@ def issue( )) response.read() + def update_latest( current_commit, relevant_pr_number, @@ -194,7 +199,7 @@ def update_latest( for status in latest: tool = status['tool'] changed = False - create_issue_for_status = None # set to the status that caused the issue + create_issue_for_status = None # set to the status that caused the issue for os, s in current_status.items(): old = status[os] From 60889d418e37897e272844d15b03fed62c60b92d Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Fri, 7 Feb 2020 23:35:27 -0500 Subject: [PATCH 086/657] remove unnecessary semicolons --- src/ci/cpu-usage-over-time.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py index daf21670b3339..78ac060368193 100644 --- a/src/ci/cpu-usage-over-time.py +++ b/src/ci/cpu-usage-over-time.py @@ -148,11 +148,11 @@ def idle_since(self, prev): print('unknown platform', sys.platform) sys.exit(1) -cur_state = State(); +cur_state = State() print("Time,Idle") while True: - time.sleep(1); - next_state = State(); + time.sleep(1) + next_state = State() now = datetime.datetime.utcnow().isoformat() idle = next_state.idle_since(cur_state) print("%s,%s" % (now, idle)) From 92fc98c695d133ae28fb9d386d22efef57e2fc87 Mon Sep 17 00:00:00 2001 From: Josh White Date: Fri, 7 Feb 2020 23:40:16 -0500 Subject: [PATCH 087/657] Cleaned up long error description --- src/librustc_error_codes/error_codes/E0637.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0637.md b/src/librustc_error_codes/error_codes/E0637.md index ba81e42ce0850..13be503676790 100644 --- a/src/librustc_error_codes/error_codes/E0637.md +++ b/src/librustc_error_codes/error_codes/E0637.md @@ -11,8 +11,7 @@ loop. The `_` character, which represents the ignore pattern, cannot be used as the identifier because it is a reserved lifetime name. To fix this, use a lowercase letter, or a series of lowercase letters as the lifetime identifier. Often a single lowercase letter, such as `'a`, is sufficient. For -more information, see -[the book][bk-no]. +more information, see [the book][bk-no]. Corrected underscore example: ``` From e30dd86c61c8159b02940b888d876a57d8b07b7e Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Fri, 7 Feb 2020 23:47:29 -0500 Subject: [PATCH 088/657] PEP8 format spacing --- src/etc/debugger_pretty_printers_common.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/etc/debugger_pretty_printers_common.py b/src/etc/debugger_pretty_printers_common.py index 385ce8efab87b..b3f8f50636bee 100644 --- a/src/etc/debugger_pretty_printers_common.py +++ b/src/etc/debugger_pretty_printers_common.py @@ -212,7 +212,6 @@ def __classify_struct(self): # REGULAR STRUCT return TYPE_KIND_REGULAR_STRUCT - def __classify_union(self): assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION @@ -233,7 +232,6 @@ def __classify_union(self): else: return TYPE_KIND_REGULAR_UNION - def __conforms_to_field_layout(self, expected_fields): actual_fields = self.get_fields() actual_field_count = len(actual_fields) @@ -363,6 +361,7 @@ def extract_tail_head_ptr_and_cap_from_std_vecdeque(vec_val): assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR return (tail, head, data_ptr, capacity) + def extract_length_and_ptr_from_slice(slice_val): assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE) @@ -376,8 +375,10 @@ def extract_length_and_ptr_from_slice(slice_val): assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR return (length, data_ptr) + UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"]) + def extract_type_name(qualified_type_name): """Extracts the type name from a fully qualified path""" if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS: @@ -393,6 +394,7 @@ def extract_type_name(qualified_type_name): else: return qualified_type_name[index + 2:] + try: compat_str = unicode # Python 2 except NameError: From f38e2701d862379eca06475d196438038ca72564 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Fri, 7 Feb 2020 23:49:40 -0500 Subject: [PATCH 089/657] remove unnecessary sys import --- src/etc/dec2flt_table.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py index 85395d2ecdfc7..4979882ffeaff 100755 --- a/src/etc/dec2flt_table.py +++ b/src/etc/dec2flt_table.py @@ -14,7 +14,6 @@ even larger, and it's already uncomfortably large (6 KiB). """ from __future__ import print_function -import sys from math import ceil, log from fractions import Fraction from collections import namedtuple @@ -82,6 +81,7 @@ def error(f, e, z): ulp_err = abs_err / Fraction(2) ** z.exp return float(ulp_err) + HEADER = """ //! Tables of approximations of powers of ten. //! DO NOT MODIFY: Generated by `src/etc/dec2flt_table.py` From d36634315a9e07ca4517b9d04c5bd10f218d61d8 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Sat, 8 Feb 2020 00:01:32 -0500 Subject: [PATCH 090/657] PEP8 format spacing --- src/etc/gdb_rust_pretty_printing.py | 43 +++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index 5da01b96fa5e3..0914c22eb13f0 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -9,7 +9,7 @@ if sys.version_info[0] >= 3: xrange = range -rust_enabled = 'set language rust' in gdb.execute('complete set language ru', to_string = True) +rust_enabled = 'set language rust' in gdb.execute('complete set language ru', to_string=True) # The btree pretty-printers fail in a confusing way unless # https://sourceware.org/bugzilla/show_bug.cgi?id=21763 is fixed. @@ -21,9 +21,10 @@ if int(_match.group(1)) > 8 or (int(_match.group(1)) == 8 and int(_match.group(2)) >= 1): gdb_81 = True -#=============================================================================== +# =============================================================================== # GDB Pretty Printing Module for Rust -#=============================================================================== +# =============================================================================== + class GdbType(rustpp.Type): @@ -133,39 +134,39 @@ def rust_pretty_printer_lookup_function(gdb_val): if type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT: return RustStructPrinter(val, - omit_first_field = False, - omit_type_name = False, - is_tuple_like = False) + omit_first_field=False, + omit_type_name=False, + is_tuple_like=False) if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT: return RustStructPrinter(val, - omit_first_field = True, - omit_type_name = False, - is_tuple_like = False) + omit_first_field=True, + omit_type_name=False, + is_tuple_like=False) if type_kind == rustpp.TYPE_KIND_STR_SLICE: return RustStringSlicePrinter(val) if type_kind == rustpp.TYPE_KIND_TUPLE: return RustStructPrinter(val, - omit_first_field = False, - omit_type_name = True, - is_tuple_like = True) + omit_first_field=False, + omit_type_name=True, + is_tuple_like=True) if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT: return RustStructPrinter(val, - omit_first_field = False, - omit_type_name = False, - is_tuple_like = True) + omit_first_field=False, + omit_type_name=False, + is_tuple_like=True) if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT: return RustCStyleVariantPrinter(val.get_child_at_index(0)) if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT: return RustStructPrinter(val, - omit_first_field = True, - omit_type_name = False, - is_tuple_like = True) + omit_first_field=True, + omit_type_name=False, + is_tuple_like=True) if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM: variant = get_field_at_index(gdb_val, 0) @@ -189,9 +190,9 @@ def rust_pretty_printer_lookup_function(gdb_val): return None -#=------------------------------------------------------------------------------ +# =------------------------------------------------------------------------------ # Pretty Printer Classes -#=------------------------------------------------------------------------------ +# =------------------------------------------------------------------------------ class RustEmptyPrinter(object): def __init__(self, val): self.__val = val @@ -355,6 +356,7 @@ def children_of_node(boxed_node, height, want_values): else: yield keys[i]['value']['value'] + class RustStdBTreeSetPrinter(object): def __init__(self, val): self.__val = val @@ -429,6 +431,7 @@ def to_string(self): def display_hint(self): return "string" + class RustCStyleVariantPrinter(object): def __init__(self, val): assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM From a53f45fe90daf376558d018bc0a474d2a83626f0 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Sat, 8 Feb 2020 00:02:11 -0500 Subject: [PATCH 091/657] PEP8 format spacing, split import statements --- src/etc/generate-deriving-span-tests.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index afa6bbdae4e9e..c42f942c63cf5 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -8,7 +8,8 @@ sample usage: src/etc/generate-deriving-span-tests.py """ -import os, stat +import os +import stat TEST_DIR = os.path.abspath( os.path.join(os.path.dirname(__file__), '../test/ui/derives/')) @@ -56,6 +57,7 @@ ENUM_TUPLE, ENUM_STRUCT, STRUCT_FIELDS, STRUCT_TUPLE = range(4) + def create_test_case(type, trait, super_traits, error_count): string = [ENUM_STRING, ENUM_STRUCT_VARIANT_STRING, STRUCT_STRING, STRUCT_TUPLE_STRING][type] all_traits = ','.join([trait] + super_traits) @@ -63,8 +65,9 @@ def create_test_case(type, trait, super_traits, error_count): error_deriving = '#[derive(%s)]' % super_traits if super_traits else '' errors = '\n'.join('//~%s ERROR' % ('^' * n) for n in range(error_count)) - code = string.format(traits = all_traits, errors = errors) - return TEMPLATE.format(error_deriving=error_deriving, code = code) + code = string.format(traits=all_traits, errors=errors) + return TEMPLATE.format(error_deriving=error_deriving, code=code) + def write_file(name, string): test_file = os.path.join(TEST_DIR, 'derives-span-%s.rs' % name) @@ -86,10 +89,10 @@ def write_file(name, string): traits = { 'Default': (STRUCT, [], 1), - 'FromPrimitive': (0, [], 0), # only works for C-like enums + 'FromPrimitive': (0, [], 0), # only works for C-like enums - 'Decodable': (0, [], 0), # FIXME: quoting gives horrible spans - 'Encodable': (0, [], 0), # FIXME: quoting gives horrible spans + 'Decodable': (0, [], 0), # FIXME: quoting gives horrible spans + 'Encodable': (0, [], 0), # FIXME: quoting gives horrible spans } for (trait, supers, errs) in [('Clone', [], 1), From 8d04b95188fc96236472b7affae73ccfc5547636 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Sat, 8 Feb 2020 00:03:51 -0500 Subject: [PATCH 092/657] remove unnecessary import statement --- src/etc/generate-keyword-tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/etc/generate-keyword-tests.py b/src/etc/generate-keyword-tests.py index bc046a8f42d0b..77c3d2758c6dc 100755 --- a/src/etc/generate-keyword-tests.py +++ b/src/etc/generate-keyword-tests.py @@ -11,7 +11,6 @@ import sys import os -import datetime import stat From 85e3661214564010bdb6858d3253c214e686dc04 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Sat, 8 Feb 2020 00:12:25 -0500 Subject: [PATCH 093/657] PEP8 format spacing, remove unnecessary local variable assignment --- src/etc/htmldocck.py | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index e8be2b9b53710..7789b24b62c83 100644 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -131,6 +131,7 @@ except NameError: unichr = chr + class CustomHTMLParser(HTMLParser): """simplified HTML parser. @@ -169,21 +170,25 @@ def close(self): HTMLParser.close(self) return self.__builder.close() + Command = namedtuple('Command', 'negated cmd args lineno context') + class FailedCheck(Exception): pass + class InvalidCheck(Exception): pass + def concat_multi_lines(f): """returns a generator out of the file object, which - removes `\\` then `\n` then a shared prefix with the previous line then optional whitespace; - keeps a line number (starting from 0) of the first line being concatenated.""" - lastline = None # set to the last line when the last line has a backslash + lastline = None # set to the last line when the last line has a backslash firstlineno = None catenated = '' for lineno, line in enumerate(f): @@ -208,6 +213,7 @@ def concat_multi_lines(f): if lastline is not None: print_err(lineno, line, 'Trailing backslash at the end of the file') + LINE_PATTERN = re.compile(r''' (?<=(?!?) (?P[A-Za-z]+(?:-[A-Za-z]+)*) @@ -252,7 +258,7 @@ def flatten(node): def normalize_xpath(path): if path.startswith('//'): - return '.' + path # avoid warnings + return '.' + path # avoid warnings elif path.startswith('.//'): return path else: @@ -316,7 +322,7 @@ def get_dir(self, path): def check_string(data, pat, regexp): if not pat: - return True # special case a presence testing + return True # special case a presence testing elif regexp: return re.search(pat, data, flags=re.UNICODE) is not None else: @@ -353,7 +359,7 @@ def check_tree_text(tree, path, pat, regexp): ret = check_string(value, pat, regexp) if ret: break - except Exception as e: + except Exception: print('Failed to get path "{}"'.format(path)) raise return ret @@ -363,6 +369,7 @@ def get_tree_count(tree, path): path = normalize_xpath(path) return len(tree.findall(path)) + def stderr(*args): if sys.version_info.major < 3: file = codecs.getwriter('utf-8')(sys.stderr) @@ -371,6 +378,7 @@ def stderr(*args): print(*args, file=file) + def print_err(lineno, context, err, message=None): global ERR_COUNT ERR_COUNT += 1 @@ -381,31 +389,33 @@ def print_err(lineno, context, err, message=None): if context: stderr("\t{}".format(context)) + ERR_COUNT = 0 + def check_command(c, cache): try: cerr = "" - if c.cmd == 'has' or c.cmd == 'matches': # string test + if c.cmd == 'has' or c.cmd == 'matches': # string test regexp = (c.cmd == 'matches') - if len(c.args) == 1 and not regexp: # @has = file existence + if len(c.args) == 1 and not regexp: # @has = file existence try: cache.get_file(c.args[0]) ret = True except FailedCheck as err: cerr = str(err) ret = False - elif len(c.args) == 2: # @has/matches = string test + elif len(c.args) == 2: # @has/matches = string test cerr = "`PATTERN` did not match" ret = check_string(cache.get_file(c.args[0]), c.args[1], regexp) - elif len(c.args) == 3: # @has/matches = XML tree test + elif len(c.args) == 3: # @has/matches = XML tree test cerr = "`XPATH PATTERN` did not match" tree = cache.get_tree(c.args[0]) pat, sep, attr = c.args[1].partition('/@') - if sep: # attribute + if sep: # attribute tree = cache.get_tree(c.args[0]) ret = check_tree_attr(tree, pat, attr, c.args[2], regexp) - else: # normalized text + else: # normalized text pat = c.args[1] if pat.endswith('/text()'): pat = pat[:-7] @@ -413,16 +423,16 @@ def check_command(c, cache): else: raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd)) - elif c.cmd == 'count': # count test - if len(c.args) == 3: # @count = count test + elif c.cmd == 'count': # count test + if len(c.args) == 3: # @count = count test expected = int(c.args[2]) found = get_tree_count(cache.get_tree(c.args[0]), c.args[1]) cerr = "Expected {} occurrences but found {}".format(expected, found) ret = expected == found else: raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd)) - elif c.cmd == 'has-dir': # has-dir test - if len(c.args) == 1: # @has-dir = has-dir test + elif c.cmd == 'has-dir': # has-dir test + if len(c.args) == 1: # @has-dir = has-dir test try: cache.get_dir(c.args[0]) ret = True @@ -448,11 +458,13 @@ def check_command(c, cache): except InvalidCheck as err: print_err(c.lineno, c.context, str(err)) + def check(target, commands): cache = CachedFiles(target) for c in commands: check_command(c, cache) + if __name__ == '__main__': if len(sys.argv) != 3: stderr('Usage: {}