From 14eb94fe7a3ca3a92d5d7e42744d105c0fc6d527 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sat, 16 Jan 2021 15:41:52 -0800 Subject: [PATCH 01/12] don't suggest erroneous trailing comma after `..` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In #76612, suggestions were added for missing fields in patterns. However, the suggestions are being inserted just at the end of the last field in the pattern—before any trailing comma after the last field. This resulted in the "if you don't care about missing fields" suggestion to recommend code with a trailing comma after the field ellipsis (`..,`), which is actually not legal ("`..` must be at the end and cannot have a trailing comma")! Incidentally, the doc-comment on `error_unmentioned_fields` was using `you_cant_use_this_field` as an example field name (presumably copy-paste inherited from the description of Issue #76077), but the present author found this confusing, because unmentioned fields aren't necessarily unusable. The suggested code in the diff this commit introduces to `destructuring-assignment/struct_destructure_fail.stderr` doesn't work, but it didn't work beforehand, either (because of the "found reserved identifier `_`" thing), so you can't really call it a regression; it could be fixed in a separate PR. Resolves #78511. --- compiler/rustc_typeck/src/check/pat.rs | 32 +++++++++++------ .../struct_destructure_fail.stderr | 4 +-- src/test/ui/error-codes/E0027.rs | 9 +++++ src/test/ui/error-codes/E0027.stderr | 36 +++++++++++++++++-- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index ecc6e8599ad01..79234f076acd1 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1486,11 +1486,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Returns a diagnostic reporting a struct pattern which does not mention some fields. /// /// ```text - /// error[E0027]: pattern does not mention field `you_cant_use_this_field` + /// error[E0027]: pattern does not mention field `bar` /// --> src/main.rs:15:9 /// | /// LL | let foo::Foo {} = foo::Foo::new(); - /// | ^^^^^^^^^^^ missing field `you_cant_use_this_field` + /// | ^^^^^^^^^^^ missing field `bar` /// ``` fn error_unmentioned_fields( &self, @@ -1524,14 +1524,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => return err, }, - [.., field] => ( - match pat.kind { - PatKind::Struct(_, [_, ..], _) => ", ", - _ => "", - }, - "", - field.span.shrink_to_hi(), - ), + [.., field] => { + // if last field has a trailing comma, use the comma + // as the span to avoid trailing comma in ultimate + // suggestion (Issue #78511) + let tail = field.span.shrink_to_hi().until(pat.span.shrink_to_hi()); + let tail_through_comma = self.tcx.sess.source_map().span_through_char(tail, ','); + let sp = if tail_through_comma == tail { + field.span.shrink_to_hi() + } else { + tail_through_comma + }; + ( + match pat.kind { + PatKind::Struct(_, [_, ..], _) => ", ", + _ => "", + }, + "", + sp, + ) + } }; err.span_suggestion( sp, diff --git a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr index 81661a357e750..c0955ef8b065a 100644 --- a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr @@ -32,11 +32,11 @@ LL | Struct { a, _ } = Struct { a: 1, b: 2 }; | help: include the missing field in the pattern | -LL | Struct { a, b, _ } = Struct { a: 1, b: 2 }; +LL | Struct { a, b _ } = Struct { a: 1, b: 2 }; | ^^^ help: if you don't care about this missing field, you can explicitly ignore it | -LL | Struct { a, .., _ } = Struct { a: 1, b: 2 }; +LL | Struct { a, .. _ } = Struct { a: 1, b: 2 }; | ^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/error-codes/E0027.rs b/src/test/ui/error-codes/E0027.rs index 8d08e17893480..e7eca1ce5af97 100644 --- a/src/test/ui/error-codes/E0027.rs +++ b/src/test/ui/error-codes/E0027.rs @@ -3,12 +3,21 @@ struct Dog { age: u32, } + fn main() { let d = Dog { name: "Rusty".to_string(), age: 8 }; match d { Dog { age: x } => {} //~ ERROR pattern does not mention field `name` } + match d { + // trailing comma + Dog { name: x, } => {} //~ ERROR pattern does not mention field `age` + } + match d { + // trailing comma with weird whitespace + Dog { name: x , } => {} //~ ERROR pattern does not mention field `age` + } match d { Dog {} => {} //~ ERROR pattern does not mention fields `name`, `age` } diff --git a/src/test/ui/error-codes/E0027.stderr b/src/test/ui/error-codes/E0027.stderr index cf0ff6311483c..694bbc358fee2 100644 --- a/src/test/ui/error-codes/E0027.stderr +++ b/src/test/ui/error-codes/E0027.stderr @@ -1,5 +1,5 @@ error[E0027]: pattern does not mention field `name` - --> $DIR/E0027.rs:10:9 + --> $DIR/E0027.rs:11:9 | LL | Dog { age: x } => {} | ^^^^^^^^^^^^^^ missing field `name` @@ -13,8 +13,38 @@ help: if you don't care about this missing field, you can explicitly ignore it LL | Dog { age: x, .. } => {} | ^^^^ +error[E0027]: pattern does not mention field `age` + --> $DIR/E0027.rs:15:9 + | +LL | Dog { name: x, } => {} + | ^^^^^^^^^^^^^^^^ missing field `age` + | +help: include the missing field in the pattern + | +LL | Dog { name: x, age } => {} + | ^^^^^ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | Dog { name: x, .. } => {} + | ^^^^ + +error[E0027]: pattern does not mention field `age` + --> $DIR/E0027.rs:19:9 + | +LL | Dog { name: x , } => {} + | ^^^^^^^^^^^^^^^^^^ missing field `age` + | +help: include the missing field in the pattern + | +LL | Dog { name: x, age } => {} + | ^^^^^ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | Dog { name: x, .. } => {} + | ^^^^ + error[E0027]: pattern does not mention fields `name`, `age` - --> $DIR/E0027.rs:13:9 + --> $DIR/E0027.rs:22:9 | LL | Dog {} => {} | ^^^^^^ missing fields `name`, `age` @@ -28,6 +58,6 @@ help: if you don't care about these missing fields, you can explicitly ignore th LL | Dog { .. } => {} | ^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0027`. From ad5aa2359d45654953405763090dbc0cd63b0c97 Mon Sep 17 00:00:00 2001 From: oli Date: Mon, 4 Jan 2021 23:32:19 +0000 Subject: [PATCH 02/12] Remove an unnecessary field from a `NonConstOp` --- compiler/rustc_mir/src/transform/check_consts/ops.rs | 2 +- compiler/rustc_mir/src/transform/check_consts/validation.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 9e90a7519cf2c..99ffb0edce9e1 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -72,7 +72,7 @@ impl NonConstOp for FnCallIndirect { /// A function call where the callee is not marked as `const`. #[derive(Debug)] -pub struct FnCallNonConst(pub DefId); +pub struct FnCallNonConst; impl NonConstOp for FnCallNonConst { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { struct_span_err!( diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index d1c07d1051d2f..ebb4e7e7fa049 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -817,7 +817,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // Attempting to call a trait method? if let Some(trait_id) = tcx.trait_of_item(callee) { if !self.tcx.features().const_trait_impl { - self.check_op(ops::FnCallNonConst(callee)); + self.check_op(ops::FnCallNonConst); return; } @@ -883,7 +883,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } if !tcx.is_const_fn_raw(callee) { - self.check_op(ops::FnCallNonConst(callee)); + self.check_op(ops::FnCallNonConst); return; } From 949bdd8b79a48ac25408f9cfb0e9d57a75d5f12b Mon Sep 17 00:00:00 2001 From: oli Date: Mon, 4 Jan 2021 23:01:58 +0000 Subject: [PATCH 03/12] Add regression test --- .../src/transform/check_consts/validation.rs | 20 ++++++++++++++----- .../ui/consts/intrinsic_without_const_stab.rs | 20 +++++++++++++++++++ .../intrinsic_without_const_stab_fail.rs | 15 ++++++++++++++ .../intrinsic_without_const_stab_fail.stderr | 9 +++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/consts/intrinsic_without_const_stab.rs create mode 100644 src/test/ui/consts/intrinsic_without_const_stab_fail.rs create mode 100644 src/test/ui/consts/intrinsic_without_const_stab_fail.stderr diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index ebb4e7e7fa049..ca7c393d4afdd 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -789,10 +789,10 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } + #[instrument(skip(self))] fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { use rustc_target::spec::abi::Abi::RustIntrinsic; - trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); self.super_terminator(terminator, location); match &terminator.kind { @@ -816,6 +816,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // Attempting to call a trait method? if let Some(trait_id) = tcx.trait_of_item(callee) { + trace!("attempting to call a trait method"); if !self.tcx.features().const_trait_impl { self.check_op(ops::FnCallNonConst); return; @@ -871,13 +872,13 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { return; } + let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic; + // HACK: This is to "unstabilize" the `transmute` intrinsic // within const fns. `transmute` is allowed in all other const contexts. // This won't really scale to more intrinsics or functions. Let's allow const // transmutes in const fn before we add more hacks to this. - if tcx.fn_sig(callee).abi() == RustIntrinsic - && tcx.item_name(callee) == sym::transmute - { + if is_intrinsic && tcx.item_name(callee) == sym::transmute { self.check_op(ops::Transmute); return; } @@ -890,6 +891,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // If the `const fn` we are trying to call is not const-stable, ensure that we have // the proper feature gate enabled. if let Some(gate) = is_unstable_const_fn(tcx, callee) { + trace!(?gate, "calling unstable const fn"); if self.span.allows_unstable(gate) { return; } @@ -904,12 +906,14 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // If this crate is not using stability attributes, or the caller is not claiming to be a // stable `const fn`, that is all that is required. if !self.ccx.is_const_stable_const_fn() { + trace!("crate not using stability attributes or caller not stably const"); return; } // Otherwise, we are something const-stable calling a const-unstable fn. if super::rustc_allow_const_fn_unstable(tcx, caller, gate) { + trace!("rustc_allow_const_fn_unstable gate active"); return; } @@ -923,10 +927,16 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable()); if callee_is_unstable_unmarked { - if self.ccx.is_const_stable_const_fn() { + trace!("callee_is_unstable_unmarked"); + // We do not use `const` modifiers for intrinsic "functions", as intrinsics are + // `extern` funtions, and these have way to get marked `const`. So instead we + // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const` + if self.ccx.is_const_stable_const_fn() || is_intrinsic { self.check_op(ops::FnCallUnstable(callee, None)); + return; } } + trace!("permitting call"); } // Forbid all `Drop` terminators unless the place being dropped is a local with no diff --git a/src/test/ui/consts/intrinsic_without_const_stab.rs b/src/test/ui/consts/intrinsic_without_const_stab.rs new file mode 100644 index 0000000000000..8f71cd26e5fab --- /dev/null +++ b/src/test/ui/consts/intrinsic_without_const_stab.rs @@ -0,0 +1,20 @@ +// check-pass + +#![feature(intrinsics, staged_api, const_intrinsic_copy)] +#![stable(feature = "core", since = "1.6.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] +#[inline] +pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + extern "rust-intrinsic" { + fn copy(src: *const T, dst: *mut T, count: usize); + } + + // Even though the `copy` intrinsic lacks stability attributes, this works, because it + // inherits its stability attributes from its parent. That includes `rustc_const_(un)stable` + // attributes. + unsafe { copy(src, dst, count) } +} + +fn main() {} diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs new file mode 100644 index 0000000000000..bf2c44169d48b --- /dev/null +++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs @@ -0,0 +1,15 @@ +#![feature(intrinsics, staged_api, const_intrinsic_copy)] +#![stable(feature = "core", since = "1.6.0")] + +extern "rust-intrinsic" { + fn copy(src: *const T, dst: *mut T, count: usize); +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] +#[inline] +pub const unsafe fn stuff(src: *const T, dst: *mut T, count: usize) { + unsafe { copy(src, dst, count) } //~ ERROR calls in constant functions are limited +} + +fn main() {} diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr new file mode 100644 index 0000000000000..d4a2989e785e0 --- /dev/null +++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr @@ -0,0 +1,9 @@ +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants + --> $DIR/intrinsic_without_const_stab_fail.rs:12:14 + | +LL | unsafe { copy(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. From 2136a5cfad69337222b5b02f934825e5d346f9ca Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 17 Jan 2021 11:07:43 +0100 Subject: [PATCH 04/12] Fix `unused_unsafe` label with `unsafe_block_in_unsafe_fn --- .../rustc_mir/src/transform/check_unsafety.rs | 17 ++++--- .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 5 ++ .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 50 +++++++++++++------ 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index e64955c4986ce..4f177d4ef0248 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -580,24 +580,23 @@ fn is_enclosed( tcx: TyCtxt<'_>, used_unsafe: &FxHashSet, id: hir::HirId, -) -> Option<(String, hir::HirId)> { + unsafe_op_in_unsafe_fn_allowed: bool, +) -> Option<(&'static str, hir::HirId)> { let parent_id = tcx.hir().get_parent_node(id); if parent_id != id { if used_unsafe.contains(&parent_id) { - Some(("block".to_string(), parent_id)) + Some(("block", parent_id)) } else if let Some(Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, _, _), .. })) = tcx.hir().find(parent_id) { - if sig.header.unsafety == hir::Unsafety::Unsafe - && !tcx.features().unsafe_block_in_unsafe_fn - { - Some(("fn".to_string(), parent_id)) + if sig.header.unsafety == hir::Unsafety::Unsafe && unsafe_op_in_unsafe_fn_allowed { + Some(("fn", parent_id)) } else { None } } else { - is_enclosed(tcx, used_unsafe, parent_id) + is_enclosed(tcx, used_unsafe, parent_id, unsafe_op_in_unsafe_fn_allowed) } } else { None @@ -610,7 +609,9 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, used_unsafe: &FxHashSet, id let msg = "unnecessary `unsafe` block"; let mut db = lint.build(msg); db.span_label(span, msg); - if let Some((kind, id)) = is_enclosed(tcx, used_unsafe, id) { + if let Some((kind, id)) = + is_enclosed(tcx, used_unsafe, id, unsafe_op_in_unsafe_fn_allowed(tcx, id)) + { db.span_label( tcx.sess.source_map().guess_head_span(tcx.hir().span(id)), format!("because it's nested under this `unsafe` {}", kind), diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 1e57b03ced48b..9eec7e0e8fe62 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -13,6 +13,9 @@ unsafe fn deny_level() { //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block VOID = (); //~^ ERROR use of mutable static is unsafe and requires unsafe block + + unsafe {} + //~^ ERROR unnecessary `unsafe` block } // Check that `unsafe_op_in_unsafe_fn` works starting from the `warn` level. @@ -25,6 +28,8 @@ unsafe fn warning_level() { //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block VOID = (); //~^ ERROR use of mutable static is unsafe and requires unsafe block + unsafe {} + //~^ ERROR unnecessary `unsafe` block } unsafe fn explicit_block() { diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr index cc595df12cc44..278a036c9f19f 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -27,14 +27,26 @@ LL | VOID = (); | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:5 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:3:9 + | +LL | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + error: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:5 | LL | unsf(); | ^^^^^^ call to unsafe function | note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:8 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:23:8 | LL | #[deny(warnings)] | ^^^^^^^^ @@ -42,7 +54,7 @@ LL | #[deny(warnings)] = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -50,7 +62,7 @@ LL | *PTR; = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static @@ -58,33 +70,39 @@ LL | VOID = (); = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:40:14 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:45:14 | LL | unsafe { unsafe { unsf() } } | ------ ^^^^^^ unnecessary `unsafe` block | | | because it's nested under this `unsafe` block - | -note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:3:9 - | -LL | #![deny(unused_unsafe)] - | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:51:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:56:5 | +LL | unsafe fn allow_level() { + | ----------------------- because it's nested under this `unsafe` fn +... LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:63:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:68:9 | +LL | unsafe fn nested_allow_level() { + | ------------------------------ because it's nested under this `unsafe` fn +... LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error[E0133]: call to unsafe function is unsafe and requires unsafe block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:69:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:74:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -92,13 +110,13 @@ LL | unsf(); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:78:9 | LL | unsf(); | ^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 11 previous errors +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0133`. From 70a43e07f6887dd1de62a9bbbc77b4a0c6e8d0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Jan 2021 16:48:52 -0800 Subject: [PATCH 05/12] Fix structured suggestion for explicit `drop` call --- compiler/rustc_typeck/src/check/callee.rs | 18 ++++++------- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 2 +- .../rustc_typeck/src/check/method/confirm.rs | 1 + src/test/ui/error-codes/E0040.fixed | 18 +++++++++++++ src/test/ui/error-codes/E0040.rs | 3 +++ src/test/ui/error-codes/E0040.stderr | 10 +++---- .../ui/explicit/explicit-call-to-dtor.fixed | 16 ++++++++++++ src/test/ui/explicit/explicit-call-to-dtor.rs | 2 ++ .../ui/explicit/explicit-call-to-dtor.stderr | 10 +++---- .../explicit-call-to-supertrait-dtor.fixed | 26 +++++++++++++++++++ .../explicit-call-to-supertrait-dtor.rs | 5 +++- .../explicit-call-to-supertrait-dtor.stderr | 10 +++---- src/test/ui/illegal-ufcs-drop.fixed | 10 +++++++ src/test/ui/illegal-ufcs-drop.rs | 1 + src/test/ui/illegal-ufcs-drop.stderr | 2 +- 15 files changed, 107 insertions(+), 27 deletions(-) create mode 100644 src/test/ui/error-codes/E0040.fixed create mode 100644 src/test/ui/explicit/explicit-call-to-dtor.fixed create mode 100644 src/test/ui/explicit/explicit-call-to-supertrait-dtor.fixed create mode 100644 src/test/ui/illegal-ufcs-drop.fixed diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 116b079e7425a..4836418b3c210 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -25,24 +25,24 @@ pub fn check_legal_trait_for_method_call( tcx: TyCtxt<'_>, span: Span, receiver: Option, + expr_span: Span, trait_id: DefId, ) { if tcx.lang_items().drop_trait() == Some(trait_id) { let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method"); err.span_label(span, "explicit destructor calls not allowed"); - let snippet = receiver + let (sp, suggestion) = receiver .and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok()) - .unwrap_or_default(); - - let suggestion = - if snippet.is_empty() { "drop".to_string() } else { format!("drop({})", snippet) }; + .filter(|snippet| !snippet.is_empty()) + .map(|snippet| (expr_span, format!("drop({})", snippet))) + .unwrap_or_else(|| (span, "drop".to_string())); err.span_suggestion( - span, - &format!("consider using `drop` function: `{}`", suggestion), - String::new(), - Applicability::Unspecified, + sp, + "consider using `drop` function", + suggestion, + Applicability::MaybeIncorrect, ); err.emit(); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 47799c95fc0a7..8e9074ba3a289 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1163,7 +1163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); match container { ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(tcx, span, None, trait_did) + callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did) } ty::ImplContainer(impl_def_id) => { if segments.len() == 1 { diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index e604419f41378..2ff9607726db1 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -507,6 +507,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.tcx, self.span, Some(self.self_expr.span), + self.call_expr.span, trait_def_id, ), ty::ImplContainer(..) => {} diff --git a/src/test/ui/error-codes/E0040.fixed b/src/test/ui/error-codes/E0040.fixed new file mode 100644 index 0000000000000..139dc8f94964f --- /dev/null +++ b/src/test/ui/error-codes/E0040.fixed @@ -0,0 +1,18 @@ +// run-rustfix +struct Foo { + x: i32, +} + +impl Drop for Foo { + fn drop(&mut self) { + println!("kaboom"); + } +} + +fn main() { + let mut x = Foo { x: -7 }; + x.x = 0; + println!("{}", x.x); + drop(x); + //~^ ERROR E0040 +} diff --git a/src/test/ui/error-codes/E0040.rs b/src/test/ui/error-codes/E0040.rs index 113efae82c510..9ffc42d0c7804 100644 --- a/src/test/ui/error-codes/E0040.rs +++ b/src/test/ui/error-codes/E0040.rs @@ -1,3 +1,4 @@ +// run-rustfix struct Foo { x: i32, } @@ -10,6 +11,8 @@ impl Drop for Foo { fn main() { let mut x = Foo { x: -7 }; + x.x = 0; + println!("{}", x.x); x.drop(); //~^ ERROR E0040 } diff --git a/src/test/ui/error-codes/E0040.stderr b/src/test/ui/error-codes/E0040.stderr index 69cf28b29704f..9fcda1a9385d2 100644 --- a/src/test/ui/error-codes/E0040.stderr +++ b/src/test/ui/error-codes/E0040.stderr @@ -1,11 +1,11 @@ error[E0040]: explicit use of destructor method - --> $DIR/E0040.rs:13:7 + --> $DIR/E0040.rs:16:7 | LL | x.drop(); - | ^^^^ - | | - | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(x)` + | --^^^^-- + | | | + | | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(x)` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-dtor.fixed b/src/test/ui/explicit/explicit-call-to-dtor.fixed new file mode 100644 index 0000000000000..91a4ca608da4e --- /dev/null +++ b/src/test/ui/explicit/explicit-call-to-dtor.fixed @@ -0,0 +1,16 @@ +// run-rustfix +struct Foo { + x: isize +} + +impl Drop for Foo { + fn drop(&mut self) { + println!("kaboom"); + } +} + +fn main() { + let x = Foo { x: 3 }; + println!("{}", x.x); + drop(x); //~ ERROR explicit use of destructor method +} diff --git a/src/test/ui/explicit/explicit-call-to-dtor.rs b/src/test/ui/explicit/explicit-call-to-dtor.rs index a6f9acc37a16d..0656871eb1b34 100644 --- a/src/test/ui/explicit/explicit-call-to-dtor.rs +++ b/src/test/ui/explicit/explicit-call-to-dtor.rs @@ -1,3 +1,4 @@ +// run-rustfix struct Foo { x: isize } @@ -10,5 +11,6 @@ impl Drop for Foo { fn main() { let x = Foo { x: 3 }; + println!("{}", x.x); x.drop(); //~ ERROR explicit use of destructor method } diff --git a/src/test/ui/explicit/explicit-call-to-dtor.stderr b/src/test/ui/explicit/explicit-call-to-dtor.stderr index 5ebe4ee4b90f8..f3c9bf6cccdd3 100644 --- a/src/test/ui/explicit/explicit-call-to-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-dtor.stderr @@ -1,11 +1,11 @@ error[E0040]: explicit use of destructor method - --> $DIR/explicit-call-to-dtor.rs:13:7 + --> $DIR/explicit-call-to-dtor.rs:15:7 | LL | x.drop(); - | ^^^^ - | | - | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(x)` + | --^^^^-- + | | | + | | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(x)` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.fixed b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.fixed new file mode 100644 index 0000000000000..47c4c9f67b692 --- /dev/null +++ b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.fixed @@ -0,0 +1,26 @@ +// run-rustfix +struct Foo { + x: isize +} + +#[allow(drop_bounds)] +trait Bar: Drop { + fn blah(&self); +} + +impl Drop for Foo { + fn drop(&mut self) { + println!("kaboom"); + } +} + +impl Bar for Foo { + fn blah(&self) { + drop(self); //~ ERROR explicit use of destructor method + } +} + +fn main() { + let x = Foo { x: 3 }; + println!("{}", x.x); +} diff --git a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.rs b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.rs index ff56b9a8ae424..c698de50c75b8 100644 --- a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.rs +++ b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.rs @@ -1,8 +1,10 @@ +// run-rustfix struct Foo { x: isize } -trait Bar : Drop { +#[allow(drop_bounds)] +trait Bar: Drop { fn blah(&self); } @@ -20,4 +22,5 @@ impl Bar for Foo { fn main() { let x = Foo { x: 3 }; + println!("{}", x.x); } diff --git a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr index cd3fb3119a5cf..7f5106eb57e54 100644 --- a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -1,11 +1,11 @@ error[E0040]: explicit use of destructor method - --> $DIR/explicit-call-to-supertrait-dtor.rs:17:14 + --> $DIR/explicit-call-to-supertrait-dtor.rs:19:14 | LL | self.drop(); - | ^^^^ - | | - | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(self)` + | -----^^^^-- + | | | + | | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(self)` error: aborting due to previous error diff --git a/src/test/ui/illegal-ufcs-drop.fixed b/src/test/ui/illegal-ufcs-drop.fixed new file mode 100644 index 0000000000000..d73b391be0621 --- /dev/null +++ b/src/test/ui/illegal-ufcs-drop.fixed @@ -0,0 +1,10 @@ +// run-rustfix +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) {} +} + +fn main() { + drop(&mut Foo) //~ ERROR explicit use of destructor method +} diff --git a/src/test/ui/illegal-ufcs-drop.rs b/src/test/ui/illegal-ufcs-drop.rs index 5c072663eda45..11411f55494c5 100644 --- a/src/test/ui/illegal-ufcs-drop.rs +++ b/src/test/ui/illegal-ufcs-drop.rs @@ -1,3 +1,4 @@ +// run-rustfix struct Foo; impl Drop for Foo { diff --git a/src/test/ui/illegal-ufcs-drop.stderr b/src/test/ui/illegal-ufcs-drop.stderr index 57c99739afd24..91f47d5e456d3 100644 --- a/src/test/ui/illegal-ufcs-drop.stderr +++ b/src/test/ui/illegal-ufcs-drop.stderr @@ -1,5 +1,5 @@ error[E0040]: explicit use of destructor method - --> $DIR/illegal-ufcs-drop.rs:8:5 + --> $DIR/illegal-ufcs-drop.rs:9:5 | LL | Drop::drop(&mut Foo) | ^^^^^^^^^^ From dc04ceae710a432baa11ddb986541d89253279a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jan 2021 11:24:16 +0100 Subject: [PATCH 06/12] use raw-ptr-addr-of for slice::swap --- library/core/src/lib.rs | 1 + library/core/src/slice/mod.rs | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index df8d9ff371fe4..263c6c9cf0f26 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -126,6 +126,7 @@ #![feature(auto_traits)] #![feature(or_patterns)] #![feature(prelude_import)] +#![feature(raw_ref_macros)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(simd_ffi)] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index de8d7fc29dc05..b06b6e93373f3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -542,10 +542,9 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn swap(&mut self, a: usize, b: usize) { - // Can't take two mutable loans from one vector, so instead just cast - // them to their raw pointers to do the swap. - let pa: *mut T = &mut self[a]; - let pb: *mut T = &mut self[b]; + // Can't take two mutable loans from one vector, so instead use raw pointers. + let pa = ptr::raw_mut!(self[a]); + let pb = ptr::raw_mut!(self[b]); // SAFETY: `pa` and `pb` have been created from safe mutable references and refer // to elements in the slice and therefore are guaranteed to be valid and aligned. // Note that accessing the elements behind `a` and `b` is checked and will From 1d1ab21ad937608d89f0c9f29394be4995823f9c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 18 Jan 2021 12:03:53 +0100 Subject: [PATCH 07/12] Remove inline script tags --- src/librustdoc/html/layout.rs | 5 +--- src/librustdoc/html/markdown.rs | 2 ++ src/librustdoc/html/render/mod.rs | 7 ++---- src/librustdoc/html/static/main.js | 39 +++++++++++++++++++++--------- src/tools/rustdoc-js/tester.js | 3 +-- 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index b5169b0599773..4458eea95f3e1 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -111,10 +111,7 @@ crate fn render(
\
\ {after_content}\ - \ +
\ {static_extra_scripts}\ {extra_scripts}\ diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 33639055b59ef..cfa6cd96595d6 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1313,6 +1313,8 @@ fn init_id_map() -> FxHashMap { map.insert("toggle-all-docs".to_owned(), 1); map.insert("all-types".to_owned(), 1); map.insert("default-settings".to_owned(), 1); + map.insert("rustdoc-vars".to_owned(), 1); + map.insert("sidebar-vars".to_owned(), 1); // This is the list of IDs used by rustdoc sections. map.insert("fields".to_owned(), 1); map.insert("variants".to_owned(), 1); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 2db89e8a7ca68..03e091297e5b6 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -4216,11 +4216,8 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache: let relpath = if it.is_mod() { "../" } else { "" }; write!( buffer, - "", + "
\ +
", name = it.name.unwrap_or(kw::Empty), ty = it.type_(), path = relpath diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 3ffb72ba3ee8b..78a825fcca0ba 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1,5 +1,5 @@ // From rust: -/* global ALIASES, currentCrate, rootPath */ +/* global ALIASES */ // Local js definitions: /* global addClass, getCurrentValue, hasClass */ @@ -40,6 +40,21 @@ if (!DOMTokenList.prototype.remove) { }; } +(function () { + var rustdocVars = document.getElementById("rustdoc-vars"); + if (rustdocVars) { + window.rootPath = rustdocVars.attributes["data-root-path"].value; + window.currentCrate = rustdocVars.attributes["data-current-crate"].value; + } + var sidebarVars = document.getElementById("sidebar-vars"); + if (sidebarVars) { + window.sidebarCurrent = { + name: sidebarVars.attributes["data-name"].value, + ty: sidebarVars.attributes["data-ty"].value, + relpath: sidebarVars.attributes["data-relpath"].value, + }; + } +}()); // Gets the human-readable string for the virtual-key code of the // given KeyboardEvent, ev. @@ -565,7 +580,7 @@ function defocusSearchBar() { var i, match, url = document.location.href, stripped = "", - len = rootPath.match(/\.\.\//g).length + 1; + len = window.rootPath.match(/\.\.\//g).length + 1; for (i = 0; i < len; ++i) { match = url.match(/\/[^\/]*$/); @@ -1504,15 +1519,15 @@ function defocusSearchBar() { if (type === "mod") { displayPath = path + "::"; - href = rootPath + path.replace(/::/g, "/") + "/" + + href = window.rootPath + path.replace(/::/g, "/") + "/" + name + "/index.html"; } else if (type === "primitive" || type === "keyword") { displayPath = ""; - href = rootPath + path.replace(/::/g, "/") + + href = window.rootPath + path.replace(/::/g, "/") + "/" + type + "." + name + ".html"; } else if (type === "externcrate") { displayPath = ""; - href = rootPath + name + "/index.html"; + href = window.rootPath + name + "/index.html"; } else if (item.parent !== undefined) { var myparent = item.parent; var anchor = "#" + type + "." + name; @@ -1535,13 +1550,13 @@ function defocusSearchBar() { } else { displayPath = path + "::" + myparent.name + "::"; } - href = rootPath + path.replace(/::/g, "/") + + href = window.rootPath + path.replace(/::/g, "/") + "/" + pageType + "." + pageName + ".html" + anchor; } else { displayPath = item.path + "::"; - href = rootPath + item.path.replace(/::/g, "/") + + href = window.rootPath + item.path.replace(/::/g, "/") + "/" + type + "." + name + ".html"; } return [displayPath, href]; @@ -1973,7 +1988,7 @@ function defocusSearchBar() { startSearch(); // Draw a convenient sidebar of known crates if we have a listing - if (rootPath === "../" || rootPath === "./") { + if (window.rootPath === "../" || window.rootPath === "./") { var sidebar = document.getElementsByClassName("sidebar-elems")[0]; if (sidebar) { var div = document.createElement("div"); @@ -1992,11 +2007,11 @@ function defocusSearchBar() { crates.sort(); for (var i = 0; i < crates.length; ++i) { var klass = "crate"; - if (rootPath !== "./" && crates[i] === window.currentCrate) { + if (window.rootPath !== "./" && crates[i] === window.currentCrate) { klass += " current"; } var link = document.createElement("a"); - link.href = rootPath + crates[i] + "/index.html"; + link.href = window.rootPath + crates[i] + "/index.html"; // The summary in the search index has HTML, so we need to // dynamically render it as plaintext. link.title = convertHTMLToPlaintext(rawSearchIndex[crates[i]].doc); @@ -2118,7 +2133,7 @@ function defocusSearchBar() { var libs = Object.getOwnPropertyNames(imp); for (var i = 0, llength = libs.length; i < llength; ++i) { - if (libs[i] === currentCrate) { continue; } + if (libs[i] === window.currentCrate) { continue; } var structs = imp[libs[i]]; struct_loop: @@ -2143,7 +2158,7 @@ function defocusSearchBar() { var href = elem.getAttribute("href"); if (href && href.indexOf("http") !== 0) { - elem.setAttribute("href", rootPath + href); + elem.setAttribute("href", window.rootPath + href); } }); diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 63f2d2f5d2f68..3f6bd60397526 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -263,8 +263,7 @@ function loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate) { "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch"]; ALIASES = {}; - finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; - finalJS += 'var rootPath = "../";\n'; + finalJS += 'window = { "currentCrate": "' + crate + '", rootPath: "../" };\n'; finalJS += loadThings(["hasOwnProperty", "onEach"], 'function', extractFunction, storageJs); finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); From 5bac1c9229331105bab558f7d3be1685a76d110c Mon Sep 17 00:00:00 2001 From: oli Date: Sat, 16 Jan 2021 19:59:21 +0000 Subject: [PATCH 08/12] Only inherit const stability for methods of `impl const Trait` blocks --- .../src/transform/check_consts/validation.rs | 2 +- compiler/rustc_passes/src/stability.rs | 70 ++++++++++++++++--- library/core/src/intrinsics.rs | 2 + .../ui/consts/intrinsic_without_const_stab.rs | 7 +- .../intrinsic_without_const_stab.stderr | 9 +++ 5 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/consts/intrinsic_without_const_stab.stderr diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index ca7c393d4afdd..e884454f5c6ec 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -929,7 +929,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if callee_is_unstable_unmarked { trace!("callee_is_unstable_unmarked"); // We do not use `const` modifiers for intrinsic "functions", as intrinsics are - // `extern` funtions, and these have way to get marked `const`. So instead we + // `extern` funtions, and these have no way to get marked `const`. So instead we // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const` if self.ccx.is_const_stable_const_fn() || is_intrinsic { self.check_op(ops::FnCallUnstable(callee, None)); diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4a3d6ecf8cc61..b70cec25dfb5a 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -55,6 +55,21 @@ impl InheritDeprecation { } } +/// Whether to inherit const stability flags for nested items. In most cases, we do not want to +/// inherit const stability: just because an enclosing `fn` is const-stable does not mean +/// all `extern` imports declared in it should be const-stable! However, trait methods +/// inherit const stability attributes from their parent and do not have their own. +enum InheritConstStability { + Yes, + No, +} + +impl InheritConstStability { + fn yes(&self) -> bool { + matches!(self, InheritConstStability::Yes) + } +} + // A private tree-walker for producing an Index. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -75,6 +90,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { item_sp: Span, kind: AnnotationKind, inherit_deprecation: InheritDeprecation, + inherit_const_stability: InheritConstStability, visit_children: F, ) where F: FnOnce(&mut Self), @@ -140,6 +156,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { const_stab }); + // `impl const Trait for Type` items forward their const stability to their + // immediate children. if const_stab.is_none() { debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); if let Some(parent) = self.parent_const_stab { @@ -228,7 +246,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.recurse_with_stability_attrs( depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)), stab, - const_stab, + if inherit_const_stability.yes() { const_stab } else { None }, visit_children, ); } @@ -325,6 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_item(&mut self, i: &'tcx Item<'tcx>) { let orig_in_trait_impl = self.in_trait_impl; let mut kind = AnnotationKind::Required; + let mut const_stab_inherit = InheritConstStability::No; match i.kind { // Inherent impls and foreign modules serve only as containers for other items, // they don't have their own stability. They still can be annotated as unstable @@ -338,6 +357,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => { self.in_trait_impl = true; kind = AnnotationKind::DeprecationProhibited; + const_stab_inherit = InheritConstStability::Yes; } hir::ItemKind::Struct(ref sd, _) => { if let Some(ctor_hir_id) = sd.ctor_hir_id() { @@ -347,6 +367,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { i.span, AnnotationKind::Required, InheritDeprecation::Yes, + InheritConstStability::No, |_| {}, ) } @@ -354,9 +375,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { _ => {} } - self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| { - intravisit::walk_item(v, i) - }); + self.annotate( + i.hir_id, + &i.attrs, + i.span, + kind, + InheritDeprecation::Yes, + const_stab_inherit, + |v| intravisit::walk_item(v, i), + ); self.in_trait_impl = orig_in_trait_impl; } @@ -367,6 +394,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ti.span, AnnotationKind::Required, InheritDeprecation::Yes, + InheritConstStability::No, |v| { intravisit::walk_trait_item(v, ti); }, @@ -376,9 +404,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { let kind = if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required }; - self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| { - intravisit::walk_impl_item(v, ii); - }); + self.annotate( + ii.hir_id, + &ii.attrs, + ii.span, + kind, + InheritDeprecation::Yes, + InheritConstStability::No, + |v| { + intravisit::walk_impl_item(v, ii); + }, + ); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) { @@ -388,6 +424,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { var.span, AnnotationKind::Required, InheritDeprecation::Yes, + InheritConstStability::No, |v| { if let Some(ctor_hir_id) = var.data.ctor_hir_id() { v.annotate( @@ -396,6 +433,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { var.span, AnnotationKind::Required, InheritDeprecation::Yes, + InheritConstStability::No, |_| {}, ); } @@ -412,6 +450,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { s.span, AnnotationKind::Required, InheritDeprecation::Yes, + InheritConstStability::No, |v| { intravisit::walk_struct_field(v, s); }, @@ -425,6 +464,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { i.span, AnnotationKind::Required, InheritDeprecation::Yes, + InheritConstStability::No, |v| { intravisit::walk_foreign_item(v, i); }, @@ -438,6 +478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { md.span, AnnotationKind::Required, InheritDeprecation::Yes, + InheritConstStability::No, |_| {}, ); } @@ -451,9 +492,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { _ => AnnotationKind::Prohibited, }; - self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| { - intravisit::walk_generic_param(v, p); - }); + self.annotate( + p.hir_id, + &p.attrs, + p.span, + kind, + InheritDeprecation::No, + InheritConstStability::No, + |v| { + intravisit::walk_generic_param(v, p); + }, + ); } } @@ -618,6 +667,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { krate.item.span, AnnotationKind::Required, InheritDeprecation::Yes, + InheritConstStability::No, |v| intravisit::walk_crate(v, krate), ); } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index fa5f0d5040047..7c1a9b82f99b2 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1842,6 +1842,7 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - #[inline] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } @@ -1926,6 +1927,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[inline] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] fn copy(src: *const T, dst: *mut T, count: usize); } diff --git a/src/test/ui/consts/intrinsic_without_const_stab.rs b/src/test/ui/consts/intrinsic_without_const_stab.rs index 8f71cd26e5fab..810158a295792 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab.rs +++ b/src/test/ui/consts/intrinsic_without_const_stab.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(intrinsics, staged_api, const_intrinsic_copy)] #![stable(feature = "core", since = "1.6.0")] @@ -7,14 +5,13 @@ #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[inline] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + // Const stability attributes are not inherited from parent items. extern "rust-intrinsic" { fn copy(src: *const T, dst: *mut T, count: usize); } - // Even though the `copy` intrinsic lacks stability attributes, this works, because it - // inherits its stability attributes from its parent. That includes `rustc_const_(un)stable` - // attributes. unsafe { copy(src, dst, count) } + //~^ ERROR calls in constant functions are limited to constant functions } fn main() {} diff --git a/src/test/ui/consts/intrinsic_without_const_stab.stderr b/src/test/ui/consts/intrinsic_without_const_stab.stderr new file mode 100644 index 0000000000000..5a42823a6052a --- /dev/null +++ b/src/test/ui/consts/intrinsic_without_const_stab.stderr @@ -0,0 +1,9 @@ +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants + --> $DIR/intrinsic_without_const_stab.rs:13:14 + | +LL | unsafe { copy(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. From 222e0e4fe21d0152e2f7e6bce05e7023736bda33 Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Mon, 18 Jan 2021 20:52:10 +0900 Subject: [PATCH 09/12] Fix typo in simplify.rs prexisting -> preexisting --- compiler/rustc_mir_build/src/build/matches/simplify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 705266d4a0bd8..f30745d71859d 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // * the bindings from the previous iteration of the loop is prepended to the bindings from // the current iteration (in the implementation this is done by mem::swap and extend) // * after all iterations, these new bindings are then appended to the bindings that were - // prexisting (i.e. `candidate.binding` when the function was called). + // preexisting (i.e. `candidate.binding` when the function was called). // // example: // candidate.bindings = [1, 2, 3] From 712d0650615f206b140d6060bfeb02fb379087ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jan 2021 13:06:01 +0100 Subject: [PATCH 10/12] remove some outdated comments regarding debug assertions --- library/core/src/ptr/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index d2e1bac58f402..8d901c08f91a3 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -687,7 +687,6 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] pub const unsafe fn read(src: *const T) -> T { - // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. // `src` cannot overlap `tmp` because `tmp` was just allocated on @@ -787,7 +786,6 @@ pub const unsafe fn read(src: *const T) -> T { #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] pub const unsafe fn read_unaligned(src: *const T) -> T { - // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. // `src` cannot overlap `tmp` because `tmp` was just allocated on @@ -988,7 +986,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { - // `copy_nonoverlapping` takes care of debug_assert. copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::()); } mem::forget(src); From 47c2476c689577d14e271c0d85578fb82417552c Mon Sep 17 00:00:00 2001 From: soniasingla Date: Mon, 18 Jan 2021 20:31:47 +0530 Subject: [PATCH 11/12] Fixes #81109 - Typo in pointer::wrapping_sub Signed-off-by: soniasingla --- library/core/src/ptr/const_ptr.rs | 2 +- library/core/src/ptr/mut_ptr.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 663001167865a..28de28c70e4b4 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -633,7 +633,7 @@ impl *const T { } /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) + /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 785bf70c2992c..99744fc711216 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -740,7 +740,7 @@ impl *mut T { } /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) + /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. From 4775334f362b9e196738b0ccd2349ddd03de4007 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 17 Jan 2021 12:59:44 +0100 Subject: [PATCH 12/12] BTreeMap: prefer bulk_steal functions over specialized ones --- library/alloc/src/collections/btree/node.rs | 121 +----------------- library/alloc/src/collections/btree/remove.rs | 8 +- 2 files changed, 8 insertions(+), 121 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 097e3e6d34e86..8ab3f58c1adba 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -592,17 +592,6 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { self.val_area_mut(idx).write(val); } } - - /// Adds a key-value pair to the beginning of the node. - fn push_front(&mut self, key: K, val: V) { - let new_len = self.len() + 1; - assert!(new_len <= CAPACITY); - unsafe { - slice_insert(self.key_area_mut(..new_len), 0, key); - slice_insert(self.val_area_mut(..new_len), 0, val); - *self.len_mut() = new_len as u16; - } - } } impl<'a, K, V> NodeRef, K, V, marker::Internal> { @@ -638,88 +627,6 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } } - - /// Adds a key-value pair, and an edge to go to the left of that pair, - /// to the beginning of the node. - fn push_front(&mut self, key: K, val: V, edge: Root) { - let new_len = self.len() + 1; - assert!(edge.height == self.height - 1); - assert!(new_len <= CAPACITY); - - unsafe { - slice_insert(self.key_area_mut(..new_len), 0, key); - slice_insert(self.val_area_mut(..new_len), 0, val); - slice_insert(self.edge_area_mut(..new_len + 1), 0, edge.node); - *self.len_mut() = new_len as u16; - } - - self.correct_all_childrens_parent_links(); - } -} - -impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { - /// Removes a key-value pair from the end of the node and returns the pair. - /// Also removes the edge that was to the right of that pair and, if the node - /// is internal, returns the orphaned subtree that this edge owned. - /// - /// # Safety - /// The node must not be empty. - unsafe fn pop(&mut self) -> (K, V, Option>) { - debug_assert!(self.len() > 0); - - let idx = self.len() - 1; - - unsafe { - let key = self.key_area_mut(idx).assume_init_read(); - let val = self.val_area_mut(idx).assume_init_read(); - let edge = match self.reborrow_mut().force() { - ForceResult::Leaf(_) => None, - ForceResult::Internal(mut internal) => { - let node = internal.edge_area_mut(idx + 1).assume_init_read(); - let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; - // Currently, clearing the parent link is superfluous, because we will - // insert the node elsewhere and set its parent link again. - edge.clear_parent_link(); - Some(edge) - } - }; - - *self.len_mut() -= 1; - (key, val, edge) - } - } - - /// Removes a key-value pair from the beginning of the node and returns the pair. - /// Also removes the edge that was to the left of that pair and, if the node is - /// internal, returns the orphaned subtree that this edge owned. - fn pop_front(&mut self) -> (K, V, Option>) { - debug_assert!(self.len() > 0); - - let old_len = self.len(); - - unsafe { - let key = slice_remove(self.key_area_mut(..old_len), 0); - let val = slice_remove(self.val_area_mut(..old_len), 0); - let edge = match self.reborrow_mut().force() { - ForceResult::Leaf(_) => None, - ForceResult::Internal(mut internal) => { - let node = slice_remove(internal.edge_area_mut(..old_len + 1), 0); - let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; - // Currently, clearing the parent link is superfluous, because we will - // insert the node elsewhere and set its parent link again. - edge.clear_parent_link(); - - internal.correct_childrens_parent_links(0..old_len); - - Some(edge) - } - }; - - *self.len_mut() -= 1; - - (key, val, edge) - } - } } impl NodeRef { @@ -1399,18 +1306,8 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { mut self, track_right_edge_idx: usize, ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { - unsafe { - let (k, v, edge) = self.left_child.pop(); - - let (k, v) = self.parent.replace_kv(k, v); - - match self.right_child.reborrow_mut().force() { - ForceResult::Leaf(mut leaf) => leaf.push_front(k, v), - ForceResult::Internal(mut internal) => internal.push_front(k, v, edge.unwrap()), - } - - Handle::new_edge(self.right_child, 1 + track_right_edge_idx) - } + self.bulk_steal_left(1); + unsafe { Handle::new_edge(self.right_child, 1 + track_right_edge_idx) } } /// Removes a key-value pair from the right child and places it in the key-value storage @@ -1421,18 +1318,8 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { mut self, track_left_edge_idx: usize, ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { - unsafe { - let (k, v, edge) = self.right_child.pop_front(); - - let (k, v) = self.parent.replace_kv(k, v); - - match self.left_child.reborrow_mut().force() { - ForceResult::Leaf(mut leaf) => leaf.push(k, v), - ForceResult::Internal(mut internal) => internal.push(k, v, edge.unwrap()), - } - - Handle::new_edge(self.left_child, track_left_edge_idx) - } + self.bulk_steal_right(1); + unsafe { Handle::new_edge(self.left_child, track_left_edge_idx) } } /// This does stealing similar to `steal_left` but steals multiple elements at once. diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs index 04683e01de35e..ff842197d1918 100644 --- a/library/alloc/src/collections/btree/remove.rs +++ b/library/alloc/src/collections/btree/remove.rs @@ -121,25 +121,25 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { self, ) -> Option, K, V, marker::Internal>> { match self.forget_type().choose_parent_kv() { - Ok(Left(left_parent_kv)) => { + Ok(Left(mut left_parent_kv)) => { debug_assert_eq!(left_parent_kv.right_child_len(), MIN_LEN - 1); if left_parent_kv.can_merge() { let parent = left_parent_kv.merge_tracking_parent(); Some(parent) } else { debug_assert!(left_parent_kv.left_child_len() > MIN_LEN); - left_parent_kv.steal_left(0); + left_parent_kv.bulk_steal_left(1); None } } - Ok(Right(right_parent_kv)) => { + Ok(Right(mut right_parent_kv)) => { debug_assert_eq!(right_parent_kv.left_child_len(), MIN_LEN - 1); if right_parent_kv.can_merge() { let parent = right_parent_kv.merge_tracking_parent(); Some(parent) } else { debug_assert!(right_parent_kv.right_child_len() > MIN_LEN); - right_parent_kv.steal_right(0); + right_parent_kv.bulk_steal_right(1); None } }