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 45964b1c988ed..d8be90cd8452f 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 456e32680fe50..15b67ca9fafb7 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 5fc573a57ad0b..f16f8c9caf2dd 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 0000000000000..0ebbff75e59ff --- /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 0000000000000..2021aa9d70e39 --- /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 a9a08a4d76200..de4b63030fa7c 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 2baea7842a796..4c28d9cd673af 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 4c28d9cd673af..4032e7770772e 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 a81fd55f6f192..34bda2b7883ea 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 1af5e8f03b44e..8f0c4e5e64184 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 0000000000000..5c4530c97a9b3 --- /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 5c4530c97a9b3..ce166b7906459 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 9938cddc94106..688be7aedea38 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 bc59c378609f0..64938745a4a16 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 4032e7770772e..bbdb2a5d41b99 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 6bdfa18fa434c..7563a742b9a90 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 37ca0a0779b17..b333b46310532 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 ce166b7906459..a1ca2699554e5 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 9da3072ec282f..dceafd6458c41 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 4134ef676719c..6050620729f83 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 bbdb2a5d41b99..3ddf0e638946c 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 7563a742b9a90..42ccdd00bbd6a 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 b333b46310532..37ca0a0779b17 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 eb8994681937a..0c267cbc106b9 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 99c42a4ba4423..71b4883aca284 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 3218b3535c970..3ab5ca4f566ad 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 b40c1a8c57aa4..5c20f382224c1 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 0571dc74b9af9..7a0dd5a8f0f72 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 19a3b45e568c0..90351be69291e 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 0e95d5ded9296..0000000000000 --- 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 0000000000000..ea3f01ff5f9d1 --- /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 0c267cbc106b9..319ca666fc622 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 71b4883aca284..ade2e3fed2c2d 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 3ab5ca4f566ad..ef2f264ec7ea8 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 5c20f382224c1..1a7b846bd8514 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 7a0dd5a8f0f72..b30ff9450ff02 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 90351be69291e..e78b647651101 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 ea3f01ff5f9d1..0000000000000 --- 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 0000000000000..8b5a21a34cfbb --- /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 8b5a21a34cfbb..0000000000000 --- 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 319ca666fc622..f7cefdce27856 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 ade2e3fed2c2d..c020a969f1fb9 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 cb015b949305c..c5ffade12619f 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 ef2f264ec7ea8..b4deedc52638c 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 1a7b846bd8514..a8474f8ca5921 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 b30ff9450ff02..dbeb391213006 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 660c8a2da5da0..d20986bb724fc 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 e78b647651101..8256d2cc6070e 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 a8474f8ca5921..77302d33bc187 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 cd2bea86ea1a7..718e81c84eddd 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 08d969b27bea5..d8e325f1da7e9 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 f16f8c9caf2dd..cfcd0d673d015 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 fc034a0cbf3b8..4f9618232313f 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 6583524aad18f..81d208e4bc3f3 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 89232a519d7b2..86086cf97ecce 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 0ebbff75e59ff..7bd54af1dbee5 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 2021aa9d70e39..80c6187cbbef4 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 bd4d2071c2059..78c14d37518c0 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 42ccdd00bbd6a..c13f000a73615 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 1c37a6b2aca18..de6210d1893de 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 adf996fc78275..2fa349e3a4f41 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 cb015b949305c..f8cc6a4587777 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 c9c8f68cd9cce..c1629d8b8f95e 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 1889e54933867..66135a719be17 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 de6210d1893de..83b13e7d93c11 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 2fa349e3a4f41..cec322518190e 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 f8cc6a4587777..839f742f1afa7 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 c1629d8b8f95e..6af5adf4cd860 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 66135a719be17..759b233c7c138 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 718e81c84eddd..cd2bea86ea1a7 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 d8e325f1da7e9..34db0c9ab162b 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 83b13e7d93c11..1137a83bc77da 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 cec322518190e..bdb2d67347e43 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 3218b3535c970..00fd1c2908b82 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 6af5adf4cd860..13c8022820bc3 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 759b233c7c138..afb28518b727d 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 fd0ff5b66e607..289629d921545 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 023555d91cc92..66dd278b57840 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 85aaff5ab7293..2d20f0d9547c1 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 34db0c9ab162b..aaf2c83d1d936 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 ec89ae0228c5e..e8daa8414a274 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 9800ed9bfa948..a0be7442d597a 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 f9c3406d3b335..a2e961465681a 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 4533b37f10b42..e4f7e140281cd 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 baa0502521da7..d439753d042bb 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 5b14795f5457c..f7b49ac52b0af 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 0000000000000..4f811ce98c181 --- /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 8198dbaa5278c..9e927067bf016 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 9e927067bf016..6335709dc48b9 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 6050620729f83..83debdfc86043 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 66dd278b57840..9530efaedbce4 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 289231e52cb41..d9abfec85c9e7 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 cfcd0d673d015..c21e7d8aebc55 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 4f9618232313f..7df86d7326bc6 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 81d208e4bc3f3..a95b5bb94d24a 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 86086cf97ecce..9b9d2bc4972b4 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 80c6187cbbef4..29e721465215d 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 78c14d37518c0..c3d41ae68cd6a 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 b2395b7bb2502..f95627cfdee83 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 a0465ca6aef07..9d816e76c0020 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 e88b12712fb8c..1db759a2181d5 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 ee07c36763356..75c0e7bb47560 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 324aed0ad7cf6..09a6d7cbeb176 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 0000000000000..72798c720f3a1 --- /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 0000000000000..d079e0b080d10 --- /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 4836418b3c210..f2fbb95fc021c 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 9d816e76c0020..e5a2e1398178d 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 d629054911dac..352a88ac10cd5 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 46615dae7e2ba..26e81a52c2141 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 3dce459ddbdae..4fcd0ee2c48e2 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 0538701290297..345520d4852ae 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 535428f1c91f7..6ef921bef3d7a 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 d079e0b080d10..6eeaf5b3412e7 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 445bc1646f04e..7a2b75a1c1f0a 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 6e4cee18c1603..438075083d370 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 4df8c44e62b38..840099841839a 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 f95627cfdee83..159c97d8bfaa9 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 3326be796cee3..155c10e891652 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 e5a2e1398178d..416b75d9e2e0c 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 d4845290d8a90..7f96aa289d0ab 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 75c0e7bb47560..2a70127485785 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 a2252d4e4d282..3ea5ca565c5e5 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 6eeaf5b3412e7..52c63c8e223e4 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 03cbed1376ea3..0000000000000 --- 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 f34071ac75886..833555d0e406e 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 28abd089525df..3739c9940f0cc 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 72798c720f3a1..83266abfa06e6 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 840099841839a..9b2077f0039bb 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 52c63c8e223e4..f8527961374dd 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 fd6ee088e961c..f61e402e37027 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;