From 1d64b59664b50529291b9fb8e38bde0cd6f98f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 3 Jan 2022 00:00:00 +0000 Subject: [PATCH 1/9] Make `Fingerprint::combine_commutative` associative The previous implementation swapped lower and upper 64-bits of a result of modular addition, so the function was non-associative. --- compiler/rustc_data_structures/src/fingerprint.rs | 5 ++++- .../rustc_data_structures/src/fingerprint/tests.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_data_structures/src/fingerprint/tests.rs diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index c9af35da4bcef..18a607f944289 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -3,6 +3,9 @@ use rustc_serialize::{Decodable, Encodable}; use std::convert::TryInto; use std::hash::{Hash, Hasher}; +#[cfg(test)] +mod tests; + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)] #[repr(C)] pub struct Fingerprint(u64, u64); @@ -54,7 +57,7 @@ impl Fingerprint { let c = a.wrapping_add(b); - Fingerprint((c >> 64) as u64, c as u64) + Fingerprint(c as u64, (c >> 64) as u64) } pub fn to_hex(&self) -> String { diff --git a/compiler/rustc_data_structures/src/fingerprint/tests.rs b/compiler/rustc_data_structures/src/fingerprint/tests.rs new file mode 100644 index 0000000000000..9b0783e33ab47 --- /dev/null +++ b/compiler/rustc_data_structures/src/fingerprint/tests.rs @@ -0,0 +1,14 @@ +use super::*; + +// Check that `combine_commutative` is order independent. +#[test] +fn combine_commutative_is_order_independent() { + let a = Fingerprint::new(0xf6622fb349898b06, 0x70be9377b2f9c610); + let b = Fingerprint::new(0xa9562bf5a2a5303c, 0x67d9b6c82034f13d); + let c = Fingerprint::new(0x0d013a27811dbbc3, 0x9a3f7b3d9142ec43); + let permutations = [(a, b, c), (a, c, b), (b, a, c), (b, c, a), (c, a, b), (c, b, a)]; + let f = a.combine_commutative(b).combine_commutative(c); + for p in &permutations { + assert_eq!(f, p.0.combine_commutative(p.1).combine_commutative(p.2)); + } +} From b885700c7b1f8e9ba26e1f930dcb55ef56130b28 Mon Sep 17 00:00:00 2001 From: Alyssa Verkade Date: Sat, 22 Jan 2022 15:35:09 -0800 Subject: [PATCH 2/9] [borrowck] Fix help on mutating &self in async fns Previously, when rustc was provided an async function that tried to mutate through a shared reference to an implicit self (as shown in the ui test), rustc would suggest modifying the parameter signature to `&mut` + the fully qualified name of the ty (in the case of the repro `S`). If a user modified their code to match the suggestion, the compiler would not accept it. This commit modifies the suggestion so that when rustc is provided the ui test that is also attached in this commit, it suggests (correctly) `&mut self`. We try to be careful about distinguishing between implicit and explicit self annotations, since the latter seem to be handled correctly already. Fixes rust-lang/rust#93093 --- .../src/diagnostics/mutability_errors.rs | 32 +++++++++++++++---- src/test/ui/borrowck/issue-93093.rs | 14 ++++++++ src/test/ui/borrowck/issue-93093.stderr | 12 +++++++ 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/borrowck/issue-93093.rs create mode 100644 src/test/ui/borrowck/issue-93093.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 8f4e574fbd618..a0b269bc44ad7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -488,12 +488,32 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // don't create labels for compiler-generated spans Some(_) => None, None => { - let (span, suggestion) = suggest_ampmut( - self.infcx.tcx, - local_decl, - opt_assignment_rhs_span, - *opt_ty_info, - ); + let (span, suggestion) = if name != kw::SelfLower { + suggest_ampmut( + self.infcx.tcx, + local_decl, + opt_assignment_rhs_span, + *opt_ty_info, + ) + } else { + match local_decl.local_info.as_deref() { + Some(LocalInfo::User(ClearCrossCrate::Set( + mir::BindingForm::Var(mir::VarBindingForm { + opt_ty_info: None, + .. + }), + ))) => { + suggest_ampmut_self(self.infcx.tcx, local_decl) + } + // explicit self (eg `self: &'a Self`) + _ => suggest_ampmut( + self.infcx.tcx, + local_decl, + opt_assignment_rhs_span, + *opt_ty_info, + ), + } + }; Some((true, span, suggestion)) } } diff --git a/src/test/ui/borrowck/issue-93093.rs b/src/test/ui/borrowck/issue-93093.rs new file mode 100644 index 0000000000000..f4db5ecafac40 --- /dev/null +++ b/src/test/ui/borrowck/issue-93093.rs @@ -0,0 +1,14 @@ +// edition:2018 +struct S { + foo: usize, +} +impl S { + async fn bar(&self) { //~ HELP consider changing this to be a mutable reference + //~| SUGGESTION &mut self + self.foo += 1; //~ ERROR cannot assign to `self.foo`, which is behind a `&` reference [E0594] + } +} + +fn main() { + S { foo: 1 }.bar(); +} diff --git a/src/test/ui/borrowck/issue-93093.stderr b/src/test/ui/borrowck/issue-93093.stderr new file mode 100644 index 0000000000000..031128af47655 --- /dev/null +++ b/src/test/ui/borrowck/issue-93093.stderr @@ -0,0 +1,12 @@ +error[E0594]: cannot assign to `self.foo`, which is behind a `&` reference + --> $DIR/issue-93093.rs:8:9 + | +LL | async fn bar(&self) { + | ----- help: consider changing this to be a mutable reference: `&mut self` +LL | +LL | self.foo += 1; + | ^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. From 22872e508f32158a0f325ab1b3399c00de081ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 1 Feb 2022 00:00:00 +0000 Subject: [PATCH 3/9] Validate that values in switch int terminator are unique --- .../rustc_const_eval/src/transform/validate.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 22ef0b2dda506..cf15fc4ddc3a5 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -55,6 +55,7 @@ impl<'tcx> MirPass<'tcx> for Validator { reachable_blocks: traversal::reachable_as_bitset(body), storage_liveness, place_cache: Vec::new(), + value_cache: Vec::new(), } .visit_body(body); } @@ -109,6 +110,7 @@ struct TypeChecker<'a, 'tcx> { reachable_blocks: BitSet, storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>, place_cache: Vec>, + value_cache: Vec, } impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -398,6 +400,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.check_edge(location, target, EdgeKind::Normal); } self.check_edge(location, targets.otherwise(), EdgeKind::Normal); + + self.value_cache.clear(); + self.value_cache.extend(targets.iter().map(|(value, _)| value)); + let all_len = self.value_cache.len(); + self.value_cache.sort_unstable(); + self.value_cache.dedup(); + let has_duplicates = all_len != self.value_cache.len(); + if has_duplicates { + self.fail( + location, + format!( + "duplicated values in `SwitchInt` terminator: {:?}", + terminator.kind, + ), + ); + } } TerminatorKind::Drop { target, unwind, .. } => { self.check_edge(location, *target, EdgeKind::Normal); From 3e01b0a8fd9325928a1df10ee1c5210dacc5a859 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Feb 2022 12:29:22 +0100 Subject: [PATCH 4/9] Fix lifetime elision in type aliases --- src/librustdoc/clean/mod.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 33612c8065477..6a654eebaa2c0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1426,15 +1426,25 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option> { return None; } + use crate::rustc_trait_selection::infer::TyCtxtInferExt; + use crate::rustc_trait_selection::traits::query::normalize::AtExt; + use rustc_middle::traits::ObligationCause; + // Try to normalize `::T` to a type let lifted = ty.lift_to_tcx(cx.tcx).unwrap(); - match cx.tcx.try_normalize_erasing_regions(cx.param_env, lifted) { + let normalized = cx.tcx.infer_ctxt().enter(|infcx| { + infcx + .at(&ObligationCause::dummy(), cx.param_env) + .normalize(lifted) + .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)) + }); + match normalized { Ok(normalized_value) => { - trace!("normalized {:?} to {:?}", ty, normalized_value); + debug!("normalized {:?} to {:?}", ty, normalized_value); Some(normalized_value) } Err(err) => { - info!("failed to normalize {:?}: {:?}", ty, err); + debug!("failed to normalize {:?}: {:?}", ty, err); None } } From 230846433df2acde778b31fb1b3d3e194c29a0af Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Feb 2022 12:29:46 +0100 Subject: [PATCH 5/9] Add test to ensure lifetime is not elided in type alias --- src/test/rustdoc/lifetime-name.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/test/rustdoc/lifetime-name.rs diff --git a/src/test/rustdoc/lifetime-name.rs b/src/test/rustdoc/lifetime-name.rs new file mode 100644 index 0000000000000..5d30a745a61a6 --- /dev/null +++ b/src/test/rustdoc/lifetime-name.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +// @has 'foo/type.Resolutions.html' +// @has - '//*[@class="rust typedef"]' "pub type Resolutions<'tcx> = &'tcx u8;" +pub type Resolutions<'tcx> = &'tcx u8; From bc23bbb99034b762870d3e4372b53f2772ae5dee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 1 Feb 2022 23:27:04 -0800 Subject: [PATCH 6/9] don't suggest adding `let` due to expressions inside of `while` loop --- compiler/rustc_typeck/src/check/expr.rs | 24 ++++++++++++++++-------- src/test/ui/typeck/issue-93486.rs | 6 ++++++ src/test/ui/typeck/issue-93486.stderr | 11 +++++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/typeck/issue-93486.rs create mode 100644 src/test/ui/typeck/issue-93486.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 0e1dbc53806ff..82cda5a2f2e73 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -865,14 +865,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), .. }) => { - // We have a situation like `while Some(0) = value.get(0) {`, where `while let` - // was more likely intended. - err.span_suggestion_verbose( - expr.span.shrink_to_lo(), - "you might have meant to use pattern destructuring", - "let ".to_string(), - Applicability::MachineApplicable, - ); + // Check if our lhs is a child of the condition of a while loop + let expr_is_ancestor = std::iter::successors(Some(lhs.hir_id), |id| { + self.tcx.hir().find_parent_node(*id) + }) + .take_while(|id| *id != parent) + .any(|id| id == expr.hir_id); + // if it is, then we have a situation like `while Some(0) = value.get(0) {`, + // where `while let` was more likely intended. + if expr_is_ancestor { + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "you might have meant to use pattern destructuring", + "let ".to_string(), + Applicability::MachineApplicable, + ); + } break; } hir::Node::Item(_) diff --git a/src/test/ui/typeck/issue-93486.rs b/src/test/ui/typeck/issue-93486.rs new file mode 100644 index 0000000000000..f8f98d5c1c7dc --- /dev/null +++ b/src/test/ui/typeck/issue-93486.rs @@ -0,0 +1,6 @@ +fn main() { + while let 1 = 1 { + vec![].last_mut().unwrap() = 3_u8; + //~^ ERROR invalid left-hand side of assignment + } +} diff --git a/src/test/ui/typeck/issue-93486.stderr b/src/test/ui/typeck/issue-93486.stderr new file mode 100644 index 0000000000000..70b5b63f1cba7 --- /dev/null +++ b/src/test/ui/typeck/issue-93486.stderr @@ -0,0 +1,11 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/issue-93486.rs:3:36 + | +LL | vec![].last_mut().unwrap() = 3_u8; + | -------------------------- ^ + | | + | cannot assign to this expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0070`. From f35d43cdf01f8405009ee6167ac2afe4e02ba51c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 1 Feb 2022 21:44:44 -0800 Subject: [PATCH 7/9] better suggestion for duplicated `where` --- compiler/rustc_parse/src/parser/generics.rs | 18 ++++- compiler/rustc_parse/src/parser/item.rs | 29 +++++-- .../ui/parser/bad-struct-following-where.rs | 2 + .../parser/bad-struct-following-where.stderr | 8 ++ src/test/ui/parser/duplicate-where-clauses.rs | 19 +++++ .../ui/parser/duplicate-where-clauses.stderr | 80 +++++++++++++++++++ 6 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/parser/bad-struct-following-where.rs create mode 100644 src/test/ui/parser/bad-struct-following-where.stderr create mode 100644 src/test/ui/parser/duplicate-where-clauses.rs create mode 100644 src/test/ui/parser/duplicate-where-clauses.stderr diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 419ea9cced0d7..62ed104aef37c 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -4,7 +4,7 @@ use rustc_ast::token; use rustc_ast::{ self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause, }; -use rustc_errors::PResult; +use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::kw; impl<'a> Parser<'a> { @@ -256,7 +256,21 @@ impl<'a> Parser<'a> { break; } - if !self.eat(&token::Comma) { + let prev_token = self.prev_token.span; + let ate_comma = self.eat(&token::Comma); + + if self.eat_keyword_noexpect(kw::Where) { + let msg = &format!("cannot define duplicate `where` clauses on an item"); + let mut err = self.struct_span_err(self.token.span, msg); + err.span_label(lo, "previous `where` clause starts here"); + err.span_suggestion_verbose( + prev_token.shrink_to_hi().to(self.prev_token.span), + "consider joining the two `where` clauses into one", + ",".to_owned(), + Applicability::MaybeIncorrect, + ); + err.emit(); + } else if !ate_comma { break; } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 06849b3125683..93f5d79c0db13 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1221,7 +1221,7 @@ impl<'a> Parser<'a> { let struct_def = if this.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. - let (fields, recovered) = this.parse_record_struct_body("struct")?; + let (fields, recovered) = this.parse_record_struct_body("struct", false)?; VariantData::Struct(fields, recovered) } else if this.check(&token::OpenDelim(token::Paren)) { VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID) @@ -1275,7 +1275,8 @@ impl<'a> Parser<'a> { VariantData::Unit(DUMMY_NODE_ID) } else { // If we see: `struct Foo where T: Copy { ... }` - let (fields, recovered) = self.parse_record_struct_body("struct")?; + let (fields, recovered) = + self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?; VariantData::Struct(fields, recovered) } // No `where` so: `struct Foo;` @@ -1283,7 +1284,8 @@ impl<'a> Parser<'a> { VariantData::Unit(DUMMY_NODE_ID) // Record-style struct definition } else if self.token == token::OpenDelim(token::Brace) { - let (fields, recovered) = self.parse_record_struct_body("struct")?; + let (fields, recovered) = + self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?; VariantData::Struct(fields, recovered) // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(token::Paren) { @@ -1313,10 +1315,12 @@ impl<'a> Parser<'a> { let vdata = if self.token.is_keyword(kw::Where) { generics.where_clause = self.parse_where_clause()?; - let (fields, recovered) = self.parse_record_struct_body("union")?; + let (fields, recovered) = + self.parse_record_struct_body("union", generics.where_clause.has_where_token)?; VariantData::Struct(fields, recovered) } else if self.token == token::OpenDelim(token::Brace) { - let (fields, recovered) = self.parse_record_struct_body("union")?; + let (fields, recovered) = + self.parse_record_struct_body("union", generics.where_clause.has_where_token)?; VariantData::Struct(fields, recovered) } else { let token_str = super::token_descr(&self.token); @@ -1332,6 +1336,7 @@ impl<'a> Parser<'a> { fn parse_record_struct_body( &mut self, adt_ty: &str, + parsed_where: bool, ) -> PResult<'a, (Vec, /* recovered */ bool)> { let mut fields = Vec::new(); let mut recovered = false; @@ -1353,9 +1358,19 @@ impl<'a> Parser<'a> { self.eat(&token::CloseDelim(token::Brace)); } else { let token_str = super::token_descr(&self.token); - let msg = &format!("expected `where`, or `{{` after struct name, found {}", token_str); + let msg = &format!( + "expected {}`{{` after struct name, found {}", + if parsed_where { "" } else { "`where`, or " }, + token_str + ); let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, "expected `where`, or `{` after struct name"); + err.span_label( + self.token.span, + format!( + "expected {}`{{` after struct name", + if parsed_where { "" } else { "`where`, or " } + ), + ); return Err(err); } diff --git a/src/test/ui/parser/bad-struct-following-where.rs b/src/test/ui/parser/bad-struct-following-where.rs new file mode 100644 index 0000000000000..823880b1b42c6 --- /dev/null +++ b/src/test/ui/parser/bad-struct-following-where.rs @@ -0,0 +1,2 @@ +struct A where T: Sized ! +//~^ ERROR expected `{` after struct name, found diff --git a/src/test/ui/parser/bad-struct-following-where.stderr b/src/test/ui/parser/bad-struct-following-where.stderr new file mode 100644 index 0000000000000..bb79776dc8459 --- /dev/null +++ b/src/test/ui/parser/bad-struct-following-where.stderr @@ -0,0 +1,8 @@ +error: expected `{` after struct name, found `!` + --> $DIR/bad-struct-following-where.rs:1:25 + | +LL | struct A where T: Sized ! + | ^ expected `{` after struct name + +error: aborting due to previous error + diff --git a/src/test/ui/parser/duplicate-where-clauses.rs b/src/test/ui/parser/duplicate-where-clauses.rs new file mode 100644 index 0000000000000..9eb2ffb06f02d --- /dev/null +++ b/src/test/ui/parser/duplicate-where-clauses.rs @@ -0,0 +1,19 @@ +struct A where (): Sized where (): Sized {} +//~^ ERROR cannot define duplicate `where` clauses on an item + +fn b() where (): Sized where (): Sized {} +//~^ ERROR cannot define duplicate `where` clauses on an item + +enum C where (): Sized where (): Sized {} +//~^ ERROR cannot define duplicate `where` clauses on an item + +struct D where (): Sized, where (): Sized {} +//~^ ERROR cannot define duplicate `where` clauses on an item + +fn e() where (): Sized, where (): Sized {} +//~^ ERROR cannot define duplicate `where` clauses on an item + +enum F where (): Sized, where (): Sized {} +//~^ ERROR cannot define duplicate `where` clauses on an item + +fn main() {} diff --git a/src/test/ui/parser/duplicate-where-clauses.stderr b/src/test/ui/parser/duplicate-where-clauses.stderr new file mode 100644 index 0000000000000..8250d4f1e0568 --- /dev/null +++ b/src/test/ui/parser/duplicate-where-clauses.stderr @@ -0,0 +1,80 @@ +error: cannot define duplicate `where` clauses on an item + --> $DIR/duplicate-where-clauses.rs:1:32 + | +LL | struct A where (): Sized where (): Sized {} + | - ^ + | | + | previous `where` clause starts here + | +help: consider joining the two `where` clauses into one + | +LL | struct A where (): Sized, (): Sized {} + | ~ + +error: cannot define duplicate `where` clauses on an item + --> $DIR/duplicate-where-clauses.rs:4:30 + | +LL | fn b() where (): Sized where (): Sized {} + | - ^ + | | + | previous `where` clause starts here + | +help: consider joining the two `where` clauses into one + | +LL | fn b() where (): Sized, (): Sized {} + | ~ + +error: cannot define duplicate `where` clauses on an item + --> $DIR/duplicate-where-clauses.rs:7:30 + | +LL | enum C where (): Sized where (): Sized {} + | - ^ + | | + | previous `where` clause starts here + | +help: consider joining the two `where` clauses into one + | +LL | enum C where (): Sized, (): Sized {} + | ~ + +error: cannot define duplicate `where` clauses on an item + --> $DIR/duplicate-where-clauses.rs:10:33 + | +LL | struct D where (): Sized, where (): Sized {} + | - ^ + | | + | previous `where` clause starts here + | +help: consider joining the two `where` clauses into one + | +LL | struct D where (): Sized, (): Sized {} + | ~ + +error: cannot define duplicate `where` clauses on an item + --> $DIR/duplicate-where-clauses.rs:13:31 + | +LL | fn e() where (): Sized, where (): Sized {} + | - ^ + | | + | previous `where` clause starts here + | +help: consider joining the two `where` clauses into one + | +LL | fn e() where (): Sized, (): Sized {} + | ~ + +error: cannot define duplicate `where` clauses on an item + --> $DIR/duplicate-where-clauses.rs:16:31 + | +LL | enum F where (): Sized, where (): Sized {} + | - ^ + | | + | previous `where` clause starts here + | +help: consider joining the two `where` clauses into one + | +LL | enum F where (): Sized, (): Sized {} + | ~ + +error: aborting due to 6 previous errors + From 670f5c6ef385f251df5cd7bcba9e8039a80bdb4d Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 2 Feb 2022 12:45:20 +0100 Subject: [PATCH 8/9] More let_else adoptions --- compiler/rustc_ast_lowering/src/item.rs | 4 +- compiler/rustc_ast_lowering/src/lib.rs | 1 + compiler/rustc_attr/src/builtin.rs | 138 +++++++++--------- compiler/rustc_attr/src/lib.rs | 2 + .../src/diagnostics/region_name.rs | 137 +++++++++-------- compiler/rustc_borrowck/src/lib.rs | 5 +- .../rustc_mir_build/src/build/matches/mod.rs | 47 +++--- .../rustc_mir_build/src/build/matches/test.rs | 94 ++++++------ .../rustc_save_analysis/src/dump_visitor.rs | 5 +- compiler/rustc_save_analysis/src/lib.rs | 1 + 10 files changed, 208 insertions(+), 226 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8b4a0840df583..cacc36b616a1e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -471,9 +471,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // two imports. for new_node_id in [id1, id2] { let new_id = self.resolver.local_def_id(new_node_id); - let res = if let Some(res) = resolutions.next() { - res - } else { + let Some(res) = resolutions.next() else { // Associate an HirId to both ids even if there is no resolution. let _old = self .node_id_to_hir_id diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a594339296f32..b1e601516ab97 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,6 +32,7 @@ #![feature(crate_visibility_modifier)] #![feature(box_patterns)] +#![feature(let_else)] #![feature(never_type)] #![recursion_limit = "256"] #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index bab50df3dd543..8c5beb1025803 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -217,85 +217,81 @@ where let mut issue_num = None; let mut is_soft = false; for meta in metas { - if let Some(mi) = meta.meta_item() { - match mi.name_or_empty() { - sym::feature => { - if !get(mi, &mut feature) { - continue 'outer; - } + let Some(mi) = meta.meta_item() else { + handle_errors( + &sess.parse_sess, + meta.span(), + AttrError::UnsupportedLiteral("unsupported literal", false), + ); + continue 'outer; + }; + match mi.name_or_empty() { + sym::feature => { + if !get(mi, &mut feature) { + continue 'outer; } - sym::reason => { - if !get(mi, &mut reason) { - continue 'outer; - } + } + sym::reason => { + if !get(mi, &mut reason) { + continue 'outer; + } + } + sym::issue => { + if !get(mi, &mut issue) { + continue 'outer; } - sym::issue => { - if !get(mi, &mut issue) { - continue 'outer; - } - // These unwraps are safe because `get` ensures the meta item - // is a name/value pair string literal. - issue_num = match issue.unwrap().as_str() { - "none" => None, - issue => { - let emit_diag = |msg: &str| { - struct_span_err!( - diagnostic, - mi.span, - E0545, - "`issue` must be a non-zero numeric string \ - or \"none\"", - ) - .span_label( - mi.name_value_literal_span().unwrap(), - msg, - ) - .emit(); - }; - match issue.parse() { - Ok(0) => { - emit_diag( - "`issue` must not be \"0\", \ - use \"none\" instead", - ); - continue 'outer; - } - Ok(num) => NonZeroU32::new(num), - Err(err) => { - emit_diag(&err.to_string()); - continue 'outer; - } + // These unwraps are safe because `get` ensures the meta item + // is a name/value pair string literal. + issue_num = match issue.unwrap().as_str() { + "none" => None, + issue => { + let emit_diag = |msg: &str| { + struct_span_err!( + diagnostic, + mi.span, + E0545, + "`issue` must be a non-zero numeric string \ + or \"none\"", + ) + .span_label(mi.name_value_literal_span().unwrap(), msg) + .emit(); + }; + match issue.parse() { + Ok(0) => { + emit_diag( + "`issue` must not be \"0\", \ + use \"none\" instead", + ); + continue 'outer; + } + Ok(num) => NonZeroU32::new(num), + Err(err) => { + emit_diag(&err.to_string()); + continue 'outer; } } - }; - } - sym::soft => { - if !mi.is_word() { - let msg = "`soft` should not have any arguments"; - sess.parse_sess.span_diagnostic.span_err(mi.span, msg); } - is_soft = true; - } - _ => { - handle_errors( - &sess.parse_sess, - meta.span(), - AttrError::UnknownMetaItem( - pprust::path_to_string(&mi.path), - &["feature", "reason", "issue", "soft"], - ), - ); - continue 'outer; + }; + } + sym::soft => { + if !mi.is_word() { + let msg = "`soft` should not have any arguments"; + sess.parse_sess.span_diagnostic.span_err(mi.span, msg); } + is_soft = true; + } + _ => { + handle_errors( + &sess.parse_sess, + meta.span(), + AttrError::UnknownMetaItem( + pprust::path_to_string(&mi.path), + &["feature", "reason", "issue", "soft"], + ), + ); + continue 'outer; } - } else { - handle_errors( - &sess.parse_sess, - meta.span(), - AttrError::UnsupportedLiteral("unsupported literal", false), - ); - continue 'outer; } } diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index 3fb11f77872be..c95c1c40a34c2 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -4,6 +4,8 @@ //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. +#![feature(let_else)] + #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 01cc72121c7d4..3409f14c98b73 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -311,43 +311,39 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ty::BoundRegionKind::BrEnv => { let def_ty = self.regioncx.universal_regions().defining_ty; - if let DefiningTy::Closure(_, substs) = def_ty { - let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) = - tcx.hir().expect_expr(self.mir_hir_id()).kind - { - span - } else { - bug!("Closure is not defined by a closure expr"); - }; - let region_name = self.synthesize_region_name(); - - let closure_kind_ty = substs.as_closure().kind_ty(); - let note = match closure_kind_ty.to_opt_closure_kind() { - Some(ty::ClosureKind::Fn) => { - "closure implements `Fn`, so references to captured variables \ - can't escape the closure" - } - Some(ty::ClosureKind::FnMut) => { - "closure implements `FnMut`, so references to captured variables \ - can't escape the closure" - } - Some(ty::ClosureKind::FnOnce) => { - bug!("BrEnv in a `FnOnce` closure"); - } - None => bug!("Closure kind not inferred in borrow check"), - }; - - Some(RegionName { - name: region_name, - source: RegionNameSource::SynthesizedFreeEnvRegion( - args_span, - note.to_string(), - ), - }) - } else { + let DefiningTy::Closure(_, substs) = def_ty else { // Can't have BrEnv in functions, constants or generators. bug!("BrEnv outside of closure."); - } + }; + let hir::ExprKind::Closure(_, _, _, args_span, _) = + tcx.hir().expect_expr(self.mir_hir_id()).kind else { + bug!("Closure is not defined by a closure expr"); + }; + let region_name = self.synthesize_region_name(); + + let closure_kind_ty = substs.as_closure().kind_ty(); + let note = match closure_kind_ty.to_opt_closure_kind() { + Some(ty::ClosureKind::Fn) => { + "closure implements `Fn`, so references to captured variables \ + can't escape the closure" + } + Some(ty::ClosureKind::FnMut) => { + "closure implements `FnMut`, so references to captured variables \ + can't escape the closure" + } + Some(ty::ClosureKind::FnOnce) => { + bug!("BrEnv in a `FnOnce` closure"); + } + None => bug!("Closure kind not inferred in borrow check"), + }; + + Some(RegionName { + name: region_name, + source: RegionNameSource::SynthesizedFreeEnvRegion( + args_span, + note.to_string(), + ), + }) } ty::BoundRegionKind::BrAnon(_) => None, @@ -765,48 +761,45 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { let hir = self.infcx.tcx.hir(); - if let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind { - let opaque_ty = hir.item(id); - if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { - bounds: - [ - hir::GenericBound::LangItemTrait( - hir::LangItem::Future, - _, - _, - hir::GenericArgs { - bindings: - [ - hir::TypeBinding { - ident: Ident { name: sym::Output, .. }, - kind: - hir::TypeBindingKind::Equality { - term: hir::Term::Ty(ty), - }, - .. - }, - ], - .. - }, - ), - ], - .. - }) = opaque_ty.kind - { - ty - } else { - span_bug!( - hir_ty.span, - "bounds from lowered return type of async fn did not match expected format: {:?}", - opaque_ty - ); - } - } else { + let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else { span_bug!( hir_ty.span, "lowered return type of async fn is not OpaqueDef: {:?}", hir_ty ); + }; + let opaque_ty = hir.item(id); + if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { + bounds: + [ + hir::GenericBound::LangItemTrait( + hir::LangItem::Future, + _, + _, + hir::GenericArgs { + bindings: + [ + hir::TypeBinding { + ident: Ident { name: sym::Output, .. }, + kind: + hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) }, + .. + }, + ], + .. + }, + ), + ], + .. + }) = opaque_ty.kind + { + ty + } else { + span_bug!( + hir_ty.span, + "bounds from lowered return type of async fn did not match expected format: {:?}", + opaque_ty + ); } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c288cc96990c2..5597a8b091554 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1427,9 +1427,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { bug!("temporary should be initialized exactly once") }; - let loc = match init.location { - InitLocation::Statement(stmt) => stmt, - _ => bug!("temporary initialized in arguments"), + let InitLocation::Statement(loc) = init.location else { + bug!("temporary initialized in arguments") }; let body = self.body; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 3294f2cf64172..6329bcee4fa3f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -602,33 +602,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for binding in &candidate_ref.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); - if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, - )))) = self.local_decls[local].local_info - { - // `try_upvars_resolved` may fail if it is unable to resolve the given - // `PlaceBuilder` inside a closure. In this case, we don't want to include - // a scrutinee place. `scrutinee_place_builder` will fail for destructured - // assignments. This is because a closure only captures the precise places - // that it will read and as a result a closure may not capture the entire - // tuple/struct and rather have individual places that will be read in the - // final MIR. - // Example: - // ``` - // let foo = (0, 1); - // let c = || { - // let (v1, v2) = foo; - // }; - // ``` - if let Ok(match_pair_resolved) = - initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { - let place = - match_pair_resolved.into_place(self.tcx, self.typeck_results); - *match_place = Some(place); - } - } else { + )))) = self.local_decls[local].local_info else { bug!("Let binding to non-user variable.") + }; + // `try_upvars_resolved` may fail if it is unable to resolve the given + // `PlaceBuilder` inside a closure. In this case, we don't want to include + // a scrutinee place. `scrutinee_place_builder` will fail for destructured + // assignments. This is because a closure only captures the precise places + // that it will read and as a result a closure may not capture the entire + // tuple/struct and rather have individual places that will be read in the + // final MIR. + // Example: + // ``` + // let foo = (0, 1); + // let c = || { + // let (v1, v2) = foo; + // }; + // ``` + if let Ok(match_pair_resolved) = + initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { + let place = match_pair_resolved.into_place(self.tcx, self.typeck_results); + *match_place = Some(place); } } // All of the subcandidates should bind the same locals, so we diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index f4bf28bfa5ce2..49cd21c2137b7 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -227,16 +227,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_blocks = make_target_blocks(self); let terminator = if *switch_ty.kind() == ty::Bool { assert!(!options.is_empty() && options.len() <= 2); - if let [first_bb, second_bb] = *target_blocks { - let (true_bb, false_bb) = match options[0] { - 1 => (first_bb, second_bb), - 0 => (second_bb, first_bb), - v => span_bug!(test.span, "expected boolean value but got {:?}", v), - }; - TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb) - } else { + let [first_bb, second_bb] = *target_blocks else { bug!("`TestKind::SwitchInt` on `bool` should have two targets") - } + }; + let (true_bb, false_bb) = match options[0] { + 1 => (first_bb, second_bb), + 0 => (second_bb, first_bb), + v => span_bug!(test.span, "expected boolean value but got {:?}", v), + }; + TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb) } else { // The switch may be inexhaustive so we have a catch all block debug_assert_eq!(options.len() + 1, target_blocks.len()); @@ -285,24 +284,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let hi = self.literal_operand(test.span, hi); let val = Operand::Copy(place); - if let [success, fail] = *target_blocks { - self.compare( - block, - lower_bound_success, - fail, - source_info, - BinOp::Le, - lo, - val.clone(), - ); - let op = match *end { - RangeEnd::Included => BinOp::Le, - RangeEnd::Excluded => BinOp::Lt, - }; - self.compare(lower_bound_success, success, fail, source_info, op, val, hi); - } else { + let [success, fail] = *target_blocks else { bug!("`TestKind::Range` should have two target blocks"); - } + }; + self.compare( + block, + lower_bound_success, + fail, + source_info, + BinOp::Le, + lo, + val.clone(), + ); + let op = match *end { + RangeEnd::Included => BinOp::Le, + RangeEnd::Excluded => BinOp::Lt, + }; + self.compare(lower_bound_success, success, fail, source_info, op, val, hi); } TestKind::Len { len, op } => { @@ -317,21 +315,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // expected = let expected = self.push_usize(block, source_info, len); - if let [true_bb, false_bb] = *target_blocks { - // result = actual == expected OR result = actual < expected - // branch based on result - self.compare( - block, - true_bb, - false_bb, - source_info, - op, - Operand::Move(actual), - Operand::Move(expected), - ); - } else { + let [true_bb, false_bb] = *target_blocks else { bug!("`TestKind::Len` should have two target blocks"); - } + }; + // result = actual == expected OR result = actual < expected + // branch based on result + self.compare( + block, + true_bb, + false_bb, + source_info, + op, + Operand::Move(actual), + Operand::Move(expected), + ); } } } @@ -459,16 +456,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); self.diverge_from(block); - if let [success_block, fail_block] = *make_target_blocks(self) { - // check the result - self.cfg.terminate( - eq_block, - source_info, - TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block), - ); - } else { + let [success_block, fail_block] = *make_target_blocks(self) else { bug!("`TestKind::Eq` should have two target blocks") - } + }; + // check the result + self.cfg.terminate( + eq_block, + source_info, + TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block), + ); } /// Given that we are performing `test` against `test_place`, this job diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 8b4ab77dffb5f..a3f7e84b1d524 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -47,11 +47,10 @@ use rls_data::{ use tracing::{debug, error}; +#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5213 macro_rules! down_cast_data { ($id:ident, $kind:ident, $sp:expr) => { - let $id = if let super::Data::$kind(data) = $id { - data - } else { + let super::Data::$kind($id) = $id else { span_bug!($sp, "unexpected data kind: {:?}", $id); }; }; diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index c14b459570f5e..2eebddb47df5c 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,6 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(if_let_guard)] #![feature(nll)] +#![feature(let_else)] #![recursion_limit = "256"] #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] From 3cb7618f5874060a25cc204c6ed81413f2b2f7be Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 2 Feb 2022 17:37:14 +0100 Subject: [PATCH 9/9] Remove unused dep from rustc_arena --- Cargo.lock | 1 - compiler/rustc_arena/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53ba61da2b002..208ce841759b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3403,7 +3403,6 @@ dependencies = [ name = "rustc_arena" version = "0.0.0" dependencies = [ - "rustc_data_structures", "smallvec", ] diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml index 33ccd0445030f..ee3a7b51b699a 100644 --- a/compiler/rustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -4,5 +4,4 @@ version = "0.0.0" edition = "2021" [dependencies] -rustc_data_structures = { path = "../rustc_data_structures" } smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }