From a29557c9a672d24dcbd69c4237989d3d31fb4d61 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 4 Oct 2021 12:08:31 -0700 Subject: [PATCH 01/14] [beta] Update cargo --- Cargo.lock | 4 ++-- src/tools/cargo | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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 From c0f9379260531ae3780c71cc924b4c997abd12c2 Mon Sep 17 00:00:00 2001 From: bors Date: Thu, 23 Sep 2021 06:18:07 +0000 Subject: [PATCH 02/14] Auto merge of #88587 - bdbai:fix/uwpio, r=joshtriplett Fix WinUWP std compilation errors due to I/O safety I/O safety for Windows has landed in #87329. However, it does not cover UWP specific parts and prevents all UWP targets from building. See https://github.com/YtFlow/Maple/issues/18. This PR fixes these compile errors when building std for UWP targets. --- library/std/src/sys/windows/fs.rs | 4 ++-- library/std/src/sys/windows/stdio_uwp.rs | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) 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) } } From d2e10d5cc60eab699f7ae0f11fe5be4c7ccf1b53 Mon Sep 17 00:00:00 2001 From: bors Date: Thu, 16 Sep 2021 16:46:02 +0000 Subject: [PATCH 03/14] Auto merge of #88979 - tmiasko:no-remove-zsts-in-generators, r=oli-obk Disable RemoveZsts in generators to avoid query cycles Querying layout of a generator requires its optimized MIR. Thus computing layout during MIR optimization of a generator might create a query cycle. Disable RemoveZsts in generators to avoid the issue (similar approach is used in ConstProp transform already). Fixes #88972. --- compiler/rustc_mir/src/transform/remove_zsts.rs | 4 ++++ src/test/ui/mir/remove-zsts-query-cycle.rs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/ui/mir/remove-zsts-query-cycle.rs 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/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() +} From b893d562d6f2fb9d1715374ece11d2d4784d8ac3 Mon Sep 17 00:00:00 2001 From: bors Date: Sat, 18 Sep 2021 17:18:28 +0000 Subject: [PATCH 04/14] Auto merge of #88994 - Aaron1011:intercrate-caching, r=jackh726 Disable the evaluation cache when in intercrate mode It's possible to use the same `InferCtxt` with both an intercrate and non-intercrate `SelectionContext`. However, the local (inferctxt) evaluation cache is not aware of this distinction, so this kind of `InferCtxt` re-use will pollute the cache wth bad results. This commit avoids the issue by disabling the evaluation cache entirely during intercrate mode. --- .../src/traits/select/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 22013fb79cf79..42a3d780c67c0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -982,6 +982,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 +1012,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"); From c981a57fe453da52f61a311799518af2cdbc766a Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 19 Sep 2021 17:31:31 +0900 Subject: [PATCH 05/14] Rollup merge of #88996 - Aaron1011:trailing-macro-semi, r=petrochenkov Fix linting when trailing macro expands to a trailing semi When a macro is used in the trailing expression position of a block (e.g. `fn foo() { my_macro!() }`), we currently parse it as an expression, rather than a statement. As a result, we ended up using the `NodeId` of the containing statement as our `lint_node_id`, even though we don't normally do this for macro calls. If such a macro expands to an expression with a `#[cfg]` attribute, then the trailing statement can get removed entirely. This lead to an ICE, since we were usng the `NodeId` of the expression to emit a lint. Ths commit makes us skip updating `lint_node_id` when handling a macro in trailing expression position. This will cause us to lint at the closest parent of the macro call. --- compiler/rustc_expand/src/expand.rs | 15 +++++++++------ src/test/ui/macros/lint-trailing-macro-call.rs | 16 ++++++++++++++++ .../ui/macros/lint-trailing-macro-call.stderr | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/macros/lint-trailing-macro-call.rs create mode 100644 src/test/ui/macros/lint-trailing-macro-call.stderr 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/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 + From f8e5fdaab6c4fb99a730fd0712738806c3325127 Mon Sep 17 00:00:00 2001 From: bors Date: Tue, 21 Sep 2021 13:25:14 +0000 Subject: [PATCH 06/14] Auto merge of #89125 - Aaron1011:remove-intercrate-cache, r=jackh726 Don't use projection cache or candidate cache in intercrate mode Fixes #88969 It appears that *just* disabling the evaluation cache (in #88994) leads to other issues involving intercrate mode caching. I suspect that since we now always end up performing the full evaluation in intercrate mode, we end up 'polluting' the candidate and projection caches with results that depend on being in intercrate mode in some way. Previously, we might have hit a cached evaluation (stored during non-intercrate mode), and skipped doing this extra work in intercrate mode. The whole situation with intercrate mode caching is turning into a mess. Ideally, we would remove intercrate mode entirely - however, this might require waiting on Chalk. --- .../src/traits/project.rs | 30 +++++++++++++++---- .../src/traits/select/mod.rs | 18 +++++++++++ ...oherence-projection-conflict-orphan.stderr | 1 + 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 7038f16a2c9c4..af546c86d226c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -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/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 42a3d780c67c0..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 { @@ -1201,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; @@ -1237,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/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 From 945cf4fb21efde1ca765778dec263492bc560af9 Mon Sep 17 00:00:00 2001 From: bors Date: Sun, 26 Sep 2021 19:36:00 +0000 Subject: [PATCH 07/14] Auto merge of #89144 - sexxi-goose:insig_stdlib, r=nikomatsakis 2229: Mark insignificant dtor in stdlib I looked at all public [stdlib Drop implementations](https://doc.rust-lang.org/stable/std/ops/trait.Drop.html#implementors) and categorized them into Insigificant/Maybe/Significant Drop. Reasons are noted here: https://docs.google.com/spreadsheets/d/19edb9r5lo2UqMrCOVjV0fwcSdS-R7qvKNL76q7tO8VA/edit#gid=1838773501 One thing missing from this PR is tagging HashMap as insigificant destructor as that needs some discussion. r? `@Mark-Simulacrum` cc `@nikomatsakis` --- compiler/rustc_ty_utils/src/needs_drop.rs | 76 +++++-- library/alloc/src/collections/btree/map.rs | 2 + library/alloc/src/collections/linked_list.rs | 1 + .../alloc/src/collections/vec_deque/mod.rs | 1 + library/alloc/src/rc.rs | 1 + library/alloc/src/vec/into_iter.rs | 1 + library/alloc/src/vec/mod.rs | 1 + library/core/src/array/iter.rs | 1 + library/std/src/collections/hash/map.rs | 1 + .../migrations/auto_traits.fixed | 14 +- .../migrations/auto_traits.rs | 14 +- .../migrations/auto_traits.stderr | 6 +- .../closure-body-macro-fragment.fixed | 12 +- .../migrations/closure-body-macro-fragment.rs | 12 +- .../closure-body-macro-fragment.stderr | 4 +- .../migrations/insignificant_drop.fixed | 185 +++--------------- .../migrations/insignificant_drop.rs | 178 +++-------------- .../migrations/insignificant_drop.stderr | 161 --------------- .../insignificant_drop_attr_migrations.fixed | 12 +- .../insignificant_drop_attr_migrations.rs | 12 +- .../insignificant_drop_attr_migrations.stderr | 4 +- .../insignificant_drop_attr_no_migrations.rs | 2 +- .../migrations/macro.fixed | 11 +- .../2229_closure_analysis/migrations/macro.rs | 11 +- .../migrations/macro.stderr | 2 +- .../migrations/multi_diagnostics.fixed | 31 ++- .../migrations/multi_diagnostics.rs | 31 ++- .../migrations/multi_diagnostics.stderr | 10 +- .../migrations/significant_drop.fixed | 18 +- .../migrations/significant_drop.rs | 18 +- .../migrations/significant_drop.stderr | 19 +- 31 files changed, 307 insertions(+), 545 deletions(-) delete mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr 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/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/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/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 From 4779e624e55e2f365d951e9f0183f9075a3fcc9f Mon Sep 17 00:00:00 2001 From: Jubilee <46493976+workingjubilee@users.noreply.github.com> Date: Thu, 23 Sep 2021 17:31:46 -0700 Subject: [PATCH 08/14] Rollup merge of #89184 - joshtriplett:master, r=estebank Temporarily rename int_roundings functions to avoid conflicts These functions are unstable, but because they're inherent they still introduce conflicts with stable trait functions in crates. Temporarily rename them to fix these conflicts, until we can resolve those conflicts in a better way. --- library/core/src/num/int_macros.rs | 38 +++++++++++++-------------- library/core/src/num/uint_macros.rs | 14 +++++----- library/core/tests/num/int_macros.rs | 34 ++++++++++++------------ library/core/tests/num/uint_macros.rs | 10 +++---- 4 files changed, 48 insertions(+), 48 deletions(-) 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] From d0a803317c650498c2f229cde6cb2804704b8b81 Mon Sep 17 00:00:00 2001 From: Jubilee <46493976+workingjubilee@users.noreply.github.com> Date: Fri, 24 Sep 2021 11:40:14 -0700 Subject: [PATCH 09/14] Rollup merge of #89208 - wesleywiser:rfc_2229_droporder, r=nikomatsakis [rfc 2229] Drop fully captured upvars in the same order as the regular drop code Currently, with the new 2021 edition, if a closure captures all of the fields of an upvar, we'll drop those fields in the order they are used within the closure instead of the normal drop order (the definition order of the fields in the type). This changes that so we sort the captured fields by the definition order which causes them to drop in that same order as well. Fixes rust-lang/project-rfc-2229#42 r? `@nikomatsakis` --- compiler/rustc_typeck/src/check/upvar.rs | 73 +++++- .../preserve_field_drop_order.rs | 101 ++++++++ .../preserve_field_drop_order.stderr | 228 ++++++++++++++++++ .../preserve_field_drop_order2.rs | 58 +++++ ...eld_drop_order2.twenty_eighteen.run.stdout | 13 + ...ld_drop_order2.twenty_twentyone.run.stdout | 13 + 6 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout 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/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 From a6c3c1ba3e0a3a41a5529ed8a2d15c70405c3638 Mon Sep 17 00:00:00 2001 From: bors Date: Tue, 28 Sep 2021 05:50:00 +0000 Subject: [PATCH 10/14] Auto merge of #89277 - jyn514:codeblock-edition, r=GuillaumeGomez Use the correct edition for syntax highlighting doctests Previously it would unconditionally use edition 2015, which was incorrect. Helps with https://github.com/rust-lang/rust/issues/89135 in that you can now override the doctest to be 2018 edition instead of being forced to fix the error. This doesn't resolve any of the deeper problems that rustdoc disagrees with most rust users on what a code block is. cc `@Mark-Simulacrum` --- src/librustdoc/html/markdown.rs | 23 +++++++------------ .../passes/check_code_block_syntax.rs | 18 +++++++++++---- src/test/rustdoc-ui/doctest-edition.rs | 16 +++++++++++++ src/test/rustdoc-ui/doctest-edition.stderr | 22 ++++++++++++++++++ 4 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 src/test/rustdoc-ui/doctest-edition.rs create mode 100644 src/test/rustdoc-ui/doctest-edition.stderr 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..1643d605375a1 --- /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 + From bb4672b168bdbd7c03ba137104d076c1a99d635a Mon Sep 17 00:00:00 2001 From: bors Date: Mon, 27 Sep 2021 14:08:13 +0000 Subject: [PATCH 11/14] Auto merge of #89285 - jackh726:issue-88862, r=nikomatsakis Don't normalize opaque types with escaping late-bound regions Fixes #88862 Turns out, this has some really bad perf implications in large types (issue #88862). While we technically can handle them fine, it doesn't change test output either way. For now, revert with an added benchmark. Future attempts to change this back will have to consider perf. Needs a perf run once https://github.com/rust-lang/rustc-perf/pull/1033 is merged r? `@nikomatsakis` --- compiler/rustc_trait_selection/src/traits/project.rs | 8 ++++---- .../rustc_trait_selection/src/traits/query/normalize.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index af546c86d226c..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( 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) { From a6b733599ec44bc1f31664a221078d7b5d5a7ae1 Mon Sep 17 00:00:00 2001 From: bors Date: Sun, 3 Oct 2021 19:03:23 +0000 Subject: [PATCH 12/14] Auto merge of #89486 - rusticstuff:docker_letsencrypt_ca_update, r=Mark-Simulacrum Update Let's Encrypt ROOT CA certificate in dist-(i686|x86_64)-linux docker images The DST Root CA X3 used by Let's Encrypt has expired ([Let's Encrypt announcement](https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/)). This patch installs the new root certificate (ISRG Root X1) and disables the old one. Disabling the old one is necessary because otherwise curl still fails to download from servers with Let's Encrypt certs even though they are cross-signed. Fixes #89484. --- .../host-x86_64/dist-i686-linux/Dockerfile | 5 +++ .../host-x86_64/dist-x86_64-linux/Dockerfile | 5 +++ .../host-x86_64/shared/ISRG_Root_X1.crt | 31 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt 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----- From cfa1cd029ef5454cda349aed6999bb9b63343323 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 4 Oct 2021 13:45:49 -0700 Subject: [PATCH 13/14] Bless src/test/rustdoc-ui/doctest-edition.stderr The backport of #89277 needed adjustment due to another PR (#87915 - Use smaller spans for some structured suggestions) causing the test to have a slightly different span. --- src/test/rustdoc-ui/doctest-edition.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/rustdoc-ui/doctest-edition.stderr b/src/test/rustdoc-ui/doctest-edition.stderr index 1643d605375a1..019f259288cbf 100644 --- a/src/test/rustdoc-ui/doctest-edition.stderr +++ b/src/test/rustdoc-ui/doctest-edition.stderr @@ -16,7 +16,7 @@ LL | #![deny(rustdoc::invalid_rust_codeblocks)] help: mark blocks that do not contain Rust code as text | LL | //! ```text - | ++++ + | ~~~~~~~ error: aborting due to previous error From 06b37f15216362a27f1ac0abd1cb7dc1460d691f Mon Sep 17 00:00:00 2001 From: bors Date: Wed, 29 Sep 2021 22:39:40 +0000 Subject: [PATCH 14/14] Auto merge of #89380 - ehuss:fix-windows-llvm, r=Mark-Simulacrum Fix Windows LLVM issue. GitHub image 20210928.2 added LLVM 12.0.1 to the stock image. However, the `lldb` executable doesn't work, it fails with: > C:/Program Files/LLVM/bin/lldb.exe: error while loading shared libraries: ?: cannot open shared object file: No such file or directory We probably don't want to start testing LLDB on windows anyways (at least not without intent). The hacky solution for now is to just delete the system LLVM. --- src/ci/scripts/install-clang.sh | 6 ++++++ 1 file changed, 6 insertions(+) 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