From a32fb2f8aa0780af750189356a06d501a72698b7 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 15 May 2024 15:11:23 -0400 Subject: [PATCH 01/11] Remove `ref_pat_everywhere` --- compiler/rustc_feature/src/removed.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 - compiler/rustc_hir_typeck/src/pat.rs | 65 ++++--------------- .../feature-gate-ref_pat_everywhere.rs | 14 ---- .../feature-gate-ref_pat_everywhere.stderr | 49 -------------- tests/ui/match/ref_pat_everywhere-fail.rs | 12 ---- tests/ui/match/ref_pat_everywhere-fail.stderr | 38 ----------- tests/ui/match/ref_pat_everywhere.rs | 24 ------- 8 files changed, 14 insertions(+), 191 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs delete mode 100644 tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr delete mode 100644 tests/ui/match/ref_pat_everywhere-fail.rs delete mode 100644 tests/ui/match/ref_pat_everywhere-fail.stderr delete mode 100644 tests/ui/match/ref_pat_everywhere.rs diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index eaaf7ca34e012..f1afde31803e4 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -181,6 +181,7 @@ declare_features! ( (removed, pushpop_unsafe, "1.2.0", None, None), (removed, quad_precision_float, "1.0.0", None, None), (removed, quote, "1.33.0", Some(29601), None), + (removed, ref_pat_everywhere, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024")), (removed, reflect, "1.0.0", Some(27749), None), /// Allows using the `#[register_attr]` attribute. (removed, register_attr, "1.65.0", Some(66080), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 60b386acf9106..1a058a121f3ad 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -571,8 +571,6 @@ declare_features! ( (unstable, raw_ref_op, "1.41.0", Some(64490)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), - /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references. - (incomplete, ref_pat_everywhere, "1.79.0", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index b9b220d5af8e4..d2897f1c01131 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2125,25 +2125,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected: Ty<'tcx>, mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - // FIXME: repace with `bool` once final decision on 1 vs 2 layers is made - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - enum MatchErgonomicsMode { - EatOneLayer, - EatTwoLayers, - Legacy, - } - - let match_ergonomics_mode = - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { - MatchErgonomicsMode::EatOneLayer - } else if self.tcx.features().ref_pat_everywhere { - MatchErgonomicsMode::EatTwoLayers - } else { - MatchErgonomicsMode::Legacy - }; + let new_match_ergonomics = + pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024; - let mut inherited_ref_mutbl_match = false; - if match_ergonomics_mode != MatchErgonomicsMode::Legacy { + if new_match_ergonomics { if pat_mutbl == Mutability::Not { // Prevent the inner pattern from binding with `ref mut`. pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not( @@ -2151,20 +2136,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if let ByRef::Yes(inh_mut) = pat_info.binding_mode { - inherited_ref_mutbl_match = pat_mutbl <= inh_mut; - } - - if inherited_ref_mutbl_match { - pat_info.binding_mode = ByRef::No; - if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer { - self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); - self.check_pat(inner, expected, pat_info); - return expected; - } - } else if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer - && pat_mutbl == Mutability::Mut + if let ByRef::Yes(inh_mut) = pat_info.binding_mode + && pat_mutbl <= inh_mut { + pat_info.binding_mode = ByRef::No; + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } else if pat_mutbl == Mutability::Mut { // `&mut` patterns pell off `&` references let (new_expected, new_bm, max_ref_mutbl) = self.peel_off_references( pat, @@ -2204,33 +2183,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the bad interactions of the given hack detailed in (note_1). debug!("check_pat_ref: expected={:?}", expected); match *expected.kind() { - ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => { - if r_mutbl == Mutability::Not - && match_ergonomics_mode != MatchErgonomicsMode::Legacy - { + ty::Ref(_, r_ty, r_mutbl) if r_mutbl >= pat_mutbl && new_match_ergonomics => { + if r_mutbl == Mutability::Not { pat_info.max_ref_mutbl = MutblCap::Not; } (expected, r_ty) } - // `&` pattern eats `&mut` reference - ty::Ref(_, r_ty, Mutability::Mut) - if pat_mutbl == Mutability::Not - && match_ergonomics_mode != MatchErgonomicsMode::Legacy => - { - (expected, r_ty) - } - - _ if inherited_ref_mutbl_match - && match_ergonomics_mode == MatchErgonomicsMode::EatTwoLayers => - { - // We already matched against a match-ergonmics inserted reference, - // so we don't need to match against a reference from the original type. - // Save this info for use in lowering later - self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); - (expected, expected) - } + ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => (expected, r_ty), _ => { let inner_ty = self.next_ty_var(inner.span); diff --git a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs deleted file mode 100644 index ed5db56e0e83d..0000000000000 --- a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn main() { - if let Some(Some(&x)) = &Some(&Some(0)) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } - if let Some(&Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } - if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } -} diff --git a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr deleted file mode 100644 index 0f0051325cdf0..0000000000000 --- a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_everywhere.rs:2:22 - | -LL | if let Some(Some(&x)) = &Some(&Some(0)) { - | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL | if let Some(Some(x)) = &Some(&Some(0)) { - | ~ - -error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_everywhere.rs:6:17 - | -LL | if let Some(&Some(x)) = &Some(Some(0)) { - | ^^^^^^^^ -------------- this expression has type `&Option>` - | | - | expected `Option<{integer}>`, found `&_` - | - = note: expected enum `Option<{integer}>` - found reference `&_` - -error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22 - | -LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` - | | - | expected integer, found `&mut _` - | - = note: expected type `{integer}` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut x` - --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22 - | -LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - | ^^^^^^ -help: consider removing `&mut` from the pattern - | -LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) { - | ~ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_everywhere-fail.rs b/tests/ui/match/ref_pat_everywhere-fail.rs deleted file mode 100644 index d1b1c04730d34..0000000000000 --- a/tests/ui/match/ref_pat_everywhere-fail.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(incomplete_features)] -#![feature(ref_pat_everywhere)] -pub fn main() { - if let Some(&x) = Some(0) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } - if let Some(&mut x) = Some(&0) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } -} diff --git a/tests/ui/match/ref_pat_everywhere-fail.stderr b/tests/ui/match/ref_pat_everywhere-fail.stderr deleted file mode 100644 index 25a01129f4a9d..0000000000000 --- a/tests/ui/match/ref_pat_everywhere-fail.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/ref_pat_everywhere-fail.rs:4:17 - | -LL | if let Some(&x) = Some(0) { - | ^^ ------- this expression has type `Option<{integer}>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL | if let Some(x) = Some(0) { - | ~ - -error[E0308]: mismatched types - --> $DIR/ref_pat_everywhere-fail.rs:8:17 - | -LL | if let Some(&mut x) = Some(&0) { - | ^^^^^^ -------- this expression has type `Option<&{integer}>` - | | - | types differ in mutability - | - = note: expected reference `&{integer}` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut x` - --> $DIR/ref_pat_everywhere-fail.rs:8:17 - | -LL | if let Some(&mut x) = Some(&0) { - | ^^^^^^ -help: consider removing `&mut` from the pattern - | -LL | if let Some(x) = Some(&0) { - | ~ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_everywhere.rs b/tests/ui/match/ref_pat_everywhere.rs deleted file mode 100644 index 9a79c548475f6..0000000000000 --- a/tests/ui/match/ref_pat_everywhere.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass -#![allow(incomplete_features)] -#![feature(ref_pat_everywhere)] - -pub fn main() { - if let Some(Some(&x)) = &Some(&Some(0)) { - let _: u32 = x; - } - if let Some(&Some(x)) = &Some(Some(0)) { - let _: u32 = x; - } - if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - let _: u32 = x; - } - if let Some(Some(&x)) = &Some(&mut Some(0)) { - let _: u32 = x; - } - if let &Some(x) = &mut Some(0) { - let _: u32 = x; - } - if let Some(&x) = &mut Some(0) { - let _: u32 = x; - } -} From eb91f3b0513acf34701d8598c1312875c6e489a5 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 15 May 2024 15:54:28 -0400 Subject: [PATCH 02/11] `&mut` no longer peels off `&` --- compiler/rustc_hir_typeck/src/pat.rs | 54 +++---- .../ref_pat_eat_one_layer_2024.rs | 15 -- .../ref_pat_eat_one_layer_2024_fail.rs | 29 +++- .../ref_pat_eat_one_layer_2024_fail.stderr | 137 ++++++++++++------ 4 files changed, 147 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index d2897f1c01131..6cd74961cc7fe 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -335,9 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match adjust_mode { AdjustMode::Pass => (expected, def_br, max_ref_mutbl), AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut), - AdjustMode::Peel => { - self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl) - } + AdjustMode::Peel => self.peel_off_references(pat, expected, def_br, max_ref_mutbl), } } @@ -408,7 +406,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, mut def_br: ByRef, - max_peelable_mutability: Mutability, mut max_ref_mutability: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap) { let mut expected = self.try_structurally_resolve_type(pat.span, expected); @@ -421,9 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // See the examples in `ui/match-defbm*.rs`. let mut pat_adjustments = vec![]; - while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() - && inner_mutability <= max_peelable_mutability - { + while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { debug!("inspecting {:?}", expected); debug!("current discriminant is Ref, inserting implicit deref"); @@ -2129,32 +2124,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024; if new_match_ergonomics { + let pat_prefix_span = + inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)); + if pat_mutbl == Mutability::Not { // Prevent the inner pattern from binding with `ref mut`. - pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not( - inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)), - ); - } + pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span); + } + + if let ByRef::Yes(inh_mut) = pat_info.binding_mode { + // ref pattern consumes inherited reference + + if pat_mutbl > inh_mut { + // Tried to match inherited `ref` with `&mut`, which is an error + let err_msg = "cannot match inherited `&` with `&mut` pattern"; + let err = if let Some(span) = pat_prefix_span { + let mut err = self.dcx().struct_span_err(span, err_msg); + err.span_suggestion_verbose( + span, + "replace this `&mut` pattern with `&`", + "&", + Applicability::MachineApplicable, + ); + err + } else { + self.dcx().struct_span_err(pat.span, err_msg) + }; + err.emit(); + } - if let ByRef::Yes(inh_mut) = pat_info.binding_mode - && pat_mutbl <= inh_mut - { pat_info.binding_mode = ByRef::No; self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); self.check_pat(inner, expected, pat_info); return expected; - } else if pat_mutbl == Mutability::Mut { - // `&mut` patterns pell off `&` references - let (new_expected, new_bm, max_ref_mutbl) = self.peel_off_references( - pat, - expected, - pat_info.binding_mode, - Mutability::Not, - pat_info.max_ref_mutbl, - ); - expected = new_expected; - pat_info.binding_mode = new_bm; - pat_info.max_ref_mutbl = max_ref_mutbl; } } else { // Reset binding mode on old editions diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs index 62e4f82a3ffbb..829b7f86e2621 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs @@ -23,9 +23,6 @@ pub fn main() { if let Some(Some(&x)) = &Some(&Some(0)) { let _: u32 = x; } - if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { - let _: u32 = x; - } if let Some(&Some(&x)) = &mut Some(&Some(0)) { let _: u32 = x; } @@ -35,9 +32,6 @@ pub fn main() { if let Some(&Some(&mut ref x)) = Some(&Some(&mut 0)) { let _: &u32 = x; } - if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { - let _: &u32 = x; - } if let &Some(Some(x)) = &Some(&mut Some(0)) { let _: &u32 = x; } @@ -59,13 +53,4 @@ pub fn main() { if let Some(&Some(x)) = &mut Some(Some(0)) { let _: u32 = x; } - - let &mut x = &&mut 0; - let _: &u32 = x; - - let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; - let _: &u32 = x; - - let &mut &mut &mut &mut x = &mut &&&&mut &&&mut &mut 0; - let _: &u32 = x; } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs index 96b4ff77ddb4b..a2a0c73b53b25 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs @@ -5,26 +5,26 @@ pub fn main() { if let Some(&mut Some(&_)) = &Some(&Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&Some(x)) = &mut Some(&Some(0)) { let _: &mut u32 = x; //~^ ERROR: mismatched types } if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } let &mut _ = &&0; @@ -32,4 +32,21 @@ pub fn main() { let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; //~^ ERROR: mismatched types + + if let Some(&mut Some(&_)) = &Some(&mut Some(0)) { + //~^ ERROR: cannot match inherited `&` with `&mut` pattern + } + + if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { + //~^ ERROR: cannot match inherited `&` with `&mut` pattern + } + + let &mut _ = &&mut 0; + //~^ ERROR: mismatched types + + let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; + //~^ ERROR: mismatched types + + let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; + //~^ ERROR: mismatched types } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr index e06a645fc0d33..cad67b4f8d673 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr @@ -1,24 +1,24 @@ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:7:17 | LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { - | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | expected `Option<{integer}>`, found `&mut _` + | ^^^^^ | - = note: expected enum `Option<{integer}>` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&Some(0)) { + | ~ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:10:23 | LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - | ^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` - | | - | expected integer, found `&mut _` + | ^^^^^ | - = note: expected type `{integer}` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { + | ~ error[E0308]: mismatched types --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:14:27 @@ -31,49 +31,49 @@ LL | let _: &mut u32 = x; = note: expected mutable reference `&mut u32` found reference `&{integer}` -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23 | LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { - | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` - | | - | expected integer, found `&mut _` + | ^^^^^ | - = note: expected type `{integer}` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) { + | ~ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:29 | LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - | ^^^^^^ ------------------------- this expression has type `&Option>>` - | | - | expected integer, found `&mut _` + | ^^^^^ | - = note: expected type `{integer}` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) { + | ~ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:17 | LL | if let Some(&mut Some(x)) = &Some(Some(0)) { - | ^^^^^^^^^^^^ -------------- this expression has type `&Option>` - | | - | expected `Option<{integer}>`, found `&mut _` + | ^^^^^ | - = note: expected enum `Option<{integer}>` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ~ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17 | LL | if let Some(&mut Some(x)) = &Some(Some(0)) { - | ^^^^^^^^^^^^ -------------- this expression has type `&Option>` - | | - | expected `Option<{integer}>`, found `&mut _` + | ^^^^^ | - = note: expected enum `Option<{integer}>` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ~ error[E0308]: mismatched types --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:30:9 @@ -81,9 +81,9 @@ error[E0308]: mismatched types LL | let &mut _ = &&0; | ^^^^^^ --- this expression has type `&&{integer}` | | - | expected integer, found `&mut _` + | types differ in mutability | - = note: expected type `{integer}` + = note: expected reference `&&{integer}` found mutable reference `&mut _` error[E0308]: mismatched types @@ -92,11 +92,66 @@ error[E0308]: mismatched types LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` | | - | expected integer, found `&mut _` + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + found mutable reference `&mut _` + +error: cannot match inherited `&` with `&mut` pattern + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:36:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&mut Some(0)) { + | ^^^^^ + | +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { + | ~ + +error: cannot match inherited `&` with `&mut` pattern + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:40:22 + | +LL | if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { + | ^^^^^ + | +help: replace this `&mut` pattern with `&` + | +LL | if let Some(Some(&x)) = &Some(Some(&mut 0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:44:9 + | +LL | let &mut _ = &&mut 0; + | ^^^^^^ ------- this expression has type `&&mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:47:9 + | +LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; + | ^^^^^^ --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:50:14 + | +LL | let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; + | ^^^^^^^^^^^^^^^^ -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}` + | | + | types differ in mutability | - = note: expected type `{integer}` + = note: expected reference `&&&&mut &&&mut &mut {integer}` found mutable reference `&mut _` -error: aborting due to 9 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0308`. From 0746577fa27f2a322f3ab5f4e85c6eeb51c6fc6c Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 15 May 2024 16:55:54 -0400 Subject: [PATCH 03/11] Gate implicit mutable by-reference bindings behind `mut ref` --- compiler/rustc_feature/src/removed.rs | 2 ++ compiler/rustc_feature/src/unstable.rs | 2 -- compiler/rustc_hir_typeck/src/pat.rs | 34 ++++++++++++------- .../ref_pat_eat_one_layer_2024_fail.rs | 10 ++++++ .../ref_pat_eat_one_layer_2024_fail.stderr | 25 ++++++++++++-- ...ure-gate-mut_preserve_binding_mode_2024.rs | 14 -------- ...gate-mut_preserve_binding_mode_2024.stderr | 31 ----------------- tests/ui/pattern/match_ergonomics_2024.fixed | 2 +- tests/ui/pattern/match_ergonomics_2024.rs | 2 +- .../pattern/mut_preserve_binding_mode_2021.rs | 2 +- .../pattern/mut_preserve_binding_mode_2024.rs | 2 +- 11 files changed, 61 insertions(+), 65 deletions(-) delete mode 100644 tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.rs delete mode 100644 tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.stderr diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index f1afde31803e4..aea447b2aff10 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -128,6 +128,8 @@ declare_features! ( /// Allows the use of type alias impl trait in function return positions (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), Some("removed in favor of full type_alias_impl_trait")), + /// Make `mut` not reset the binding mode on edition >= 2024. + (removed, mut_preserve_binding_mode_2024, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`")), (removed, needs_allocator, "1.4.0", Some(27389), Some("subsumed by `#![feature(allocator_internals)]`")), /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1a058a121f3ad..a4ccb0f1412e9 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -527,8 +527,6 @@ declare_features! ( (unstable, more_qualified_paths, "1.54.0", Some(86935)), /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), - /// Make `mut` not reset the binding mode on edition >= 2024. - (incomplete, mut_preserve_binding_mode_2024, "1.79.0", Some(123076)), /// Allows `mut ref` and `mut ref mut` identifier patterns. (incomplete, mut_ref, "1.79.0", Some(123076)), /// Allows using `#[naked]` on functions. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 6cd74961cc7fe..8e3b19f79a5b5 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -12,7 +12,7 @@ use rustc_infer::infer; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; -use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; +use rustc_session::{lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS, parse::feature_err}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; @@ -669,17 +669,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match user_bind_annot { - // `mut` resets binding mode on edition <= 2021 - BindingMode(ByRef::No, Mutability::Mut) - if !(pat.span.at_least_rust_2024() - && self.tcx.features().mut_preserve_binding_mode_2024) - && matches!(def_br, ByRef::Yes(_)) => - { - self.typeck_results - .borrow_mut() - .rust_2024_migration_desugared_pats_mut() - .insert(pat_info.top_info.hir_id); - BindingMode(ByRef::No, Mutability::Mut) + BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { + if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { + if !self.tcx.features().mut_ref { + feature_err( + &self.tcx.sess, + sym::mut_ref, + pat.span.until(ident.span), + "binding cannot be both mutable and by-reference", + ) + .emit(); + } + + BindingMode(def_br, Mutability::Mut) + } else { + // `mut` resets binding mode on edition <= 2021 + self.typeck_results + .borrow_mut() + .rust_2024_migration_desugared_pats_mut() + .insert(pat_info.top_info.hir_id); + BindingMode(ByRef::No, Mutability::Mut) + } } BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl), BindingMode(ByRef::Yes(_), _) => user_bind_annot, diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs index a2a0c73b53b25..40e8293e24111 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs @@ -49,4 +49,14 @@ pub fn main() { let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; //~^ ERROR: mismatched types + + struct Foo(u8); + + let Foo(mut a) = &Foo(0); + //~^ ERROR: binding cannot be both mutable and by-reference + a = &42; + + let Foo(mut a) = &mut Foo(0); + //~^ ERROR: binding cannot be both mutable and by-reference + a = &mut 42; } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr index cad67b4f8d673..26317e43d023e 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr @@ -152,6 +152,27 @@ LL | let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; = note: expected reference `&&&&mut &&&mut &mut {integer}` found mutable reference `&mut _` -error: aborting due to 14 previous errors +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:55:13 + | +LL | let Foo(mut a) = &Foo(0); + | ^^^^ + | + = note: see issue #123076 for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:59:13 + | +LL | let Foo(mut a) = &mut Foo(0); + | ^^^^ + | + = note: see issue #123076 for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 16 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.rs b/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.rs deleted file mode 100644 index 15c542e6bf104..0000000000000 --- a/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ edition: 2024 -//@ compile-flags: -Zunstable-options - -struct Foo(u8); - -fn main() { - let Foo(mut a) = &Foo(0); - a = &42; - //~^ ERROR: mismatched types - - let Foo(mut a) = &mut Foo(0); - a = &mut 42; - //~^ ERROR: mismatched types -} diff --git a/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.stderr b/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.stderr deleted file mode 100644 index 6d0a034be21c7..0000000000000 --- a/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/feature-gate-mut_preserve_binding_mode_2024.rs:8:9 - | -LL | let Foo(mut a) = &Foo(0); - | ----- expected due to the type of this binding -LL | a = &42; - | ^^^ expected `u8`, found `&{integer}` - | -help: consider removing the borrow - | -LL - a = &42; -LL + a = 42; - | - -error[E0308]: mismatched types - --> $DIR/feature-gate-mut_preserve_binding_mode_2024.rs:12:9 - | -LL | let Foo(mut a) = &mut Foo(0); - | ----- expected due to the type of this binding -LL | a = &mut 42; - | ^^^^^^^ expected `u8`, found `&mut {integer}` - | -help: consider removing the borrow - | -LL - a = &mut 42; -LL + a = 42; - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/match_ergonomics_2024.fixed b/tests/ui/pattern/match_ergonomics_2024.fixed index d8dbcb217c040..1ec2b5a214bfa 100644 --- a/tests/ui/pattern/match_ergonomics_2024.fixed +++ b/tests/ui/pattern/match_ergonomics_2024.fixed @@ -2,7 +2,7 @@ //@ run-rustfix //@ rustfix-only-machine-applicable //@ aux-build:match_ergonomics_2024_macros.rs -#![feature(mut_preserve_binding_mode_2024, ref_pat_eat_one_layer_2024)] +#![feature(mut_ref, ref_pat_eat_one_layer_2024)] #![allow(incomplete_features, unused)] #![deny(rust_2024_incompatible_pat)] diff --git a/tests/ui/pattern/match_ergonomics_2024.rs b/tests/ui/pattern/match_ergonomics_2024.rs index 38dc0c8bebb2f..c9f992c12d4a2 100644 --- a/tests/ui/pattern/match_ergonomics_2024.rs +++ b/tests/ui/pattern/match_ergonomics_2024.rs @@ -2,7 +2,7 @@ //@ run-rustfix //@ rustfix-only-machine-applicable //@ aux-build:match_ergonomics_2024_macros.rs -#![feature(mut_preserve_binding_mode_2024, ref_pat_eat_one_layer_2024)] +#![feature(mut_ref, ref_pat_eat_one_layer_2024)] #![allow(incomplete_features, unused)] #![deny(rust_2024_incompatible_pat)] diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2021.rs b/tests/ui/pattern/mut_preserve_binding_mode_2021.rs index befa49fdc2472..282e0ef95d224 100644 --- a/tests/ui/pattern/mut_preserve_binding_mode_2021.rs +++ b/tests/ui/pattern/mut_preserve_binding_mode_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 //@ compile-flags: -Zunstable-options -#![feature(mut_preserve_binding_mode_2024)] +#![feature(ref_pat_eat_one_layer_2024)] #![allow(incomplete_features)] struct Foo(u8); diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024.rs b/tests/ui/pattern/mut_preserve_binding_mode_2024.rs index 5454962e16ce1..19aa73573b46b 100644 --- a/tests/ui/pattern/mut_preserve_binding_mode_2024.rs +++ b/tests/ui/pattern/mut_preserve_binding_mode_2024.rs @@ -1,7 +1,7 @@ //@ run-pass //@ edition: 2024 //@ compile-flags: -Zunstable-options -#![feature(mut_preserve_binding_mode_2024)] +#![feature(mut_ref, ref_pat_eat_one_layer_2024)] #![allow(incomplete_features, unused)] struct Foo(u8); From af75014cc52a97c93eb3d115441337874f525236 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 15 May 2024 17:20:18 -0400 Subject: [PATCH 04/11] "No `ref mut` behind `&`" on all editions --- compiler/rustc_hir_typeck/src/pat.rs | 35 ++++++++++++----------- tests/ui/pattern/no_ref_mut_behind_and.rs | 9 ++++++ 2 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 tests/ui/pattern/no_ref_mut_behind_and.rs diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 8e3b19f79a5b5..617c08181fb0d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -406,7 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, mut def_br: ByRef, - mut max_ref_mutability: MutblCap, + mut max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap) { let mut expected = self.try_structurally_resolve_type(pat.span, expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, @@ -438,10 +438,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { - def_br = def_br.cap_ref_mutability(max_ref_mutability.as_mutbl()); + if self.tcx.features().ref_pat_eat_one_layer_2024 { + def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { - max_ref_mutability = MutblCap::Not; + max_ref_mutbl = MutblCap::Not; } } @@ -453,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(pat.hir_id, pat_adjustments); } - (expected, def_br, max_ref_mutability) + (expected, def_br, max_ref_mutbl) } fn check_pat_lit( @@ -2130,18 +2130,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected: Ty<'tcx>, mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let new_match_ergonomics = - pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024; + let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024; + let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and; - if new_match_ergonomics { - let pat_prefix_span = - inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)); + let pat_prefix_span = + inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)); + if no_ref_mut_behind_and { if pat_mutbl == Mutability::Not { // Prevent the inner pattern from binding with `ref mut`. pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span); } + } else { + pat_info.max_ref_mutbl = MutblCap::Mut; + } + if new_match_ergonomics { if let ByRef::Yes(inh_mut) = pat_info.binding_mode { // ref pattern consumes inherited reference @@ -2179,8 +2183,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .rust_2024_migration_desugared_pats_mut() .insert(pat_info.top_info.hir_id); } - - pat_info.max_ref_mutbl = MutblCap::Mut; } let tcx = self.tcx; @@ -2195,16 +2197,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the bad interactions of the given hack detailed in (note_1). debug!("check_pat_ref: expected={:?}", expected); match *expected.kind() { - ty::Ref(_, r_ty, r_mutbl) if r_mutbl >= pat_mutbl && new_match_ergonomics => { - if r_mutbl == Mutability::Not { + ty::Ref(_, r_ty, r_mutbl) + if (new_match_ergonomics && r_mutbl >= pat_mutbl) + || r_mutbl == pat_mutbl => + { + if no_ref_mut_behind_and && r_mutbl == Mutability::Not { pat_info.max_ref_mutbl = MutblCap::Not; } (expected, r_ty) } - ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => (expected, r_ty), - _ => { let inner_ty = self.next_ty_var(inner.span); let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty); diff --git a/tests/ui/pattern/no_ref_mut_behind_and.rs b/tests/ui/pattern/no_ref_mut_behind_and.rs new file mode 100644 index 0000000000000..c18d64904d035 --- /dev/null +++ b/tests/ui/pattern/no_ref_mut_behind_and.rs @@ -0,0 +1,9 @@ +//@ edition: 2021 +//@ run-pass +#![allow(incomplete_features)] +#![feature(ref_pat_eat_one_layer_2024)] + +fn main() { + let &[[x]] = &[&mut [42]]; + let _: &i32 = x; +} From 9d1ec7ea069ab3897e715464be8b6d93e529020a Mon Sep 17 00:00:00 2001 From: dalance Date: Sun, 5 May 2024 09:01:47 +0900 Subject: [PATCH 05/11] Add translation support by mdbook-i18n-helpers to bootstrap --- Cargo.lock | 148 +++++++++++++++++++++- src/bootstrap/src/core/build_steps/doc.rs | 40 ++++-- src/tools/rustbook/Cargo.toml | 1 + src/tools/rustbook/src/main.rs | 13 ++ 4 files changed, 186 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1018eac13ff12..0e950e2880727 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,7 +372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "regex-automata 0.3.9", + "regex-automata 0.3.7", "serde", ] @@ -2206,6 +2206,21 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "line-wrap" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e" + +[[package]] +name = "linereader" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d921fea6860357575519aca014c6e22470585accdd543b370c404a8a72d0dd1d" +dependencies = [ + "memchr", +] + [[package]] name = "linkchecker" version = "0.1.0" @@ -2214,6 +2229,12 @@ dependencies = [ "regex", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "lint-docs" version = "0.1.0" @@ -2364,6 +2385,25 @@ dependencies = [ "topological-sort", ] +[[package]] +name = "mdbook-i18n-helpers" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f71f5961d6f3376e1ff3e5989c2e3ecccc3e8a00f3a3acde446847f84852e4" +dependencies = [ + "anyhow", + "chrono", + "mdbook", + "polib", + "pulldown-cmark 0.10.3", + "pulldown-cmark-to-cmark", + "regex", + "semver", + "serde_json", + "syntect", + "textwrap", +] + [[package]] name = "mdbook-trpl-listing" version = "0.1.0" @@ -2650,6 +2690,28 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "onig" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +dependencies = [ + "bitflags 1.3.2", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "opener" version = "0.6.1" @@ -2968,6 +3030,29 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "plist" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9" +dependencies = [ + "base64", + "indexmap", + "line-wrap", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "polib" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b393b155cf9be86249cba1b56cc81be0e6212c66d94ac0d76d37a1761f3bb1b" +dependencies = [ + "linereader", +] + [[package]] name = "polonius-engine" version = "0.13.0" @@ -3126,6 +3211,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe" +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + [[package]] name = "quine-mc_cluskey" version = "0.2.4" @@ -3261,12 +3355,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", + "regex-automata 0.3.7", "regex-syntax 0.7.5", ] @@ -3290,9 +3385,14 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", +] [[package]] name = "regex-lite" @@ -3367,6 +3467,7 @@ dependencies = [ "clap", "env_logger", "mdbook", + "mdbook-i18n-helpers", "mdbook-trpl-listing", "mdbook-trpl-note", ] @@ -5372,6 +5473,28 @@ dependencies = [ "syn 2.0.64", ] +[[package]] +name = "syntect" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" +dependencies = [ + "bincode", + "bitflags 1.3.2", + "flate2", + "fnv", + "once_cell", + "onig", + "plist", + "regex-syntax 0.8.3", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + [[package]] name = "sysinfo" version = "0.30.12" @@ -5497,6 +5620,12 @@ dependencies = [ "std", ] +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + [[package]] name = "thin-vec" version = "0.2.13" @@ -6476,6 +6605,15 @@ dependencies = [ "lzma-sys", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi-term" version = "0.1.2" diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 30b3edfd3aed5..b37b2b5bcefb7 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -29,7 +29,7 @@ macro_rules! submodule_helper { } macro_rules! book { - ($($name:ident, $path:expr, $book_name:expr $(, submodule $(= $submodule:literal)? )? ;)+) => { + ($($name:ident, $path:expr, $book_name:expr, $lang:expr $(, submodule $(= $submodule:literal)? )? ;)+) => { $( #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $name { @@ -61,6 +61,7 @@ macro_rules! book { name: $book_name.to_owned(), src: builder.src.join($path), parent: Some(self), + languages: $lang.into(), }) } } @@ -74,15 +75,15 @@ macro_rules! book { // FIXME: Make checking for a submodule automatic somehow (maybe by having a list of all submodules // and checking against it?). book!( - CargoBook, "src/tools/cargo/src/doc", "cargo", submodule = "src/tools/cargo"; - ClippyBook, "src/tools/clippy/book", "clippy"; - EditionGuide, "src/doc/edition-guide", "edition-guide", submodule; - EmbeddedBook, "src/doc/embedded-book", "embedded-book", submodule; - Nomicon, "src/doc/nomicon", "nomicon", submodule; - Reference, "src/doc/reference", "reference", submodule; - RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule; - RustdocBook, "src/doc/rustdoc", "rustdoc"; - StyleGuide, "src/doc/style-guide", "style-guide"; + CargoBook, "src/tools/cargo/src/doc", "cargo", &[], submodule = "src/tools/cargo"; + ClippyBook, "src/tools/clippy/book", "clippy", &[]; + EditionGuide, "src/doc/edition-guide", "edition-guide", &[], submodule; + EmbeddedBook, "src/doc/embedded-book", "embedded-book", &[], submodule; + Nomicon, "src/doc/nomicon", "nomicon", &[], submodule; + Reference, "src/doc/reference", "reference", &[], submodule; + RustByExample, "src/doc/rust-by-example", "rust-by-example", &["ja"], submodule; + RustdocBook, "src/doc/rustdoc", "rustdoc", &[]; + StyleGuide, "src/doc/style-guide", "style-guide", &[]; ); #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -110,6 +111,7 @@ impl Step for UnstableBook { name: "unstable-book".to_owned(), src: builder.md_doc_out(self.target).join("unstable-book"), parent: Some(self), + languages: vec![], }) } } @@ -120,6 +122,7 @@ struct RustbookSrc { name: String, src: PathBuf, parent: Option

