From 8a83c8f64f717f7cf569f589b42c6535591f8854 Mon Sep 17 00:00:00 2001 From: Reese Williams Date: Wed, 20 Jan 2021 21:49:11 -0500 Subject: [PATCH 01/38] Improve suggestion for tuple struct pattern matching errors. Currently, when a user uses a struct pattern to pattern match on a tuple struct, the errors we emit generally suggest adding fields using their field names, which are numbers. However, numbers are not valid identifiers, so the suggestions, which use the shorthand notation, are not valid syntax. This commit changes those errors to suggest using the actual tuple struct pattern syntax instead, which is a more actionable suggestion. --- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_typeck/src/check/pat.rs | 98 ++++++++++++++++--- .../ui/structs/struct-tuple-field-names.rs | 15 +++ .../structs/struct-tuple-field-names.stderr | 15 +++ 5 files changed, 118 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/structs/struct-tuple-field-names.rs create mode 100644 src/test/ui/structs/struct-tuple-field-names.stderr diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 45964b1c988..d8be90cd845 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -932,7 +932,7 @@ impl<'a> Parser<'a> { self.bump(); Ok(Ident::new(symbol, self.prev_token.span)) } else { - self.parse_ident_common(false) + self.parse_ident_common(true) } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 456e32680fe..15b67ca9faf 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -999,7 +999,7 @@ impl<'a> Parser<'a> { let boxed_span = self.token.span; let is_ref = self.eat_keyword(kw::Ref); let is_mut = self.eat_keyword(kw::Mut); - let fieldname = self.parse_ident()?; + let fieldname = self.parse_field_name()?; hi = self.prev_token.span; let bind_type = match (is_ref, is_mut) { diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 5fc573a57ad..f16f8c9caf2 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -16,6 +16,7 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Ident; use rustc_trait_selection::traits::{ObligationCause, Pattern}; +use ty::VariantDef; use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -1209,14 +1210,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { u.emit(); } } - (None, Some(mut err)) | (Some(mut err), None) => { + (None, Some(mut u)) => { + if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + u.delay_as_bug(); + e.emit(); + } else { + u.emit(); + } + } + (Some(mut err), None) => { err.emit(); } - (None, None) => {} + (None, None) => { + if let Some(mut err) = + self.error_tuple_variant_index_shorthand(variant, pat, fields) + { + err.emit(); + } + } } no_field_errors } + fn error_tuple_variant_index_shorthand( + &self, + variant: &VariantDef, + pat: &'_ Pat<'_>, + fields: &[hir::FieldPat<'_>], + ) -> Option> { + // if this is a tuple struct, then all field names will be numbers + // so if any fields in a struct pattern use shorthand syntax, they will + // be invalid identifiers (for example, Foo { 0, 1 }). + if let (CtorKind::Fn, PatKind::Struct(qpath, field_patterns, ..)) = + (variant.ctor_kind, &pat.kind) + { + let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand); + if has_shorthand_field_name { + let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { + s.print_qpath(qpath, false) + }); + let mut err = struct_span_err!( + self.tcx.sess, + pat.span, + E0769, + "tuple variant `{}` uses a bare index in a struct pattern", + path + ); + err.span_suggestion( + pat.span, + "use the tuple variant pattern syntax instead", + format!( + "{}({})", + path, + self.get_suggested_tuple_struct_pattern(fields, variant) + ), + Applicability::MaybeIncorrect, + ); + return Some(err); + } + } + None + } + fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) { let sess = self.tcx.sess; let sm = sess.source_map(); @@ -1356,16 +1411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let (sugg, appl) = if fields.len() == variant.fields.len() { ( - fields - .iter() - .map(|f| match self.tcx.sess.source_map().span_to_snippet(f.pat.span) { - Ok(f) => f, - Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_pat(f.pat) - }), - }) - .collect::>() - .join(", "), + self.get_suggested_tuple_struct_pattern(fields, variant), Applicability::MachineApplicable, ) } else { @@ -1385,6 +1431,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } + fn get_suggested_tuple_struct_pattern( + &self, + fields: &[hir::FieldPat<'_>], + variant: &VariantDef, + ) -> String { + let variant_field_idents = variant.fields.iter().map(|f| f.ident).collect::>(); + fields + .iter() + .map(|field| { + match self.tcx.sess.source_map().span_to_snippet(field.pat.span) { + Ok(f) => { + // Field names are numbers, but numbers + // are not valid identifiers + if variant_field_idents.contains(&field.ident) { + String::from("_") + } else { + f + } + } + Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { + s.print_pat(field.pat) + }), + } + }) + .collect::>() + .join(", ") + } + /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to /// inaccessible fields. /// diff --git a/src/test/ui/structs/struct-tuple-field-names.rs b/src/test/ui/structs/struct-tuple-field-names.rs new file mode 100644 index 00000000000..0ebbff75e59 --- /dev/null +++ b/src/test/ui/structs/struct-tuple-field-names.rs @@ -0,0 +1,15 @@ +struct S(i32, f32); +enum E { + S(i32, f32), +} +fn main() { + let x = E::S(1, 2.2); + match x { + E::S { 0, 1 } => {} + //~^ ERROR tuple variant `E::S` uses a bare index in a struct pattern [E0769] + } + let y = S(1, 2.2); + match y { + S { } => {} //~ ERROR: tuple variant `S` written as struct variant [E0769] + } +} diff --git a/src/test/ui/structs/struct-tuple-field-names.stderr b/src/test/ui/structs/struct-tuple-field-names.stderr new file mode 100644 index 00000000000..2021aa9d70e --- /dev/null +++ b/src/test/ui/structs/struct-tuple-field-names.stderr @@ -0,0 +1,15 @@ +error[E0769]: tuple variant `E::S` uses a bare index in a struct pattern + --> $DIR/struct-tuple-field-names.rs:8:9 + | +LL | E::S { 0, 1 } => {} + | ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)` + +error[E0769]: tuple variant `S` written as struct variant + --> $DIR/struct-tuple-field-names.rs:13:9 + | +LL | S { } => {} + | ^^^^^ help: use the tuple variant pattern syntax instead: `S(_, _)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0769`. From f165f49d228d2582d2dbfd588c2729cfc9585eb0 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Sat, 6 Feb 2021 19:14:13 +0000 Subject: [PATCH 02/38] Slight perf improvement on char::to_ascii_lowercase --- library/core/benches/char/methods.rs | 10 ++++++++++ library/core/src/char/methods.rs | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/library/core/benches/char/methods.rs b/library/core/benches/char/methods.rs index a9a08a4d762..de4b63030fa 100644 --- a/library/core/benches/char/methods.rs +++ b/library/core/benches/char/methods.rs @@ -35,3 +35,13 @@ fn bench_to_digit_radix_var(b: &mut Bencher) { .min() }) } + +#[bench] +fn bench_to_ascii_uppercase(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_uppercase()).min()) +} + +#[bench] +fn bench_to_ascii_lowercase(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_lowercase()).min()) +} diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 2baea7842a7..4c28d9cd673 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1090,7 +1090,8 @@ impl char { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> char { - if self.is_ascii() { (*self as u8).to_ascii_uppercase() as char } else { *self } + // 6th bit dictates ascii case. + if self.is_ascii_lowercase() { ((*self as u8) & !0b10_0000u8) as char } else { *self } } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -1118,7 +1119,8 @@ impl char { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> char { - if self.is_ascii() { (*self as u8).to_ascii_lowercase() as char } else { *self } + // 6th bit dictates ascii case. + if self.is_ascii_uppercase() { ((*self as u8) | 0b10_0000u8) as char } else { *self } } /// Checks that two values are an ASCII case-insensitive match. From f30c51abe8ce62756f86abbbd6623a9131d3954c Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Sat, 6 Feb 2021 20:35:21 +0000 Subject: [PATCH 03/38] Pulling out constant. --- library/core/src/char/methods.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 4c28d9cd673..4032e777077 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -7,6 +7,9 @@ use crate::unicode::{self, conversions}; use super::*; +/// If 6th bit set ascii is upper case. +const ASCII_CASE_MASK: u8 = 0b10_0000u8; + #[lang = "char"] impl char { /// The highest valid code point a `char` can have. @@ -1090,8 +1093,7 @@ impl char { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> char { - // 6th bit dictates ascii case. - if self.is_ascii_lowercase() { ((*self as u8) & !0b10_0000u8) as char } else { *self } + if self.is_ascii_lowercase() { ((*self as u8) & !ASCII_CASE_MASK) as char } else { *self } } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -1119,8 +1121,7 @@ impl char { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> char { - // 6th bit dictates ascii case. - if self.is_ascii_uppercase() { ((*self as u8) | 0b10_0000u8) as char } else { *self } + if self.is_ascii_uppercase() { ((*self as u8) | ASCII_CASE_MASK) as char } else { *self } } /// Checks that two values are an ASCII case-insensitive match. From a0f9d4beec3a89eec88289701c152a69d488487b Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 15 Sep 2020 16:18:05 -0700 Subject: [PATCH 04/38] Enable smart punctuation --- src/librustdoc/html/markdown.rs | 3 ++- src/test/rustdoc/inline_cross/add-docs.rs | 2 +- src/test/rustdoc/smart-punct.rs | 13 +++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc/smart-punct.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a81fd55f6f1..34bda2b7883 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -52,11 +52,12 @@ pub(crate) fn opts() -> Options { | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH | Options::ENABLE_TASKLISTS + | Options::ENABLE_SMART_PUNCTUATION } /// A subset of [`opts()`] used for rendering summaries. pub(crate) fn summary_opts() -> Options { - Options::ENABLE_STRIKETHROUGH + Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION } /// When `to_string` is called, this struct will emit the HTML corresponding to diff --git a/src/test/rustdoc/inline_cross/add-docs.rs b/src/test/rustdoc/inline_cross/add-docs.rs index 1af5e8f03b4..8f0c4e5e641 100644 --- a/src/test/rustdoc/inline_cross/add-docs.rs +++ b/src/test/rustdoc/inline_cross/add-docs.rs @@ -4,6 +4,6 @@ extern crate inner; // @has add_docs/struct.MyStruct.html -// @has add_docs/struct.MyStruct.html "Doc comment from 'pub use', Doc comment from definition" +// @has add_docs/struct.MyStruct.html "Doc comment from ‘pub use’, Doc comment from definition" /// Doc comment from 'pub use', pub use inner::MyStruct; diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs new file mode 100644 index 00000000000..5c4530c97a9 --- /dev/null +++ b/src/test/rustdoc/smart-punct.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +//! This is the "start" of the 'document'! How'd you know that "it's" the start? +//! +//! # Header with "smart punct'" +//! +//! [link with "smart punct'" -- yessiree!][] +//! +//! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org + +// @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" +// @has "foo/index.html" "//h1" "Header with “smart punct’”" +// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" From f1581ed8fc752417a02d7664067e6895d2f448eb Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 7 Feb 2021 19:54:54 -0800 Subject: [PATCH 05/38] Test that code does not get smart-punctuated --- src/test/rustdoc/smart-punct.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs index 5c4530c97a9..ce166b79064 100644 --- a/src/test/rustdoc/smart-punct.rs +++ b/src/test/rustdoc/smart-punct.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + #![crate_name = "foo"] //! This is the "start" of the 'document'! How'd you know that "it's" the start? @@ -7,7 +9,22 @@ //! [link with "smart punct'" -- yessiree!][] //! //! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org +//! +//! # Code should not be smart-punct'd +//! +//! `this inline code -- it shouldn't have "smart punct"` +//! +//! ``` +//! let x = "don't smart-punct me -- please!"; +//! ``` +//! +//! ```text +//! I say "don't smart-punct me -- please!" +//! ``` // @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" // @has "foo/index.html" "//h1" "Header with “smart punct’”" // @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" +// @has "foo/index.html" '//code' 'this inline code -- it shouldn\'t have "smart punct"' +// @has "foo/index.html" '//pre' 'let x = "don\'t smart-punct me -- please!";' +// @has "foo/index.html" '//pre' 'I say "don\'t smart-punct me -- please!"' From e4b83fcad48dc78e0d0753d4441ffdb34121b1c2 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 7 Feb 2021 20:12:26 -0800 Subject: [PATCH 06/38] Document smart punctuation --- .../rustdoc/src/how-to-write-documentation.md | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md index 9938cddc941..688be7aedea 100644 --- a/src/doc/rustdoc/src/how-to-write-documentation.md +++ b/src/doc/rustdoc/src/how-to-write-documentation.md @@ -101,7 +101,7 @@ what an item is, how it is used, and for what purpose it exists. Let's see an example coming from the [standard library] by taking a look at the [`std::env::args()`][env::args] function: -``````text +``````markdown Returns the arguments which this program was started with (normally passed via the command line). @@ -135,7 +135,7 @@ for argument in env::args() { Everything before the first empty line will be reused to describe the component in searches and module overviews. For example, the function `std::env::args()` -above will be shown on the [`std::env`] module documentation. It is good +above will be shown on the [`std::env`] module documentation. It is good practice to keep the summary to one line: concise writing is a goal of good documentation. @@ -153,9 +153,10 @@ and finally provides a code example. ## Markdown -`rustdoc` uses the [CommonMark markdown specification]. You might be -interested into taking a look at their website to see what's possible to do. - - [commonmark quick reference] +`rustdoc` uses the [CommonMark Markdown specification]. You might be +interested in taking a look at their website to see what's possible: + + - [CommonMark quick reference] - [current spec] In addition to the standard CommonMark syntax, `rustdoc` supports several @@ -240,6 +241,21 @@ This will render as See the specification for the [task list extension] for more details. +### Smart punctuation + +Some ASCII punctuation sequences will be automatically turned into fancy Unicode +characters: + +| ASCII sequence | Unicode | +|----------------|---------| +| `--` | – | +| `---` | — | +| `...` | … | +| `"` | “ or ”, depending on context | +| `'` | ‘ or ’, depending on context | + +So, no need to manually enter those Unicode characters! + [`backtrace`]: https://docs.rs/backtrace/0.3.50/backtrace/ [commonmark markdown specification]: https://commonmark.org/ [commonmark quick reference]: https://commonmark.org/help/ From cadcf5ed990dc02ad86cbb9f31423959a5517f50 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Mon, 8 Feb 2021 12:21:36 +0000 Subject: [PATCH 07/38] Unify way to flip 6th bit. (Same assembly generated) --- library/core/benches/ascii.rs | 6 ++++-- library/core/src/char/methods.rs | 5 +---- library/core/src/num/mod.rs | 5 +++-- library/core/src/unicode/mod.rs | 3 +++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs index bc59c378609..64938745a4a 100644 --- a/library/core/benches/ascii.rs +++ b/library/core/benches/ascii.rs @@ -66,6 +66,8 @@ macro_rules! benches { use test::black_box; use test::Bencher; +const ASCII_CASE_MASK: u8 = 0b0010_0000; + benches! { fn case00_alloc_only(_bytes: &mut [u8]) {} @@ -204,7 +206,7 @@ benches! { } } for byte in bytes { - *byte &= !((is_ascii_lowercase(*byte) as u8) << 5) + *byte &= !((is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK) } } @@ -216,7 +218,7 @@ benches! { } } for byte in bytes { - *byte -= (is_ascii_lowercase(*byte) as u8) << 5 + *byte -= (is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK } } diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 4032e777077..bbdb2a5d41b 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -3,13 +3,10 @@ use crate::slice; use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; -use crate::unicode::{self, conversions}; +use crate::unicode::{self, conversions, ASCII_CASE_MASK}; use super::*; -/// If 6th bit set ascii is upper case. -const ASCII_CASE_MASK: u8 = 0b10_0000u8; - #[lang = "char"] impl char { /// The highest valid code point a `char` can have. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 6bdfa18fa43..7563a742b9a 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -5,6 +5,7 @@ use crate::intrinsics; use crate::mem; use crate::str::FromStr; +use crate::unicode::ASCII_CASE_MASK; // Used because the `?` operator is not allowed in a const context. macro_rules! try_opt { @@ -195,7 +196,7 @@ impl u8 { #[inline] pub fn to_ascii_uppercase(&self) -> u8 { // Unset the fifth bit if this is a lowercase letter - *self & !((self.is_ascii_lowercase() as u8) << 5) + *self & !((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK) } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -218,7 +219,7 @@ impl u8 { #[inline] pub fn to_ascii_lowercase(&self) -> u8 { // Set the fifth bit if this is an uppercase letter - *self | ((self.is_ascii_uppercase() as u8) << 5) + *self | (self.is_ascii_uppercase() as u8 * ASCII_CASE_MASK) } /// Checks that two values are an ASCII case-insensitive match. diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs index 37ca0a0779b..b333b463105 100644 --- a/library/core/src/unicode/mod.rs +++ b/library/core/src/unicode/mod.rs @@ -17,6 +17,9 @@ mod unicode_data; #[stable(feature = "unicode_version", since = "1.45.0")] pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION; +/// If 6th bit set ascii is upper case. +pub(crate) const ASCII_CASE_MASK: u8 = 0b0010_0000; + // For use in liballoc, not re-exported in libstd. pub use unicode_data::{ case_ignorable::lookup as Case_Ignorable, cased::lookup as Cased, conversions, From 0a3452110c605655e7ab949c0904f053ab0cc71b Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 8 Feb 2021 15:49:04 -0800 Subject: [PATCH 08/38] Fix `@has` checks "no closing quotation" error Apparently `"foo\""` has different behavior from `'foo\''` in Python shlex. See the [discussion on Zulip][z] for more. [z]: https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/.40has.20checks.20.22no.20closing.20quotation.22 --- src/test/rustdoc/smart-punct.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs index ce166b79064..a1ca2699554 100644 --- a/src/test/rustdoc/smart-punct.rs +++ b/src/test/rustdoc/smart-punct.rs @@ -25,6 +25,6 @@ // @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" // @has "foo/index.html" "//h1" "Header with “smart punct’”" // @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" -// @has "foo/index.html" '//code' 'this inline code -- it shouldn\'t have "smart punct"' -// @has "foo/index.html" '//pre' 'let x = "don\'t smart-punct me -- please!";' -// @has "foo/index.html" '//pre' 'I say "don\'t smart-punct me -- please!"' +// @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\"" +// @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";" +// @has "foo/index.html" '//pre' "I say \"don't smart-punct me -- please!\"" From 1b29b2920033a48ec950a4b4b74402029a155a50 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 8 Feb 2021 16:49:11 -0800 Subject: [PATCH 09/38] Update Markdown unit tests --- src/librustdoc/html/markdown/tests.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 9da3072ec28..dceafd6458c 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -201,8 +201,8 @@ fn test_short_markdown_summary() { t("Hard-break \nsummary", "Hard-break summary"); t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); - t("code `let x = i32;` ...", "code let x = i32; ..."); - t("type `Type<'static>` ...", "type Type<'static> ..."); + t("code `let x = i32;` ...", "code let x = i32; …"); + t("type `Type<'static>` ...", "type Type<'static> …"); t("# top header", "top header"); t("## header", "header"); t("first paragraph\n\nsecond paragraph", "first paragraph"); @@ -227,8 +227,8 @@ fn test_plain_text_summary() { t("Hard-break \nsummary", "Hard-break summary"); t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); - t("code `let x = i32;` ...", "code `let x = i32;` ..."); - t("type `Type<'static>` ...", "type `Type<'static>` ..."); + t("code `let x = i32;` ...", "code `let x = i32;` …"); + t("type `Type<'static>` ...", "type `Type<'static>` …"); t("# top header", "top header"); t("## header", "header"); t("first paragraph\n\nsecond paragraph", "first paragraph"); @@ -250,6 +250,6 @@ fn test_markdown_html_escape() { } t("`Struct<'a, T>`", "

Struct<'a, T>

\n"); - t("Struct<'a, T>", "

Struct<'a, T>

\n"); + t("Struct<'a, T>", "

Struct<’a, T>

\n"); t("Struct
", "

Struct<br>

\n"); } From 0060c91cfc9b8c0a73e7a23e16cddf8ac09440fb Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 10 Feb 2021 17:52:36 -0800 Subject: [PATCH 10/38] Make WASI's `hard_link` behavior match other platforms. Following #78026, `std::fs::hard_link` on most platforms does not follow symlinks. Change the WASI implementation to also not follow symlinks. --- library/std/src/sys/wasi/fs.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 4134ef67671..6050620729f 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -557,8 +557,9 @@ pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { pub fn link(original: &Path, link: &Path) -> io::Result<()> { let (original, original_file) = open_parent(original)?; let (link, link_file) = open_parent(link)?; + // Pass 0 as the flags argument, meaning don't follow symlinks. original.link( - wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, + 0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?, From daa55acdb0bd174bb0bca1f88d5920289808a8f1 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Fri, 12 Feb 2021 13:42:42 +0000 Subject: [PATCH 11/38] Slightly more explicit --- library/core/src/char/methods.rs | 14 +++++++++++--- library/core/src/num/mod.rs | 10 +++++++++- library/core/src/unicode/mod.rs | 3 --- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index bbdb2a5d41b..3ddf0e63894 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -3,7 +3,7 @@ use crate::slice; use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; -use crate::unicode::{self, conversions, ASCII_CASE_MASK}; +use crate::unicode::{self, conversions}; use super::*; @@ -1090,7 +1090,11 @@ impl char { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> char { - if self.is_ascii_lowercase() { ((*self as u8) & !ASCII_CASE_MASK) as char } else { *self } + if self.is_ascii_lowercase() { + (*self as u8).ascii_change_case_unchecked() as char + } else { + *self + } } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -1118,7 +1122,11 @@ impl char { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> char { - if self.is_ascii_uppercase() { ((*self as u8) | ASCII_CASE_MASK) as char } else { *self } + if self.is_ascii_uppercase() { + (*self as u8).ascii_change_case_unchecked() as char + } else { + *self + } } /// Checks that two values are an ASCII case-insensitive match. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 7563a742b9a..42ccdd00bbd 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -5,7 +5,9 @@ use crate::intrinsics; use crate::mem; use crate::str::FromStr; -use crate::unicode::ASCII_CASE_MASK; + +/// If 6th bit set ascii is upper case. +const ASCII_CASE_MASK: u8 = 0b0010_0000; // Used because the `?` operator is not allowed in a const context. macro_rules! try_opt { @@ -222,6 +224,12 @@ impl u8 { *self | (self.is_ascii_uppercase() as u8 * ASCII_CASE_MASK) } + /// Assumes self is ascii + #[inline] + pub(crate) fn ascii_change_case_unchecked(&self) -> u8 { + *self ^ ASCII_CASE_MASK + } + /// Checks that two values are an ASCII case-insensitive match. /// /// This is equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`. diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs index b333b463105..37ca0a0779b 100644 --- a/library/core/src/unicode/mod.rs +++ b/library/core/src/unicode/mod.rs @@ -17,9 +17,6 @@ mod unicode_data; #[stable(feature = "unicode_version", since = "1.45.0")] pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION; -/// If 6th bit set ascii is upper case. -pub(crate) const ASCII_CASE_MASK: u8 = 0b0010_0000; - // For use in liballoc, not re-exported in libstd. pub use unicode_data::{ case_ignorable::lookup as Case_Ignorable, cased::lookup as Cased, conversions, From 9d29793614cc810fb8febf7f1a2e0202f3919bb6 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Sun, 17 Jan 2021 23:12:29 -0500 Subject: [PATCH 12/38] Improve design of `assert_len` --- .../alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/string.rs | 4 +-- library/alloc/src/vec/mod.rs | 2 +- library/core/src/ops/range.rs | 35 ++++++++++++------- library/core/src/slice/mod.rs | 2 +- .../range-bounds-assert-len.md | 10 ------ .../range-bounds-ensure-subset-of.md | 10 ++++++ 8 files changed, 38 insertions(+), 29 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-bounds-assert-len.md create mode 100644 src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index eb899468193..0c267cbc106 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = range.assert_len(self.len()); + let Range { start, end } = range.ensure_subset_of(..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 99c42a4ba44..71b4883aca2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,7 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_bounds_assert_len)] +#![feature(range_bounds_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3218b3535c9..3ab5ca4f566 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1510,14 +1510,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = range.assert_len(self.len()); + let Range { start, end } = range.ensure_subset_of(..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `assert_len` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `ensure_subset_of` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b40c1a8c57a..5c20f382224 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = range.assert_len(len); + let Range { start, end } = range.ensure_subset_of(..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 0571dc74b9a..7a0dd5a8f0f 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -766,8 +766,15 @@ pub trait RangeBounds { /// Performs bounds-checking of this range. /// + /// This method is similar to [`Index::index`] for slices, but it returns a + /// [`Range`] equivalent to this range. You can use this method to turn any + /// range into `start` and `end` values. + /// + /// The given range is the range of the slice to use for bounds-checking. It + /// should be a [`RangeTo`] range that ends at the length of the slice. + /// /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and - /// [`slice::get_unchecked_mut`] for slices of the given length. + /// [`slice::get_unchecked_mut`] for slices with the given range. /// /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut @@ -779,49 +786,51 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// /// let v = [10, 40, 30]; - /// assert_eq!(1..2, (1..2).assert_len(v.len())); - /// assert_eq!(0..2, (..2).assert_len(v.len())); - /// assert_eq!(1..3, (1..).assert_len(v.len())); + /// assert_eq!(1..2, (1..2).ensure_subset_of(..v.len())); + /// assert_eq!(0..2, (..2).ensure_subset_of(..v.len())); + /// assert_eq!(1..3, (1..).ensure_subset_of(..v.len())); /// ``` /// /// Panics when [`Index::index`] would panic: /// /// ```should_panic - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (2..1).assert_len(3); + /// (2..1).ensure_subset_of(..3); /// ``` /// /// ```should_panic - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (1..4).assert_len(3); + /// (1..4).ensure_subset_of(..3); /// ``` /// /// ```should_panic - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (1..=usize::MAX).assert_len(3); + /// (1..=usize::MAX).ensure_subset_of(..3); /// ``` /// /// [`Index::index`]: crate::ops::Index::index #[track_caller] - #[unstable(feature = "range_bounds_assert_len", issue = "76393")] - fn assert_len(self, len: usize) -> Range + #[unstable(feature = "range_bounds_ensure_subset_of", issue = "76393")] + fn ensure_subset_of(self, range: RangeTo) -> Range where Self: RangeBounds, { + let len = range.end; + let start: Bound<&usize> = self.start_bound(); let start = match start { Bound::Included(&start) => start, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 19a3b45e568..90351be6929 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3052,7 +3052,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = src.assert_len(self.len()); + let Range { start: src_start, end: src_end } = src.ensure_subset_of(..self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, diff --git a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md deleted file mode 100644 index 0e95d5ded92..00000000000 --- a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_bounds_assert_len` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`RangeBounds::assert_len`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`RangeBounds::assert_len`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.assert_len diff --git a/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md new file mode 100644 index 00000000000..ea3f01ff5f9 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md @@ -0,0 +1,10 @@ +# `range_bounds_ensure_subset_of` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`RangeBounds::ensure_subset_of`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`RangeBounds::ensure_subset_of`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.ensure_subset_of From cb647f3e8e32180cde0f0e7a2599a5dc5b35345a Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 18 Jan 2021 09:22:17 -0500 Subject: [PATCH 13/38] Fix possible soundness issue in `ensure_subset_of` --- .../alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/string.rs | 2 +- library/alloc/src/vec/mod.rs | 2 +- library/core/src/ops/range.rs | 192 +++++++++--------- library/core/src/slice/mod.rs | 2 +- .../range-bounds-ensure-subset-of.md | 10 - .../range-ensure-subset-of.md | 10 + 8 files changed, 112 insertions(+), 110 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md create mode 100644 src/doc/unstable-book/src/library-features/range-ensure-subset-of.md diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 0c267cbc106..319ca666fc6 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = range.ensure_subset_of(..self.len()); + let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 71b4883aca2..ade2e3fed2c 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,7 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_bounds_ensure_subset_of)] +#![feature(range_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3ab5ca4f566..ef2f264ec7e 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1510,7 +1510,7 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = range.ensure_subset_of(..self.len()); + let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 5c20f382224..1a7b846bd85 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = range.ensure_subset_of(..len); + let Range { start, end } = Range::ensure_subset_of(range, ..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 7a0dd5a8f0f..b30ff9450ff 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -151,6 +151,103 @@ impl> Range { } } +impl Range { + /// Performs bounds-checking of a range. + /// + /// This method is similar to [`Index::index`] for slices, but it returns a + /// `Range` equivalent to `range`. You can use this method to turn any range + /// into `start` and `end` values. + /// + /// `bounds` is the range of the slice to use for bounds-checking. It should + /// be a [`RangeTo`] range that ends at the length of the slice. + /// + /// The returned `Range` is safe to pass to [`slice::get_unchecked`] and + /// [`slice::get_unchecked_mut`] for slices with the given range. + /// + /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked + /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut + /// + /// # Panics + /// + /// Panics if `range` would be out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// let v = [10, 40, 30]; + /// assert_eq!(1..2, Range::ensure_subset_of(1..2, ..v.len())); + /// assert_eq!(0..2, Range::ensure_subset_of(..2, ..v.len())); + /// assert_eq!(1..3, Range::ensure_subset_of(1.., ..v.len())); + /// ``` + /// + /// Panics when [`Index::index`] would panic: + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(2..1, ..3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(1..4, ..3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(1..=usize::MAX, ..3); + /// ``` + /// + /// [`Index::index`]: crate::ops::Index::index + #[track_caller] + #[unstable(feature = "range_ensure_subset_of", issue = "76393")] + pub fn ensure_subset_of(range: R, bounds: RangeTo) -> Self + where + R: RangeBounds, + { + let len = bounds.end; + + let start: Bound<&usize> = range.start_bound(); + let start = match start { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end: Bound<&usize> = range.end_bound(); + let end = match end { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Self { start, end } + } +} + /// A range only bounded inclusively below (`start..`). /// /// The `RangeFrom` `start..` contains all values with `x >= start`. @@ -764,101 +861,6 @@ pub trait RangeBounds { #[stable(feature = "collections_range", since = "1.28.0")] fn end_bound(&self) -> Bound<&T>; - /// Performs bounds-checking of this range. - /// - /// This method is similar to [`Index::index`] for slices, but it returns a - /// [`Range`] equivalent to this range. You can use this method to turn any - /// range into `start` and `end` values. - /// - /// The given range is the range of the slice to use for bounds-checking. It - /// should be a [`RangeTo`] range that ends at the length of the slice. - /// - /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and - /// [`slice::get_unchecked_mut`] for slices with the given range. - /// - /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked - /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut - /// - /// # Panics - /// - /// Panics if the range would be out of bounds. - /// - /// # Examples - /// - /// ``` - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// let v = [10, 40, 30]; - /// assert_eq!(1..2, (1..2).ensure_subset_of(..v.len())); - /// assert_eq!(0..2, (..2).ensure_subset_of(..v.len())); - /// assert_eq!(1..3, (1..).ensure_subset_of(..v.len())); - /// ``` - /// - /// Panics when [`Index::index`] would panic: - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (2..1).ensure_subset_of(..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (1..4).ensure_subset_of(..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (1..=usize::MAX).ensure_subset_of(..3); - /// ``` - /// - /// [`Index::index`]: crate::ops::Index::index - #[track_caller] - #[unstable(feature = "range_bounds_ensure_subset_of", issue = "76393")] - fn ensure_subset_of(self, range: RangeTo) -> Range - where - Self: RangeBounds, - { - let len = range.end; - - let start: Bound<&usize> = self.start_bound(); - let start = match start { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let end: Bound<&usize> = self.end_bound(); - let end = match end { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Range { start, end } - } - /// Returns `true` if `item` is contained in the range. /// /// # Examples diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 90351be6929..e78b6476511 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3052,7 +3052,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = src.ensure_subset_of(..self.len()); + let Range { start: src_start, end: src_end } = Range::ensure_subset_of(src, ..self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, diff --git a/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md deleted file mode 100644 index ea3f01ff5f9..00000000000 --- a/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_bounds_ensure_subset_of` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`RangeBounds::ensure_subset_of`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`RangeBounds::ensure_subset_of`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.ensure_subset_of diff --git a/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md new file mode 100644 index 00000000000..8b5a21a34cf --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md @@ -0,0 +1,10 @@ +# `range_ensure_subset_of` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`Range::ensure_subset_of`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`Range::ensure_subset_of`]: https://doc.rust-lang.org/std/ops/struct.Range.html#method.ensure_subset_of From f6111a256e94855f18f36f02930f8b0ae0012542 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 18 Jan 2021 14:48:22 -0500 Subject: [PATCH 14/38] Remove unnecessary documentation page --- .../src/library-features/range-ensure-subset-of.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-ensure-subset-of.md diff --git a/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md deleted file mode 100644 index 8b5a21a34cf..00000000000 --- a/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_ensure_subset_of` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`Range::ensure_subset_of`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`Range::ensure_subset_of`]: https://doc.rust-lang.org/std/ops/struct.Range.html#method.ensure_subset_of From 5d519eaa6e9a583257b2f9e28a743ab85d1cabc5 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 1 Feb 2021 21:20:44 -0500 Subject: [PATCH 15/38] Rename `Range::ensure_subset_of` to `slice::range` --- .../alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/slice.rs | 2 + library/alloc/src/string.rs | 5 +- library/alloc/src/vec/mod.rs | 2 +- library/core/src/ops/range.rs | 101 ----------------- library/core/src/slice/index.rs | 105 +++++++++++++++++- library/core/src/slice/mod.rs | 8 +- 8 files changed, 115 insertions(+), 112 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 319ca666fc6..f7cefdce278 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); + let Range { start, end } = slice::range(range, ..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ade2e3fed2c..c020a969f1f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,6 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] @@ -123,6 +122,7 @@ #![feature(set_ptr_value)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] +#![feature(slice_range)] #![feature(staged_api)] #![feature(str_internals)] #![feature(trusted_len)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index cb015b94930..c5ffade1261 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -92,6 +92,8 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; +#[unstable(feature = "slice_range", issue = "76393")] +pub use core::slice::range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ef2f264ec7e..b4deedc5263 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; +use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1510,14 +1511,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); + let Range { start, end } = slice::range(range, ..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `ensure_subset_of` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1a7b846bd85..a8474f8ca59 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = Range::ensure_subset_of(range, ..len); + let Range { start, end } = slice::range(range, ..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index b30ff9450ff..dbeb3912130 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -1,9 +1,5 @@ use crate::fmt; use crate::hash::Hash; -use crate::slice::index::{ - slice_end_index_len_fail, slice_end_index_overflow_fail, slice_index_order_fail, - slice_start_index_overflow_fail, -}; /// An unbounded range (`..`). /// @@ -151,103 +147,6 @@ impl> Range { } } -impl Range { - /// Performs bounds-checking of a range. - /// - /// This method is similar to [`Index::index`] for slices, but it returns a - /// `Range` equivalent to `range`. You can use this method to turn any range - /// into `start` and `end` values. - /// - /// `bounds` is the range of the slice to use for bounds-checking. It should - /// be a [`RangeTo`] range that ends at the length of the slice. - /// - /// The returned `Range` is safe to pass to [`slice::get_unchecked`] and - /// [`slice::get_unchecked_mut`] for slices with the given range. - /// - /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked - /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut - /// - /// # Panics - /// - /// Panics if `range` would be out of bounds. - /// - /// # Examples - /// - /// ``` - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// let v = [10, 40, 30]; - /// assert_eq!(1..2, Range::ensure_subset_of(1..2, ..v.len())); - /// assert_eq!(0..2, Range::ensure_subset_of(..2, ..v.len())); - /// assert_eq!(1..3, Range::ensure_subset_of(1.., ..v.len())); - /// ``` - /// - /// Panics when [`Index::index`] would panic: - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(2..1, ..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(1..4, ..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(1..=usize::MAX, ..3); - /// ``` - /// - /// [`Index::index`]: crate::ops::Index::index - #[track_caller] - #[unstable(feature = "range_ensure_subset_of", issue = "76393")] - pub fn ensure_subset_of(range: R, bounds: RangeTo) -> Self - where - R: RangeBounds, - { - let len = bounds.end; - - let start: Bound<&usize> = range.start_bound(); - let start = match start { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let end: Bound<&usize> = range.end_bound(); - let end = match end { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Self { start, end } - } -} - /// A range only bounded inclusively below (`start..`). /// /// The `RangeFrom` `start..` contains all values with `x >= start`. diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 660c8a2da5d..d20986bb724 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -37,28 +37,28 @@ fn slice_start_index_len_fail(index: usize, len: usize) -> ! { #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { +fn slice_end_index_len_fail(index: usize, len: usize) -> ! { panic!("range end index {} out of range for slice of length {}", index, len); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! { +fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_start_index_overflow_fail() -> ! { +fn slice_start_index_overflow_fail() -> ! { panic!("attempted to index slice from after maximum usize"); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_end_index_overflow_fail() -> ! { +fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } @@ -449,3 +449,100 @@ unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { (0..=self.end).index_mut(slice) } } + +/// Performs bounds-checking of a range. +/// +/// This method is similar to [`Index::index`] for slices, but it returns a +/// [`Range`] equivalent to `range`. You can use this method to turn any range +/// into `start` and `end` values. +/// +/// `bounds` is the range of the slice to use for bounds-checking. It should +/// be a [`RangeTo`] range that ends at the length of the slice. +/// +/// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and +/// [`slice::get_unchecked_mut`] for slices with the given range. +/// +/// [`Range`]: ops::Range +/// [`RangeTo`]: ops::RangeTo +/// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked +/// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut +/// +/// # Panics +/// +/// Panics if `range` would be out of bounds. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// let v = [10, 40, 30]; +/// assert_eq!(1..2, slice::range(1..2, ..v.len())); +/// assert_eq!(0..2, slice::range(..2, ..v.len())); +/// assert_eq!(1..3, slice::range(1.., ..v.len())); +/// ``` +/// +/// Panics when [`Index::index`] would panic: +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(2..1, ..3); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(1..4, ..3); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(1..=usize::MAX, ..3); +/// ``` +/// +/// [`Index::index`]: ops::Index::index +#[track_caller] +#[unstable(feature = "slice_range", issue = "76393")] +pub fn range(range: R, bounds: ops::RangeTo) -> ops::Range +where + R: ops::RangeBounds, +{ + let len = bounds.end; + + let start: ops::Bound<&usize> = range.start_bound(); + let start = match start { + ops::Bound::Included(&start) => start, + ops::Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + ops::Bound::Unbounded => 0, + }; + + let end: ops::Bound<&usize> = range.end_bound(); + let end = match end { + ops::Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + ops::Bound::Excluded(&end) => end, + ops::Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + ops::Range { start, end } +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e78b6476511..8256d2cc607 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -18,6 +18,7 @@ use crate::option::Option::{None, Some}; use crate::ptr; use crate::result::Result; use crate::result::Result::{Err, Ok}; +use crate::slice; #[unstable( feature = "slice_internals", @@ -29,7 +30,7 @@ pub mod memchr; mod ascii; mod cmp; -pub(crate) mod index; +mod index; mod iter; mod raw; mod rotate; @@ -76,6 +77,9 @@ pub use sort::heapsort; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; +#[unstable(feature = "slice_range", issue = "76393")] +pub use index::range; + #[lang = "slice"] #[cfg(not(test))] impl [T] { @@ -3052,7 +3056,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = Range::ensure_subset_of(src, ..self.len()); + let Range { start: src_start, end: src_end } = slice::range(src, ..self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, From fe4fe19ddc38a2da883e1e38d18c821ad1c26fc5 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Fri, 12 Feb 2021 22:03:39 -0500 Subject: [PATCH 16/38] Update new usage of `assert_len` --- library/alloc/src/vec/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a8474f8ca59..77302d33bc1 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2036,11 +2036,11 @@ impl Vec { where R: RangeBounds, { - let range = src.assert_len(self.len()); + let range = slice::range(src, ..self.len()); self.reserve(range.len()); // SAFETY: - // - `assert_len` guarantees that the given range is valid for indexing self + // - `slice::range` guarantees that the given range is valid for indexing self unsafe { self.spec_extend_from_within(range); } From eace240ebebf46c88959d15bdd634af104de92fe Mon Sep 17 00:00:00 2001 From: Henry Boisdequin <65845077+henryboisdequin@users.noreply.github.com> Date: Sun, 14 Feb 2021 14:39:24 +0530 Subject: [PATCH 17/38] use option> to clean up mir code a little --- compiler/rustc_middle/src/mir/mod.rs | 6 ++---- .../src/transform/check_consts/validation.rs | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cd2bea86ea1..718e81c84ed 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -962,8 +962,7 @@ impl<'tcx> LocalDecl<'tcx> { opt_ty_info: _, opt_match_place: _, pat_span: _, - }) - | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm), + }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm), ))) ) } @@ -980,8 +979,7 @@ impl<'tcx> LocalDecl<'tcx> { opt_ty_info: _, opt_match_place: _, pat_span: _, - }) - | BindingForm::ImplicitSelf(_), + }) | BindingForm::ImplicitSelf(_), ))) ) } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 08d969b27be..d8e325f1da7 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -492,7 +492,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // Special-case reborrows to be more like a copy of a reference. match *rvalue { Rvalue::Ref(_, kind, place) => { - if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, self.body, place) { + if let Some(place_ref) = place_as_reborrow(self.tcx, self.body, place) { let ctx = match kind { BorrowKind::Shared => { PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) @@ -508,12 +508,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } }; self.visit_local(&place.local, ctx, location); - self.visit_projection(place.local, reborrowed_proj, ctx, location); + self.visit_projection(place.local, place_ref.projection, ctx, location); return; } } Rvalue::AddressOf(mutbl, place) => { - if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, self.body, place) { + if let Some(place_ref) = place_as_reborrow(self.tcx, self.body, place) { let ctx = match mutbl { Mutability::Not => { PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) @@ -521,7 +521,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), }; self.visit_local(&place.local, ctx, location); - self.visit_projection(place.local, reborrowed_proj, ctx, location); + self.visit_projection(place.local, place_ref.projection, ctx, location); return; } } @@ -1016,7 +1016,7 @@ fn place_as_reborrow( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>, -) -> Option<&'a [PlaceElem<'tcx>]> { +) -> Option> { match place.as_ref().last_projection() { Some((place_base, ProjectionElem::Deref)) => { // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` @@ -1025,13 +1025,14 @@ fn place_as_reborrow( None } else { // Ensure the type being derefed is a reference and not a raw pointer. - // // This is sufficient to prevent an access to a `static mut` from being marked as a // reborrow, even if the check above were to disappear. let inner_ty = place_base.ty(body, tcx).ty; - match inner_ty.kind() { - ty::Ref(..) => Some(place_base.projection), - _ => None, + + if let ty::Ref(..) = inner_ty.kind() { + return Some(place_base); + } else { + return None; } } } From 7879099ad3ef6c84d8df96521c30b7bf4c573615 Mon Sep 17 00:00:00 2001 From: Reese Williams Date: Sun, 14 Feb 2021 13:14:11 -0500 Subject: [PATCH 18/38] Clarify error message and remove pretty printing in help suggestions. --- compiler/rustc_typeck/src/check/pat.rs | 14 +++++--------- src/test/ui/issues/issue-17800.stderr | 4 +++- .../missing-fields-in-struct-pattern.stderr | 4 +++- src/test/ui/parser/recover-from-bad-variant.stderr | 4 +++- src/test/ui/structs/struct-tuple-field-names.rs | 2 +- .../ui/structs/struct-tuple-field-names.stderr | 10 +++++++--- src/test/ui/type/type-check/issue-41314.stderr | 4 +++- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index f16f8c9caf2..cfcd0d673d0 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1253,17 +1253,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess, pat.span, E0769, - "tuple variant `{}` uses a bare index in a struct pattern", + "tuple variant `{}` written as struct variant", path ); err.span_suggestion( - pat.span, + qpath.span().shrink_to_hi().until(pat.span), "use the tuple variant pattern syntax instead", - format!( - "{}({})", - path, - self.get_suggested_tuple_struct_pattern(fields, variant) - ), + format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)), Applicability::MaybeIncorrect, ); return Some(err); @@ -1421,9 +1417,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }; err.span_suggestion( - pat.span, + qpath.span().shrink_to_hi().until(pat.span), "use the tuple variant pattern syntax instead", - format!("{}({})", path, sugg), + format!("({})", sugg), appl, ); return Some(err); diff --git a/src/test/ui/issues/issue-17800.stderr b/src/test/ui/issues/issue-17800.stderr index fc034a0cbf3..4f961823231 100644 --- a/src/test/ui/issues/issue-17800.stderr +++ b/src/test/ui/issues/issue-17800.stderr @@ -2,7 +2,9 @@ error[E0769]: tuple variant `MyOption::MySome` written as struct variant --> $DIR/issue-17800.rs:8:9 | LL | MyOption::MySome { x: 42 } => (), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `MyOption::MySome(42)` + | ----------------^^^^^^^^^^ + | | + | help: use the tuple variant pattern syntax instead: `(42)` error: aborting due to previous error diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr index 6583524aad1..81d208e4bc3 100644 --- a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr +++ b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr @@ -2,7 +2,9 @@ error[E0769]: tuple variant `S` written as struct variant --> $DIR/missing-fields-in-struct-pattern.rs:4:12 | LL | if let S { a, b, c, d } = S(1, 2, 3, 4) { - | ^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `S(a, b, c, d)` + | -^^^^^^^^^^^^^^^ + | | + | help: use the tuple variant pattern syntax instead: `(a, b, c, d)` error: aborting due to previous error diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr index 89232a519d7..86086cf97ec 100644 --- a/src/test/ui/parser/recover-from-bad-variant.stderr +++ b/src/test/ui/parser/recover-from-bad-variant.stderr @@ -22,7 +22,9 @@ error[E0769]: tuple variant `Enum::Bar` written as struct variant --> $DIR/recover-from-bad-variant.rs:12:9 | LL | Enum::Bar { a, b } => {} - | ^^^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Enum::Bar(a, b)` + | ---------^^^^^^^^^ + | | + | help: use the tuple variant pattern syntax instead: `(a, b)` error: aborting due to 3 previous errors diff --git a/src/test/ui/structs/struct-tuple-field-names.rs b/src/test/ui/structs/struct-tuple-field-names.rs index 0ebbff75e59..7bd54af1dbe 100644 --- a/src/test/ui/structs/struct-tuple-field-names.rs +++ b/src/test/ui/structs/struct-tuple-field-names.rs @@ -6,7 +6,7 @@ fn main() { let x = E::S(1, 2.2); match x { E::S { 0, 1 } => {} - //~^ ERROR tuple variant `E::S` uses a bare index in a struct pattern [E0769] + //~^ ERROR tuple variant `E::S` written as struct variant [E0769] } let y = S(1, 2.2); match y { diff --git a/src/test/ui/structs/struct-tuple-field-names.stderr b/src/test/ui/structs/struct-tuple-field-names.stderr index 2021aa9d70e..80c6187cbbe 100644 --- a/src/test/ui/structs/struct-tuple-field-names.stderr +++ b/src/test/ui/structs/struct-tuple-field-names.stderr @@ -1,14 +1,18 @@ -error[E0769]: tuple variant `E::S` uses a bare index in a struct pattern +error[E0769]: tuple variant `E::S` written as struct variant --> $DIR/struct-tuple-field-names.rs:8:9 | LL | E::S { 0, 1 } => {} - | ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)` + | ----^^^^^^^^^ + | | + | help: use the tuple variant pattern syntax instead: `(_, _)` error[E0769]: tuple variant `S` written as struct variant --> $DIR/struct-tuple-field-names.rs:13:9 | LL | S { } => {} - | ^^^^^ help: use the tuple variant pattern syntax instead: `S(_, _)` + | -^^^^ + | | + | help: use the tuple variant pattern syntax instead: `(_, _)` error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-check/issue-41314.stderr b/src/test/ui/type/type-check/issue-41314.stderr index bd4d2071c20..78c14d37518 100644 --- a/src/test/ui/type/type-check/issue-41314.stderr +++ b/src/test/ui/type/type-check/issue-41314.stderr @@ -2,7 +2,9 @@ error[E0769]: tuple variant `X::Y` written as struct variant --> $DIR/issue-41314.rs:7:9 | LL | X::Y { number } => {} - | ^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `X::Y(number)` + | ----^^^^^^^^^^^ + | | + | help: use the tuple variant pattern syntax instead: `(number)` error: aborting due to previous error From 33d8b0456876181883f8d97997a3a0a6e9ff652f Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Sun, 14 Feb 2021 18:23:30 +0000 Subject: [PATCH 19/38] Move const def nearer usage. --- library/core/src/num/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 42ccdd00bbd..c13f000a736 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -6,9 +6,6 @@ use crate::intrinsics; use crate::mem; use crate::str::FromStr; -/// If 6th bit set ascii is upper case. -const ASCII_CASE_MASK: u8 = 0b0010_0000; - // Used because the `?` operator is not allowed in a const context. macro_rules! try_opt { ($e:expr) => { @@ -155,6 +152,9 @@ impl isize { usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } +/// If 6th bit set ascii is upper case. +const ASCII_CASE_MASK: u8 = 0b0010_0000; + #[lang = "u8"] impl u8 { uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", From 5ef202520f9c4c87dd6218bbfbbf57587e88f8be Mon Sep 17 00:00:00 2001 From: Andrea Nall Date: Mon, 15 Feb 2021 02:27:20 +0000 Subject: [PATCH 20/38] add diagnostic items Add diagnostic items to the following types: OsString (os_string_type) PathBuf (path_buf_type) Owned (to_owned_trait) As well as the to_vec method on slice/[T] --- compiler/rustc_span/src/symbol.rs | 4 ++++ library/alloc/src/borrow.rs | 1 + library/alloc/src/slice.rs | 1 + library/std/src/ffi/os_str.rs | 1 + library/std/src/path.rs | 1 + 5 files changed, 8 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1c37a6b2aca..de6210d1893 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -796,6 +796,7 @@ symbols! { options, or, or_patterns, + os_string_type, other, out, overlapping_marker_traits, @@ -824,6 +825,7 @@ symbols! { pat2018, pat2021, path, + path_buf_type, pattern_parentheses, phantom_data, pin, @@ -1084,6 +1086,7 @@ symbols! { slice, slice_alloc, slice_patterns, + slice_to_vec_method, slice_u8, slice_u8_alloc, slicing_syntax, @@ -1159,6 +1162,7 @@ symbols! { then_with, thread, thread_local, + to_owned_trait, tool_attributes, tool_lints, trace_macros, diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index adf996fc782..2fa349e3a4f 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -32,6 +32,7 @@ where /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_trait")] pub trait ToOwned { /// The resulting type after obtaining ownership. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index cb015b94930..f8cc6a45877 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -442,6 +442,7 @@ impl [T] { /// // Here, `s` and `x` can be modified independently. /// ``` #[rustc_conversion_suggestion] + #[rustc_diagnostic_item = "slice_to_vec_method"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_vec(&self) -> Vec diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c9c8f68cd9c..c1629d8b8f9 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -71,6 +71,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions #[derive(Clone)] +#[cfg_attr(not(test), rustc_diagnostic_item = "os_string_type")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { inner: Buf, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 1889e549338..66135a719be 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1066,6 +1066,7 @@ impl FusedIterator for Ancestors<'_> {} /// /// Which method works best depends on what kind of situation you're in. #[derive(Clone)] +#[cfg_attr(not(test), rustc_diagnostic_item = "path_buf_type")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `PathBuf::as_mut_vec` current implementation relies From c6bb62810ae226b35e0181d8c4efc6d0377d196d Mon Sep 17 00:00:00 2001 From: Andrea Nall Date: Mon, 15 Feb 2021 22:58:03 +0000 Subject: [PATCH 21/38] requested/proposed changes --- compiler/rustc_span/src/symbol.rs | 7 +++---- library/alloc/src/borrow.rs | 2 +- library/alloc/src/slice.rs | 2 +- library/std/src/ffi/os_str.rs | 2 +- library/std/src/path.rs | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index de6210d1893..83b13e7d93c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -169,10 +169,12 @@ symbols! { Option, Ord, Ordering, + OsString, Output, Param, PartialEq, PartialOrd, + PathBuf, Pending, Pin, Poll, @@ -198,6 +200,7 @@ symbols! { StructuralPartialEq, Sync, Target, + ToOwned, Try, Ty, TyCtxt, @@ -796,7 +799,6 @@ symbols! { options, or, or_patterns, - os_string_type, other, out, overlapping_marker_traits, @@ -825,7 +827,6 @@ symbols! { pat2018, pat2021, path, - path_buf_type, pattern_parentheses, phantom_data, pin, @@ -1086,7 +1087,6 @@ symbols! { slice, slice_alloc, slice_patterns, - slice_to_vec_method, slice_u8, slice_u8_alloc, slicing_syntax, @@ -1162,7 +1162,6 @@ symbols! { then_with, thread, thread_local, - to_owned_trait, tool_attributes, tool_lints, trace_macros, diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 2fa349e3a4f..cec32251819 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -32,7 +32,7 @@ where /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_trait")] +#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")] pub trait ToOwned { /// The resulting type after obtaining ownership. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index f8cc6a45877..839f742f1af 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -220,6 +220,7 @@ mod hack { } #[lang = "slice_alloc"] +#[cfg_attr(not(test), rustc_diagnostic_item = "slice")] #[cfg(not(test))] impl [T] { /// Sorts the slice. @@ -442,7 +443,6 @@ impl [T] { /// // Here, `s` and `x` can be modified independently. /// ``` #[rustc_conversion_suggestion] - #[rustc_diagnostic_item = "slice_to_vec_method"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_vec(&self) -> Vec diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c1629d8b8f9..6af5adf4cd8 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -71,7 +71,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions #[derive(Clone)] -#[cfg_attr(not(test), rustc_diagnostic_item = "os_string_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { inner: Buf, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 66135a719be..759b233c7c1 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1066,7 +1066,7 @@ impl FusedIterator for Ancestors<'_> {} /// /// Which method works best depends on what kind of situation you're in. #[derive(Clone)] -#[cfg_attr(not(test), rustc_diagnostic_item = "path_buf_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `PathBuf::as_mut_vec` current implementation relies From 30c5125fbe86f48a547a23917dcafab1b3f3ac7e Mon Sep 17 00:00:00 2001 From: Henry Boisdequin <65845077+henryboisdequin@users.noreply.github.com> Date: Tue, 16 Feb 2021 07:01:55 +0530 Subject: [PATCH 22/38] update formating --- compiler/rustc_middle/src/mir/mod.rs | 6 +++-- .../src/transform/check_consts/validation.rs | 22 ++++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 718e81c84ed..cd2bea86ea1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -962,7 +962,8 @@ impl<'tcx> LocalDecl<'tcx> { opt_ty_info: _, opt_match_place: _, pat_span: _, - }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm), + }) + | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm), ))) ) } @@ -979,7 +980,8 @@ impl<'tcx> LocalDecl<'tcx> { opt_ty_info: _, opt_match_place: _, pat_span: _, - }) | BindingForm::ImplicitSelf(_), + }) + | BindingForm::ImplicitSelf(_), ))) ) } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index d8e325f1da7..34db0c9ab16 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -492,7 +492,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // Special-case reborrows to be more like a copy of a reference. match *rvalue { Rvalue::Ref(_, kind, place) => { - if let Some(place_ref) = place_as_reborrow(self.tcx, self.body, place) { + if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { let ctx = match kind { BorrowKind::Shared => { PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) @@ -507,21 +507,31 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } }; - self.visit_local(&place.local, ctx, location); - self.visit_projection(place.local, place_ref.projection, ctx, location); + self.visit_local(&reborrowed_place_ref.local, ctx, location); + self.visit_projection( + reborrowed_place_ref.local, + reborrowed_place_ref.projection, + ctx, + location, + ); return; } } Rvalue::AddressOf(mutbl, place) => { - if let Some(place_ref) = place_as_reborrow(self.tcx, self.body, place) { + if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { let ctx = match mutbl { Mutability::Not => { PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) } Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), }; - self.visit_local(&place.local, ctx, location); - self.visit_projection(place.local, place_ref.projection, ctx, location); + self.visit_local(&reborrowed_place_ref.local, ctx, location); + self.visit_projection( + reborrowed_place_ref.local, + reborrowed_place_ref.projection, + ctx, + location, + ); return; } } From 67fcaaaa7a9c393926e25db600a9976137425d68 Mon Sep 17 00:00:00 2001 From: Andrea Nall Date: Tue, 16 Feb 2021 02:32:21 +0000 Subject: [PATCH 23/38] a few more diagnostic items --- compiler/rustc_span/src/symbol.rs | 3 +++ library/alloc/src/borrow.rs | 2 +- library/alloc/src/string.rs | 1 + library/std/src/ffi/os_str.rs | 1 + library/std/src/path.rs | 1 + 5 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 83b13e7d93c..1137a83bc77 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -169,11 +169,13 @@ symbols! { Option, Ord, Ordering, + OsStr, OsString, Output, Param, PartialEq, PartialOrd, + Path, PathBuf, Pending, Pin, @@ -201,6 +203,7 @@ symbols! { Sync, Target, ToOwned, + ToString, Try, Ty, TyCtxt, diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index cec32251819..bdb2d67347e 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -31,8 +31,8 @@ where /// implementing the `Clone` trait. But `Clone` works only for going from `&T` /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. -#[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")] +#[stable(feature = "rust1", since = "1.0.0")] pub trait ToOwned { /// The resulting type after obtaining ownership. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3218b3535c9..00fd1c2908b 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2174,6 +2174,7 @@ impl FromStr for String { /// implementation for free. /// /// [`Display`]: fmt::Display +#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToString { /// Converts the given value to a `String`. diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 6af5adf4cd8..13c8022820b 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -90,6 +90,7 @@ pub struct OsString { /// /// [`&str`]: str /// [conversions]: super#conversions +#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `OsStr::from_inner` current implementation relies diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 759b233c7c1..afb28518b72 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1720,6 +1720,7 @@ impl AsRef for PathBuf { /// let extension = path.extension(); /// assert_eq!(extension, Some(OsStr::new("txt"))); /// ``` +#[cfg_attr(not(test), rustc_diagnostic_item = "Path")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `Path::new` current implementation relies From 5ec4b060a793b7e04e87654b1d96f5d1fca23667 Mon Sep 17 00:00:00 2001 From: Henry Boisdequin <65845077+henryboisdequin@users.noreply.github.com> Date: Tue, 16 Feb 2021 14:20:36 +0530 Subject: [PATCH 24/38] make `visit_projection` take a `PlaceRef` --- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 2 +- compiler/rustc_middle/src/mir/visit.rs | 7 +++---- compiler/rustc_mir/src/dataflow/impls/liveness.rs | 2 +- .../src/transform/check_consts/validation.rs | 14 ++------------ 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index fd0ff5b66e6..289629d9215 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -199,7 +199,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } self.visit_local(&place_ref.local, context, location); - self.visit_projection(place_ref.local, place_ref.projection, context, location); + self.visit_projection(*place_ref, context, location); } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 023555d91cc..66dd278b578 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -998,12 +998,11 @@ macro_rules! visit_place_fns { () => { fn visit_projection( &mut self, - local: Local, - projection: &[PlaceElem<'tcx>], + place_ref: PlaceRef<'tcx>, context: PlaceContext, location: Location, ) { - self.super_projection(local, projection, context, location); + self.super_projection(place_ref.local, place_ref.projection, context, location); } fn visit_projection_elem( @@ -1033,7 +1032,7 @@ macro_rules! visit_place_fns { self.visit_local(&place.local, context, location); - self.visit_projection(place.local, &place.projection, context, location); + self.visit_projection(place.as_ref(), context, location); } fn super_projection( diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs index 85aaff5ab72..2d20f0d9547 100644 --- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs @@ -95,7 +95,7 @@ where // We purposefully do not call `super_place` here to avoid calling `visit_local` for this // place with one of the `Projection` variants of `PlaceContext`. - self.visit_projection(local, projection, context, location); + self.visit_projection(place.as_ref(), context, location); match DefUse::for_place(context) { // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use. diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 34db0c9ab16..aaf2c83d1d9 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -508,12 +508,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } }; self.visit_local(&reborrowed_place_ref.local, ctx, location); - self.visit_projection( - reborrowed_place_ref.local, - reborrowed_place_ref.projection, - ctx, - location, - ); + self.visit_projection(reborrowed_place_ref, ctx, location); return; } } @@ -526,12 +521,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), }; self.visit_local(&reborrowed_place_ref.local, ctx, location); - self.visit_projection( - reborrowed_place_ref.local, - reborrowed_place_ref.projection, - ctx, - location, - ); + self.visit_projection(reborrowed_place_ref, ctx, location); return; } } From eeb555266764069937491a26e817d4bcfea5da3a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Feb 2021 20:24:50 +0100 Subject: [PATCH 25/38] Remove query parameters when leaving search results --- src/librustdoc/html/static/main.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ec89ae0228c..e8daa8414a2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -101,7 +101,7 @@ function focusSearchBar() { getSearchInput().focus(); } -// Removes the focus from the search bar +// Removes the focus from the search bar. function defocusSearchBar() { getSearchInput().blur(); } @@ -220,6 +220,11 @@ function defocusSearchBar() { addClass(search, "hidden"); removeClass(main, "hidden"); document.title = titleBeforeSearch; + // We also remove the query parameter from the URL. + if (browserSupportsHistoryApi()) { + history.replaceState("", window.currentCrate + " - Rust", + getNakedUrl() + window.location.hash); + } } // used for special search precedence From 8ddd846ce118e5f0bb423d310cb38c7f4a76890e Mon Sep 17 00:00:00 2001 From: Nathan Nguyen Date: Thu, 18 Feb 2021 05:25:45 -0600 Subject: [PATCH 26/38] nhwn: make treat_err_as_bug Option --- compiler/rustc_errors/src/lib.rs | 13 +++++++------ compiler/rustc_interface/src/tests.rs | 3 ++- compiler/rustc_session/src/config.rs | 2 ++ compiler/rustc_session/src/options.rs | 9 +++++---- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9800ed9bfa9..a0be7442d59 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -30,6 +30,7 @@ use rustc_span::{Loc, MultiSpan, Span}; use std::borrow::Cow; use std::hash::{Hash, Hasher}; +use std::num::NonZeroUsize; use std::panic; use std::path::Path; use std::{error, fmt}; @@ -359,7 +360,7 @@ pub struct HandlerFlags { pub can_emit_warnings: bool, /// If true, error-level diagnostics are upgraded to bug-level. /// (rustc: see `-Z treat-err-as-bug`) - pub treat_err_as_bug: Option, + pub treat_err_as_bug: Option, /// If true, immediately emit diagnostics that would otherwise be buffered. /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`) pub dont_buffer_diagnostics: bool, @@ -396,7 +397,7 @@ impl Handler { pub fn with_tty_emitter( color_config: ColorConfig, can_emit_warnings: bool, - treat_err_as_bug: Option, + treat_err_as_bug: Option, sm: Option>, ) -> Self { Self::with_tty_emitter_and_flags( @@ -424,7 +425,7 @@ impl Handler { pub fn with_emitter( can_emit_warnings: bool, - treat_err_as_bug: Option, + treat_err_as_bug: Option, emitter: Box, ) -> Self { Handler::with_emitter_and_flags( @@ -841,7 +842,7 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c) + self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get()) } fn print_error_count(&mut self, registry: &Registry) { @@ -950,7 +951,7 @@ impl HandlerInner { // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before // incrementing `err_count` by one, so we need to +1 the comparing. // FIXME: Would be nice to increment err_count in a more coherent way. - if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c) { + if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c.get()) { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } @@ -1023,7 +1024,7 @@ impl HandlerInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { - match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { + match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) { (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), (0, _) | (1, _) => {} (count, as_bug) => panic!( diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index f9c3406d3b3..a2e96146568 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -20,6 +20,7 @@ use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy} use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel}; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; +use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; type CfgSpecs = FxHashSet<(String, Option)>; @@ -595,7 +596,7 @@ fn test_debugging_options_tracking_hash() { tracked!(tune_cpu, Some(String::from("abc"))); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); tracked!(trap_unreachable, Some(false)); - tracked!(treat_err_as_bug, Some(1)); + tracked!(treat_err_as_bug, NonZeroUsize::new(1)); tracked!(unleash_the_miri_inside_of_you, true); tracked!(use_ctors_section, Some(true)); tracked!(verify_llvm_ir, true); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 4533b37f10b..e4f7e140281 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2313,6 +2313,7 @@ crate mod dep_tracking { use std::collections::hash_map::DefaultHasher; use std::collections::BTreeMap; use std::hash::Hash; + use std::num::NonZeroUsize; use std::path::PathBuf; pub trait DepTrackingHash { @@ -2353,6 +2354,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(lint::Level); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option<(String, u64)>); impl_dep_tracking_hash_via_hash!(Option>); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index baa0502521d..d439753d042 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -16,6 +16,7 @@ use std::collections::BTreeMap; use std::collections::hash_map::DefaultHasher; use std::hash::Hasher; +use std::num::NonZeroUsize; use std::path::PathBuf; use std::str; @@ -591,10 +592,10 @@ macro_rules! options { true } - fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { + fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { match v { - Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 } - None => { *slot = Some(1); true } + Some(s) => { *slot = s.parse().ok(); slot.is_some() } + None => { *slot = NonZeroUsize::new(1); true } } } @@ -1141,7 +1142,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "for every macro invocation, print its name and arguments (default: no)"), trap_unreachable: Option = (None, parse_opt_bool, [TRACKED], "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"), - treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], + treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], "treat error number `val` that occurs as bug"), trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], "in diagnostics, use heuristics to shorten paths referring to items"), From 48b5c093d62f670dc2ca4dd3fb65052a4bb20766 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 16 Feb 2021 00:46:14 +0000 Subject: [PATCH 27/38] add s390x-unknown-linux-musl target --- compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/s390x_unknown_linux_musl.rs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 5b14795f545..f7b49ac52b0 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -641,6 +641,7 @@ supported_targets! { ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), ("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl), ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), + ("s390x-unknown-linux-musl", s390x_unknown_linux_musl), ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu), ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs new file mode 100644 index 00000000000..4f811ce98c1 --- /dev/null +++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs @@ -0,0 +1,24 @@ +use crate::abi::Endian; +use crate::spec::Target; + +pub fn target() -> Target { + let mut base = super::linux_musl_base::opts(); + base.endian = Endian::Big; + // z10 is the oldest CPU supported by LLVM + base.cpu = "z10".to_string(); + // FIXME: The data_layout string below and the ABI implementation in + // cabi_s390x.rs are for now hard-coded to assume the no-vector ABI. + // Pass the -vector feature string to LLVM to respect this assumption. + base.features = "-vector".to_string(); + base.max_atomic_width = Some(64); + base.min_global_align = Some(16); + base.static_position_independent_executables = true; + + Target { + llvm_target: "s390x-unknown-linux-musl".to_string(), + pointer_width: 64, + data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(), + arch: "s390x".to_string(), + options: base, + } +} From 597118baa86f0e799065f2043a8a467238660f33 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 16 Feb 2021 01:34:25 +0000 Subject: [PATCH 28/38] add s390x-unknown-linux-musl target to platform support --- src/doc/rustc/src/platform-support.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 8198dbaa527..9e927067bf0 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -207,6 +207,7 @@ target | std | host | notes `riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) +`s390x-unknown-linux-musl` | ✓ | ✓ | S390x Linux (kernel 2.6.32, MUSL) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 `sparc64-unknown-openbsd` | ? | | From 62ee3ec7ba17fe705ba21f25c1a28ce751efc1b7 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 19 Feb 2021 01:12:53 +0000 Subject: [PATCH 29/38] remove checkboxes from s390x-unknown-linux-musl triplet --- src/doc/rustc/src/platform-support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 9e927067bf0..6335709dc48 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -207,7 +207,7 @@ target | std | host | notes `riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) -`s390x-unknown-linux-musl` | ✓ | ✓ | S390x Linux (kernel 2.6.32, MUSL) +`s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 `sparc64-unknown-openbsd` | ? | | From 1abcdfe4493b781cea654840b497674907038faf Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 19 Feb 2021 07:31:01 -0800 Subject: [PATCH 30/38] x.py fmt --- library/std/src/sys/wasi/fs.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 6050620729f..83debdfc860 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -558,12 +558,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { let (original, original_file) = open_parent(original)?; let (link, link_file) = open_parent(link)?; // Pass 0 as the flags argument, meaning don't follow symlinks. - original.link( - 0, - osstr2str(original_file.as_ref())?, - &link, - osstr2str(link_file.as_ref())?, - ) + original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?) } pub fn stat(p: &Path) -> io::Result { From a9c61888896da6feea45875813b894e7fa4067f6 Mon Sep 17 00:00:00 2001 From: Henry Boisdequin <65845077+henryboisdequin@users.noreply.github.com> Date: Sat, 20 Feb 2021 16:46:05 +0530 Subject: [PATCH 31/38] make `super_projection` take a `PlaceRef` --- compiler/rustc_middle/src/mir/visit.rs | 10 +++++----- compiler/rustc_mir/src/transform/simplify.rs | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 66dd278b578..9530efaedbc 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1002,7 +1002,7 @@ macro_rules! visit_place_fns { context: PlaceContext, location: Location, ) { - self.super_projection(place_ref.local, place_ref.projection, context, location); + self.super_projection(place_ref, context, location); } fn visit_projection_elem( @@ -1037,15 +1037,15 @@ macro_rules! visit_place_fns { fn super_projection( &mut self, - local: Local, - projection: &[PlaceElem<'tcx>], + place_ref: PlaceRef<'tcx>, context: PlaceContext, location: Location, ) { - let mut cursor = projection; + // FIXME: Use PlaceRef::iter_projections, once that exists. + let mut cursor = place_ref.projection; while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; - self.visit_projection_elem(local, cursor, elem, context, location); + self.visit_projection_elem(place_ref.local, cursor, elem, context, location); } } diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index 289231e52cb..d9abfec85c9 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -414,8 +414,7 @@ impl UsedLocals { } else { // A definition. Although, it still might use other locals for indexing. self.super_projection( - place.local, - &place.projection, + place.as_ref(), PlaceContext::MutatingUse(MutatingUseContext::Projection), location, ); From d8540ae5a98b6135253521cdbf34c5953494a5bf Mon Sep 17 00:00:00 2001 From: Reese Williams Date: Sat, 20 Feb 2021 15:33:08 -0500 Subject: [PATCH 32/38] Fix suggestion span and move suggestions into new subwindow. --- compiler/rustc_typeck/src/check/pat.rs | 8 ++++---- src/test/ui/issues/issue-17800.stderr | 9 ++++++--- .../missing-fields-in-struct-pattern.stderr | 9 ++++++--- .../ui/parser/recover-from-bad-variant.stderr | 9 ++++++--- .../ui/structs/struct-tuple-field-names.stderr | 18 ++++++++++++------ src/test/ui/type/type-check/issue-41314.stderr | 9 ++++++--- 6 files changed, 40 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index cfcd0d673d0..c21e7d8aebc 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1256,8 +1256,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "tuple variant `{}` written as struct variant", path ); - err.span_suggestion( - qpath.span().shrink_to_hi().until(pat.span), + err.span_suggestion_verbose( + qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()), "use the tuple variant pattern syntax instead", format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)), Applicability::MaybeIncorrect, @@ -1416,8 +1416,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ) }; - err.span_suggestion( - qpath.span().shrink_to_hi().until(pat.span), + err.span_suggestion_verbose( + qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()), "use the tuple variant pattern syntax instead", format!("({})", sugg), appl, diff --git a/src/test/ui/issues/issue-17800.stderr b/src/test/ui/issues/issue-17800.stderr index 4f961823231..7df86d7326b 100644 --- a/src/test/ui/issues/issue-17800.stderr +++ b/src/test/ui/issues/issue-17800.stderr @@ -2,9 +2,12 @@ error[E0769]: tuple variant `MyOption::MySome` written as struct variant --> $DIR/issue-17800.rs:8:9 | LL | MyOption::MySome { x: 42 } => (), - | ----------------^^^^^^^^^^ - | | - | help: use the tuple variant pattern syntax instead: `(42)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | MyOption::MySome(42) => (), + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr index 81d208e4bc3..a95b5bb94d2 100644 --- a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr +++ b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr @@ -2,9 +2,12 @@ error[E0769]: tuple variant `S` written as struct variant --> $DIR/missing-fields-in-struct-pattern.rs:4:12 | LL | if let S { a, b, c, d } = S(1, 2, 3, 4) { - | -^^^^^^^^^^^^^^^ - | | - | help: use the tuple variant pattern syntax instead: `(a, b, c, d)` + | ^^^^^^^^^^^^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | if let S(a, b, c, d) = S(1, 2, 3, 4) { + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr index 86086cf97ec..9b9d2bc4972 100644 --- a/src/test/ui/parser/recover-from-bad-variant.stderr +++ b/src/test/ui/parser/recover-from-bad-variant.stderr @@ -22,9 +22,12 @@ error[E0769]: tuple variant `Enum::Bar` written as struct variant --> $DIR/recover-from-bad-variant.rs:12:9 | LL | Enum::Bar { a, b } => {} - | ---------^^^^^^^^^ - | | - | help: use the tuple variant pattern syntax instead: `(a, b)` + | ^^^^^^^^^^^^^^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | Enum::Bar(a, b) => {} + | ^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/structs/struct-tuple-field-names.stderr b/src/test/ui/structs/struct-tuple-field-names.stderr index 80c6187cbbe..29e72146521 100644 --- a/src/test/ui/structs/struct-tuple-field-names.stderr +++ b/src/test/ui/structs/struct-tuple-field-names.stderr @@ -2,17 +2,23 @@ error[E0769]: tuple variant `E::S` written as struct variant --> $DIR/struct-tuple-field-names.rs:8:9 | LL | E::S { 0, 1 } => {} - | ----^^^^^^^^^ - | | - | help: use the tuple variant pattern syntax instead: `(_, _)` + | ^^^^^^^^^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | E::S(_, _) => {} + | ^^^^^^ error[E0769]: tuple variant `S` written as struct variant --> $DIR/struct-tuple-field-names.rs:13:9 | LL | S { } => {} - | -^^^^ - | | - | help: use the tuple variant pattern syntax instead: `(_, _)` + | ^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | S(_, _) => {} + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-check/issue-41314.stderr b/src/test/ui/type/type-check/issue-41314.stderr index 78c14d37518..c3d41ae68cd 100644 --- a/src/test/ui/type/type-check/issue-41314.stderr +++ b/src/test/ui/type/type-check/issue-41314.stderr @@ -2,9 +2,12 @@ error[E0769]: tuple variant `X::Y` written as struct variant --> $DIR/issue-41314.rs:7:9 | LL | X::Y { number } => {} - | ----^^^^^^^^^^^ - | | - | help: use the tuple variant pattern syntax instead: `(number)` + | ^^^^^^^^^^^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | X::Y(number) => {} + | ^^^^^^^^ error: aborting due to previous error From 796ce9fcb7e35767e6e57ad79099dcf730a0a94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 4 Feb 2021 12:22:01 -0800 Subject: [PATCH 33/38] Suggest `return`ing tail expressions that match return type Some newcomers are confused by the behavior of tail expressions, interpreting that "leaving out the `;` makes it the return value". To help them go in the right direction, suggest using `return` instead when applicable. --- compiler/rustc_typeck/src/check/coercion.rs | 12 +++++++- .../src/check/fn_ctxt/suggestions.rs | 28 +++++++++++++++++++ src/test/ui/macros/empty-trailing-stmt.stderr | 5 ++++ src/test/ui/parser/expr-as-stmt-2.stderr | 22 +++++++++++++-- src/test/ui/parser/expr-as-stmt.stderr | 20 +++++++++++++ .../return/tail-expr-as-potential-return.rs | 11 ++++++++ .../tail-expr-as-potential-return.stderr | 27 ++++++++++++++++++ 7 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/return/tail-expr-as-potential-return.rs create mode 100644 src/test/ui/return/tail-expr-as-potential-return.stderr diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index b2395b7bb25..f95627cfdee 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1458,7 +1458,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.get_fn_decl(parent_id) }; - if let (Some((fn_decl, can_suggest)), _) = (fn_decl, pointing_at_return_type) { + if let Some((fn_decl, can_suggest)) = fn_decl { if expression.is_none() { pointing_at_return_type |= fcx.suggest_missing_return_type( &mut err, @@ -1472,6 +1472,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn_output = Some(&fn_decl.output); // `impl Trait` return type } } + + let parent_id = fcx.tcx.hir().get_parent_item(id); + let parent_item = fcx.tcx.hir().get(parent_id); + + if let (Some((expr, _)), Some((fn_decl, _, _))) = + (expression, fcx.get_node_fn_decl(parent_item)) + { + fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found); + } + if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) { self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index a0465ca6aef..9d816e76c00 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -464,6 +464,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(in super::super) fn suggest_missing_return_expr( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &'tcx hir::Expr<'tcx>, + fn_decl: &hir::FnDecl<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + if !expected.is_unit() { + return; + } + let found = self.resolve_vars_with_obligations(found); + if let hir::FnRetTy::Return(ty) = fn_decl.output { + let ty = AstConv::ast_ty_to_ty(self, ty); + let ty = self.normalize_associated_types_in(expr.span, ty); + if self.can_coerce(found, ty) { + err.multipart_suggestion( + "you might have meant to return this value", + vec![ + (expr.span.shrink_to_lo(), "return ".to_string()), + (expr.span.shrink_to_hi(), ";".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } + } + } + pub(in super::super) fn suggest_missing_parentheses( &self, err: &mut DiagnosticBuilder<'_>, diff --git a/src/test/ui/macros/empty-trailing-stmt.stderr b/src/test/ui/macros/empty-trailing-stmt.stderr index e88b12712fb..1db759a2181 100644 --- a/src/test/ui/macros/empty-trailing-stmt.stderr +++ b/src/test/ui/macros/empty-trailing-stmt.stderr @@ -3,6 +3,11 @@ error[E0308]: mismatched types | LL | { true } | ^^^^ expected `()`, found `bool` + | +help: you might have meant to return this value + | +LL | { return true; } + | ^^^^^^ ^ error[E0308]: mismatched types --> $DIR/empty-trailing-stmt.rs:5:13 diff --git a/src/test/ui/parser/expr-as-stmt-2.stderr b/src/test/ui/parser/expr-as-stmt-2.stderr index ee07c367633..75c0e7bb475 100644 --- a/src/test/ui/parser/expr-as-stmt-2.stderr +++ b/src/test/ui/parser/expr-as-stmt-2.stderr @@ -2,19 +2,37 @@ error[E0308]: mismatched types --> $DIR/expr-as-stmt-2.rs:3:26 | LL | if let Some(x) = a { true } else { false } - | ---------------------^^^^------------------ help: consider using a semicolon here + | ---------------------^^^^----------------- | | | | | expected `()`, found `bool` | expected this to be `()` + | +help: consider using a semicolon here + | +LL | if let Some(x) = a { true } else { false }; + | ^ +help: you might have meant to return this value + | +LL | if let Some(x) = a { return true; } else { false } + | ^^^^^^ ^ error[E0308]: mismatched types --> $DIR/expr-as-stmt-2.rs:3:40 | LL | if let Some(x) = a { true } else { false } - | -----------------------------------^^^^^--- help: consider using a semicolon here + | -----------------------------------^^^^^-- | | | | | expected `()`, found `bool` | expected this to be `()` + | +help: consider using a semicolon here + | +LL | if let Some(x) = a { true } else { false }; + | ^ +help: you might have meant to return this value + | +LL | if let Some(x) = a { true } else { return false; } + | ^^^^^^ ^ error[E0308]: mismatched types --> $DIR/expr-as-stmt-2.rs:6:5 diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr index 324aed0ad7c..09a6d7cbeb1 100644 --- a/src/test/ui/parser/expr-as-stmt.stderr +++ b/src/test/ui/parser/expr-as-stmt.stderr @@ -40,24 +40,44 @@ error[E0308]: mismatched types | LL | {2} + {2} | ^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | {return 2;} + {2} + | ^^^^^^ ^ error[E0308]: mismatched types --> $DIR/expr-as-stmt.rs:12:6 | LL | {2} + 2 | ^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | {return 2;} + 2 + | ^^^^^^ ^ error[E0308]: mismatched types --> $DIR/expr-as-stmt.rs:18:7 | LL | { 42 } + foo; | ^^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | { return 42; } + foo; + | ^^^^^^ ^ error[E0308]: mismatched types --> $DIR/expr-as-stmt.rs:24:7 | LL | { 3 } * 3 | ^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | { return 3; } * 3 + | ^^^^^^ ^ error[E0614]: type `{integer}` cannot be dereferenced --> $DIR/expr-as-stmt.rs:24:11 diff --git a/src/test/ui/return/tail-expr-as-potential-return.rs b/src/test/ui/return/tail-expr-as-potential-return.rs new file mode 100644 index 00000000000..72798c720f3 --- /dev/null +++ b/src/test/ui/return/tail-expr-as-potential-return.rs @@ -0,0 +1,11 @@ +fn main() { + let _ = foo(true); +} + +fn foo(x: bool) -> Result { + if x { + Err(42) //~ ERROR mismatched types + } + Ok(42.0) +} + diff --git a/src/test/ui/return/tail-expr-as-potential-return.stderr b/src/test/ui/return/tail-expr-as-potential-return.stderr new file mode 100644 index 00000000000..d079e0b080d --- /dev/null +++ b/src/test/ui/return/tail-expr-as-potential-return.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/tail-expr-as-potential-return.rs:7:9 + | +LL | / if x { +LL | | Err(42) + | | ^^^^^^^ expected `()`, found enum `std::result::Result` +LL | | } + | |_____- expected this to be `()` + | + = note: expected unit type `()` + found enum `std::result::Result<_, {integer}>` +help: try adding a semicolon + | +LL | Err(42); + | ^ +help: consider using a semicolon here + | +LL | }; + | ^ +help: you might have meant to return this value + | +LL | return Err(42); + | ^^^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 020edd91a911cebf8aeada9f04dff047dc76171e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 4 Feb 2021 13:59:23 -0800 Subject: [PATCH 34/38] reword `;` suggestions to have consistent wording --- compiler/rustc_typeck/src/check/callee.rs | 2 +- compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs | 2 +- src/test/ui/async-await/suggest-missing-await.rs | 2 +- src/test/ui/async-await/suggest-missing-await.stderr | 2 +- src/test/ui/block-result/unexpected-return-on-unit.stderr | 2 +- src/test/ui/proc-macro/issue-37788.stderr | 2 +- src/test/ui/return/return-type.stderr | 2 +- src/test/ui/return/tail-expr-as-potential-return.stderr | 2 +- .../ui/specialization/specialization-default-projection.stderr | 2 +- .../issue-51055-missing-semicolon-between-call-and-tuple.stderr | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 4836418b3c2..f2fbb95fc02 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if call_is_multiline { err.span_suggestion( callee.span.shrink_to_hi(), - "try adding a semicolon", + "consider using a semicolon here", ";".to_owned(), Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 9d816e76c00..e5a2e139817 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ExprKind::Block(..) => { err.span_suggestion( cause_span.shrink_to_hi(), - "try adding a semicolon", + "consider using a semicolon here", ";".to_string(), Applicability::MachineApplicable, ); diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs index d629054911d..352a88ac10c 100644 --- a/src/test/ui/async-await/suggest-missing-await.rs +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -21,7 +21,7 @@ async fn dummy() {} async fn suggest_await_in_async_fn_return() { dummy() //~^ ERROR mismatched types [E0308] - //~| HELP try adding a semicolon + //~| HELP consider using a semicolon here //~| HELP consider `await`ing on the `Future` //~| SUGGESTION .await } diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 46615dae7e2..26e81a52c21 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -29,7 +29,7 @@ help: consider `await`ing on the `Future` | LL | dummy().await | ^^^^^^ -help: try adding a semicolon +help: consider using a semicolon here | LL | dummy(); | ^ diff --git a/src/test/ui/block-result/unexpected-return-on-unit.stderr b/src/test/ui/block-result/unexpected-return-on-unit.stderr index 3dce459ddbd..4fcd0ee2c48 100644 --- a/src/test/ui/block-result/unexpected-return-on-unit.stderr +++ b/src/test/ui/block-result/unexpected-return-on-unit.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo() | ^^^^^ expected `()`, found `usize` | -help: try adding a semicolon +help: consider using a semicolon here | LL | foo(); | ^ diff --git a/src/test/ui/proc-macro/issue-37788.stderr b/src/test/ui/proc-macro/issue-37788.stderr index 05387012902..345520d4852 100644 --- a/src/test/ui/proc-macro/issue-37788.stderr +++ b/src/test/ui/proc-macro/issue-37788.stderr @@ -5,7 +5,7 @@ LL | fn main() { | - expected `()` because of default return type LL | // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE. LL | std::cell::Cell::new(0) - | ^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` + | ^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;` | | | expected `()`, found struct `Cell` | diff --git a/src/test/ui/return/return-type.stderr b/src/test/ui/return/return-type.stderr index 535428f1c91..6ef921bef3d 100644 --- a/src/test/ui/return/return-type.stderr +++ b/src/test/ui/return/return-type.stderr @@ -6,7 +6,7 @@ LL | foo(4 as usize) | = note: expected unit type `()` found struct `S` -help: try adding a semicolon +help: consider using a semicolon here | LL | foo(4 as usize); | ^ diff --git a/src/test/ui/return/tail-expr-as-potential-return.stderr b/src/test/ui/return/tail-expr-as-potential-return.stderr index d079e0b080d..6eeaf5b3412 100644 --- a/src/test/ui/return/tail-expr-as-potential-return.stderr +++ b/src/test/ui/return/tail-expr-as-potential-return.stderr @@ -9,7 +9,7 @@ LL | | } | = note: expected unit type `()` found enum `std::result::Result<_, {integer}>` -help: try adding a semicolon +help: consider using a semicolon here | LL | Err(42); | ^ diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr index 445bc1646f0..7a2b75a1c1f 100644 --- a/src/test/ui/specialization/specialization-default-projection.stderr +++ b/src/test/ui/specialization/specialization-default-projection.stderr @@ -29,7 +29,7 @@ LL | fn monomorphic() -> () { | -- expected `()` because of return type ... LL | generic::<()>() - | ^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` + | ^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;` | | | expected `()`, found associated type | diff --git a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr index 6e4cee18c16..438075083d3 100644 --- a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr +++ b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr @@ -5,7 +5,7 @@ LL | fn vindictive() -> bool { true } | ----------------------- `vindictive` defined here returns `bool` ... LL | vindictive() - | -^^^^^^^^^^^- help: try adding a semicolon: `;` + | -^^^^^^^^^^^- help: consider using a semicolon here: `;` | _____| | | LL | | (1, 2) From d669882f386e26d214284fbe8f7696519b802778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 4 Feb 2021 17:36:06 -0800 Subject: [PATCH 35/38] Do not suggest `;` if expression is side effect free When a tail expression isn't unit, we previously always suggested adding a trailing `;` to turn it into a statement. This suggestion isn't appropriate for any expression that doesn't have side-effects, as the user will have likely wanted to call something else or do something with the resulting value, instead of just discarding it. --- compiler/rustc_hir/src/hir.rs | 58 +++++++++++++++++++ compiler/rustc_typeck/src/check/coercion.rs | 4 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 4 +- .../src/check/fn_ctxt/suggestions.rs | 9 ++- .../block-must-not-have-result-while.stderr | 4 +- src/test/ui/parser/expr-as-stmt-2.stderr | 8 --- .../struct-literal-variant-in-if.stderr | 2 +- .../tail-expr-as-potential-return.stderr | 8 --- .../ui/suggestions/match-needing-semi.fixed | 18 ------ src/test/ui/suggestions/match-needing-semi.rs | 7 ++- .../ui/suggestions/match-needing-semi.stderr | 21 ++++--- 11 files changed, 92 insertions(+), 51 deletions(-) delete mode 100644 src/test/ui/suggestions/match-needing-semi.fixed diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4df8c44e62b..84009984183 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,5 +1,6 @@ // ignore-tidy-filelength use crate::def::{DefKind, Namespace, Res}; +use crate::def::{CtorKind, DefKind, Namespace, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; use crate::{itemlikevisit, LangItem}; @@ -1554,6 +1555,63 @@ impl Expr<'_> { } expr } + + pub fn can_have_side_effects(&self) -> bool { + match self.peel_drop_temps().kind { + ExprKind::Path(_) | ExprKind::Lit(_) => false, + ExprKind::Type(base, _) + | ExprKind::Unary(_, base) + | ExprKind::Field(base, _) + | ExprKind::Index(base, _) + | ExprKind::AddrOf(.., base) + | ExprKind::Cast(base, _) => { + // This isn't exactly true for `Index` and all `Unnary`, but we are using this + // method exclusively for diagnostics and there's a *cultural* pressure against + // them being used only for its side-effects. + base.can_have_side_effects() + } + ExprKind::Struct(_, fields, init) => fields + .iter() + .map(|field| field.expr) + .chain(init.into_iter()) + .all(|e| e.can_have_side_effects()), + + ExprKind::Array(args) + | ExprKind::Tup(args) + | ExprKind::Call( + Expr { + kind: + ExprKind::Path(QPath::Resolved( + None, + Path { res: Res::Def(DefKind::Ctor(_, CtorKind::Fn), _), .. }, + )), + .. + }, + args, + ) => args.iter().all(|arg| arg.can_have_side_effects()), + ExprKind::If(..) + | ExprKind::Match(..) + | ExprKind::MethodCall(..) + | ExprKind::Call(..) + | ExprKind::Closure(..) + | ExprKind::Block(..) + | ExprKind::Repeat(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::Loop(..) + | ExprKind::Assign(..) + | ExprKind::InlineAsm(..) + | ExprKind::LlvmInlineAsm(..) + | ExprKind::AssignOp(..) + | ExprKind::ConstBlock(..) + | ExprKind::Box(..) + | ExprKind::Binary(..) + | ExprKind::Yield(..) + | ExprKind::DropTemps(..) + | ExprKind::Err => true, + } + } } /// Checks if the specified expression is a built-in range literal. diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index f95627cfdee..159c97d8bfa 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1450,7 +1450,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ) { if cond_expr.span.desugaring_kind().is_none() { err.span_label(cond_expr.span, "expected this to be `()`"); - fcx.suggest_semicolon_at_end(cond_expr.span, &mut err); + if expr.can_have_side_effects() { + fcx.suggest_semicolon_at_end(cond_expr.span, &mut err); + } } } fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 3326be796ce..155c10e8916 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -561,7 +561,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::StmtKind::Expr(ref expr) => { // Check with expected type of `()`. self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { - self.suggest_semicolon_at_end(expr.span, err); + if expr.can_have_side_effects() { + self.suggest_semicolon_at_end(expr.span, err); + } }); } hir::StmtKind::Semi(ref expr) => { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index e5a2e139817..416b75d9e2e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -44,11 +44,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { blk_id: hir::HirId, ) -> bool { let expr = expr.peel_drop_temps(); - self.suggest_missing_semicolon(err, expr, expected, cause_span); + if expr.can_have_side_effects() { + self.suggest_missing_semicolon(err, expr, expected, cause_span); + } let mut pointing_at_return_type = false; if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { pointing_at_return_type = self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); + self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found); } pointing_at_return_type } @@ -392,7 +395,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ExprKind::Loop(..) | ExprKind::If(..) | ExprKind::Match(..) - | ExprKind::Block(..) => { + | ExprKind::Block(..) + if expression.can_have_side_effects() => + { err.span_suggestion( cause_span.shrink_to_hi(), "consider using a semicolon here", diff --git a/src/test/ui/block-result/block-must-not-have-result-while.stderr b/src/test/ui/block-result/block-must-not-have-result-while.stderr index d4845290d8a..7f96aa289d0 100644 --- a/src/test/ui/block-result/block-must-not-have-result-while.stderr +++ b/src/test/ui/block-result/block-must-not-have-result-while.stderr @@ -14,9 +14,7 @@ LL | | true | | ^^^^ expected `()`, found `bool` LL | | LL | | } - | | -- help: consider using a semicolon here - | |_____| - | expected this to be `()` + | |_____- expected this to be `()` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/parser/expr-as-stmt-2.stderr b/src/test/ui/parser/expr-as-stmt-2.stderr index 75c0e7bb475..2a701274857 100644 --- a/src/test/ui/parser/expr-as-stmt-2.stderr +++ b/src/test/ui/parser/expr-as-stmt-2.stderr @@ -7,10 +7,6 @@ LL | if let Some(x) = a { true } else { false } | | expected `()`, found `bool` | expected this to be `()` | -help: consider using a semicolon here - | -LL | if let Some(x) = a { true } else { false }; - | ^ help: you might have meant to return this value | LL | if let Some(x) = a { return true; } else { false } @@ -25,10 +21,6 @@ LL | if let Some(x) = a { true } else { false } | | expected `()`, found `bool` | expected this to be `()` | -help: consider using a semicolon here - | -LL | if let Some(x) = a { true } else { false }; - | ^ help: you might have meant to return this value | LL | if let Some(x) = a { true } else { return false; } diff --git a/src/test/ui/parser/struct-literal-variant-in-if.stderr b/src/test/ui/parser/struct-literal-variant-in-if.stderr index a2252d4e4d2..3ea5ca565c5 100644 --- a/src/test/ui/parser/struct-literal-variant-in-if.stderr +++ b/src/test/ui/parser/struct-literal-variant-in-if.stderr @@ -57,7 +57,7 @@ error[E0308]: mismatched types --> $DIR/struct-literal-variant-in-if.rs:10:20 | LL | if x == E::V { field } {} - | ---------------^^^^^--- help: consider using a semicolon here + | ---------------^^^^^-- | | | | | expected `()`, found `bool` | expected this to be `()` diff --git a/src/test/ui/return/tail-expr-as-potential-return.stderr b/src/test/ui/return/tail-expr-as-potential-return.stderr index 6eeaf5b3412..52c63c8e223 100644 --- a/src/test/ui/return/tail-expr-as-potential-return.stderr +++ b/src/test/ui/return/tail-expr-as-potential-return.stderr @@ -9,14 +9,6 @@ LL | | } | = note: expected unit type `()` found enum `std::result::Result<_, {integer}>` -help: consider using a semicolon here - | -LL | Err(42); - | ^ -help: consider using a semicolon here - | -LL | }; - | ^ help: you might have meant to return this value | LL | return Err(42); diff --git a/src/test/ui/suggestions/match-needing-semi.fixed b/src/test/ui/suggestions/match-needing-semi.fixed deleted file mode 100644 index 03cbed1376e..00000000000 --- a/src/test/ui/suggestions/match-needing-semi.fixed +++ /dev/null @@ -1,18 +0,0 @@ -// check-only -// run-rustfix - -fn main() { - match 3 { - 4 => 1, - 3 => { - 2 //~ ERROR mismatched types - } - _ => 2 - }; - match 3 { //~ ERROR mismatched types - 4 => 1, - 3 => 2, - _ => 2 - }; - let _ = (); -} diff --git a/src/test/ui/suggestions/match-needing-semi.rs b/src/test/ui/suggestions/match-needing-semi.rs index f34071ac758..833555d0e40 100644 --- a/src/test/ui/suggestions/match-needing-semi.rs +++ b/src/test/ui/suggestions/match-needing-semi.rs @@ -1,11 +1,10 @@ // check-only -// run-rustfix fn main() { match 3 { 4 => 1, 3 => { - 2 //~ ERROR mismatched types + foo() //~ ERROR mismatched types } _ => 2 } @@ -16,3 +15,7 @@ fn main() { } let _ = (); } + +fn foo() -> i32 { + 42 +} diff --git a/src/test/ui/suggestions/match-needing-semi.stderr b/src/test/ui/suggestions/match-needing-semi.stderr index 28abd089525..3739c9940f0 100644 --- a/src/test/ui/suggestions/match-needing-semi.stderr +++ b/src/test/ui/suggestions/match-needing-semi.stderr @@ -1,20 +1,27 @@ error[E0308]: mismatched types - --> $DIR/match-needing-semi.rs:8:13 + --> $DIR/match-needing-semi.rs:7:13 | LL | / match 3 { LL | | 4 => 1, LL | | 3 => { -LL | | 2 - | | ^ expected `()`, found integer +LL | | foo() + | | ^^^^^ expected `()`, found `i32` LL | | } LL | | _ => 2 LL | | } - | | -- help: consider using a semicolon here - | |_____| - | expected this to be `()` + | |_____- expected this to be `()` + | +help: consider using a semicolon here + | +LL | foo(); + | ^ +help: consider using a semicolon here + | +LL | }; + | ^ error[E0308]: mismatched types - --> $DIR/match-needing-semi.rs:12:5 + --> $DIR/match-needing-semi.rs:11:5 | LL | / match 3 { LL | | 4 => 1, From 86b3f3f2b39726e489df7f550c92f32515cee56b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 5 Feb 2021 11:34:55 -0800 Subject: [PATCH 36/38] tidy --- src/test/ui/return/tail-expr-as-potential-return.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/ui/return/tail-expr-as-potential-return.rs b/src/test/ui/return/tail-expr-as-potential-return.rs index 72798c720f3..83266abfa06 100644 --- a/src/test/ui/return/tail-expr-as-potential-return.rs +++ b/src/test/ui/return/tail-expr-as-potential-return.rs @@ -8,4 +8,3 @@ fn foo(x: bool) -> Result { } Ok(42.0) } - From fc6c19e2dcbb3039a380755699669d317a6a3fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 21 Feb 2021 16:54:42 -0800 Subject: [PATCH 37/38] fix rebase --- compiler/rustc_hir/src/hir.rs | 3 +-- src/test/ui/return/tail-expr-as-potential-return.stderr | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 84009984183..9b2077f0039 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,5 +1,4 @@ // ignore-tidy-filelength -use crate::def::{DefKind, Namespace, Res}; use crate::def::{CtorKind, DefKind, Namespace, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; @@ -1562,7 +1561,7 @@ impl Expr<'_> { ExprKind::Type(base, _) | ExprKind::Unary(_, base) | ExprKind::Field(base, _) - | ExprKind::Index(base, _) + | ExprKind::Index(base, _) | ExprKind::AddrOf(.., base) | ExprKind::Cast(base, _) => { // This isn't exactly true for `Index` and all `Unnary`, but we are using this diff --git a/src/test/ui/return/tail-expr-as-potential-return.stderr b/src/test/ui/return/tail-expr-as-potential-return.stderr index 52c63c8e223..f8527961374 100644 --- a/src/test/ui/return/tail-expr-as-potential-return.stderr +++ b/src/test/ui/return/tail-expr-as-potential-return.stderr @@ -3,12 +3,12 @@ error[E0308]: mismatched types | LL | / if x { LL | | Err(42) - | | ^^^^^^^ expected `()`, found enum `std::result::Result` + | | ^^^^^^^ expected `()`, found enum `Result` LL | | } | |_____- expected this to be `()` | = note: expected unit type `()` - found enum `std::result::Result<_, {integer}>` + found enum `Result<_, {integer}>` help: you might have meant to return this value | LL | return Err(42); From 7bc501687b39a9d47938c58f2661b54f014ff7d3 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 10 Feb 2021 19:35:35 +0100 Subject: [PATCH 38/38] Avoid `cfg_if` in `std::os` --- library/std/src/os/mod.rs | 54 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index fd6ee088e96..f61e402e370 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -3,40 +3,40 @@ #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, nonstandard_style, missing_debug_implementations)] -cfg_if::cfg_if! { - if #[cfg(doc)] { +// When documenting libstd we want to show unix/windows/linux modules as these are the "main +// modules" that are used across platforms, so all modules are enabled when `cfg(doc)` is set. +// This should help show platform-specific functionality in a hopefully cross-platform way in the +// documentation. +// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make +// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038 - // When documenting libstd we want to show unix/windows/linux modules as - // these are the "main modules" that are used across platforms. This - // should help show platform-specific functionality in a hopefully - // cross-platform way in the documentation +#[cfg(doc)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::unix_ext as unix; - #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::unix_ext as unix; +#[cfg(doc)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::windows_ext as windows; - #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::windows_ext as windows; +#[cfg(doc)] +#[doc(cfg(target_os = "linux"))] +pub mod linux; - #[doc(cfg(target_os = "linux"))] - pub mod linux; - } else { +// If we're not documenting libstd then we just expose the main modules as we otherwise would. - // If we're not documenting libstd then we just expose the main modules - // as we otherwise would. +#[cfg(not(doc))] +#[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))] +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::ext as unix; - #[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))] - #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext as unix; +#[cfg(not(doc))] +#[cfg(windows)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::ext as windows; - #[cfg(windows)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext as windows; - - #[cfg(any(target_os = "linux", target_os = "l4re"))] - pub mod linux; - - } -} +#[cfg(not(doc))] +#[cfg(any(target_os = "linux", target_os = "l4re"))] +pub mod linux; #[cfg(target_os = "android")] pub mod android;