diff --git a/Cargo.lock b/Cargo.lock index 5b8d28752b4da..07ee10deee519 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -871,9 +871,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.45+curl-7.78.0" +version = "0.4.49+curl-7.79.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9e5a72b1c744eb5dd20b2be4d7eb84625070bb5c4ab9b347b70464ab1e62eb" +checksum = "e0f44960aea24a786a46907b8824ebc0e66ca06bf4e4978408c7499620343483" dependencies = [ "cc", "libc", diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 3ccf9f446a63e..48ad7be3e9bdc 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1373,14 +1373,17 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed. // See #78991 for an investigation of treating macros in this position // as statements, rather than expressions, during parsing. - if let StmtKind::Expr(expr) = &stmt.kind { - if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) { + let res = match &stmt.kind { + StmtKind::Expr(expr) + if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) => + { self.cx.current_expansion.is_trailing_mac = true; + // Don't use `assign_id` for this statement - it may get removed + // entirely due to a `#[cfg]` on the contained expression + noop_flat_map_stmt(stmt, self) } - } - - let res = assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)); - + _ => assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)), + }; self.cx.current_expansion.is_trailing_mac = false; res } diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs index 03277b1b2e0be..5876ac22c66a7 100644 --- a/compiler/rustc_mir/src/transform/remove_zsts.rs +++ b/compiler/rustc_mir/src/transform/remove_zsts.rs @@ -9,6 +9,10 @@ pub struct RemoveZsts; impl<'tcx> MirPass<'tcx> for RemoveZsts { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // Avoid query cycles (generators require optimized MIR for layout). + if tcx.type_of(body.source.def_id()).is_generator() { + return; + } let param_env = tcx.param_env(body.source.def_id()); let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); for block in basic_blocks.iter_mut() { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 7038f16a2c9c4..42c5afbd5df99 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -388,15 +388,15 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // to make sure we don't forget to fold the substs regardless. match *ty.kind() { - ty::Opaque(def_id, substs) => { + // This is really important. While we *can* handle this, this has + // severe performance implications for large opaque types with + // late-bound regions. See `issue-88862` benchmark. + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - // N.b. there is an assumption here all this code can handle - // escaping bound vars. - let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { let obligation = Obligation::with_depth( @@ -844,6 +844,10 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( obligations: &mut Vec>, ) -> Result>, InProgress> { let infcx = selcx.infcx(); + // Don't use the projection cache in intercrate mode - + // the `infcx` may be re-used between intercrate in non-intercrate + // mode, which could lead to using incorrect cache results. + let use_cache = !selcx.is_intercrate(); let projection_ty = infcx.resolve_vars_if_possible(projection_ty); let cache_key = ProjectionCacheKey::new(projection_ty); @@ -856,7 +860,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // bounds. It might be the case that we want two distinct caches, // or else another kind of cache entry. - let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key); + let cache_result = if use_cache { + infcx.inner.borrow_mut().projection_cache().try_start(cache_key) + } else { + Ok(()) + }; match cache_result { Ok(()) => debug!("no cache"), Err(ProjectionCacheEntry::Ambiguous) => { @@ -881,7 +889,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // should ensure that, unless this happens within a snapshot that's // rolled back, fulfillment or evaluation will notice the cycle. - infcx.inner.borrow_mut().projection_cache().recur(cache_key); + if use_cache { + infcx.inner.borrow_mut().projection_cache().recur(cache_key); + } return Err(InProgress); } Err(ProjectionCacheEntry::Recur) => { @@ -963,20 +973,26 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( .map_or(false, |res| res.must_apply_considering_regions()) }); - infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + if use_cache { + infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + } obligations.extend(result.obligations); Ok(Some(result.value)) } Ok(ProjectedTy::NoProgress(projected_ty)) => { debug!(?projected_ty, "opt_normalize_projection_type: no progress"); let result = Normalized { value: projected_ty, obligations: vec![] }; - infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + if use_cache { + infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + } // No need to extend `obligations`. Ok(Some(result.value)) } Err(ProjectionTyError::TooManyCandidates) => { debug!("opt_normalize_projection_type: too many candidates"); - infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); + if use_cache { + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); + } Ok(None) } Err(ProjectionTyError::TraitSelectionError(_)) => { @@ -986,7 +1002,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // Trait`, which when processed will cause the error to be // reported later - infcx.inner.borrow_mut().projection_cache().error(cache_key); + if use_cache { + infcx.inner.borrow_mut().projection_cache().error(cache_key); + } let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); Ok(Some(result.value)) diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index ed5fe466c69f7..1364cf1c99535 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -206,15 +206,15 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // Wrap this in a closure so we don't accidentally return from the outer function let res = (|| match *ty.kind() { - ty::Opaque(def_id, substs) => { + // This is really important. While we *can* handle this, this has + // severe performance implications for large opaque types with + // late-bound regions. See `issue-88862` benchmark. + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - // N.b. there is an assumption here all this code can handle - // escaping bound vars. - let substs = substs.super_fold_with(self); let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 22013fb79cf79..cf6f76a932585 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -315,6 +315,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } + pub fn is_intercrate(&self) -> bool { + self.intercrate + } + /// Returns `true` if the trait predicate is considerd `const` to this selection context. pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool { match pred.constness { @@ -982,6 +986,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, trait_ref: ty::ConstnessAnd>, ) -> Option { + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return None; + } + let tcx = self.tcx(); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) { @@ -1004,6 +1016,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return; + } + if self.can_use_global_caches(param_env) { if !trait_ref.needs_infer() { debug!(?trait_ref, ?result, "insert_evaluation_cache global"); @@ -1185,6 +1205,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option>> { + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return None; + } let tcx = self.tcx(); let pred = &cache_fresh_trait_pred.skip_binder(); let trait_ref = pred.trait_ref; @@ -1221,6 +1248,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &self, result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) -> bool { + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return false; + } match result { Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(), _ => true, diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index d837af85d58ae..bf155ecbd19c1 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::Limit; @@ -12,7 +13,8 @@ type NeedsDropResult = Result; fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { let adt_fields = - move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); + move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); + // If we don't know a type doesn't need drop, for example if it's a type // parameter without a `Copy` bound, then we conservatively return that it // needs drop. @@ -25,8 +27,9 @@ fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> bool { - let significant_drop_fields = - move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()); + let significant_drop_fields = move |adt_def: &ty::AdtDef, _| { + tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()) + }; let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields) .next() .is_some(); @@ -71,7 +74,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> where - F: Fn(&ty::AdtDef) -> NeedsDropResult, + F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult, I: Iterator>, { type Item = NeedsDropResult>; @@ -135,7 +138,7 @@ where // `ManuallyDrop`. If it's a struct or enum without a `Drop` // impl then check whether the field types need `Drop`. ty::Adt(adt_def, substs) => { - let tys = match (self.adt_components)(adt_def) { + let tys = match (self.adt_components)(adt_def, substs) { Err(e) => return Some(Err(e)), Ok(tys) => tys, }; @@ -168,22 +171,44 @@ where } } +enum DtorType { + /// Type has a `Drop` but it is considered insignificant. + /// Check the query `adt_significant_drop_tys` for understanding + /// "significant" / "insignificant". + Insignificant, + + /// Type has a `Drop` implentation. + Significant, +} + // This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`. // Depending on the implentation of `adt_has_dtor`, it is used to check if the // ADT has a destructor or if the ADT only has a significant destructor. For // understanding significant destructor look at `adt_significant_drop_tys`. -fn adt_drop_tys_helper( - tcx: TyCtxt<'_>, +fn adt_drop_tys_helper<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, - adt_has_dtor: impl Fn(&ty::AdtDef) -> bool, -) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_components = move |adt_def: &ty::AdtDef| { + adt_has_dtor: impl Fn(&ty::AdtDef) -> Option, +) -> Result<&ty::List>, AlwaysRequiresDrop> { + let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| { if adt_def.is_manually_drop() { debug!("adt_drop_tys: `{:?}` is manually drop", adt_def); return Ok(Vec::new().into_iter()); - } else if adt_has_dtor(adt_def) { - debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); - return Err(AlwaysRequiresDrop); + } else if let Some(dtor_info) = adt_has_dtor(adt_def) { + match dtor_info { + DtorType::Significant => { + debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); + return Err(AlwaysRequiresDrop); + } + DtorType::Insignificant => { + debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def); + + // Since the destructor is insignificant, we just want to make sure all of + // the passed in type parameters are also insignificant. + // Eg: Vec dtor is insignificant when T=i32 but significant when T=Mutex. + return Ok(substs.types().collect::>>().into_iter()); + } + } } else if adt_def.is_union() { debug!("adt_drop_tys: `{:?}` is a union", adt_def); return Ok(Vec::new().into_iter()); @@ -201,7 +226,10 @@ fn adt_drop_tys_helper( } fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some(); + // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are + // significant. + let adt_has_dtor = + |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); adt_drop_tys_helper(tcx, def_id, adt_has_dtor) } @@ -210,10 +238,22 @@ fn adt_significant_drop_tys( def_id: DefId, ) -> Result<&ty::List>, AlwaysRequiresDrop> { let adt_has_dtor = |adt_def: &ty::AdtDef| { - adt_def - .destructor(tcx) - .map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor)) - .unwrap_or(false) + let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor); + if is_marked_insig { + // In some cases like `std::collections::HashMap` where the struct is a wrapper around + // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies + // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with + // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl. + Some(DtorType::Insignificant) + } else if adt_def.destructor(tcx).is_some() { + // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be + // significant. + Some(DtorType::Significant) + } else { + // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we + // treat this as the simple case of Drop impl for type. + None + } }; adt_drop_tys_helper(tcx, def_id, adt_has_dtor) } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 53b99a14f379d..917bf4ecd8c4a 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -602,7 +602,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list); + debug!( + "For closure={:?}, min_captures before sorting={:?}", + closure_def_id, root_var_min_capture_list + ); + + // Now that we have the minimized list of captures, sort the captures by field id. + // This causes the closure to capture the upvars in the same order as the fields are + // declared which is also the drop order. Thus, in situations where we capture all the + // fields of some type, the obserable drop order will remain the same as it previously + // was even though we're dropping each capture individually. + // See https://github.com/rust-lang/project-rfc-2229/issues/42 and + // `src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`. + for (_, captures) in &mut root_var_min_capture_list { + captures.sort_by(|capture1, capture2| { + for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) { + // We do not need to look at the `Projection.ty` fields here because at each + // step of the iteration, the projections will either be the same and therefore + // the types must be as well or the current projection will be different and + // we will return the result of comparing the field indexes. + match (p1.kind, p2.kind) { + // Paths are the same, continue to next loop. + (ProjectionKind::Deref, ProjectionKind::Deref) => {} + (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) + if i1 == i2 => {} + + // Fields are different, compare them. + (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => { + return i1.cmp(&i2); + } + + // We should have either a pair of `Deref`s or a pair of `Field`s. + // Anything else is a bug. + ( + l @ (ProjectionKind::Deref | ProjectionKind::Field(..)), + r @ (ProjectionKind::Deref | ProjectionKind::Field(..)), + ) => bug!( + "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})", + l, + r + ), + ( + l + @ + (ProjectionKind::Index + | ProjectionKind::Subslice + | ProjectionKind::Deref + | ProjectionKind::Field(..)), + r + @ + (ProjectionKind::Index + | ProjectionKind::Subslice + | ProjectionKind::Deref + | ProjectionKind::Field(..)), + ) => bug!( + "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})", + l, + r + ), + } + } + + unreachable!( + "we captured two identical projections: capture1 = {:?}, capture2 = {:?}", + capture1, capture2 + ); + }); + } + + debug!( + "For closure={:?}, min_captures after sorting={:#?}", + closure_def_id, root_var_min_capture_list + ); typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list); } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 70a838a35f9d2..406150b1445eb 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -153,6 +153,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")] +#[rustc_insignificant_dtor] pub struct BTreeMap { root: Option>, length: usize, @@ -328,6 +329,7 @@ impl fmt::Debug for IterMut<'_, K, V> { /// /// [`into_iter`]: IntoIterator::into_iter #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct IntoIter { range: LazyLeafRange, length: usize, diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 9d45c5082db43..cef9bb60b885e 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -43,6 +43,7 @@ mod tests; /// more memory efficient, and make better use of CPU cache. #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] +#[rustc_insignificant_dtor] pub struct LinkedList { head: Option>>, tail: Option>>, diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index e4b28204158d9..e5f7c45a54d9c 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -90,6 +90,7 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible /// [`make_contiguous`]: VecDeque::make_contiguous #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct VecDeque< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0814652a5d47d..78356f7a48ac8 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -305,6 +305,7 @@ struct RcBox { /// [get_mut]: Rc::get_mut #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct Rc { ptr: NonNull>, phantom: PhantomData>, diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 0bd152f17a670..4cb0a4b10bd0c 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -22,6 +22,7 @@ use core::slice::{self}; /// let iter: std::vec::IntoIter<_> = v.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct IntoIter< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 87a0d37181562..cfbf207aee99c 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -394,6 +394,7 @@ mod spec_extend; /// [owned slice]: Box #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] +#[rustc_insignificant_dtor] pub struct Vec { buf: RawVec, len: usize, diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index ecdbf09881985..4a77fe358180c 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -10,6 +10,7 @@ use crate::{ /// A by-value [array] iterator. #[stable(feature = "array_value_iter", since = "1.51.0")] +#[cfg_attr(not(bootstrap), rustc_insignificant_dtor)] pub struct IntoIter { /// This is the array we are iterating over. /// diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 780d6c34c9197..81209e9750c1a 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1849,17 +1849,17 @@ macro_rules! int_impl { #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] /// let b = 3; /// - /// assert_eq!(a.div_floor(b), 2); - /// assert_eq!(a.div_floor(-b), -3); - /// assert_eq!((-a).div_floor(b), -3); - /// assert_eq!((-a).div_floor(-b), 2); + /// assert_eq!(a.unstable_div_floor(b), 2); + /// assert_eq!(a.unstable_div_floor(-b), -3); + /// assert_eq!((-a).unstable_div_floor(b), -3); + /// assert_eq!((-a).unstable_div_floor(-b), 2); /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_floor(self, rhs: Self) -> Self { + pub const fn unstable_div_floor(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { @@ -1884,17 +1884,17 @@ macro_rules! int_impl { #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] /// let b = 3; /// - /// assert_eq!(a.div_ceil(b), 3); - /// assert_eq!(a.div_ceil(-b), -2); - /// assert_eq!((-a).div_ceil(b), -2); - /// assert_eq!((-a).div_ceil(-b), 3); + /// assert_eq!(a.unstable_div_ceil(b), 3); + /// assert_eq!(a.unstable_div_ceil(-b), -2); + /// assert_eq!((-a).unstable_div_ceil(b), -2); + /// assert_eq!((-a).unstable_div_ceil(-b), 3); /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_ceil(self, rhs: Self) -> Self { + pub const fn unstable_div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) { @@ -1919,21 +1919,21 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(-8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(-8), 16);")] - #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(8), -16);")] - #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(8), -16);")] - #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(-8), -16);")] - #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(-8), -24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(8), 24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(-8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(-8), 16);")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").unstable_next_multiple_of(8), -16);")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").unstable_next_multiple_of(8), -16);")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").unstable_next_multiple_of(-8), -16);")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").unstable_next_multiple_of(-8), -24);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn next_multiple_of(self, rhs: Self) -> Self { + pub const fn unstable_next_multiple_of(self, rhs: Self) -> Self { // This would otherwise fail when calculating `r` when self == T::MIN. if rhs == -1 { return self; diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 02a5ed4ca800e..e79bf7bd7f3c7 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1862,12 +1862,12 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")] + #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_floor(4), 1);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[inline(always)] #[rustc_inherit_overflow_checks] - pub const fn div_floor(self, rhs: Self) -> Self { + pub const fn unstable_div_floor(self, rhs: Self) -> Self { self / rhs } @@ -1883,12 +1883,12 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")] + #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_ceil(4), 2);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_ceil(self, rhs: Self) -> Self { + pub const fn unstable_div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if r > 0 && rhs > 0 { @@ -1911,15 +1911,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(8), 24);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn next_multiple_of(self, rhs: Self) -> Self { + pub const fn unstable_next_multiple_of(self, rhs: Self) -> Self { match self % rhs { 0 => self, r => self + (rhs - r) diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index d2d655ea2c750..0ad85bf6d943d 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -294,33 +294,33 @@ macro_rules! int_module { fn test_div_floor() { let a: $T = 8; let b = 3; - assert_eq!(a.div_floor(b), 2); - assert_eq!(a.div_floor(-b), -3); - assert_eq!((-a).div_floor(b), -3); - assert_eq!((-a).div_floor(-b), 2); + assert_eq!(a.unstable_div_floor(b), 2); + assert_eq!(a.unstable_div_floor(-b), -3); + assert_eq!((-a).unstable_div_floor(b), -3); + assert_eq!((-a).unstable_div_floor(-b), 2); } #[test] fn test_div_ceil() { let a: $T = 8; let b = 3; - assert_eq!(a.div_ceil(b), 3); - assert_eq!(a.div_ceil(-b), -2); - assert_eq!((-a).div_ceil(b), -2); - assert_eq!((-a).div_ceil(-b), 3); + assert_eq!(a.unstable_div_ceil(b), 3); + assert_eq!(a.unstable_div_ceil(-b), -2); + assert_eq!((-a).unstable_div_ceil(b), -2); + assert_eq!((-a).unstable_div_ceil(-b), 3); } #[test] fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!((16 as $T).next_multiple_of(-8), 16); - assert_eq!((23 as $T).next_multiple_of(-8), 16); - assert_eq!((-16 as $T).next_multiple_of(8), -16); - assert_eq!((-23 as $T).next_multiple_of(8), -16); - assert_eq!((-16 as $T).next_multiple_of(-8), -16); - assert_eq!((-23 as $T).next_multiple_of(-8), -24); - assert_eq!(MIN.next_multiple_of(-1), MIN); + assert_eq!((16 as $T).unstable_next_multiple_of(8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(8), 24); + assert_eq!((16 as $T).unstable_next_multiple_of(-8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(-8), 16); + assert_eq!((-16 as $T).unstable_next_multiple_of(8), -16); + assert_eq!((-23 as $T).unstable_next_multiple_of(8), -16); + assert_eq!((-16 as $T).unstable_next_multiple_of(-8), -16); + assert_eq!((-23 as $T).unstable_next_multiple_of(-8), -24); + assert_eq!(MIN.unstable_next_multiple_of(-1), MIN); } #[test] diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 49f8f1f13fad4..35ec88c6af7d6 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -208,19 +208,19 @@ macro_rules! uint_module { #[test] fn test_div_floor() { - assert_eq!((8 as $T).div_floor(3), 2); + assert_eq!((8 as $T).unstable_div_floor(3), 2); } #[test] fn test_div_ceil() { - assert_eq!((8 as $T).div_ceil(3), 3); + assert_eq!((8 as $T).unstable_div_ceil(3), 3); } #[test] fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!(MAX.next_multiple_of(1), MAX); + assert_eq!((16 as $T).unstable_next_multiple_of(8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(8), 24); + assert_eq!(MAX.unstable_next_multiple_of(1), MAX); } #[test] diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 36077a42b48ac..4dff4fa4a60e8 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -205,6 +205,7 @@ use crate::sys; #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), rustc_insignificant_dtor)] pub struct HashMap { base: base::HashMap, } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 0c1a50e231cd4..cc137771bb8d4 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -357,7 +357,7 @@ impl File { let mut info: c::FILE_BASIC_INFO = mem::zeroed(); let size = mem::size_of_val(&info); cvt(c::GetFileInformationByHandleEx( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileBasicInfo, &mut info as *mut _ as *mut libc::c_void, size as c::DWORD, @@ -385,7 +385,7 @@ impl File { let mut info: c::FILE_STANDARD_INFO = mem::zeroed(); let size = mem::size_of_val(&info); cvt(c::GetFileInformationByHandleEx( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileStandardInfo, &mut info as *mut _ as *mut libc::c_void, size as c::DWORD, diff --git a/library/std/src/sys/windows/stdio_uwp.rs b/library/std/src/sys/windows/stdio_uwp.rs index 872511af862a7..32550f796ec64 100644 --- a/library/std/src/sys/windows/stdio_uwp.rs +++ b/library/std/src/sys/windows/stdio_uwp.rs @@ -2,6 +2,7 @@ use crate::io; use crate::mem::ManuallyDrop; +use crate::os::windows::io::FromRawHandle; use crate::sys::c; use crate::sys::handle::Handle; @@ -25,7 +26,8 @@ pub fn get_handle(handle_id: c::DWORD) -> io::Result { fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result { let handle = get_handle(handle_id)?; - let handle = Handle::new(handle); + // SAFETY: The handle returned from `get_handle` must be valid and non-null. + let handle = unsafe { Handle::from_raw_handle(handle) }; ManuallyDrop::new(handle).write(data) } @@ -38,7 +40,8 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { let handle = get_handle(c::STD_INPUT_HANDLE)?; - let handle = Handle::new(handle); + // SAFETY: The handle returned from `get_handle` must be valid and non-null. + let handle = unsafe { Handle::from_raw_handle(handle) }; ManuallyDrop::new(handle).read(buf) } } diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index 42fda98bc7a4b..63836654293f2 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -34,6 +34,11 @@ RUN apt-get update && \ xz-utils \ zlib1g-dev +# Install new Let's Encrypt root CA certificate and remove the expired one. +COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt +RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf +RUN /usr/sbin/update-ca-certificates + ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index e29d990f0f974..7b560aaaaa688 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -34,6 +34,11 @@ RUN apt-get update && \ xz-utils \ zlib1g-dev +# Install new Let's Encrypt root CA certificate and remove the expired one. +COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt +RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf +RUN /usr/sbin/update-ca-certificates + ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig diff --git a/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt b/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt new file mode 100644 index 0000000000000..b85c8037f6b60 --- /dev/null +++ b/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index fd29d3a022ad3..b17398bb6b440 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -61,3 +61,9 @@ elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then ciCommandSetEnv RUST_CONFIGURE_ARGS \ "${RUST_CONFIGURE_ARGS} --set llvm.clang-cl=$(pwd)/clang-rust/bin/clang-cl.exe" fi + +if isWindows; then + # GitHub image 20210928.2 added LLVM, but it is broken (and we don't want + # to use it anyways). + rm -rf /c/Program\ Files/LLVM +fi diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index aa3723eddfcce..5c0525506db9c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1266,8 +1266,7 @@ crate struct RustCodeBlock { /// The range in the markdown that the code within the code block occupies. crate code: Range, crate is_fenced: bool, - crate syntax: Option, - crate is_ignore: bool, + crate lang_string: LangString, } /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or @@ -1283,7 +1282,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec { let syntax = syntax.as_ref(); let lang_string = if syntax.is_empty() { @@ -1294,8 +1293,6 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec (offset.start, offset.end), Some((_, sub_offset)) => { @@ -1304,8 +1301,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec) -> Vec) -> Vec { // The ending of the offset goes too far sometime so we reduce it by one in // these cases. if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") { ( - None, + LangString::default(), offset.start, offset.end, Range { start: offset.start, end: offset.end - 1 }, false, - false, ) } else { - (None, offset.start, offset.end, offset, false, false) + (LangString::default(), offset.start, offset.end, offset, false) } } }; @@ -1348,8 +1342,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec SyntaxChecker<'a, 'tcx> { let source = dox[code_block.code].to_owned(); let sess = ParseSess::with_span_handler(handler, sm); + let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition()); + let expn_data = ExpnData::default( + ExpnKind::AstPass(AstPass::TestHarness), + DUMMY_SP, + edition, + None, + None, + ); + let span = DUMMY_SP.fresh_expansion(expn_data, self.cx.tcx.create_stable_hashing_context()); + let is_empty = rustc_driver::catch_fatal_errors(|| { parse_stream_from_source_str( FileName::Custom(String::from("doctest")), source, &sess, - None, + Some(span), ) .is_empty() }) @@ -61,8 +71,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { }; let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id); - let empty_block = code_block.syntax.is_none() && code_block.is_fenced; - let is_ignore = code_block.is_ignore; + let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; + let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; // The span and whether it is precise or not. let (sp, precise_span) = match super::source_span_for_markdown_range( diff --git a/src/test/rustdoc-ui/doctest-edition.rs b/src/test/rustdoc-ui/doctest-edition.rs new file mode 100644 index 0000000000000..b0787be972f2f --- /dev/null +++ b/src/test/rustdoc-ui/doctest-edition.rs @@ -0,0 +1,16 @@ +// edition:2021 + +#![deny(rustdoc::invalid_rust_codeblocks)] +//~^ NOTE lint level is defined here + +// By default, rustdoc should use the edition of the crate. +//! ``` +//! foo'b' +//! ``` +//~^^^ ERROR could not parse +//~| NOTE prefix `foo` is unknown + +// Rustdoc should respect `edition2018` when highlighting syntax. +//! ```edition2018 +//! foo'b' +//! ``` diff --git a/src/test/rustdoc-ui/doctest-edition.stderr b/src/test/rustdoc-ui/doctest-edition.stderr new file mode 100644 index 0000000000000..019f259288cbf --- /dev/null +++ b/src/test/rustdoc-ui/doctest-edition.stderr @@ -0,0 +1,22 @@ +error: could not parse code block as Rust code + --> $DIR/doctest-edition.rs:7:5 + | +LL | //! ``` + | _____^ +LL | | //! foo'b' +LL | | //! ``` + | |_______^ + | +note: the lint level is defined here + --> $DIR/doctest-edition.rs:3:9 + | +LL | #![deny(rustdoc::invalid_rust_codeblocks)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: error from rustc: prefix `foo` is unknown +help: mark blocks that do not contain Rust code as text + | +LL | //! ```text + | ~~~~~~~ + +error: aborting due to previous error + diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index beebb118399f3..b0fc5120f08f2 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -4,6 +4,14 @@ use std::thread; +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + /* Test Send Trait Migration */ struct SendPointer(*mut i32); unsafe impl Send for SendPointer {} @@ -42,19 +50,19 @@ fn test_sync_trait() { } /* Test Clone Trait Migration */ -struct S(String); +struct S(Foo); struct T(i32); struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo(0)), T(0)) } } fn test_clone_trait() { - let f = U(S(String::from("Hello World")), T(0)); + let f = U(S(Foo(0)), T(0)); let c = || { let _ = &f; //~^ ERROR: `Clone` trait implementation for closure and drop order diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index 812ecae262f77..2bcf9a795edbd 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -4,6 +4,14 @@ use std::thread; +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + /* Test Send Trait Migration */ struct SendPointer(*mut i32); unsafe impl Send for SendPointer {} @@ -42,19 +50,19 @@ fn test_sync_trait() { } /* Test Clone Trait Migration */ -struct S(String); +struct S(Foo); struct T(i32); struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo(0)), T(0)) } } fn test_clone_trait() { - let f = U(S(String::from("Hello World")), T(0)); + let f = U(S(Foo(0)), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 98396abb6ff66..8d2d3553d4040 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure - --> $DIR/auto_traits.rs:14:19 + --> $DIR/auto_traits.rs:22:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` @@ -24,7 +24,7 @@ LL | *fptr.0 = 20; ... error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/auto_traits.rs:34:19 + --> $DIR/auto_traits.rs:42:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` @@ -44,7 +44,7 @@ LL | *fptr.0.0 = 20; ... error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/auto_traits.rs:58:13 + --> $DIR/auto_traits.rs:66:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed index f91454aa2111e..9a6db588c8bf5 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed @@ -3,6 +3,14 @@ // check-pass #![warn(rust_2021_compatibility)] +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + macro_rules! m { (@ $body:expr) => {{ let f = || $body; @@ -15,11 +23,11 @@ macro_rules! m { } fn main() { - let a = (1.to_string(), 2.to_string()); + let a = (Foo(0), Foo(1)); m!({ let _ = &a; //~^ HELP: add a dummy let x = a.0; - println!("{}", x); + println!("{:?}", x); }); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs index 5a1026d043319..08cc24b4b3fe8 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs @@ -3,6 +3,14 @@ // check-pass #![warn(rust_2021_compatibility)] +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + macro_rules! m { (@ $body:expr) => {{ let f = || $body; @@ -15,10 +23,10 @@ macro_rules! m { } fn main() { - let a = (1.to_string(), 2.to_string()); + let a = (Foo(0), Foo(1)); m!({ //~^ HELP: add a dummy let x = a.0; - println!("{}", x); + println!("{:?}", x); }); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr index e6e5598f6d2a1..a2a9da5f87ced 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr @@ -1,5 +1,5 @@ warning: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/closure-body-macro-fragment.rs:8:17 + --> $DIR/closure-body-macro-fragment.rs:16:17 | LL | let f = || $body; | _________________^ @@ -15,7 +15,7 @@ LL | / m!({ LL | | LL | | let x = a.0; | | --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0` -LL | | println!("{}", x); +LL | | println!("{:?}", x); LL | | }); | |_______- in this macro invocation | diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed index c82bc369f4301..2652bf5988e65 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed @@ -1,169 +1,38 @@ +// run-pass // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] -//~^ NOTE: the lint level is defined here +#![allow(unused)] // Test cases for types that implement an insignificant drop (stlib defined) -// `t` needs Drop because one of its elements needs drop, -// therefore precise capture might affect drop ordering -fn test1_all_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); +macro_rules! test_insig_dtor_for_type { + ($t: ty, $disambiguator: ident) => { + mod $disambiguator { + use std::collections::*; + use std::rc::Rc; + use std::sync::Mutex; - let c = || { - let _ = (&t, &t1, &t2); - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured + fn test_for_type(t: $t) { + let tup = (Mutex::new(0), t); - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` - let _t2 = t2.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0` + let _c = || tup.0; + } + } }; - - c(); } -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure -//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure - -// String implements drop and therefore should be migrated. -// But in this test cases, `t2` is completely captured and when it is dropped won't be affected -fn test2_only_precise_paths_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); - - let c = || { - let _ = (&t, &t1); - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` - let _t2 = t2; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure - -// If a variable would've not been captured by value then it would've not been -// dropped with the closure and therefore doesn't need migration. -fn test3_only_by_value_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let c = || { - let _ = &t; - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - println!("{}", t1.1); - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Copy types get copied into the closure instead of move. Therefore we don't need to -// migrate then as their drop order isn't tied to the closure. -fn test4_only_non_copy_types_need_migration() { - let t = (String::new(), String::new()); - - // `t1` is Copy because all of its elements are Copy - let t1 = (0i32, 0i32); - - let c = || { - let _ = &t; - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn test5_only_drop_types_need_migration() { - struct S(i32, i32); - let t = (String::new(), String::new()); - - // `s` doesn't implement Drop or any elements within it, and doesn't need migration - let s = S(0i32, 0i32); - - let c = || { - let _ = &t; - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _s = s.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Since we are using a move closure here, both `t` and `t1` get moved -// even though they are being used by ref inside the closure. -fn test6_move_closures_non_copy_types_might_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let c = move || { - let _ = (&t1, &t); - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured - println!("{} {}", t1.1, t.1); - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1` - //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure - -// Test migration analysis in case of Drop + Non Drop aggregates. -// Note we need migration here only because the non-copy (because Drop type) is captured, -// otherwise we won't need to, since we can get away with just by ref capture in that case. -fn test7_drop_non_drop_aggregate_need_migration() { - let t = (String::new(), String::new(), 0i32); - - let c = || { - let _ = &t; - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn main() { - test1_all_need_migration(); - test2_only_precise_paths_need_migration(); - test3_only_by_value_need_migration(); - test4_only_non_copy_types_need_migration(); - test5_only_drop_types_need_migration(); - test6_move_closures_non_copy_types_might_need_migration(); - test7_drop_non_drop_aggregate_need_migration(); -} +test_insig_dtor_for_type!(i32, prim_i32); +test_insig_dtor_for_type!(Vec, vec_i32); +test_insig_dtor_for_type!(String, string); +test_insig_dtor_for_type!(Vec, vec_string); +test_insig_dtor_for_type!(HashMap, hash_map); +test_insig_dtor_for_type!(BTreeMap, btree_map); +test_insig_dtor_for_type!(LinkedList, linked_list); +test_insig_dtor_for_type!(Rc, rc_i32); +test_insig_dtor_for_type!(Rc, rc_string); +test_insig_dtor_for_type!(std::vec::IntoIter, vec_into_iter); +test_insig_dtor_for_type!(btree_map::IntoIter, btree_map_into_iter); +test_insig_dtor_for_type!(std::array::IntoIter, array_into_iter); + +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs index 57ab15ae8f243..2652bf5988e65 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs @@ -1,162 +1,38 @@ +// run-pass // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] -//~^ NOTE: the lint level is defined here +#![allow(unused)] // Test cases for types that implement an insignificant drop (stlib defined) -// `t` needs Drop because one of its elements needs drop, -// therefore precise capture might affect drop ordering -fn test1_all_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); +macro_rules! test_insig_dtor_for_type { + ($t: ty, $disambiguator: ident) => { + mod $disambiguator { + use std::collections::*; + use std::rc::Rc; + use std::sync::Mutex; - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured + fn test_for_type(t: $t) { + let tup = (Mutex::new(0), t); - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` - let _t2 = t2.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0` + let _c = || tup.0; + } + } }; - - c(); } -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure -//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure - -// String implements drop and therefore should be migrated. -// But in this test cases, `t2` is completely captured and when it is dropped won't be affected -fn test2_only_precise_paths_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); - - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` - let _t2 = t2; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure - -// If a variable would've not been captured by value then it would've not been -// dropped with the closure and therefore doesn't need migration. -fn test3_only_by_value_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - println!("{}", t1.1); - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Copy types get copied into the closure instead of move. Therefore we don't need to -// migrate then as their drop order isn't tied to the closure. -fn test4_only_non_copy_types_need_migration() { - let t = (String::new(), String::new()); - - // `t1` is Copy because all of its elements are Copy - let t1 = (0i32, 0i32); - - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn test5_only_drop_types_need_migration() { - struct S(i32, i32); - let t = (String::new(), String::new()); - - // `s` doesn't implement Drop or any elements within it, and doesn't need migration - let s = S(0i32, 0i32); - - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _s = s.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Since we are using a move closure here, both `t` and `t1` get moved -// even though they are being used by ref inside the closure. -fn test6_move_closures_non_copy_types_might_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let c = move || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured - println!("{} {}", t1.1, t.1); - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1` - //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure - -// Test migration analysis in case of Drop + Non Drop aggregates. -// Note we need migration here only because the non-copy (because Drop type) is captured, -// otherwise we won't need to, since we can get away with just by ref capture in that case. -fn test7_drop_non_drop_aggregate_need_migration() { - let t = (String::new(), String::new(), 0i32); - - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn main() { - test1_all_need_migration(); - test2_only_precise_paths_need_migration(); - test3_only_by_value_need_migration(); - test4_only_non_copy_types_need_migration(); - test5_only_drop_types_need_migration(); - test6_move_closures_non_copy_types_might_need_migration(); - test7_drop_non_drop_aggregate_need_migration(); -} +test_insig_dtor_for_type!(i32, prim_i32); +test_insig_dtor_for_type!(Vec, vec_i32); +test_insig_dtor_for_type!(String, string); +test_insig_dtor_for_type!(Vec, vec_string); +test_insig_dtor_for_type!(HashMap, hash_map); +test_insig_dtor_for_type!(BTreeMap, btree_map); +test_insig_dtor_for_type!(LinkedList, linked_list); +test_insig_dtor_for_type!(Rc, rc_i32); +test_insig_dtor_for_type!(Rc, rc_string); +test_insig_dtor_for_type!(std::vec::IntoIter, vec_into_iter); +test_insig_dtor_for_type!(btree_map::IntoIter, btree_map_into_iter); +test_insig_dtor_for_type!(std::array::IntoIter, array_into_iter); + +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr deleted file mode 100644 index 7989a8fa5ccae..0000000000000 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr +++ /dev/null @@ -1,161 +0,0 @@ -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:15:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -LL | -LL | let _t1 = t1.0; - | ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` -LL | -LL | let _t2 = t2.0; - | ---- in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0` -... -LL | } - | - - | | - | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure - | in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure - | -note: the lint level is defined here - --> $DIR/insignificant_drop.rs:3:9 - | -LL | #![deny(rust_2021_incompatible_closure_captures)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: for more information, see -help: add a dummy let to cause `t`, `t1`, `t2` to be fully captured - | -LL ~ let c = || { -LL + let _ = (&t, &t1, &t2); - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:41:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -LL | -LL | let _t1 = t1.0; - | ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` -... -LL | } - | - - | | - | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t`, `t1` to be fully captured - | -LL ~ let c = || { -LL + let _ = (&t, &t1); - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:62:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -... -LL | } - | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:83:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -... -LL | } - | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:104:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -... -LL | } - | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:122:13 - | -LL | let c = move || { - | ^^^^^^^ -... -LL | println!("{} {}", t1.1, t.1); - | ---- --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1` - | | - | in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1` -... -LL | } - | - - | | - | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure - | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t1`, `t` to be fully captured - | -LL ~ let c = move || { -LL + let _ = (&t1, &t); - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:142:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -... -LL | } - | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: aborting due to 7 previous errors - diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed index e672d9266fcd1..d985e3bb9ec74 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed @@ -5,13 +5,15 @@ #![feature(rustc_attrs)] #![allow(unused)] +use std::sync::Mutex; + + #[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, - y: i32, + y: Mutex, } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } @@ -21,15 +23,15 @@ impl Drop for SigDrop { fn drop(&mut self) {} } +#[rustc_insignificant_dtor] struct GenericStruct(T, T); -struct Wrapper(GenericStruct, i32); - impl Drop for GenericStruct { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } +struct Wrapper(GenericStruct, i32); + // `SigDrop` implements drop and therefore needs to be migrated. fn significant_drop_needs_migration() { let t = (SigDrop {}, SigDrop {}); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs index 45850ec5f36dc..f95d34eeb299a 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs @@ -5,13 +5,15 @@ #![feature(rustc_attrs)] #![allow(unused)] +use std::sync::Mutex; + + #[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, - y: i32, + y: Mutex, } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } @@ -21,15 +23,15 @@ impl Drop for SigDrop { fn drop(&mut self) {} } +#[rustc_insignificant_dtor] struct GenericStruct(T, T); -struct Wrapper(GenericStruct, i32); - impl Drop for GenericStruct { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } +struct Wrapper(GenericStruct, i32); + // `SigDrop` implements drop and therefore needs to be migrated. fn significant_drop_needs_migration() { let t = (SigDrop {}, SigDrop {}); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr index 961834aca194d..832a81711b137 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop_attr_migrations.rs:37:13 + --> $DIR/insignificant_drop_attr_migrations.rs:39:13 | LL | let c = || { | ^^ @@ -23,7 +23,7 @@ LL + let _ = &t; | error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop_attr_migrations.rs:57:13 + --> $DIR/insignificant_drop_attr_migrations.rs:59:13 | LL | let c = move || { | ^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs index a527bf42e574a..3f184a67fbac9 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs @@ -3,6 +3,7 @@ #![deny(rust_2021_incompatible_closure_captures)] #![feature(rustc_attrs)] #![allow(unused)] +#[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, @@ -10,7 +11,6 @@ struct InsignificantDropPoint { } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed index b9dd8a20b093f..31fe494dc795a 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed @@ -5,8 +5,17 @@ #![deny(rust_2021_incompatible_closure_captures)] //~^ NOTE: the lint level is defined here + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + fn main() { - let a = ("hey".to_string(), "123".to_string()); + let a = (Foo(0), Foo(1)); let _ = || { let _ = &a; dbg!(a.0) }; //~^ ERROR: drop order //~| NOTE: will only capture `a.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs b/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs index f7ccdb754b858..0f0c497492290 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs @@ -5,8 +5,17 @@ #![deny(rust_2021_incompatible_closure_captures)] //~^ NOTE: the lint level is defined here + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + fn main() { - let a = ("hey".to_string(), "123".to_string()); + let a = (Foo(0), Foo(1)); let _ = || dbg!(a.0); //~^ ERROR: drop order //~| NOTE: will only capture `a.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr index d1f959dfc520e..5046a4bcbb4b3 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/macro.rs:10:13 + --> $DIR/macro.rs:19:13 | LL | let _ = || dbg!(a.0); | ^^^^^^^^---^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed index ef90257474a9f..11218eff1337f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed @@ -4,7 +4,22 @@ use std::thread; -struct S(String); +#[derive(Debug)] +struct Foo(String); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +impl Foo { + fn from(s: &str) -> Self { + Self(String::from(s)) + } +} + + +struct S(Foo); #[derive(Clone)] struct T(i32); @@ -13,13 +28,13 @@ struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo::from("Hello World")), T(0)) } } fn test_multi_issues() { - let f1 = U(S(String::from("foo")), T(0)); - let f2 = U(S(String::from("bar")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); + let f2 = U(S(Foo::from("bar")), T(0)); let c = || { let _ = (&f1, &f2); //~^ ERROR: `Clone` trait implementation for closure and drop order @@ -39,7 +54,7 @@ fn test_multi_issues() { //~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure fn test_capturing_all_disjoint_fields_individually() { - let f1 = U(S(String::from("foo")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure @@ -60,12 +75,12 @@ struct U1(S, T, S); impl Clone for U1 { fn clone(&self) -> Self { - U1(S(String::from("foo")), T(0), S(String::from("bar"))) + U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))) } } fn test_capturing_several_disjoint_fields_individually_1() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure @@ -85,7 +100,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { } fn test_capturing_several_disjoint_fields_individually_2() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure and drop order diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs index b9644c18d28e2..02f2faa2e8741 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs @@ -4,7 +4,22 @@ use std::thread; -struct S(String); +#[derive(Debug)] +struct Foo(String); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +impl Foo { + fn from(s: &str) -> Self { + Self(String::from(s)) + } +} + + +struct S(Foo); #[derive(Clone)] struct T(i32); @@ -13,13 +28,13 @@ struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo::from("Hello World")), T(0)) } } fn test_multi_issues() { - let f1 = U(S(String::from("foo")), T(0)); - let f2 = U(S(String::from("bar")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); + let f2 = U(S(Foo::from("bar")), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -38,7 +53,7 @@ fn test_multi_issues() { //~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure fn test_capturing_all_disjoint_fields_individually() { - let f1 = U(S(String::from("foo")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -58,12 +73,12 @@ struct U1(S, T, S); impl Clone for U1 { fn clone(&self) -> Self { - U1(S(String::from("foo")), T(0), S(String::from("bar"))) + U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))) } } fn test_capturing_several_disjoint_fields_individually_1() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { //~^ ERROR: `Clone` trait implementation for closure //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -82,7 +97,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { } fn test_capturing_several_disjoint_fields_individually_2() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 8bee950c13eca..d425db5aa998c 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:23:13 + --> $DIR/multi_diagnostics.rs:38:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -26,7 +26,7 @@ LL + let _ = (&f1, &f2); | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:42:13 + --> $DIR/multi_diagnostics.rs:57:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -42,7 +42,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:67:13 + --> $DIR/multi_diagnostics.rs:82:13 | LL | let c = || { | ^^ @@ -64,7 +64,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:86:13 + --> $DIR/multi_diagnostics.rs:101:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -89,7 +89,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/multi_diagnostics.rs:119:19 + --> $DIR/multi_diagnostics.rs:134:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed index aca0b2a96ac56..63e4000e833eb 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed @@ -165,7 +165,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() { fn test8_drop_order_and_blocks() { { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); { let c = || { let _ = &tuple; @@ -184,7 +184,7 @@ fn test8_drop_order_and_blocks() { fn test9_drop_order_and_nested_closures() { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); let b = || { let c = || { let _ = &tuple; @@ -202,6 +202,19 @@ fn test9_drop_order_and_nested_closures() { b(); } +// Test that we migrate if drop order of Vec would be affected if T is a significant drop type +fn test10_vec_of_significant_drop_type() { + + let tup = (Foo(0), vec![Foo(3)]); + + let _c = || { let _ = &tup; tup.0 }; + //~^ ERROR: drop order + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `tup` to be fully captured + //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0` +} +//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure + fn main() { test1_all_need_migration(); test2_only_precise_paths_need_migration(); @@ -212,4 +225,5 @@ fn main() { test7_move_closures_non_copy_types_might_need_migration(); test8_drop_order_and_blocks(); test9_drop_order_and_nested_closures(); + test10_vec_of_significant_drop_type(); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs index fd4134a770479..9d9c54298cf11 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs @@ -158,7 +158,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() { fn test8_drop_order_and_blocks() { { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); { let c = || { //~^ ERROR: drop order @@ -176,7 +176,7 @@ fn test8_drop_order_and_blocks() { fn test9_drop_order_and_nested_closures() { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); let b = || { let c = || { //~^ ERROR: drop order @@ -193,6 +193,19 @@ fn test9_drop_order_and_nested_closures() { b(); } +// Test that we migrate if drop order of Vec would be affected if T is a significant drop type +fn test10_vec_of_significant_drop_type() { + + let tup = (Foo(0), vec![Foo(3)]); + + let _c = || tup.0; + //~^ ERROR: drop order + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `tup` to be fully captured + //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0` +} +//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure + fn main() { test1_all_need_migration(); test2_only_precise_paths_need_migration(); @@ -203,4 +216,5 @@ fn main() { test7_move_closures_non_copy_types_might_need_migration(); test8_drop_order_and_blocks(); test9_drop_order_and_nested_closures(); + test10_vec_of_significant_drop_type(); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr index e9170eba3f176..fa1f83c37823f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr @@ -195,5 +195,22 @@ LL ~ let c = || { LL + let _ = &tuple; | -error: aborting due to 9 previous errors +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:201:18 + | +LL | let _c = || tup.0; + | ^^^----- + | | + | in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0` +... +LL | } + | - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure + | + = note: for more information, see +help: add a dummy let to cause `tup` to be fully captured + | +LL | let _c = || { let _ = &tup; tup.0 }; + | +++++++++++++++ + + +error: aborting due to 10 previous errors diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs new file mode 100644 index 0000000000000..2f8cddc06bab1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs @@ -0,0 +1,101 @@ +// edition:2021 + +// Tests that in cases where we individually capture all the fields of a type, +// we still drop them in the order they would have been dropped in the 2018 edition. + +// NOTE: It is *critical* that the order of the min capture NOTES in the stderr output +// does *not* change! + +#![feature(rustc_attrs)] + +#[derive(Debug)] +struct HasDrop; +impl Drop for HasDrop { + fn drop(&mut self) { + println!("dropped"); + } +} + +fn test_one() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: Min Capture analysis includes: + //~| ERROR + println!("{:?}", a.0); + //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", a.1); + //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow + //~| NOTE + + println!("{:?}", b.0); + //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", b.1); + //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow + //~| NOTE + }; +} + +fn test_two() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: Min Capture analysis includes: + //~| ERROR + println!("{:?}", a.1); + //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", a.0); + //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow + //~| NOTE + + println!("{:?}", b.1); + //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", b.0); + //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow + //~| NOTE + }; +} + +fn test_three() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: Min Capture analysis includes: + //~| ERROR + println!("{:?}", b.1); + //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", a.1); + //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", a.0); + //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow + //~| NOTE + + println!("{:?}", b.0); + //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow + //~| NOTE + }; +} + +fn main() { + test_one(); + test_two(); + test_three(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr new file mode 100644 index 0000000000000..2d1dc8727c255 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr @@ -0,0 +1,228 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/preserve_field_drop_order.rs:23: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/preserve_field_drop_order.rs:49: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/preserve_field_drop_order.rs:75: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: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:26:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.0); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:29:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:32:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:36:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:39:26 + | +LL | println!("{:?}", b.1); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:26:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.0); +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:29:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Min Capture a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:32:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Min Capture b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:36:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Min Capture b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:39:26 + | +LL | println!("{:?}", b.1); + | ^^^ + +error: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:52:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:55:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:58:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:62:26 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:65:26 + | +LL | println!("{:?}", b.0); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:52:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:58:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Min Capture a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:55:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Min Capture b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:65:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Min Capture b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:62:26 + | +LL | println!("{:?}", b.1); + | ^^^ + +error: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:78:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", b.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:81:26 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:84:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:87:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:91:26 + | +LL | println!("{:?}", b.0); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:78:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", b.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:91:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Min Capture b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:81:26 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Min Capture a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:87:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Min Capture a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:84:26 + | +LL | println!("{:?}", a.1); + | ^^^ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs new file mode 100644 index 0000000000000..1cae776dd68bc --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs @@ -0,0 +1,58 @@ +// run-pass +// check-run-results +// revisions: twenty_eighteen twenty_twentyone +// [twenty_eighteen]compile-flags: --edition 2018 +// [twenty_twentyone]compile-flags: --edition 2021 + +#[derive(Debug)] +struct Dropable(&'static str); + +impl Drop for Dropable { + fn drop(&mut self) { + println!("Dropping {}", self.0) + } +} + +#[derive(Debug)] +struct A { + x: Dropable, + y: Dropable, +} + +#[derive(Debug)] +struct B { + c: A, + d: A, +} + +#[derive(Debug)] +struct R<'a> { + c: &'a A, + d: &'a A, +} + +fn main() { + let a = A { x: Dropable("x"), y: Dropable("y") }; + + let c = move || println!("{:?} {:?}", a.y, a.x); + + c(); + + let b = B { + c: A { x: Dropable("b.c.x"), y: Dropable("b.c.y") }, + d: A { x: Dropable("b.d.x"), y: Dropable("b.d.y") }, + }; + + let d = move || println!("{:?} {:?} {:?} {:?}", b.d.y, b.d.x, b.c.y, b.c.x); + + d(); + + let r = R { + c: &A { x: Dropable("r.c.x"), y: Dropable("r.c.y") }, + d: &A { x: Dropable("r.d.x"), y: Dropable("r.d.y") }, + }; + + let e = move || println!("{:?} {:?} {:?} {:?}", r.d.y, r.d.x, r.c.y, r.c.x); + + e(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout new file mode 100644 index 0000000000000..557d047c1d524 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout @@ -0,0 +1,13 @@ +Dropable("y") Dropable("x") +Dropable("b.d.y") Dropable("b.d.x") Dropable("b.c.y") Dropable("b.c.x") +Dropable("r.d.y") Dropable("r.d.x") Dropable("r.c.y") Dropable("r.c.x") +Dropping r.d.x +Dropping r.d.y +Dropping r.c.x +Dropping r.c.y +Dropping b.c.x +Dropping b.c.y +Dropping b.d.x +Dropping b.d.y +Dropping x +Dropping y diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout new file mode 100644 index 0000000000000..557d047c1d524 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout @@ -0,0 +1,13 @@ +Dropable("y") Dropable("x") +Dropable("b.d.y") Dropable("b.d.x") Dropable("b.c.y") Dropable("b.c.x") +Dropable("r.d.y") Dropable("r.d.x") Dropable("r.c.y") Dropable("r.c.x") +Dropping r.d.x +Dropping r.d.y +Dropping r.c.x +Dropping r.c.y +Dropping b.c.x +Dropping b.c.y +Dropping b.d.x +Dropping b.d.y +Dropping x +Dropping y diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr index 51f6faab3c7e4..9efb5dc75f4f0 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr @@ -8,6 +8,7 @@ LL | impl Foo for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions + = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions error: aborting due to previous error diff --git a/src/test/ui/macros/lint-trailing-macro-call.rs b/src/test/ui/macros/lint-trailing-macro-call.rs new file mode 100644 index 0000000000000..f8e847563915e --- /dev/null +++ b/src/test/ui/macros/lint-trailing-macro-call.rs @@ -0,0 +1,16 @@ +// check-pass +// +// Ensures that we properly lint +// a removed 'expression' resulting from a macro +// in trailing expression position + +macro_rules! expand_it { + () => { + #[cfg(FALSE)] 25; //~ WARN trailing semicolon in macro + //~| WARN this was previously + } +} + +fn main() { + expand_it!() +} diff --git a/src/test/ui/macros/lint-trailing-macro-call.stderr b/src/test/ui/macros/lint-trailing-macro-call.stderr new file mode 100644 index 0000000000000..a98a559c8afad --- /dev/null +++ b/src/test/ui/macros/lint-trailing-macro-call.stderr @@ -0,0 +1,18 @@ +warning: trailing semicolon in macro used in expression position + --> $DIR/lint-trailing-macro-call.rs:9:25 + | +LL | #[cfg(FALSE)] 25; + | ^ +... +LL | expand_it!() + | ------------ in this macro invocation + | + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it` + = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/src/test/ui/mir/remove-zsts-query-cycle.rs b/src/test/ui/mir/remove-zsts-query-cycle.rs new file mode 100644 index 0000000000000..8f93c6cadff5a --- /dev/null +++ b/src/test/ui/mir/remove-zsts-query-cycle.rs @@ -0,0 +1,16 @@ +// Regression test for #88972. Used to cause a query cycle: +// optimized mir -> remove zsts -> layout of a generator -> optimized mir. +// +// edition:2018 +// compile-flags: --crate-type=lib +// build-pass + +pub async fn listen() -> Result<(), std::io::Error> { + let f = do_async(); + std::mem::forget(f); + Ok(()) +} + +pub async fn do_async() { + listen().await.unwrap() +} diff --git a/src/tools/cargo b/src/tools/cargo index d199d817e4bb7..4ed5d137baff5 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit d199d817e4bb70facc710716e73b5dddf80bc055 +Subproject commit 4ed5d137baff5eccf1bae5a7b2ae4b57efad4a7d