, + languages: Vec<&'static str>, } impl Step for RustbookSrc

{ @@ -151,7 +154,19 @@ impl Step for RustbookSrc

{ builder.info(&format!("Rustbook ({target}) - {name}")); let _ = fs::remove_dir_all(&out); - builder.run(rustbook_cmd.arg("build").arg(src).arg("-d").arg(out)); + builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out)); + + for lang in &self.languages { + let out = out.join(lang); + + builder.info(&format!("Rustbook ({target}) - {name} - {lang}")); + let _ = fs::remove_dir_all(&out); + + let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); + builder.run( + rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).arg("-l").arg(lang), + ); + } } if self.parent.is_some() { @@ -214,6 +229,7 @@ impl Step for TheBook { name: "book".to_owned(), src: absolute_path.clone(), parent: Some(self), + languages: vec![], }); // building older edition redirects @@ -225,6 +241,7 @@ impl Step for TheBook { // There should only be one book that is marked as the parent for each target, so // treat the other editions as not having a parent. parent: Option::::None, + languages: vec![], }); } @@ -1208,6 +1225,7 @@ impl Step for RustcBook { name: "rustc".to_owned(), src: out_base, parent: Some(self), + languages: vec![], }); } } diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 2b0dd0062b90e..95f1a5d6e1d3e 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -9,6 +9,7 @@ clap = "4.0.32" env_logger = "0.11" mdbook-trpl-listing = { path = "../../doc/book/packages/mdbook-trpl-listing" } mdbook-trpl-note = { path = "../../doc/book/packages/mdbook-trpl-note" } +mdbook-i18n-helpers = "0.3.3" [dependencies.mdbook] version = "0.4.37" diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 9a06754e4a66c..31bba56addeb4 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -7,6 +7,7 @@ use clap::{arg, ArgMatches, Command}; use mdbook::errors::Result as Result3; use mdbook::MDBook; +use mdbook_i18n_helpers::preprocessors::Gettext; use mdbook_trpl_listing::TrplListing; use mdbook_trpl_note::TrplNote; @@ -19,6 +20,11 @@ fn main() { .required(false) .value_parser(clap::value_parser!(PathBuf)); + let l_arg = arg!(-l --"lang" +"The output language") + .required(false) + .value_parser(clap::value_parser!(String)); + let dir_arg = arg!([dir] "Root directory for the book\n\ (Defaults to the current directory when omitted)") .value_parser(clap::value_parser!(PathBuf)); @@ -33,6 +39,7 @@ fn main() { Command::new("build") .about("Build the book from the markdown files") .arg(d_arg) + .arg(l_arg) .arg(&dir_arg), ) .subcommand( @@ -63,6 +70,12 @@ pub fn build(args: &ArgMatches) -> Result3<()> { let book_dir = get_book_dir(args); let mut book = load_book(&book_dir)?; + if let Some(lang) = args.get_one::("lang") { + let gettext = Gettext; + book.with_preprocessor(gettext); + book.config.set("book.language", lang).unwrap(); + } + // Set this to allow us to catch bugs in advance. book.config.build.create_missing = false; From fd5777c4c5c8fbc54d33d15afb29479180c532be Mon Sep 17 00:00:00 2001 From: schvv31n Date: Tue, 4 Jun 2024 11:53:59 +0100 Subject: [PATCH 06/11] impl OsString::leak & PathBuf::leak --- library/std/src/ffi/os_str.rs | 19 +++++++++++++++++++ library/std/src/ffi/os_str/tests.rs | 7 +++++++ library/std/src/path.rs | 19 +++++++++++++++++++ library/std/src/path/tests.rs | 7 +++++++ library/std/src/sys/os_str/bytes.rs | 5 +++++ library/std/src/sys/os_str/wtf8.rs | 5 +++++ library/std/src/sys_common/wtf8.rs | 5 +++++ 7 files changed, 67 insertions(+) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 9dd3d7d3fa16a..f6b9de26c1c4d 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -533,6 +533,25 @@ impl OsString { unsafe { Box::from_raw(rw) } } + /// Consumes and leaks the `OsString`, returning a mutable reference to the contents, + /// `&'a mut OsStr`. + /// + /// The caller has free choice over the returned lifetime, including 'static. + /// Indeed, this function is ideally used for data that lives for the remainder of + /// the program’s life, as dropping the returned reference will cause a memory leak. + /// + /// It does not reallocate or shrink the `OsString`, so the leaked allocation may include + /// unused capacity that is not part of the returned slice. If you want to discard excess + /// capacity, call [`into_boxed_os_str`], and then [`Box::leak`] instead. + /// However, keep in mind that trimming the capacity may result in a reallocation and copy. + /// + /// [`into_boxed_os_str`]: Self::into_boxed_os_str + #[unstable(feature = "os_string_pathbuf_leak", issue = "125965")] + #[inline] + pub fn leak<'a>(self) -> &'a mut OsStr { + OsStr::from_inner_mut(self.inner.leak()) + } + /// Part of a hack to make PathBuf::push/pop more efficient. #[inline] pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs index b020e05eaab20..2379f0ba489e3 100644 --- a/library/std/src/ffi/os_str/tests.rs +++ b/library/std/src/ffi/os_str/tests.rs @@ -23,6 +23,13 @@ fn test_os_string_clear() { assert_eq!(0, os_string.inner.as_inner().len()); } +#[test] +fn test_os_string_leak() { + let os_string = OsString::from("have a cake"); + let leaked = os_string.leak(); + assert_eq!(leaked.as_encoded_bytes(), b"have a cake"); +} + #[test] fn test_os_string_capacity() { let os_string = OsString::with_capacity(0); diff --git a/library/std/src/path.rs b/library/std/src/path.rs index f4e1e2a38c106..adbcdcd2e67e3 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1226,6 +1226,25 @@ impl PathBuf { self } + /// Consumes and leaks the `PathBuf`, returning a mutable reference to the contents, + /// `&'a mut Path`. + /// + /// The caller has free choice over the returned lifetime, including 'static. + /// Indeed, this function is ideally used for data that lives for the remainder of + /// the program’s life, as dropping the returned reference will cause a memory leak. + /// + /// It does not reallocate or shrink the `PathBuf`, so the leaked allocation may include + /// unused capacity that is not part of the returned slice. If you want to discard excess + /// capacity, call [`into_boxed_path`], and then [`Box::leak`] instead. + /// However, keep in mind that trimming the capacity may result in a reallocation and copy. + /// + /// [`into_boxed_path`]: Self::into_boxed_path + #[unstable(feature = "os_string_pathbuf_leak", issue = "125965")] + #[inline] + pub fn leak<'a>(self) -> &'a mut Path { + Path::from_inner_mut(self.inner.leak()) + } + /// Extends `self` with `path`. /// /// If `path` is absolute, it replaces the current path. diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 2d8e50d1f88e9..d29f895ba38ff 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -126,6 +126,13 @@ fn into() { assert_eq!(static_cow_path, owned_cow_path); } +#[test] +fn test_pathbuf_leak() { + let buf = PathBuf::from("/have/a/cake".to_owned()); + let leaked = buf.leak(); + assert_eq!(leaked.as_os_str().as_encoded_bytes(), b"/have/a/cake"); +} + #[test] #[cfg(unix)] pub fn test_decompositions_unix() { diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 18b969bca85a6..f7c6b0877aa62 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -176,6 +176,11 @@ impl Buf { self.inner.extend_from_slice(&s.inner) } + #[inline] + pub fn leak<'a>(self) -> &'a mut Slice { + unsafe { mem::transmute(self.inner.leak()) } + } + #[inline] pub fn into_box(self) -> Box { unsafe { mem::transmute(self.inner.into_boxed_slice()) } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index b3ceb55802dc5..dfff4dd4fb023 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -138,6 +138,11 @@ impl Buf { self.inner.shrink_to(min_capacity) } + #[inline] + pub fn leak<'a>(self) -> &'a mut Slice { + unsafe { mem::transmute(self.inner.leak()) } + } + #[inline] pub fn into_box(self) -> Box { unsafe { mem::transmute(self.inner.into_box()) } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 38e15f9f54960..bb1e505285bf1 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -325,6 +325,11 @@ impl Wtf8Buf { self.bytes.shrink_to(min_capacity) } + #[inline] + pub fn leak<'a>(self) -> &'a mut Wtf8 { + unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) } + } + /// Returns the number of bytes that this string buffer can hold without reallocating. #[inline] pub fn capacity(&self) -> usize { From e7ad2da7f134c66779625a09b134b85ed1c7c7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Jun 2024 19:09:15 +0000 Subject: [PATCH 07/11] When `derive`ing, account for HRTB on `BareFn` fields When given ```rust trait SomeTrait { type SomeType<'a>; } struct Foo { x: for<'a> fn(T::SomeType<'a>) } ``` expand to ```rust impl ::core::clone::Clone for Foo where for<'a> T::SomeType<'a>: ::core::clone::Clone { #[inline] fn clone(&self) -> Foo { Foo { x: ::core::clone::Clone::clone(&self.x) } } } ``` instead of the previous invalid ``` impl ::core::clone::Clone for Foo where T::SomeType<'a>: ::core::clone::Clone { #[inline] fn clone(&self) -> Foo { Foo { x: ::core::clone::Clone::clone(&self.x) } } } ``` Fix #122622. --- .../src/deriving/generic/mod.rs | 12 +++++++++++- .../derive-hrtb-for-bare-fn-field-with-lifetime.rs | 13 +++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/ui/derives/derive-hrtb-for-bare-fn-field-with-lifetime.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 217fa5ff9f1e5..ba289f9552e22 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -412,6 +412,15 @@ fn find_type_parameters( impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { + let stack_len = self.bound_generic_params_stack.len(); + if let ast::TyKind::BareFn(bare_fn) = &ty.kind + && !bare_fn.generic_params.is_empty() + { + // Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so + // that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622 + self.bound_generic_params_stack.extend(bare_fn.generic_params.iter().cloned()); + } + if let ast::TyKind::Path(_, path) = &ty.kind && let Some(segment) = path.segments.first() && self.ty_param_names.contains(&segment.ident.name) @@ -422,7 +431,8 @@ fn find_type_parameters( }); } - visit::walk_ty(self, ty) + visit::walk_ty(self, ty); + self.bound_generic_params_stack.truncate(stack_len); } // Place bound generic params on a stack, to extract them when a type is encountered. diff --git a/tests/ui/derives/derive-hrtb-for-bare-fn-field-with-lifetime.rs b/tests/ui/derives/derive-hrtb-for-bare-fn-field-with-lifetime.rs new file mode 100644 index 0000000000000..b8a42be6832d6 --- /dev/null +++ b/tests/ui/derives/derive-hrtb-for-bare-fn-field-with-lifetime.rs @@ -0,0 +1,13 @@ +//@ run-pass +// Issue #122622: `#[derive(Clone)]` should work for HRTB function type taking an associated type +#![allow(dead_code)] +trait SomeTrait { + type SomeType<'a>; +} + +#[derive(Clone)] +struct Foo { + x: for<'a> fn(T::SomeType<'a>) +} + +fn main() {} From 743c41757c3211d989334b50b71df34279add5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olaf=20Siwi=C5=84ski?= Date: Wed, 5 Jun 2024 21:54:22 +0200 Subject: [PATCH 08/11] check_expr_struct_fields: taint context with errors if struct definition is malformed --- compiler/rustc_hir_typeck/src/expr.rs | 9 ++++++++ tests/crashes/124552.rs | 12 ---------- .../static/duplicated-fields-issue-124464.rs} | 6 ++++- .../duplicated-fields-issue-124464.stderr | 22 +++++++++++++++++++ .../static/duplicated-fields-issue-125842.rs | 21 ++++++++++++++++++ .../duplicated-fields-issue-125842.stderr | 11 ++++++++++ 6 files changed, 68 insertions(+), 13 deletions(-) delete mode 100644 tests/crashes/124552.rs rename tests/{crashes/124464.rs => ui/static/duplicated-fields-issue-124464.rs} (57%) create mode 100644 tests/ui/static/duplicated-fields-issue-124464.stderr create mode 100644 tests/ui/static/duplicated-fields-issue-125842.rs create mode 100644 tests/ui/static/duplicated-fields-issue-125842.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4cc936eed08c5..7dd7b3ff055e5 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1671,6 +1671,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut error_happened = false; + if variant.fields.len() != remaining_fields.len() { + // Some field is defined more than once. Make sure we don't try to + // instantiate this struct in static/const context. + let guar = + self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names"); + self.set_tainted_by_errors(guar); + error_happened = true; + } + // Type-check each field. for (idx, field) in hir_fields.iter().enumerate() { let ident = tcx.adjust_ident(field.ident, variant.def_id); diff --git a/tests/crashes/124552.rs b/tests/crashes/124552.rs deleted file mode 100644 index 5320ce2784305..0000000000000 --- a/tests/crashes/124552.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: rust-lang/rust#124552 - -struct B; - -struct Foo { - b: u32, - b: B, -} - -static BAR: Foo = Foo { b: B }; - -fn main() {} diff --git a/tests/crashes/124464.rs b/tests/ui/static/duplicated-fields-issue-124464.rs similarity index 57% rename from tests/crashes/124464.rs rename to tests/ui/static/duplicated-fields-issue-124464.rs index 471479f5cf1b6..60609edbfebb6 100644 --- a/tests/crashes/124464.rs +++ b/tests/ui/static/duplicated-fields-issue-124464.rs @@ -1,12 +1,16 @@ -//@ known-bug: rust-lang/rust #124464 +// Don't const eval fields with ambiguous layout. +// See issues #125842 and #124464. + enum TestOption { TestSome(T), TestSome(T), +//~^ ERROR the name `TestSome` is defined multiple times } pub struct Request { bar: TestOption, bar: u8, +//~^ ERROR field `bar` is already declared } fn default_instance() -> &'static Request { diff --git a/tests/ui/static/duplicated-fields-issue-124464.stderr b/tests/ui/static/duplicated-fields-issue-124464.stderr new file mode 100644 index 0000000000000..a36192ae8d69d --- /dev/null +++ b/tests/ui/static/duplicated-fields-issue-124464.stderr @@ -0,0 +1,22 @@ +error[E0428]: the name `TestSome` is defined multiple times + --> $DIR/duplicated-fields-issue-124464.rs:6:5 + | +LL | TestSome(T), + | ----------- previous definition of the type `TestSome` here +LL | TestSome(T), + | ^^^^^^^^^^^ `TestSome` redefined here + | + = note: `TestSome` must be defined only once in the type namespace of this enum + +error[E0124]: field `bar` is already declared + --> $DIR/duplicated-fields-issue-124464.rs:12:5 + | +LL | bar: TestOption, + | -------------------- `bar` first declared here +LL | bar: u8, + | ^^^^^^^ field already declared + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0124, E0428. +For more information about an error, try `rustc --explain E0124`. diff --git a/tests/ui/static/duplicated-fields-issue-125842.rs b/tests/ui/static/duplicated-fields-issue-125842.rs new file mode 100644 index 0000000000000..580b810232e04 --- /dev/null +++ b/tests/ui/static/duplicated-fields-issue-125842.rs @@ -0,0 +1,21 @@ +// Do not try to evaluate static initalizers that reference +// ill-defined types. This used to be an ICE. +// See issues #125842 and #124464. +struct Struct { + field: Option, + field: u8, +//~^ ERROR field `field` is already declared +} + +static STATIC_A: Struct = Struct { + field: 1 +}; + +static STATIC_B: Struct = { + let field = 1; + Struct { + field, + } +}; + +fn main() {} diff --git a/tests/ui/static/duplicated-fields-issue-125842.stderr b/tests/ui/static/duplicated-fields-issue-125842.stderr new file mode 100644 index 0000000000000..c80bb99005ee5 --- /dev/null +++ b/tests/ui/static/duplicated-fields-issue-125842.stderr @@ -0,0 +1,11 @@ +error[E0124]: field `field` is already declared + --> $DIR/duplicated-fields-issue-125842.rs:6:5 + | +LL | field: Option, + | ----------------- `field` first declared here +LL | field: u8, + | ^^^^^^^^^ field already declared + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0124`. From 88e81bca9f83157afec49c4cddcdf25497cfe507 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 24 May 2024 17:09:21 +0200 Subject: [PATCH 09/11] Fix typos in cargo-specifics.md --- src/doc/rustc/src/check-cfg/cargo-specifics.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/check-cfg/cargo-specifics.md b/src/doc/rustc/src/check-cfg/cargo-specifics.md index bfa6016192614..e3b8b537c42c7 100644 --- a/src/doc/rustc/src/check-cfg/cargo-specifics.md +++ b/src/doc/rustc/src/check-cfg/cargo-specifics.md @@ -8,7 +8,7 @@ be an implementation detail, at least --check-cfg and the unexpected_cfgs are ow rustc, not Cargo. --> -This document is intented to summarize the principal ways Cargo interacts with +This document is intended to summarize the principal ways Cargo interacts with the `unexpected_cfgs` lint and `--check-cfg` flag. It is not intended to provide individual details, for that refer to the [`--check-cfg` documentation](../check-cfg.md) and to the [Cargo book](../../cargo/index.html). @@ -37,11 +37,11 @@ implementation detail and is therefor not documented in Cargo, we therefor do th *See the [`[lints]` section in the Cargo book][cargo-lints-table] for more details.* -When using a staticlly known custom config (ie. not dependant on a build-script), Cargo provides +When using a statically known custom config (ie. not dependant on a build-script), Cargo provides the custom lint config `check-cfg` under `[lints.rust.unexpected_cfgs]`. It can be used to set custom static [`--check-cfg`](../check-cfg.md) args, it is mainly useful when -the list of expected cfgs is known is advance. +the list of expected cfgs is known in advance. `Cargo.toml`: ```toml From 964e88555ba6a9fc41d3a19e114b77ed5064bad9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 5 Jun 2024 13:34:21 -0700 Subject: [PATCH 10/11] Fix some wording in cargo-specifics.md --- src/doc/rustc/src/check-cfg/cargo-specifics.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc/src/check-cfg/cargo-specifics.md b/src/doc/rustc/src/check-cfg/cargo-specifics.md index e3b8b537c42c7..bd4bebbc874a6 100644 --- a/src/doc/rustc/src/check-cfg/cargo-specifics.md +++ b/src/doc/rustc/src/check-cfg/cargo-specifics.md @@ -3,7 +3,7 @@ @@ -17,7 +17,7 @@ to the [Cargo book](../../cargo/index.html). *See the [`[features]` section in the Cargo book][cargo-features] for more details.* -With the `[features]` table Cargo provides a mechanism to express conditional compilation and +With the `[features]` table, Cargo provides a mechanism to express conditional compilation and optional dependencies. Cargo *automatically* declares corresponding cfgs for every feature as expected. @@ -32,12 +32,12 @@ my_feature = [] ## `check-cfg` in `[lints.rust]` table - + *See the [`[lints]` section in the Cargo book][cargo-lints-table] for more details.* -When using a statically known custom config (ie. not dependant on a build-script), Cargo provides +When using a statically known custom config (i.e., not dependent on a build-script), Cargo provides the custom lint config `check-cfg` under `[lints.rust.unexpected_cfgs]`. It can be used to set custom static [`--check-cfg`](../check-cfg.md) args, it is mainly useful when From bb901a114f1abef304f2420be071da8aa3c21406 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 3 Jun 2024 13:08:39 +0200 Subject: [PATCH 11/11] Don't trigger `unsafe_op_in_unsafe_fn` for deprecated safe fns Fixes #125875. --- .../rustc_mir_build/src/check_unsafety.rs | 81 +++++++++++-------- tests/ui/rust-2024/unsafe-env.e2021.stderr | 27 ++++++- tests/ui/rust-2024/unsafe-env.e2024.stderr | 49 +++++++++-- tests/ui/rust-2024/unsafe-env.rs | 12 ++- 4 files changed, 124 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 659ae1724603a..9a19445e3779b 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -88,6 +88,33 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } } + fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool { + match kind { + // Allow calls to deprecated-safe unsafe functions if the caller is + // from an edition before 2024. + &UnsafeOpKind::CallToUnsafeFunction(Some(id)) + if !span.at_least_rust_2024() + && self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => + { + self.tcx.emit_node_span_lint( + DEPRECATED_SAFE, + self.hir_context, + span, + CallToDeprecatedSafeFnRequiresUnsafe { + span, + function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), + sub: CallToDeprecatedSafeFnRequiresUnsafeSub { + left: span.shrink_to_lo(), + right: span.shrink_to_hi(), + }, + }, + ); + true + } + _ => false, + } + } + fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) { let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed(); match self.safety_context { @@ -101,43 +128,29 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {} SafetyContext::UnsafeFn => { - // unsafe_op_in_unsafe_fn is disallowed - kind.emit_unsafe_op_in_unsafe_fn_lint( - self.tcx, - self.hir_context, - span, - self.suggest_unsafe_block, - ); - self.suggest_unsafe_block = false; - } - SafetyContext::Safe => match kind { - // Allow calls to deprecated-safe unsafe functions if the - // caller is from an edition before 2024. - UnsafeOpKind::CallToUnsafeFunction(Some(id)) - if !span.at_least_rust_2024() - && self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => - { - self.tcx.emit_node_span_lint( - DEPRECATED_SAFE, + let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind); + if !deprecated_safe_fn { + // unsafe_op_in_unsafe_fn is disallowed + kind.emit_unsafe_op_in_unsafe_fn_lint( + self.tcx, self.hir_context, span, - CallToDeprecatedSafeFnRequiresUnsafe { - span, - function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), - sub: CallToDeprecatedSafeFnRequiresUnsafeSub { - left: span.shrink_to_lo(), - right: span.shrink_to_hi(), - }, - }, - ) + self.suggest_unsafe_block, + ); + self.suggest_unsafe_block = false; } - _ => kind.emit_requires_unsafe_err( - self.tcx, - span, - self.hir_context, - unsafe_op_in_unsafe_fn_allowed, - ), - }, + } + SafetyContext::Safe => { + let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind); + if !deprecated_safe_fn { + kind.emit_requires_unsafe_err( + self.tcx, + span, + self.hir_context, + unsafe_op_in_unsafe_fn_allowed, + ); + } + } } } diff --git a/tests/ui/rust-2024/unsafe-env.e2021.stderr b/tests/ui/rust-2024/unsafe-env.e2021.stderr index cc40ec2e466be..90c1df192aa05 100644 --- a/tests/ui/rust-2024/unsafe-env.e2021.stderr +++ b/tests/ui/rust-2024/unsafe-env.e2021.stderr @@ -1,5 +1,24 @@ +error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block + --> $DIR/unsafe-env.rs:15:9 + | +LL | unsafe_fn(); + | ^^^^^^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 + = note: consult the function's documentation for information on how to avoid undefined behavior +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/unsafe-env.rs:9:1 + | +LL | unsafe fn unsafe_fn() { + | ^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/unsafe-env.rs:8:8 + | +LL | #[deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe function or block - --> $DIR/unsafe-env.rs:23:5 + --> $DIR/unsafe-env.rs:33:5 | LL | unsafe_fn(); | ^^^^^^^^^^^ call to unsafe function @@ -7,17 +26,17 @@ LL | unsafe_fn(); = note: consult the function's documentation for information on how to avoid undefined behavior error: unnecessary `unsafe` block - --> $DIR/unsafe-env.rs:26:5 + --> $DIR/unsafe-env.rs:36:5 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/unsafe-env.rs:11:8 + --> $DIR/unsafe-env.rs:21:8 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-env.e2024.stderr b/tests/ui/rust-2024/unsafe-env.e2024.stderr index b43f817cf72ad..5ecdf3cd7a74c 100644 --- a/tests/ui/rust-2024/unsafe-env.e2024.stderr +++ b/tests/ui/rust-2024/unsafe-env.e2024.stderr @@ -1,5 +1,42 @@ +error[E0133]: call to unsafe function `std::env::set_var` is unsafe and requires unsafe block + --> $DIR/unsafe-env.rs:10:5 + | +LL | env::set_var("FOO", "BAR"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 + = note: consult the function's documentation for information on how to avoid undefined behavior +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/unsafe-env.rs:9:1 + | +LL | unsafe fn unsafe_fn() { + | ^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/unsafe-env.rs:8:8 + | +LL | #[deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0133]: call to unsafe function `std::env::remove_var` is unsafe and requires unsafe block + --> $DIR/unsafe-env.rs:12:5 + | +LL | env::remove_var("FOO"); + | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block + --> $DIR/unsafe-env.rs:15:9 + | +LL | unsafe_fn(); + | ^^^^^^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 + = note: consult the function's documentation for information on how to avoid undefined behavior + error[E0133]: call to unsafe function `set_var` is unsafe and requires unsafe block - --> $DIR/unsafe-env.rs:13:5 + --> $DIR/unsafe-env.rs:23:5 | LL | env::set_var("FOO", "BAR"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function @@ -7,7 +44,7 @@ LL | env::set_var("FOO", "BAR"); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function `remove_var` is unsafe and requires unsafe block - --> $DIR/unsafe-env.rs:15:5 + --> $DIR/unsafe-env.rs:25:5 | LL | env::remove_var("FOO"); | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function @@ -15,7 +52,7 @@ LL | env::remove_var("FOO"); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block - --> $DIR/unsafe-env.rs:23:5 + --> $DIR/unsafe-env.rs:33:5 | LL | unsafe_fn(); | ^^^^^^^^^^^ call to unsafe function @@ -23,17 +60,17 @@ LL | unsafe_fn(); = note: consult the function's documentation for information on how to avoid undefined behavior error: unnecessary `unsafe` block - --> $DIR/unsafe-env.rs:26:5 + --> $DIR/unsafe-env.rs:36:5 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/unsafe-env.rs:11:8 + --> $DIR/unsafe-env.rs:21:8 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-env.rs b/tests/ui/rust-2024/unsafe-env.rs index a882f077b9bb7..601f44e1d3ec5 100644 --- a/tests/ui/rust-2024/unsafe-env.rs +++ b/tests/ui/rust-2024/unsafe-env.rs @@ -5,7 +5,17 @@ use std::env; -unsafe fn unsafe_fn() {} +#[deny(unsafe_op_in_unsafe_fn)] +unsafe fn unsafe_fn() { + env::set_var("FOO", "BAR"); + //[e2024]~^ ERROR call to unsafe function `std::env::set_var` is unsafe + env::remove_var("FOO"); + //[e2024]~^ ERROR call to unsafe function `std::env::remove_var` is unsafe + if false { + unsafe_fn(); + //~^ ERROR call to unsafe function `unsafe_fn` is unsafe + } +} fn safe_fn() {} #[deny(unused_unsafe)]