diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 5880bbd3de44e..36d261fb737ce 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -13,7 +13,6 @@ #![feature(unboxed_closures)] #![feature(generator_trait)] #![feature(fn_traits)] -#![feature(int_bits_const)] #![feature(min_specialization)] #![feature(auto_traits)] #![feature(nll)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0013.md b/compiler/rustc_error_codes/src/error_codes/E0013.md index 8de177590ece8..5605302772ff6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0013.md +++ b/compiler/rustc_error_codes/src/error_codes/E0013.md @@ -8,7 +8,7 @@ static X: i32 = 42; const Y: i32 = X; ``` -In this example, `Y` cannot refer to `X` here. To fix this, the value can be +In this example, `Y` cannot refer to `X`. To fix this, the value can be extracted as a const and then used: ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md index b2cc2a2273af2..019d54b6202ed 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0038.md +++ b/compiler/rustc_error_codes/src/error_codes/E0038.md @@ -287,5 +287,5 @@ the method `get_a()` would return an object of unknown type when called on the function. `Self` type parameters let us make object safe traits no longer safe, so they are forbidden when specifying supertraits. -There's no easy fix for this, generally code will need to be refactored so that +There's no easy fix for this. Generally, code will need to be refactored so that you no longer need to derive from `Super`. diff --git a/compiler/rustc_error_codes/src/error_codes/E0107.md b/compiler/rustc_error_codes/src/error_codes/E0107.md index 4d22b17fe1016..4e37695a52964 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0107.md +++ b/compiler/rustc_error_codes/src/error_codes/E0107.md @@ -1,4 +1,4 @@ -An incorrect number of generic arguments were provided. +An incorrect number of generic arguments was provided. Erroneous code example: diff --git a/compiler/rustc_error_codes/src/error_codes/E0116.md b/compiler/rustc_error_codes/src/error_codes/E0116.md index ca849c2a128f4..653be60298977 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0116.md +++ b/compiler/rustc_error_codes/src/error_codes/E0116.md @@ -10,7 +10,7 @@ You can only define an inherent implementation for a type in the same crate where the type was defined. For example, an `impl` block as above is not allowed since `Vec` is defined in the standard library. -To fix this problem, you can do either of these things: +To fix this problem, you can either: - define a trait that has the desired associated functions/types/constants and implement the trait for the type in question diff --git a/compiler/rustc_error_codes/src/error_codes/E0277.md b/compiler/rustc_error_codes/src/error_codes/E0277.md index 2e2cd5e01fb6a..9f6db6ed7a225 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0277.md +++ b/compiler/rustc_error_codes/src/error_codes/E0277.md @@ -59,9 +59,9 @@ fn main() { } ``` -Note that the error here is in the definition of the generic function: Although +Note that the error here is in the definition of the generic function. Although we only call it with a parameter that does implement `Debug`, the compiler -still rejects the function: It must work with all possible input types. In +still rejects the function. It must work with all possible input types. In order to make this example compile, we need to restrict the generic type we're accepting: diff --git a/compiler/rustc_error_codes/src/error_codes/E0309.md b/compiler/rustc_error_codes/src/error_codes/E0309.md index e719ee590aba6..c36a56b00ce72 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0309.md +++ b/compiler/rustc_error_codes/src/error_codes/E0309.md @@ -25,7 +25,7 @@ where The type definition contains some field whose type requires an outlives annotation. Outlives annotations (e.g., `T: 'a`) are used to guarantee that all -the data in T is valid for at least the lifetime `'a`. This scenario most +the data in `T` is valid for at least the lifetime `'a`. This scenario most commonly arises when the type contains an associated type reference like `>::Output`, as shown in the previous code. diff --git a/compiler/rustc_error_codes/src/error_codes/E0597.md b/compiler/rustc_error_codes/src/error_codes/E0597.md index 3340768fa828a..f6e0b62e1b622 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0597.md +++ b/compiler/rustc_error_codes/src/error_codes/E0597.md @@ -1,4 +1,4 @@ -This error occurs because a value was dropped while it was still borrowed +This error occurs because a value was dropped while it was still borrowed. Erroneous code example: @@ -15,7 +15,7 @@ let mut x = Foo { x: None }; println!("{:?}", x.x); ``` -In here, `y` is dropped at the end of the inner scope, but it is borrowed by +Here, `y` is dropped at the end of the inner scope, but it is borrowed by `x` until the `println`. To fix the previous example, just remove the scope so that `y` isn't dropped until after the println diff --git a/compiler/rustc_error_codes/src/error_codes/E0658.md b/compiler/rustc_error_codes/src/error_codes/E0658.md index d821b9027f136..24245a38ae07f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0658.md +++ b/compiler/rustc_error_codes/src/error_codes/E0658.md @@ -11,7 +11,7 @@ enum Foo { If you're using a stable or a beta version of rustc, you won't be able to use any unstable features. In order to do so, please switch to a nightly version of -rustc (by using rustup). +rustc (by using [rustup]). If you're using a nightly version of rustc, just add the corresponding feature to be able to use it: @@ -24,3 +24,5 @@ enum Foo { Bar(u64), } ``` + +[rustup]: https://rust-lang.github.io/rustup/concepts/channels.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0754.md b/compiler/rustc_error_codes/src/error_codes/E0754.md index 57620bcd65c18..9f4b19cfda6b4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0754.md +++ b/compiler/rustc_error_codes/src/error_codes/E0754.md @@ -1,4 +1,4 @@ -An non-ascii identifier was used in an invalid context. +A non-ASCII identifier was used in an invalid context. Erroneous code examples: @@ -13,7 +13,7 @@ fn řųśť() {} // error! fn main() {} ``` -Non-ascii can be used as module names if it is inlined or if a `#[path]` +Non-ASCII can be used as module names if it is inlined or if a `#[path]` attribute is specified. For example: ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0759.md b/compiler/rustc_error_codes/src/error_codes/E0759.md index 6d525310f75c3..2fe5ada257fc2 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0759.md +++ b/compiler/rustc_error_codes/src/error_codes/E0759.md @@ -27,7 +27,7 @@ fn bar(x: &i32) -> Box { // ok! } ``` -Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit +Both [`dyn Trait`] and [`impl Trait`] in return types have an implicit `'static` requirement, meaning that the value implementing them that is being returned has to be either a `'static` borrow or an owned value. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index cd3c8fded633f..e12b533b110d2 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -485,9 +485,6 @@ declare_features! ( /// Allows `async || body` closures. (active, async_closure, "1.37.0", Some(62290), None), - /// Allows `[x; N]` where `x` is a constant (RFC 2203). - (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), - /// Allows `impl Trait` to be used inside type aliases (RFC 2515). (active, type_alias_impl_trait, "1.38.0", Some(63063), None), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 07bd1602cda32..38a3a4e3d4411 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -97,6 +97,9 @@ declare_features! ( (removed, extern_in_paths, "1.33.0", Some(55600), None, Some("subsumed by `::foo::bar` paths")), (removed, quote, "1.33.0", Some(29601), None, None), + /// Allows `[x; N]` where `x` is a constant (RFC 2203). + (removed, const_in_array_repeat_expressions, "1.37.0", Some(49147), None, + Some("removed due to causing promotable bugs")), /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), (removed, await_macro, "1.38.0", Some(50547), None, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index c1a3eecbbc7ef..b611aebad01b0 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -977,8 +977,6 @@ impl UnusedDelimLint for UnusedBraces { } } ast::ExprKind::Let(_, ref expr) => { - // FIXME(#60336): Properly handle `let true = (false && true)` - // actually needing the parenthesis. self.check_unused_delims_expr( cx, expr, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 0a663f793aa75..163b400973b7c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -228,8 +228,7 @@ pub enum ObligationCauseCode<'tcx> { /// Inline asm operand type must be `Sized`. InlineAsmSized, /// `[T, ..n]` implies that `T` must be `Copy`. - /// If `true`, suggest `const_in_array_repeat_expressions` feature flag. - RepeatVec(bool), + RepeatVec, /// Types of fields (other than the last, except for packed structs) in a struct must be sized. FieldSized { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8e8caa46c3802..babab005edb2b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -661,11 +661,28 @@ pub type RootVariableMinCaptureList<'tcx> = FxIndexMap = Vec>; -/// A `Place` and the corresponding `CaptureInfo`. +/// A composite describing a `Place` that is captured by a closure. #[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct CapturedPlace<'tcx> { + /// The `Place` that is captured. pub place: HirPlace<'tcx>, + + /// `CaptureKind` and expression(s) that resulted in such capture of `place`. pub info: CaptureInfo<'tcx>, + + /// Represents if `place` can be mutated or not. + pub mutability: hir::Mutability, +} + +impl CapturedPlace<'tcx> { + /// Returns the hir-id of the root variable for the captured place. + /// e.g., if `a.b.c` was captured, would return the hir-id for `a`. + pub fn get_root_variable(&self) -> hir::HirId { + match self.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + base => bug!("Expected upvar, found={:?}", base), + } + } } pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 6d98bf554f1cf..04ea3cbd8b66d 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -215,6 +215,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { local, projection: [proj_base @ .., elem] } => { match elem { ProjectionElem::Deref => { + // FIXME(project-rfc_2229#36): print capture precisely here. let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); @@ -259,6 +260,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ProjectionElem::Field(field, _ty) => { autoderef = true; + // FIXME(project-rfc_2229#36): print capture precisely here. let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index 350e0d045fa35..fb7694b7d88e9 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -345,7 +345,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; let upvar = &self.upvars[upvar_field.unwrap().index()]; - let upvar_hir_id = upvar.var_hir_id; + // FIXME(project-rfc-2229#8): Improve borrow-check diagnostics in case of precise + // capture. + let upvar_hir_id = upvar.place.get_root_variable(); let upvar_name = upvar.name; let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 73196c732f5bb..74abe2d35ee74 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -64,12 +64,29 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty )); - item_msg = format!("`{}`", access_place_desc.unwrap()); - if self.is_upvar_field_projection(access_place.as_ref()).is_some() { - reason = ", as it is not declared as mutable".to_string(); + let imm_borrow_derefed = self.upvars[upvar_index.index()] + .place + .place + .deref_tys() + .any(|ty| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not))); + + // If the place is immutable then: + // + // - Either we deref a immutable ref to get to our final place. + // - We don't capture derefs of raw ptrs + // - Or the final place is immut because the root variable of the capture + // isn't marked mut and we should suggest that to the user. + if imm_borrow_derefed { + // If we deref an immutable ref then the suggestion here doesn't help. + return; } else { - let name = self.upvars[upvar_index.index()].name; - reason = format!(", as `{}` is not declared as mutable", name); + item_msg = format!("`{}`", access_place_desc.unwrap()); + if self.is_upvar_field_projection(access_place.as_ref()).is_some() { + reason = ", as it is not declared as mutable".to_string(); + } else { + let name = self.upvars[upvar_index.index()].name; + reason = format!(", as `{}` is not declared as mutable", name); + } } } @@ -259,9 +276,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty )); + let captured_place = &self.upvars[upvar_index.index()].place; + err.span_label(span, format!("cannot {ACT}", ACT = act)); - let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id; + let upvar_hir_id = captured_place.get_root_variable(); + if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) { if let hir::PatKind::Binding( hir::BindingAnnotation::Unannotated, diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs index a850b85e9bbae..4abc623fc5f37 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs @@ -12,7 +12,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { tcx: TyCtxt<'tcx>, body: &Body<'tcx>, local_names: &IndexVec>, - upvars: &[Upvar], + upvars: &[Upvar<'tcx>], fr: RegionVid, ) -> Option<(Option, Span)> { debug!("get_var_name_and_span_for_region(fr={:?})", fr); @@ -21,6 +21,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("get_var_name_and_span_for_region: attempting upvar"); self.get_upvar_index_for_region(tcx, fr) .map(|index| { + // FIXME(project-rfc-2229#8): Use place span for diagnostics let (name, span) = self.get_upvar_name_and_span_for_region(tcx, upvars, index); (Some(name), span) }) @@ -59,10 +60,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn get_upvar_name_and_span_for_region( &self, tcx: TyCtxt<'tcx>, - upvars: &[Upvar], + upvars: &[Upvar<'tcx>], upvar_index: usize, ) -> (Symbol, Span) { - let upvar_hir_id = upvars[upvar_index].var_hir_id; + let upvar_hir_id = upvars[upvar_index].place.get_root_variable(); debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id); let upvar_name = tcx.hir().name(upvar_hir_id); diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 7c7edfdb5fbaf..5db52db70ac68 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -5,11 +5,10 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{HirId, Node}; +use rustc_hir::Node; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, @@ -18,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT}; use rustc_span::{Span, Symbol, DUMMY_SP}; @@ -73,16 +72,14 @@ crate use region_infer::RegionInferenceContext; // FIXME(eddyb) perhaps move this somewhere more centrally. #[derive(Debug)] -crate struct Upvar { +crate struct Upvar<'tcx> { + // FIXME(project-rfc_2229#36): print capture precisely here. name: Symbol, - // FIXME(project-rfc-2229#8): This should use Place or something similar - var_hir_id: HirId, + place: CapturedPlace<'tcx>, /// If true, the capture is behind a reference. by_ref: bool, - - mutability: Mutability, } const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref]; @@ -161,26 +158,13 @@ fn do_mir_borrowck<'a, 'tcx>( let upvars: Vec<_> = tables .closure_min_captures_flattened(def.did.to_def_id()) .map(|captured_place| { - let var_hir_id = match captured_place.place.base { - HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, - _ => bug!("Expected upvar"), - }; + let var_hir_id = captured_place.get_root_variable(); let capture = captured_place.info.capture_kind; let by_ref = match capture { ty::UpvarCapture::ByValue(_) => false, ty::UpvarCapture::ByRef(..) => true, }; - let mut upvar = Upvar { - name: tcx.hir().name(var_hir_id), - var_hir_id, - by_ref, - mutability: Mutability::Not, - }; - let bm = *tables.pat_binding_modes().get(var_hir_id).expect("missing binding mode"); - if bm == ty::BindByValue(hir::Mutability::Mut) { - upvar.mutability = Mutability::Mut; - } - upvar + Upvar { name: tcx.hir().name(var_hir_id), place: captured_place.clone(), by_ref } }) .collect(); @@ -549,7 +533,7 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { dominators: Dominators, /// Information about upvars not necessarily preserved in types or MIR - upvars: Vec, + upvars: Vec>, /// Names of local (user) variables (extracted from `var_debug_info`). local_names: IndexVec>, @@ -1374,13 +1358,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| { - if !place.projection.is_empty() { - if let Some(field) = this.is_upvar_field_projection(place.as_ref()) { + // We have three possibilities here: + // a. We are modifying something through a mut-ref + // b. We are modifying something that is local to our parent + // c. Current body is a nested closure, and we are modifying path starting from + // a Place captured by our parent closure. + + // Handle (c), the path being modified is exactly the path captured by our parent + if let Some(field) = this.is_upvar_field_projection(place.as_ref()) { + this.used_mut_upvars.push(field); + return; + } + + for (place_ref, proj) in place.iter_projections().rev() { + // Handle (a) + if proj == ProjectionElem::Deref { + match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() { + // We aren't modifying a variable directly + ty::Ref(_, _, hir::Mutability::Mut) => return, + + _ => {} + } + } + + // Handle (c) + if let Some(field) = this.is_upvar_field_projection(place_ref) { this.used_mut_upvars.push(field); + return; } - } else { - this.used_mut.insert(place.local); } + + // Handle(b) + this.used_mut.insert(place.local); }; // This relies on the current way that by-value @@ -2146,6 +2155,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place: PlaceRef<'tcx>, is_local_mutation_allowed: LocalMutationIsAllowed, ) -> Result, PlaceRef<'tcx>> { + debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed); match place.last_projection() { None => { let local = &self.body.local_decls[place.local]; @@ -2227,11 +2237,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some(field) = upvar_field_projection { let upvar = &self.upvars[field.index()]; debug!( - "upvar.mutability={:?} local_mutation_is_allowed={:?} \ - place={:?}", - upvar, is_local_mutation_allowed, place + "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \ + place={:?}, place_base={:?}", + upvar, is_local_mutation_allowed, place, place_base ); - match (upvar.mutability, is_local_mutation_allowed) { + match (upvar.place.mutability, is_local_mutation_allowed) { ( Mutability::Not, LocalMutationIsAllowed::No diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs index 359c5f261a434..a0265b20d127b 100644 --- a/compiler/rustc_mir/src/borrow_check/nll.rs +++ b/compiler/rustc_mir/src/borrow_check/nll.rs @@ -165,7 +165,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, - upvars: &[Upvar], + upvars: &[Upvar<'tcx>], ) -> NllOutput<'tcx> { let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default()); diff --git a/compiler/rustc_mir/src/borrow_check/path_utils.rs b/compiler/rustc_mir/src/borrow_check/path_utils.rs index fa3ae2367e08e..80de3b4e363bf 100644 --- a/compiler/rustc_mir/src/borrow_check/path_utils.rs +++ b/compiler/rustc_mir/src/borrow_check/path_utils.rs @@ -143,7 +143,7 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool { /// of a closure type. pub(crate) fn is_upvar_field_projection( tcx: TyCtxt<'tcx>, - upvars: &[Upvar], + upvars: &[Upvar<'tcx>], place_ref: PlaceRef<'tcx>, body: &Body<'tcx>, ) -> Option { diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index fb9820e853f8f..e689964b99858 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -43,10 +43,6 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations} use crate::dataflow::impls::MaybeInitializedPlaces; use crate::dataflow::move_paths::MoveData; use crate::dataflow::ResultsCursor; -use crate::transform::{ - check_consts::ConstCx, - promote_consts::should_suggest_const_in_array_repeat_expressions_attribute, -}; use crate::borrow_check::{ borrow_set::BorrowSet, @@ -132,7 +128,7 @@ pub(crate) fn type_check<'mir, 'tcx>( flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, elements: &Rc, - upvars: &[Upvar], + upvars: &[Upvar<'tcx>], ) -> MirTypeckResults<'tcx> { let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); let mut constraints = MirTypeckRegionConstraints { @@ -821,7 +817,7 @@ struct BorrowCheckContext<'a, 'tcx> { all_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - upvars: &'a [Upvar], + upvars: &'a [Upvar<'tcx>], } crate struct MirTypeckResults<'tcx> { @@ -1997,22 +1993,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let span = body.source_info(location).span; let ty = operand.ty(body, tcx); if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { - let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); - // To determine if `const_in_array_repeat_expressions` feature gate should - // be mentioned, need to check if the rvalue is promotable. - let should_suggest = - should_suggest_const_in_array_repeat_expressions_attribute( - &ccx, operand, - ); - debug!("check_rvalue: should_suggest={:?}", should_suggest); - let def_id = body.source.def_id().expect_local(); self.infcx.report_selection_error( &traits::Obligation::new( ObligationCause::new( span, self.tcx().hir().local_def_id_to_hir_id(def_id), - traits::ObligationCauseCode::RepeatVec(should_suggest), + traits::ObligationCauseCode::RepeatVec, ), self.param_env, ty::Binder::bind(ty::TraitRef::new( @@ -2490,7 +2477,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { body, ); let category = if let Some(field) = field { - ConstraintCategory::ClosureUpvar(self.borrowck_context.upvars[field.index()].var_hir_id) + let var_hir_id = self.borrowck_context.upvars[field.index()].place.get_root_variable(); + // FIXME(project-rfc-2229#8): Use Place for better diagnostics + ConstraintCategory::ClosureUpvar(var_hir_id) } else { ConstraintCategory::Boring }; diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index d8758e045443c..b4504a0e223f6 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -102,9 +102,6 @@ pub enum Candidate { /// Borrow of a constant temporary, candidate for lifetime extension. Ref(Location), - /// Promotion of the `x` in `[x; 32]`. - Repeat(Location), - /// Currently applied to function calls where the callee has the unstable /// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle /// intrinsic. The intrinsic requires the arguments are indeed constant and @@ -120,14 +117,14 @@ impl Candidate { /// Returns `true` if we should use the "explicit" rules for promotability for this `Candidate`. fn forces_explicit_promotion(&self) -> bool { match self { - Candidate::Ref(_) | Candidate::Repeat(_) => false, + Candidate::Ref(_) => false, Candidate::Argument { .. } | Candidate::InlineAsm { .. } => true, } } fn source_info(&self, body: &Body<'_>) -> SourceInfo { match self { - Candidate::Ref(location) | Candidate::Repeat(location) => *body.source_info(*location), + Candidate::Ref(location) => *body.source_info(*location), Candidate::Argument { bb, .. } | Candidate::InlineAsm { bb, .. } => { *body.source_info(body.terminator_loc(*bb)) } @@ -213,11 +210,6 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { Rvalue::Ref(..) => { self.candidates.push(Candidate::Ref(location)); } - Rvalue::Repeat(..) if self.ccx.tcx.features().const_in_array_repeat_expressions => { - // FIXME(#49147) only promote the element when it isn't `Copy` - // (so that code that can copy it at runtime is unaffected). - self.candidates.push(Candidate::Repeat(location)); - } _ => {} } } @@ -334,21 +326,6 @@ impl<'tcx> Validator<'_, 'tcx> { _ => bug!(), } } - Candidate::Repeat(loc) => { - assert!(!self.explicit); - - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, Rvalue::Repeat(ref operand, _))) => { - if !self.tcx.features().const_in_array_repeat_expressions { - return Err(Unpromotable); - } - - self.validate_operand(operand) - } - _ => bug!(), - } - } Candidate::Argument { bb, index } => { assert!(self.explicit); @@ -1090,18 +1067,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { _ => bug!(), } } - Candidate::Repeat(loc) => { - let statement = &mut blocks[loc.block].statements[loc.statement_index]; - match statement.kind { - StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => { - let ty = operand.ty(local_decls, self.tcx); - let span = statement.source_info.span; - - Rvalue::Use(mem::replace(operand, promoted_operand(ty, span))) - } - _ => bug!(), - } - } Candidate::Argument { bb, index } => { let terminator = blocks[bb].terminator_mut(); match terminator.kind { @@ -1182,8 +1147,7 @@ pub fn promote_candidates<'tcx>( let mut extra_statements = vec![]; for candidate in candidates.into_iter().rev() { match candidate { - Candidate::Repeat(Location { block, statement_index }) - | Candidate::Ref(Location { block, statement_index }) => { + Candidate::Ref(Location { block, statement_index }) => { if let StatementKind::Assign(box (place, _)) = &body[block].statements[statement_index].kind { @@ -1267,27 +1231,3 @@ pub fn promote_candidates<'tcx>( promotions } - -/// This function returns `true` if the `const_in_array_repeat_expressions` feature attribute should -/// be suggested. This function is probably quite expensive, it shouldn't be run in the happy path. -/// Feature attribute should be suggested if `operand` can be promoted and the feature is not -/// enabled. -crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>( - ccx: &ConstCx<'_, 'tcx>, - operand: &Operand<'tcx>, -) -> bool { - let mut rpo = traversal::reverse_postorder(&ccx.body); - let (temps, _) = collect_temps_and_candidates(&ccx, &mut rpo); - let validator = Validator { ccx, temps: &temps, explicit: false }; - - let should_promote = validator.validate_operand(operand).is_ok(); - let feature_flag = validator.ccx.tcx.features().const_in_array_repeat_expressions; - debug!( - "should_suggest_const_in_array_repeat_expressions_flag: def_id={:?} \ - should_promote={:?} feature_flag={:?}", - validator.ccx.def_id(), - should_promote, - feature_flag - ); - should_promote && !feature_flag -} diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 996615995259d..e4891eb5a3c0c 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -851,22 +851,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => bug!("Expected an upvar") }; - let mut mutability = Mutability::Not; + let mutability = captured_place.mutability; // FIXME(project-rfc-2229#8): Store more precise information let mut name = kw::Empty; if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { name = ident.name; - match hir_typeck_results - .extract_binding_mode(tcx.sess, pat.hir_id, pat.span) - { - Some(ty::BindByValue(hir::Mutability::Mut)) => { - mutability = Mutability::Mut; - } - Some(_) => mutability = Mutability::Not, - _ => {} - } } } diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 53c3adcc20c02..ea04e7bb44b3b 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -17,7 +17,6 @@ Core encoding and decoding interfaces. #![feature(min_specialization)] #![feature(vec_spare_capacity)] #![feature(core_intrinsics)] -#![feature(int_bits_const)] #![feature(maybe_uninit_slice)] #![feature(new_uninit)] #![cfg_attr(test, feature(test))] diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs index a2bcf2c251d7a..3e2aab5125ab7 100644 --- a/compiler/rustc_serialize/tests/leb128.rs +++ b/compiler/rustc_serialize/tests/leb128.rs @@ -1,4 +1,3 @@ -#![feature(int_bits_const)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] diff --git a/compiler/rustc_target/src/spec/wasm32_base.rs b/compiler/rustc_target/src/spec/wasm32_base.rs index a7957d84cbeef..bfef3d37228f0 100644 --- a/compiler/rustc_target/src/spec/wasm32_base.rs +++ b/compiler/rustc_target/src/spec/wasm32_base.rs @@ -55,15 +55,6 @@ pub fn options() -> TargetOptions { // to do so. arg("--no-demangle"); - // The symbol visibility story is a bit in flux right now with LLD. - // It's... not entirely clear to me what's going on, but this looks to - // make everything work when `export_symbols` isn't otherwise called for - // things like executables. - // - // This is really only here to get things working. If it can be removed and - // basic tests still work, then sounds like it should be removed! - arg("--export-dynamic"); - let mut pre_link_args = BTreeMap::new(); pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args); pre_link_args.insert(LinkerFlavor::Gcc, clang_args); diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index c12757b8f9812..9f69ce16c215d 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -2,6 +2,17 @@ use super::wasm32_base; use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Target { + let mut options = wasm32_base::options(); + + let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + + // Rust really needs a way for users to specify exports and imports in + // the source code. --export-dynamic isn't the right tool for this job, + // however it does have the side effect of automatically exporting a lot + // of symbols, which approximates what people want when compiling for + // wasm32-unknown-unknown expect, so use it for now. + clang_args.push("--export-dynamic".to_string()); + let mut post_link_args = LinkArgs::new(); post_link_args.insert( LinkerFlavor::Em, @@ -28,7 +39,7 @@ pub fn target() -> Target { panic_strategy: PanicStrategy::Unwind, post_link_args, os_family: Some("unix".to_string()), - ..wasm32_base::options() + ..options }; Target { llvm_target: "wasm32-unknown-emscripten".to_string(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index 6037aa5b4306e..5e89ba2520bdd 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -26,11 +26,18 @@ pub fn target() -> Target { // For now this target just never has an entry symbol no matter the output // type, so unconditionally pass this. clang_args.push("-Wl,--no-entry".to_string()); - options - .pre_link_args - .get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)) - .unwrap() - .push("--no-entry".to_string()); + + // Rust really needs a way for users to specify exports and imports in + // the source code. --export-dynamic isn't the right tool for this job, + // however it does have the side effect of automatically exporting a lot + // of symbols, which approximates what people want when compiling for + // wasm32-unknown-unknown expect, so use it for now. + clang_args.push("-Wl,--export-dynamic".to_string()); + + // Add the flags to wasm-ld's args too. + let lld_args = options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)).unwrap(); + lld_args.push("--no-entry".to_string()); + lld_args.push("--export-dynamic".to_string()); Target { llvm_target: "wasm32-unknown-unknown".to_string(), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 0724a9290e91c..690591930deb9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1881,23 +1881,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ObligationCauseCode::Coercion { source: _, target } => { err.note(&format!("required by cast to type `{}`", self.ty_to_string(target))); } - ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => { + ObligationCauseCode::RepeatVec => { err.note( "the `Copy` trait is required because the repeated element will be copied", ); - if suggest_const_in_array_repeat_expressions { - err.note( - "this array initializer can be evaluated at compile-time, see issue \ - #49147 \ - for more information", - ); - if tcx.sess.opts.unstable_features.is_nightly_build() { - err.help( - "add `#![feature(const_in_array_repeat_expressions)]` to the \ - crate attributes to enable", - ); - } - } } ObligationCauseCode::VariableType(hir_id) => { let parent_node = self.tcx.hir().get_parent_node(hir_id); diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e37b4ff742bc6..04c83a7665caa 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -36,6 +36,7 @@ use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::Ty; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{AdtKind, Visibility}; @@ -46,8 +47,6 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_trait_selection::traits::{self, ObligationCauseCode}; -use std::fmt::Display; - impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_eq_type(&self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>) { let ty = self.check_expr_with_hint(expr, expected); @@ -1585,11 +1584,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, field: Ident, ) -> Ty<'tcx> { + debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field); let expr_t = self.check_expr(base); let expr_t = self.structurally_resolved_type(base.span, expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, _)) = autoderef.next() { + debug!("base_t: {:?}", base_t); match base_t.kind() { ty::Adt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", base_t); @@ -1706,7 +1707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}", field, base, expr, expr_t ); - let mut err = self.no_such_field_err(field.span, field, expr_t); + let mut err = self.no_such_field_err(field, expr_t); match *expr_t.peel_refs().kind() { ty::Array(_, len) => { @@ -1880,21 +1881,120 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn no_such_field_err( + fn no_such_field_err( &self, - span: Span, - field: T, - expr_t: &ty::TyS<'_>, + field: Ident, + expr_t: &'tcx ty::TyS<'tcx>, ) -> DiagnosticBuilder<'_> { - type_error_struct!( + let span = field.span; + debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t); + + let mut err = type_error_struct!( self.tcx().sess, - span, + field.span, expr_t, E0609, "no field `{}` on type `{}`", field, expr_t - ) + ); + + // try to add a suggestion in case the field is a nested field of a field of the Adt + if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) { + for candidate_field in fields.iter() { + if let Some(field_path) = + self.check_for_nested_field(span, field, candidate_field, substs, vec![]) + { + let field_path_str = field_path + .iter() + .map(|id| id.name.to_ident_string()) + .collect::>() + .join("."); + debug!("field_path_str: {:?}", field_path_str); + + err.span_suggestion_verbose( + field.span.shrink_to_lo(), + "one of the expressions' fields has a field of the same name", + format!("{}.", field_path_str), + Applicability::MaybeIncorrect, + ); + } + } + } + err + } + + fn get_field_candidates( + &self, + span: Span, + base_t: Ty<'tcx>, + ) -> Option<(&Vec, SubstsRef<'tcx>)> { + debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t); + + let mut autoderef = self.autoderef(span, base_t); + while let Some((base_t, _)) = autoderef.next() { + match base_t.kind() { + ty::Adt(base_def, substs) if !base_def.is_enum() => { + let fields = &base_def.non_enum_variant().fields; + // For compile-time reasons put a limit on number of fields we search + if fields.len() > 100 { + return None; + } + return Some((fields, substs)); + } + _ => {} + } + } + None + } + + /// This method is called after we have encountered a missing field error to recursively + /// search for the field + fn check_for_nested_field( + &self, + span: Span, + target_field: Ident, + candidate_field: &ty::FieldDef, + subst: SubstsRef<'tcx>, + mut field_path: Vec, + ) -> Option> { + debug!( + "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}", + span, candidate_field, field_path + ); + + if candidate_field.ident == target_field { + Some(field_path) + } else if field_path.len() > 3 { + // For compile-time reasons and to avoid infinite recursion we only check for fields + // up to a depth of three + None + } else { + // recursively search fields of `candidate_field` if it's a ty::Adt + + field_path.push(candidate_field.ident.normalize_to_macros_2_0()); + let field_ty = candidate_field.ty(self.tcx, subst); + if let Some((nested_fields, _)) = self.get_field_candidates(span, &field_ty) { + for field in nested_fields.iter() { + let ident = field.ident.normalize_to_macros_2_0(); + if ident == target_field { + return Some(field_path); + } else { + let field_path = field_path.clone(); + if let Some(path) = self.check_for_nested_field( + span, + target_field, + field, + subst, + field_path, + ) { + return Some(path); + } + } + } + } + None + } } fn check_expr_index( diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 6b2cba62fa6b7..f039445bf7780 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -184,10 +184,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let origin = if self.tcx.features().capture_disjoint_fields { origin } else { - // FIXME(project-rfc-2229#26): Once rust-lang#80092 is merged, we should restrict the - // precision of origin as well. Otherwise, this will cause issues when project-rfc-2229#26 - // is fixed as we might see Index projections in the origin, which we can't print because - // we don't store enough information. + // FIXME(project-rfc-2229#31): Once the changes to support reborrowing are + // made, make sure we are selecting and restricting + // the origin correctly. (origin.0, Place { projections: vec![], ..origin.1 }) }; @@ -252,8 +251,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let capture = captured_place.info.capture_kind; debug!( - "place={:?} upvar_ty={:?} capture={:?}", - captured_place.place, upvar_ty, capture + "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}", + captured_place.place, upvar_ty, capture, captured_place.mutability, ); match capture { @@ -419,19 +418,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base => bug!("Expected upvar, found={:?}", base), }; - // Arrays are captured in entirety, drop Index projections and projections - // after Index projections. - let first_index_projection = - place.projections.split(|proj| ProjectionKind::Index == proj.kind).next(); - let place = Place { - base_ty: place.base_ty, - base: place.base, - projections: first_index_projection.map_or(Vec::new(), |p| p.to_vec()), - }; + let place = restrict_capture_precision(place, capture_info.capture_kind); let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) { None => { - let min_cap_list = vec![ty::CapturedPlace { place, info: capture_info }]; + let mutability = self.determine_capture_mutability(&place); + let min_cap_list = + vec![ty::CapturedPlace { place, info: capture_info, mutability }]; root_var_min_capture_list.insert(var_hir_id, min_cap_list); continue; } @@ -494,8 +487,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only need to insert when we don't have an ancestor in the existing min capture list if !ancestor_found { + let mutability = self.determine_capture_mutability(&place); let captured_place = - ty::CapturedPlace { place: place.clone(), info: updated_capture_info }; + ty::CapturedPlace { place, info: updated_capture_info, mutability }; min_cap_list.push(captured_place); } } @@ -615,6 +609,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + + /// A captured place is mutable if + /// 1. Projections don't include a Deref of an immut-borrow, **and** + /// 2. PlaceBase is mut or projections include a Deref of a mut-borrow. + fn determine_capture_mutability(&self, place: &Place<'tcx>) -> hir::Mutability { + let var_hir_id = match place.base { + PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => unreachable!(), + }; + + let bm = *self + .typeck_results + .borrow() + .pat_binding_modes() + .get(var_hir_id) + .expect("missing binding mode"); + + let mut is_mutbl = match bm { + ty::BindByValue(mutability) => mutability, + ty::BindByReference(_) => hir::Mutability::Not, + }; + + for pointer_ty in place.deref_tys() { + match pointer_ty.kind() { + // We don't capture derefs of raw ptrs + ty::RawPtr(_) => unreachable!(), + + // Derefencing a mut-ref allows us to mut the Place if we don't deref + // an immut-ref after on top of this. + ty::Ref(.., hir::Mutability::Mut) => is_mutbl = hir::Mutability::Mut, + + // The place isn't mutable once we dereference a immutable reference. + ty::Ref(.., hir::Mutability::Not) => return hir::Mutability::Not, + + // Dereferencing a box doesn't change mutability + ty::Adt(def, ..) if def.is_box() => {} + + unexpected_ty => bug!("deref of unexpected pointer type {:?}", unexpected_ty), + } + } + + is_mutbl + } } struct InferBorrowKind<'a, 'tcx> { @@ -960,6 +997,66 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { } } +/// Truncate projections so that following rules are obeyed by the captured `place`: +/// +/// - No Derefs in move closure, this will result in value behind a reference getting moved. +/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture +/// them completely. +/// - No Index projections are captured, since arrays are captured completely. +fn restrict_capture_precision<'tcx>( + mut place: Place<'tcx>, + capture_kind: ty::UpvarCapture<'tcx>, +) -> Place<'tcx> { + if place.projections.is_empty() { + // Nothing to do here + return place; + } + + if place.base_ty.is_unsafe_ptr() { + place.projections.truncate(0); + return place; + } + + let mut truncated_length = usize::MAX; + let mut first_deref_projection = usize::MAX; + + for (i, proj) in place.projections.iter().enumerate() { + if proj.ty.is_unsafe_ptr() { + // Don't apply any projections on top of an unsafe ptr + truncated_length = truncated_length.min(i + 1); + break; + } + match proj.kind { + ProjectionKind::Index => { + // Arrays are completely captured, so we drop Index projections + truncated_length = truncated_length.min(i); + break; + } + ProjectionKind::Deref => { + // We only drop Derefs in case of move closures + // There might be an index projection or raw ptr ahead, so we don't stop here. + first_deref_projection = first_deref_projection.min(i); + } + ProjectionKind::Field(..) => {} // ignore + ProjectionKind::Subslice => {} // We never capture this + } + } + + let length = place + .projections + .len() + .min(truncated_length) + // In case of capture `ByValue` we want to not capture derefs + .min(match capture_kind { + ty::UpvarCapture::ByValue(..) => first_deref_projection, + ty::UpvarCapture::ByRef(..) => usize::MAX, + }); + + place.projections.truncate(length); + + place +} + fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String { let variable_name = match place.base { PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(), diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 13f4d902d3b2a..785ce8d606b67 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -89,7 +89,6 @@ #![feature(coerce_unsized)] #![feature(const_btree_new)] #![feature(const_fn)] -#![feature(const_in_array_repeat_expressions)] #![feature(cow_is_borrowed)] #![feature(const_cow_is_borrowed)] #![feature(dispatch_from_dyn)] @@ -102,7 +101,6 @@ #![feature(fn_traits)] #![feature(fundamental)] #![feature(inplace_iteration)] -#![feature(int_bits_const)] #![feature(lang_items)] #![feature(layout_for_ptr)] #![feature(maybe_uninit_ref)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9b0b480a7e925..3218b3535c970 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -972,7 +972,7 @@ impl String { self.vec.try_reserve(additional) } - /// Tries to reserves the minimum capacity for exactly `additional` more elements to + /// Tries to reserve the minimum capacity for exactly `additional` more elements to /// be inserted in the given `String`. After calling `reserve_exact`, /// capacity will be greater than or equal to `self.len() + additional`. /// Does nothing if the capacity is already sufficient. diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 0b7eeab4e9679..7b00354629875 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -17,7 +17,6 @@ #![feature(binary_heap_retain)] #![feature(inplace_iteration)] #![feature(iter_map_while)] -#![feature(int_bits_const)] #![feature(vecdeque_binary_search)] #![feature(slice_group_by)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 8fdd7c9e5d7fb..96affd17cc520 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -32,10 +32,9 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(int_bits_const)] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")] /// ``` - #[unstable(feature = "int_bits_const", issue = "76904")] + #[stable(feature = "int_bits_const", since = "1.51.0")] pub const BITS: u32 = $BITS; /// Converts a string slice in a given base to an integer. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 9fccf3f72ce1a..aee424b9b1392 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -32,10 +32,9 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(int_bits_const)] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")] /// ``` - #[unstable(feature = "int_bits_const", issue = "76904")] + #[stable(feature = "int_bits_const", since = "1.51.0")] pub const BITS: u32 = $BITS; /// Converts a string slice in a given base to an integer. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index bc0e3e059c917..26dbcb8569b43 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -70,7 +70,6 @@ #![feature(partition_point)] #![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] -#![feature(int_bits_const)] #![feature(nonzero_leading_trailing_zeros)] #![feature(const_option)] #![feature(integer_atomics)] diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 9ce9c477ec0f0..99a0c67fc11b9 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -18,7 +18,6 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/" )] #![feature(core_intrinsics)] -#![feature(int_bits_const)] #![feature(lang_items)] #![feature(nll)] #![feature(panic_unwind)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 84449e4876718..a8a4127d40a5e 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1217,8 +1217,8 @@ impl Ipv6Addr { /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`). /// - /// A common mis-conception is to think that "unicast link-local addresses start with - /// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses: + /// A common misconception is to think that "unicast link-local addresses start with + /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses: /// /// ```no_rust /// | 10 | @@ -1228,9 +1228,9 @@ impl Ipv6Addr { /// +----------+-------------------------+----------------------------+ /// ``` /// - /// This method validates the format defined in the RFC and won't recognize the following - /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. - /// If you need a less strict validation use [`Ipv6Addr::is_unicast_link_local()`] instead. + /// This method validates the format defined in the RFC and won't recognize addresses + /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses. + /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead. /// /// # Examples /// @@ -1282,7 +1282,7 @@ impl Ipv6Addr { /// +----------+-------------------------+----------------------------+ /// ``` /// - /// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be + /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not. /// If you need a strict validation fully compliant with the RFC, use /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead. @@ -1362,7 +1362,7 @@ impl Ipv6Addr { } /// Returns [`true`] if this is an address reserved for documentation - /// (2001:db8::/32). + /// (`2001:db8::/32`). /// /// This property is defined in [IETF RFC 3849]. /// diff --git a/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md b/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md deleted file mode 100644 index 940916944bdaa..0000000000000 --- a/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md +++ /dev/null @@ -1,11 +0,0 @@ -# `const_in_array_repeat_expressions` - -The tracking issue for this feature is: [#49147] - -[#49147]: https://github.com/rust-lang/rust/issues/49147 - ------------------------- - -Relaxes the rules for repeat expressions, `[x; N]` such that `x` may also be `const` (strictly -speaking rvalue promotable), in addition to `typeof(x): Copy`. The result of `[x; N]` where `x` is -`const` is itself also `const`. diff --git a/src/test/ui/array-slice-vec/repeat_empty_ok.rs b/src/test/ui/array-slice-vec/repeat_empty_ok.rs new file mode 100644 index 0000000000000..25463ea5ee841 --- /dev/null +++ b/src/test/ui/array-slice-vec/repeat_empty_ok.rs @@ -0,0 +1,15 @@ +#![crate_type = "lib"] + +pub struct Header<'a> { + pub value: &'a [u8], +} + +pub fn test() { + let headers = [Header{value: &[]}; 128]; + //~^ ERROR the trait bound +} + +pub fn test2() { + let headers = [Header{value: &[0]}; 128]; + //~^ ERROR the trait bound +} diff --git a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr new file mode 100644 index 0000000000000..85baa1268bf04 --- /dev/null +++ b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied + --> $DIR/repeat_empty_ok.rs:8:19 + | +LL | let headers = [Header{value: &[]}; 128]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` + | + = note: the `Copy` trait is required because the repeated element will be copied + +error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied + --> $DIR/repeat_empty_ok.rs:13:19 + | +LL | let headers = [Header{value: &[0]}; 128]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` + | + = note: the `Copy` trait is required because the repeated element will be copied + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/closures/2229_closure_analysis/by_value.rs b/src/test/ui/closures/2229_closure_analysis/by_value.rs new file mode 100644 index 0000000000000..1007fb582e5ed --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/by_value.rs @@ -0,0 +1,41 @@ +// Test that we handle derferences properly when only some of the captures are being moved with +// `capture_disjoint_fields` enabled. + + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![feature(rustc_attrs)] + +#[derive(Debug, Default)] +struct SomeLargeType; +struct MuchLargerType([SomeLargeType; 32]); + +// Ensure that we don't capture any derefs when moving captures into the closures, +// i.e. only data from the enclosing stack is moved. +fn big_box() { + let s = MuchLargerType(Default::default()); + let b = Box::new(s); + let t = (b, 10); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ First Pass analysis includes: + //~| Min Capture analysis includes: + let p = t.0.0; + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue + //~| NOTE: Min Capture t[(0, 0)] -> ByValue + println!("{} {:?}", t.1, p); + //~^ NOTE: Capturing t[(1, 0)] -> ImmBorrow + //~| NOTE: Min Capture t[(1, 0)] -> ImmBorrow + }; + + c(); +} + +fn main() { + big_box(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/by_value.stderr b/src/test/ui/closures/2229_closure_analysis/by_value.stderr new file mode 100644 index 0000000000000..fe04dbef6d8b5 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/by_value.stderr @@ -0,0 +1,67 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/by_value.rs:22:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/by_value.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: First Pass analysis includes: + --> $DIR/by_value.rs:25:5 + | +LL | / || { +LL | | +LL | | +LL | | let p = t.0.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue + --> $DIR/by_value.rs:28:17 + | +LL | let p = t.0.0; + | ^^^^^ +note: Capturing t[(1, 0)] -> ImmBorrow + --> $DIR/by_value.rs:31:29 + | +LL | println!("{} {:?}", t.1, p); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/by_value.rs:25:5 + | +LL | / || { +LL | | +LL | | +LL | | let p = t.0.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0)] -> ByValue + --> $DIR/by_value.rs:28:17 + | +LL | let p = t.0.0; + | ^^^^^ +note: Min Capture t[(1, 0)] -> ImmBorrow + --> $DIR/by_value.rs:31:29 + | +LL | println!("{} {:?}", t.1, p); + | ^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs new file mode 100644 index 0000000000000..1ea38e260b645 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs @@ -0,0 +1,20 @@ +// Test that if we deref an immutable borrow to access a Place, +// then we can't mutate the final place. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +fn main() { + let mut x = (format!(""), format!("X2")); + let mut y = (&x, "Y"); + let z = (&mut y, "Z"); + + // `x.0` is mutable but we access `x` via `z.0.0`, which is an immutable reference and + // therefore can't be mutated. + let mut c = || { + //~^ ERROR: cannot borrow `z.0.0.0` as mutable, as it is behind a `&` reference + z.0.0.0 = format!("X1"); + }; + + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr new file mode 100644 index 0000000000000..861bc44b78ded --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr @@ -0,0 +1,21 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/cant-mutate-imm-borrow.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0596]: cannot borrow `z.0.0.0` as mutable, as it is behind a `&` reference + --> $DIR/cant-mutate-imm-borrow.rs:14:17 + | +LL | let mut c = || { + | ^^ cannot borrow as mutable +LL | +LL | z.0.0.0 = format!("X1"); + | - mutable borrow occurs due to use of `z.0.0.0` in closure + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs new file mode 100644 index 0000000000000..997ecc7ddddf1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs @@ -0,0 +1,35 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +// Ensure that diagnostics for mutability error (because the root variable +// isn't mutable) work with `capture_disjoint_fields` enabled. + +fn mut_error_struct() { + let x = (10, 10); + let y = (x, 10); + let z = (y, 10); + + let mut c = || { + z.0.0.0 = 20; + //~^ ERROR: cannot assign to `z`, as it is not declared as mutable + }; + + c(); +} + +fn mut_error_box() { + let x = (10, 10); + let bx = Box::new(x); + + let mut c = || { + bx.0 = 20; + //~^ ERROR: cannot assign to `bx`, as it is not declared as mutable + }; + + c(); +} + +fn main() { + mut_error_struct(); + mut_error_box(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr new file mode 100644 index 0000000000000..5e15635ac6e1b --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr @@ -0,0 +1,30 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/cant-mutate-imm.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0594]: cannot assign to `z`, as it is not declared as mutable + --> $DIR/cant-mutate-imm.rs:13:9 + | +LL | let z = (y, 10); + | - help: consider changing this to be mutable: `mut z` +... +LL | z.0.0.0 = 20; + | ^^^^^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `bx`, as it is not declared as mutable + --> $DIR/cant-mutate-imm.rs:25:9 + | +LL | let bx = Box::new(x); + | -- help: consider changing this to be mutable: `mut bx` +... +LL | bx.0 = 20; + | ^^^^^^^^^ cannot assign + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs new file mode 100644 index 0000000000000..676fde558dfbc --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs @@ -0,0 +1,38 @@ +// Test that we can't mutate a place if we need to deref an imm-borrow +// to reach it. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +fn imm_mut_ref() { + let mut x = String::new(); + let y = String::new(); + let mref_x = &mut x; + let ref_mref_x = &mref_x; + + let c = || { + //~^ ERROR: cannot borrow `**ref_mref_x` as mutable, as it is behind a `&` reference + **ref_mref_x = y; + }; + + c(); +} + +fn mut_imm_ref() { + let x = String::new(); + let y = String::new(); + let mut ref_x = &x; + let mref_ref_x = &mut ref_x; + + let c = || { + //~^ ERROR: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference + **mref_ref_x = y; + }; + + c(); +} + +fn main() { + imm_mut_ref(); + mut_imm_ref(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr new file mode 100644 index 0000000000000..8cb2ed2235d55 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr @@ -0,0 +1,33 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/mut_ref.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0596]: cannot borrow `**ref_mref_x` as mutable, as it is behind a `&` reference + --> $DIR/mut_ref.rs:13:13 + | +LL | let ref_mref_x = &mref_x; + | ------- help: consider changing this to be a mutable reference: `&mut mref_x` +LL | +LL | let c = || { + | ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable +LL | +LL | **ref_mref_x = y; + | ---------- mutable borrow occurs due to use of `**ref_mref_x` in closure + +error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference + --> $DIR/mut_ref.rs:27:13 + | +LL | let c = || { + | ^^ cannot borrow as mutable +LL | +LL | **mref_ref_x = y; + | ---------- mutable borrow occurs due to use of `**mref_ref_x` in closure + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.rs b/src/test/ui/closures/2229_closure_analysis/move_closure.rs new file mode 100644 index 0000000000000..8bdc999ca3c3f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/move_closure.rs @@ -0,0 +1,72 @@ +// Test that move closures drop derefs with `capture_disjoint_fields` enabled. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![feature(rustc_attrs)] + +// Test we truncate derefs properly +fn simple_ref() { + let mut s = 10; + let ref_s = &mut s; + + let mut c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + *ref_s += 10; + //~^ NOTE: Capturing ref_s[Deref] -> ByValue + //~| NOTE: Min Capture ref_s[] -> ByValue + }; + c(); +} + +// Test we truncate derefs properly +fn struct_contains_ref_to_another_struct() { + struct S(String); + struct T<'a>(&'a mut S); + + let mut s = S("s".into()); + let t = T(&mut s); + + let mut c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + t.0.0 = "new s".into(); + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue + //~| NOTE: Min Capture t[(0, 0)] -> ByValue + }; + + c(); +} + +// Test that we don't reduce precision when there is nothing deref. +fn no_ref() { + struct S(String); + struct T(S); + + let t = T(S("s".into())); + let mut c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + t.0.0 = "new S".into(); + //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue + //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue + }; + c(); +} + +fn main() { + simple_ref(); + struct_contains_ref_to_another_struct(); + no_ref(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.stderr b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr new file mode 100644 index 0000000000000..a745f14598ee2 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr @@ -0,0 +1,147 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:14:17 + | +LL | let mut c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:35:17 + | +LL | let mut c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:55:17 + | +LL | let mut c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/move_closure.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:17:5 + | +LL | / move || { +LL | | +LL | | +LL | | *ref_s += 10; +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Capturing ref_s[Deref] -> ByValue + --> $DIR/move_closure.rs:20:9 + | +LL | *ref_s += 10; + | ^^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:17:5 + | +LL | / move || { +LL | | +LL | | +LL | | *ref_s += 10; +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture ref_s[] -> ByValue + --> $DIR/move_closure.rs:20:9 + | +LL | *ref_s += 10; + | ^^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:38:5 + | +LL | / move || { +LL | | +LL | | +LL | | t.0.0 = "new s".into(); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue + --> $DIR/move_closure.rs:41:9 + | +LL | t.0.0 = "new s".into(); + | ^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:38:5 + | +LL | / move || { +LL | | +LL | | +LL | | t.0.0 = "new s".into(); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0)] -> ByValue + --> $DIR/move_closure.rs:41:9 + | +LL | t.0.0 = "new s".into(); + | ^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:58:5 + | +LL | / move || { +LL | | +LL | | +LL | | t.0.0 = "new S".into(); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),(0, 0)] -> ByValue + --> $DIR/move_closure.rs:61:9 + | +LL | t.0.0 = "new S".into(); + | ^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:58:5 + | +LL | / move || { +LL | | +LL | | +LL | | t.0.0 = "new S".into(); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0),(0, 0)] -> ByValue + --> $DIR/move_closure.rs:61:9 + | +LL | t.0.0 = "new S".into(); + | ^^^^^ + +error: aborting due to 9 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs new file mode 100644 index 0000000000000..9a93e6cf1e1ef --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs @@ -0,0 +1,28 @@ +// run-pass + +// Test that ByValue captures compile sucessefully especially when the captures are +// derefenced within the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +#[derive(Debug, Default)] +struct SomeLargeType; +struct MuchLargerType([SomeLargeType; 32]); + +fn big_box() { + let s = MuchLargerType(Default::default()); + let b = Box::new(s); + let t = (b, 10); + + let c = || { + let p = t.0.0; + println!("{} {:?}", t.1, p); + }; + + c(); +} + +fn main() { + big_box(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.stderr new file mode 100644 index 0000000000000..98715c6b94365 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/by_value.rs:6:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs new file mode 100644 index 0000000000000..4007a5a48aaec --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs @@ -0,0 +1,64 @@ +// run-pass + +// Test that move closures compile properly with `capture_disjoint_fields` enabled. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +fn simple_ref() { + let mut s = 10; + let ref_s = &mut s; + + let mut c = move || { + *ref_s += 10; + }; + c(); +} + +fn struct_contains_ref_to_another_struct() { + struct S(String); + struct T<'a>(&'a mut S); + + let mut s = S("s".into()); + let t = T(&mut s); + + let mut c = move || { + t.0.0 = "new s".into(); + }; + + c(); +} + +#[derive(Debug)] +struct S(String); + +#[derive(Debug)] +struct T(S); + +fn no_ref() { + let mut t = T(S("s".into())); + let mut c = move || { + t.0.0 = "new S".into(); + }; + c(); +} + +fn no_ref_nested() { + let mut t = T(S("s".into())); + let c = || { + println!("{:?}", t.0); + let mut c = move || { + t.0.0 = "new S".into(); + println!("{:?}", t.0.0); + }; + c(); + }; + c(); +} + +fn main() { + simple_ref(); + struct_contains_ref_to_another_struct(); + no_ref(); + no_ref_nested(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.stderr new file mode 100644 index 0000000000000..c1d8ba575d6fd --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/move_closure.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs new file mode 100644 index 0000000000000..315622443c3cc --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs @@ -0,0 +1,56 @@ +// run-pass + +// Test that we can mutate a place through a mut-borrow +// that is captured by the closure + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +// Check that we can mutate when one deref is required +fn mut_ref_1() { + let mut x = String::new(); + let rx = &mut x; + + let mut c = || { + *rx = String::new(); + }; + + c(); +} + +// Similar example as mut_ref_1, we don't deref the imm-borrow here, +// and so we are allowed to mutate. +fn mut_ref_2() { + let x = String::new(); + let y = String::new(); + let mut ref_x = &x; + let m_ref_x = &mut ref_x; + + let mut c = || { + *m_ref_x = &y; + }; + + c(); +} + +// Check that we can mutate when multiple derefs of mut-borrows are required to reach +// the target place. +// It works because all derefs are mutable, if either of them was an immutable +// borrow, then we would not be able to deref. +fn mut_mut_ref() { + let mut x = String::new(); + let mut mref_x = &mut x; + let m_mref_x = &mut mref_x; + + let mut c = || { + **m_mref_x = String::new(); + }; + + c(); +} + +fn main() { + mut_ref_1(); + mut_ref_2(); + mut_mut_ref(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.stderr new file mode 100644 index 0000000000000..4b37a0b405f5e --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/mut_ref.rs:6:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs new file mode 100644 index 0000000000000..2dba923647a2e --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs @@ -0,0 +1,45 @@ +// run-pass + +// Test that we can mutate a place through a mut-borrow +// that is captured by the closure + +// More specifically we test that the if the mutable reference isn't root variable of a capture +// but rather accessed while acessing the precise capture. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +fn mut_tuple() { + let mut t = (10, 10); + + let t1 = (&mut t, 10); + + let mut c = || { + // Mutable because (*t.0) is mutable + t1.0.0 += 10; + }; + + c(); +} + +fn mut_tuple_nested() { + let mut t = (10, 10); + + let t1 = (&mut t, 10); + + let mut c = || { + let mut c = || { + // Mutable because (*t.0) is mutable + t1.0.0 += 10; + }; + + c(); + }; + + c(); +} + +fn main() { + mut_tuple(); + mut_tuple_nested(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.stderr new file mode 100644 index 0000000000000..418ab29098b2a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/mut_ref_struct_mem.rs:9:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs new file mode 100644 index 0000000000000..f6e9862b26c11 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs @@ -0,0 +1,47 @@ +// run-pass + +// Test that we can use raw ptrs when using `capture_disjoint_fields`. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +#[derive(Debug)] +struct S { + s: String, + t: String, +} + +struct T(*const S); + +fn unsafe_imm() { + let s = "".into(); + let t = "".into(); + let my_speed: Box = Box::new(S { s, t }); + + let p : *const S = Box::into_raw(my_speed); + let t = T(p); + + let c = || unsafe { + println!("{:?}", (*t.0).s); + }; + + c(); +} + +fn unsafe_mut() { + let s = "".into(); + let t = "".into(); + let mut my_speed: Box = Box::new(S { s, t }); + let p : *mut S = &mut *my_speed; + + let c = || { + let x = unsafe { &mut (*p).s }; + *x = "s".into(); + }; + c(); +} + +fn main() { + unsafe_mut(); + unsafe_imm(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.stderr new file mode 100644 index 0000000000000..c64c8b72e8151 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsafe_ptr.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.rs b/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.rs new file mode 100644 index 0000000000000..79d3ecc2d2bed --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.rs @@ -0,0 +1,63 @@ +// Test that we restrict precision of a capture when we access a raw ptr, +// i.e. the capture doesn't deref the raw ptr. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| `#[warn(incomplete_features)]` on by default +//~| see issue #53488 +#![feature(rustc_attrs)] + +#[derive(Debug)] +struct S { + s: String, + t: String, +} + +struct T(*const S); + +fn unsafe_imm() { + let s = "".into(); + let t = "".into(); + let my_speed: Box = Box::new(S { s, t }); + + let p : *const S = Box::into_raw(my_speed); + let t = T(p); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || unsafe { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + println!("{:?}", (*t.0).s); + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture t[(0, 0)] -> ImmBorrow + }; + + c(); +} + +fn unsafe_mut() { + let s = "".into(); + let t = "".into(); + let mut my_speed: Box = Box::new(S { s, t }); + let p : *mut S = &mut *my_speed; + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + let x = unsafe { &mut (*p).s }; + //~^ NOTE: Capturing p[Deref,(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture p[] -> ImmBorrow + *x = "s".into(); + }; + c(); +} + +fn main() { + unsafe_mut(); + unsafe_imm(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.stderr b/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.stderr new file mode 100644 index 0000000000000..4508b2426e8ff --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.stderr @@ -0,0 +1,102 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/unsafe_ptr.rs:26:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/unsafe_ptr.rs:46:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsafe_ptr.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: First Pass analysis includes: + --> $DIR/unsafe_ptr.rs:29:6 + | +LL | / || unsafe { +LL | | +LL | | +LL | | println!("{:?}", (*t.0).s); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + --> $DIR/unsafe_ptr.rs:32:26 + | +LL | println!("{:?}", (*t.0).s); + | ^^^^^^^^ + +error: Min Capture analysis includes: + --> $DIR/unsafe_ptr.rs:29:6 + | +LL | / || unsafe { +LL | | +LL | | +LL | | println!("{:?}", (*t.0).s); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0)] -> ImmBorrow + --> $DIR/unsafe_ptr.rs:32:26 + | +LL | println!("{:?}", (*t.0).s); + | ^^^^^^^^ + +error: First Pass analysis includes: + --> $DIR/unsafe_ptr.rs:49:5 + | +LL | / || { +LL | | +LL | | +LL | | let x = unsafe { &mut (*p).s }; +... | +LL | | *x = "s".into(); +LL | | }; + | |_____^ + | +note: Capturing p[Deref,(0, 0)] -> ImmBorrow + --> $DIR/unsafe_ptr.rs:52:31 + | +LL | let x = unsafe { &mut (*p).s }; + | ^^^^^^ + +error: Min Capture analysis includes: + --> $DIR/unsafe_ptr.rs:49:5 + | +LL | / || { +LL | | +LL | | +LL | | let x = unsafe { &mut (*p).s }; +... | +LL | | *x = "s".into(); +LL | | }; + | |_____^ + | +note: Min Capture p[] -> ImmBorrow + --> $DIR/unsafe_ptr.rs:52:31 + | +LL | let x = unsafe { &mut (*p).s }; + | ^^^^^^ + +error: aborting due to 6 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/issue-71202.rs b/src/test/ui/const-generics/issue-71202.rs new file mode 100644 index 0000000000000..78dee1717f1fa --- /dev/null +++ b/src/test/ui/const-generics/issue-71202.rs @@ -0,0 +1,33 @@ +// check-pass + +#![feature(const_generics)] +#![allow(incomplete_features, const_evaluatable_unchecked)] + +use std::marker::PhantomData; + +struct DataHolder { + item: T, +} + +impl DataHolder { + const ITEM_IS_COPY: [(); 1 - { + trait NotCopy { + const VALUE: bool = false; + } + + impl<__Type: ?Sized> NotCopy for __Type {} + + struct IsCopy<__Type: ?Sized>(PhantomData<__Type>); + + impl<__Type> IsCopy<__Type> + where + __Type: Sized + Copy, + { + const VALUE: bool = true; + } + + >::VALUE + } as usize] = []; +} + +fn main() {} diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs b/src/test/ui/consts/const-blocks/const-repeat.rs similarity index 100% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs rename to src/test/ui/consts/const-blocks/const-repeat.rs diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-const.rs b/src/test/ui/consts/const-blocks/fn-call-in-const.rs similarity index 73% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-const.rs rename to src/test/ui/consts/const-blocks/fn-call-in-const.rs index da1bae1be8d4e..7936af75d84ac 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-const.rs +++ b/src/test/ui/consts/const-blocks/fn-call-in-const.rs @@ -1,7 +1,7 @@ // run-pass -#![allow(unused)] -#![feature(const_in_array_repeat_expressions)] +#![feature(inline_const)] +#![allow(unused, incomplete_features)] // Some type that is not copyable. struct Bar; @@ -18,6 +18,6 @@ const _: [u32; 2] = [type_copy(); 2]; // This is allowed because all promotion contexts use the explicit rules for promotability when // inside an explicit const context. -const _: [Option; 2] = [type_no_copy(); 2]; +const _: [Option; 2] = [const { type_no_copy() }; 2]; fn main() {} diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs b/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs similarity index 85% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs rename to src/test/ui/consts/const-blocks/fn-call-in-non-const.rs index d40facf232a67..19217843759c1 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs +++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs @@ -1,5 +1,3 @@ -#![feature(const_in_array_repeat_expressions)] - // Some type that is not copyable. struct Bar; diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr similarity index 92% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr rename to src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr index 48092432bb1d6..b75452cd21702 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr +++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/fn-call-in-non-const.rs:16:31 + --> $DIR/fn-call-in-non-const.rs:14:31 | LL | let _: [Option; 2] = [no_copy(); 2]; | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs b/src/test/ui/consts/const-blocks/migrate-fail.rs similarity index 92% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs rename to src/test/ui/consts/const-blocks/migrate-fail.rs index d04b0b7e168f5..bb12139a7bae9 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs +++ b/src/test/ui/consts/const-blocks/migrate-fail.rs @@ -1,6 +1,5 @@ // ignore-compare-mode-nll // compile-flags: -Z borrowck=migrate -#![feature(const_in_array_repeat_expressions)] #![allow(warnings)] // Some type that is not copyable. diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr b/src/test/ui/consts/const-blocks/migrate-fail.stderr similarity index 93% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr rename to src/test/ui/consts/const-blocks/migrate-fail.stderr index 476d48fd4969d..0fdbbc36288e9 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr +++ b/src/test/ui/consts/const-blocks/migrate-fail.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/migrate-fail.rs:14:37 + --> $DIR/migrate-fail.rs:13:37 | LL | let arr: [Option; 2] = [x; 2]; | ^^^^^^ the trait `Copy` is not implemented for `Option` @@ -9,7 +9,7 @@ LL | let arr: [Option; 2] = [x; 2]; = note: the `Copy` trait is required because the repeated element will be copied error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/migrate-fail.rs:20:37 + --> $DIR/migrate-fail.rs:19:37 | LL | let arr: [Option; 2] = [x; 2]; | ^^^^^^ the trait `Copy` is not implemented for `Option` diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs b/src/test/ui/consts/const-blocks/migrate-pass.rs similarity index 98% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs rename to src/test/ui/consts/const-blocks/migrate-pass.rs index bfa8ebcfdd32a..3195717fa38ba 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs +++ b/src/test/ui/consts/const-blocks/migrate-pass.rs @@ -1,7 +1,6 @@ // check-pass // compile-flags: -Z borrowck=migrate // ignore-compare-mode-nll -#![feature(const_in_array_repeat_expressions)] #![allow(warnings)] // Some type that is not copyable. diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs b/src/test/ui/consts/const-blocks/nll-fail.rs similarity index 91% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs rename to src/test/ui/consts/const-blocks/nll-fail.rs index 2d5c59d112e1b..871387c1fd0cf 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs +++ b/src/test/ui/consts/const-blocks/nll-fail.rs @@ -1,5 +1,4 @@ // ignore-compare-mode-nll -#![feature(const_in_array_repeat_expressions, nll)] #![allow(warnings)] // Some type that is not copyable. diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr b/src/test/ui/consts/const-blocks/nll-fail.stderr similarity index 93% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr rename to src/test/ui/consts/const-blocks/nll-fail.stderr index 3aa69996ff743..8122085635977 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr +++ b/src/test/ui/consts/const-blocks/nll-fail.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/nll-fail.rs:13:37 + --> $DIR/nll-fail.rs:12:37 | LL | let arr: [Option; 2] = [x; 2]; | ^^^^^^ the trait `Copy` is not implemented for `Option` @@ -9,7 +9,7 @@ LL | let arr: [Option; 2] = [x; 2]; = note: the `Copy` trait is required because the repeated element will be copied error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/nll-fail.rs:19:37 + --> $DIR/nll-fail.rs:18:37 | LL | let arr: [Option; 2] = [x; 2]; | ^^^^^^ the trait `Copy` is not implemented for `Option` diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs b/src/test/ui/consts/const-blocks/nll-pass.rs similarity index 98% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs rename to src/test/ui/consts/const-blocks/nll-pass.rs index a304f877ab7ad..d8defa19483e1 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs +++ b/src/test/ui/consts/const-blocks/nll-pass.rs @@ -1,7 +1,6 @@ // check-pass // ignore-compare-mode-nll #![allow(warnings)] -#![feature(const_in_array_repeat_expressions, nll)] // Some type that is not copyable. struct Bar; diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs b/src/test/ui/consts/const-blocks/run-pass.rs similarity index 81% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs rename to src/test/ui/consts/const-blocks/run-pass.rs index 27bf5dabf566b..e11f69babf798 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs +++ b/src/test/ui/consts/const-blocks/run-pass.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(const_in_array_repeat_expressions)] #[derive(Debug, Eq, PartialEq)] struct Bar; diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs b/src/test/ui/consts/const-blocks/trait-error.rs similarity index 77% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs rename to src/test/ui/consts/const-blocks/trait-error.rs index f8df7aafa60df..5a614cbdd1561 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs +++ b/src/test/ui/consts/const-blocks/trait-error.rs @@ -1,5 +1,3 @@ -#![feature(const_in_array_repeat_expressions)] - #[derive(Copy, Clone)] struct Foo(T); diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr b/src/test/ui/consts/const-blocks/trait-error.stderr similarity index 94% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr rename to src/test/ui/consts/const-blocks/trait-error.stderr index 26de67e50fa67..26e2848e7f7a1 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr +++ b/src/test/ui/consts/const-blocks/trait-error.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Foo: Copy` is not satisfied - --> $DIR/trait-error.rs:7:5 + --> $DIR/trait-error.rs:5:5 | LL | [Foo(String::new()); 4]; | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Foo` diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs deleted file mode 100644 index 5ed302bbff3aa..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![allow(warnings)] - -struct Bar; - -// This function would compile with the feature gate, and tests that it is suggested. -fn foo() { - let arr: [Option; 2] = [None::; 2]; - //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] -} - -// This function would not compile with the feature gate, and tests that it is not suggested. -fn bar() { - let arr: [Option; 2] = [Some("foo".to_string()); 2]; - //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr deleted file mode 100644 index ca1706169afc6..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36 - | -LL | let arr: [Option; 2] = [None::; 2]; - | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` - | - = help: the following implementations were found: - as Copy> - = note: the `Copy` trait is required because the repeated element will be copied - = note: this array initializer can be evaluated at compile-time, see issue #49147 for more information - = help: add `#![feature(const_in_array_repeat_expressions)]` to the crate attributes to enable - -error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:13:36 - | -LL | let arr: [Option; 2] = [Some("foo".to_string()); 2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` - | - = help: the following implementations were found: - as Copy> - = note: the `Copy` trait is required because the repeated element will be copied - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs new file mode 100644 index 0000000000000..98b408daa022d --- /dev/null +++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs @@ -0,0 +1,43 @@ +// In rustc_typeck::check::expr::no_such_field_err we recursively +// look in subfields for the field. This recursive search is limited +// in depth for compile-time reasons and to avoid infinite recursion +// in case of cycles. This file tests that the limit in the recursion +// depth is enforced. + +struct Foo { + first: Bar, + second: u32, + third: u32, +} + +struct Bar { + bar: C, +} + +struct C { + c: D, +} + +struct D { + test: E, +} + +struct E { + e: F, +} + +struct F { + f: u32, +} + +fn main() { + let f = F { f: 6 }; + let e = E { e: f }; + let d = D { test: e }; + let c = C { c: d }; + let bar = Bar { bar: c }; + let fooer = Foo { first: bar, second: 4, third: 5 }; + + let test = fooer.f; + //~^ ERROR no field +} diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr new file mode 100644 index 0000000000000..b294f4da7db33 --- /dev/null +++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr @@ -0,0 +1,11 @@ +error[E0609]: no field `f` on type `Foo` + --> $DIR/non-existent-field-present-in-subfield-recursion-limit.rs:41:22 + | +LL | let test = fooer.f; + | ^ unknown field + | + = note: available fields are: `first`, `second`, `third` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield.fixed b/src/test/ui/suggestions/non-existent-field-present-in-subfield.fixed new file mode 100644 index 0000000000000..167548a89defa --- /dev/null +++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield.fixed @@ -0,0 +1,42 @@ +// run-rustfix + +struct Foo { + first: Bar, + _second: u32, + _third: u32, +} + +struct Bar { + bar: C, +} + +struct C { + c: D, +} + +struct D { + test: E, +} + +struct E { + _e: F, +} + +struct F { + _f: u32, +} + +fn main() { + let f = F { _f: 6 }; + let e = E { _e: f }; + let d = D { test: e }; + let c = C { c: d }; + let bar = Bar { bar: c }; + let fooer = Foo { first: bar, _second: 4, _third: 5 }; + + let _test = &fooer.first.bar.c; + //~^ ERROR no field + + let _test2 = fooer.first.bar.c.test; + //~^ ERROR no field +} diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield.rs b/src/test/ui/suggestions/non-existent-field-present-in-subfield.rs new file mode 100644 index 0000000000000..81cc1af4dff52 --- /dev/null +++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield.rs @@ -0,0 +1,42 @@ +// run-rustfix + +struct Foo { + first: Bar, + _second: u32, + _third: u32, +} + +struct Bar { + bar: C, +} + +struct C { + c: D, +} + +struct D { + test: E, +} + +struct E { + _e: F, +} + +struct F { + _f: u32, +} + +fn main() { + let f = F { _f: 6 }; + let e = E { _e: f }; + let d = D { test: e }; + let c = C { c: d }; + let bar = Bar { bar: c }; + let fooer = Foo { first: bar, _second: 4, _third: 5 }; + + let _test = &fooer.c; + //~^ ERROR no field + + let _test2 = fooer.test; + //~^ ERROR no field +} diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield.stderr b/src/test/ui/suggestions/non-existent-field-present-in-subfield.stderr new file mode 100644 index 0000000000000..ddb7476ec6e34 --- /dev/null +++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield.stderr @@ -0,0 +1,27 @@ +error[E0609]: no field `c` on type `Foo` + --> $DIR/non-existent-field-present-in-subfield.rs:37:24 + | +LL | let _test = &fooer.c; + | ^ unknown field + | + = note: available fields are: `first`, `_second`, `_third` +help: one of the expressions' fields has a field of the same name + | +LL | let _test = &fooer.first.bar.c; + | ^^^^^^^^^^ + +error[E0609]: no field `test` on type `Foo` + --> $DIR/non-existent-field-present-in-subfield.rs:40:24 + | +LL | let _test2 = fooer.test; + | ^^^^ unknown field + | + = note: available fields are: `first`, `_second`, `_third` +help: one of the expressions' fields has a field of the same name + | +LL | let _test2 = fooer.first.bar.c.test; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/unused/unused-closure.rs b/src/test/ui/unused/unused-closure.rs index 5100636842be5..c96c907318ce9 100644 --- a/src/test/ui/unused/unused-closure.rs +++ b/src/test/ui/unused/unused-closure.rs @@ -2,7 +2,6 @@ // edition:2018 #![feature(async_closure)] -#![feature(const_in_array_repeat_expressions)] #![feature(generators)] #![deny(unused_must_use)] @@ -18,10 +17,6 @@ fn unused() { [Box::new([|| {}; 10]); 1]; //~ ERROR unused array of boxed arrays of closures that must be used - [|| { //~ ERROR unused array of generators that must be used - yield 42u32; - }; 42]; - vec![|| "a"].pop().unwrap(); //~ ERROR unused closure that must be used let b = false; diff --git a/src/test/ui/unused/unused-closure.stderr b/src/test/ui/unused/unused-closure.stderr index f8b4cbb02c4bd..265d3e8e075fd 100644 --- a/src/test/ui/unused/unused-closure.stderr +++ b/src/test/ui/unused/unused-closure.stderr @@ -1,5 +1,5 @@ error: unused closure that must be used - --> $DIR/unused-closure.rs:10:5 + --> $DIR/unused-closure.rs:9:5 | LL | / || { LL | | println!("Hello!"); @@ -7,14 +7,14 @@ LL | | }; | |______^ | note: the lint level is defined here - --> $DIR/unused-closure.rs:7:9 + --> $DIR/unused-closure.rs:6:9 | LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ = note: closures are lazy and do nothing unless called error: unused implementer of `Future` that must be used - --> $DIR/unused-closure.rs:14:5 + --> $DIR/unused-closure.rs:13:5 | LL | async {}; | ^^^^^^^^^ @@ -22,7 +22,7 @@ LL | async {}; = note: futures do nothing unless you `.await` or poll them error: unused closure that must be used - --> $DIR/unused-closure.rs:15:5 + --> $DIR/unused-closure.rs:14:5 | LL | || async {}; | ^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | || async {}; = note: closures are lazy and do nothing unless called error: unused closure that must be used - --> $DIR/unused-closure.rs:16:5 + --> $DIR/unused-closure.rs:15:5 | LL | async || {}; | ^^^^^^^^^^^^ @@ -38,25 +38,15 @@ LL | async || {}; = note: closures are lazy and do nothing unless called error: unused array of boxed arrays of closures that must be used - --> $DIR/unused-closure.rs:19:5 + --> $DIR/unused-closure.rs:18:5 | LL | [Box::new([|| {}; 10]); 1]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called -error: unused array of generators that must be used - --> $DIR/unused-closure.rs:21:5 - | -LL | / [|| { -LL | | yield 42u32; -LL | | }; 42]; - | |___________^ - | - = note: generators are lazy and do nothing unless resumed - error: unused closure that must be used - --> $DIR/unused-closure.rs:25:5 + --> $DIR/unused-closure.rs:20:5 | LL | vec![|| "a"].pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,12 +54,12 @@ LL | vec![|| "a"].pop().unwrap(); = note: closures are lazy and do nothing unless called error: unused closure that must be used - --> $DIR/unused-closure.rs:28:9 + --> $DIR/unused-closure.rs:23:9 | LL | || true; | ^^^^^^^^ | = note: closures are lazy and do nothing unless called -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors