From b2eed3a559e1e59900261f4a5abf11053590e9df Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Tue, 2 Feb 2021 03:13:19 +1100 Subject: [PATCH 01/27] Point out implicit deref coercions in borrow Clean up code --- .../diagnostics/conflict_errors.rs | 37 ++++++++++++++++-- src/test/ui/borrowck/issue-81365-2.rs | 30 +++++++++++++++ src/test/ui/borrowck/issue-81365-2.stderr | 15 ++++++++ src/test/ui/borrowck/issue-81365-3.rs | 37 ++++++++++++++++++ src/test/ui/borrowck/issue-81365-3.stderr | 15 ++++++++ src/test/ui/borrowck/issue-81365-4.rs | 38 +++++++++++++++++++ src/test/ui/borrowck/issue-81365-4.stderr | 15 ++++++++ src/test/ui/borrowck/issue-81365-5.rs | 33 ++++++++++++++++ src/test/ui/borrowck/issue-81365-5.stderr | 15 ++++++++ src/test/ui/borrowck/issue-81365-6.rs | 23 +++++++++++ src/test/ui/borrowck/issue-81365-6.stderr | 15 ++++++++ src/test/ui/borrowck/issue-81365-7.rs | 24 ++++++++++++ src/test/ui/borrowck/issue-81365-7.stderr | 15 ++++++++ src/test/ui/borrowck/issue-81365-8.rs | 26 +++++++++++++ src/test/ui/borrowck/issue-81365.rs | 26 +++++++++++++ src/test/ui/borrowck/issue-81365.stderr | 15 ++++++++ 16 files changed, 375 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/borrowck/issue-81365-2.rs create mode 100644 src/test/ui/borrowck/issue-81365-2.stderr create mode 100644 src/test/ui/borrowck/issue-81365-3.rs create mode 100644 src/test/ui/borrowck/issue-81365-3.stderr create mode 100644 src/test/ui/borrowck/issue-81365-4.rs create mode 100644 src/test/ui/borrowck/issue-81365-4.stderr create mode 100644 src/test/ui/borrowck/issue-81365-5.rs create mode 100644 src/test/ui/borrowck/issue-81365-5.stderr create mode 100644 src/test/ui/borrowck/issue-81365-6.rs create mode 100644 src/test/ui/borrowck/issue-81365-6.stderr create mode 100644 src/test/ui/borrowck/issue-81365-7.rs create mode 100644 src/test/ui/borrowck/issue-81365-7.stderr create mode 100644 src/test/ui/borrowck/issue-81365-8.rs create mode 100644 src/test/ui/borrowck/issue-81365.rs create mode 100644 src/test/ui/borrowck/issue-81365.stderr diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index cd16a88e5fc3c..4bf4df226e172 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -8,11 +8,10 @@ use rustc_index::vec::Idx; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, + ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; -use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; -use rustc_span::source_map::DesugaringKind; -use rustc_span::Span; +use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty}; +use rustc_span::{source_map::DesugaringKind, symbol::sym, Span}; use crate::dataflow::drop_flag_effects; use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex}; @@ -1543,6 +1542,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ); + let tcx = self.infcx.tcx; + // point out implicit deref coercion + if let ( + Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }), + Some((method_did, method_substs)), + ) = ( + &self.body[loan.reserve_location.block].terminator, + crate::util::find_self_call( + tcx, + self.body, + loan.assigned_place.local, + loan.reserve_location.block, + ), + ) { + if tcx.is_diagnostic_item(sym::deref_method, method_did) { + let deref_target = + tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { + Instance::resolve(tcx, self.param_env, deref_target, method_substs) + .transpose() + }); + if let Some(Ok(instance)) = deref_target { + let deref_target_ty = instance.ty(tcx, self.param_env); + err.note(&format!( + "borrow occurs due to deref coercion to `{}`", + deref_target_ty + )); + } + } + } + err.buffer(&mut self.errors_buffer); } diff --git a/src/test/ui/borrowck/issue-81365-2.rs b/src/test/ui/borrowck/issue-81365-2.rs new file mode 100644 index 0000000000000..fbbdd93b97cc8 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-2.rs @@ -0,0 +1,30 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +struct Outer { + container: Container, +} + +impl Outer { + fn bad_borrow(&mut self) { + let first = &self.container.target_field; + self.container.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-2.stderr b/src/test/ui/borrowck/issue-81365-2.stderr new file mode 100644 index 0000000000000..851cc4b1af29f --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-2.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `self.container.container_field` because it is borrowed + --> $DIR/issue-81365-2.rs:25:9 + | +LL | let first = &self.container.target_field; + | -------------- borrow of `self.container.container_field` occurs here +LL | self.container.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-3.rs b/src/test/ui/borrowck/issue-81365-3.rs new file mode 100644 index 0000000000000..9a9e3a3135822 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-3.rs @@ -0,0 +1,37 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +struct Outer { + container: Container, +} + +impl Deref for Outer { + type Target = Container; + fn deref(&self) -> &Self::Target { + &self.container + } +} + +impl Outer { + fn bad_borrow(&mut self) { + let first = &self.target_field; + self.container.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-3.stderr b/src/test/ui/borrowck/issue-81365-3.stderr new file mode 100644 index 0000000000000..eedbed3cfe6c1 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-3.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `self.container.container_field` because it is borrowed + --> $DIR/issue-81365-3.rs:32:9 + | +LL | let first = &self.target_field; + | ---- borrow of `self.container.container_field` occurs here +LL | self.container.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `Container` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-4.rs b/src/test/ui/borrowck/issue-81365-4.rs new file mode 100644 index 0000000000000..b2643eb3358ac --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-4.rs @@ -0,0 +1,38 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +struct Outer { + container: Container, + outer_field: bool, +} + +impl Deref for Outer { + type Target = Container; + fn deref(&self) -> &Self::Target { + &self.container + } +} + +impl Outer { + fn bad_borrow(&mut self) { + let first = &self.target_field; + self.outer_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-4.stderr b/src/test/ui/borrowck/issue-81365-4.stderr new file mode 100644 index 0000000000000..82c9fbbc16f6b --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-4.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `self.outer_field` because it is borrowed + --> $DIR/issue-81365-4.rs:33:9 + | +LL | let first = &self.target_field; + | ---- borrow of `self.outer_field` occurs here +LL | self.outer_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.outer_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `Container` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-5.rs b/src/test/ui/borrowck/issue-81365-5.rs new file mode 100644 index 0000000000000..d36b79615e3ad --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-5.rs @@ -0,0 +1,33 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} + +impl DerefTarget { + fn get(&self) -> &bool { + &self.target_field + } +} + +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = self.get(); + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-5.stderr b/src/test/ui/borrowck/issue-81365-5.stderr new file mode 100644 index 0000000000000..8085faf82ed06 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-5.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-5.rs:28:9 + | +LL | let first = self.get(); + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-6.rs b/src/test/ui/borrowck/issue-81365-6.rs new file mode 100644 index 0000000000000..85ea77756b3ba --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-6.rs @@ -0,0 +1,23 @@ +use std::ops::Deref; + +struct Container { + target: Vec<()>, + container_field: bool, +} + +impl Deref for Container { + type Target = [()]; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &self[0]; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-6.stderr b/src/test/ui/borrowck/issue-81365-6.stderr new file mode 100644 index 0000000000000..d35d12b9a8b5d --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-6.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-6.rs:18:9 + | +LL | let first = &self[0]; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `[()]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-7.rs b/src/test/ui/borrowck/issue-81365-7.rs new file mode 100644 index 0000000000000..cbf70f11a9acf --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-7.rs @@ -0,0 +1,24 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +fn bad_borrow(c: &mut Container) { + let first = &c.target_field; + c.container_field = true; //~ ERROR E0506 + first; +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-7.stderr b/src/test/ui/borrowck/issue-81365-7.stderr new file mode 100644 index 0000000000000..0ee9fb8282112 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-7.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `c.container_field` because it is borrowed + --> $DIR/issue-81365-7.rs:20:5 + | +LL | let first = &c.target_field; + | - borrow of `c.container_field` occurs here +LL | c.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `c.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-8.rs b/src/test/ui/borrowck/issue-81365-8.rs new file mode 100644 index 0000000000000..0bb1033fb42f7 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-8.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &(*self).target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365.rs b/src/test/ui/borrowck/issue-81365.rs new file mode 100644 index 0000000000000..8e212a7701647 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &self.target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365.stderr b/src/test/ui/borrowck/issue-81365.stderr new file mode 100644 index 0000000000000..a7dc5366f807e --- /dev/null +++ b/src/test/ui/borrowck/issue-81365.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365.rs:21:9 + | +LL | let first = &self.target_field; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. From 8412da6829cd9f71f33a039a24ea3470f586f250 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Tue, 2 Feb 2021 03:20:56 +1100 Subject: [PATCH 02/27] Add tests --- .../{issue-81365.rs => issue-81365-1.rs} | 0 ...ssue-81365.stderr => issue-81365-1.stderr} | 2 +- src/test/ui/borrowck/issue-81365-10.rs | 26 +++++++++++++++ src/test/ui/borrowck/issue-81365-10.stderr | 13 ++++++++ src/test/ui/borrowck/issue-81365-11.rs | 32 +++++++++++++++++++ src/test/ui/borrowck/issue-81365-11.stderr | 13 ++++++++ src/test/ui/borrowck/issue-81365-8.stderr | 15 +++++++++ src/test/ui/borrowck/issue-81365-9.rs | 26 +++++++++++++++ src/test/ui/borrowck/issue-81365-9.stderr | 13 ++++++++ 9 files changed, 139 insertions(+), 1 deletion(-) rename src/test/ui/borrowck/{issue-81365.rs => issue-81365-1.rs} (100%) rename src/test/ui/borrowck/{issue-81365.stderr => issue-81365-1.stderr} (94%) create mode 100644 src/test/ui/borrowck/issue-81365-10.rs create mode 100644 src/test/ui/borrowck/issue-81365-10.stderr create mode 100644 src/test/ui/borrowck/issue-81365-11.rs create mode 100644 src/test/ui/borrowck/issue-81365-11.stderr create mode 100644 src/test/ui/borrowck/issue-81365-8.stderr create mode 100644 src/test/ui/borrowck/issue-81365-9.rs create mode 100644 src/test/ui/borrowck/issue-81365-9.stderr diff --git a/src/test/ui/borrowck/issue-81365.rs b/src/test/ui/borrowck/issue-81365-1.rs similarity index 100% rename from src/test/ui/borrowck/issue-81365.rs rename to src/test/ui/borrowck/issue-81365-1.rs diff --git a/src/test/ui/borrowck/issue-81365.stderr b/src/test/ui/borrowck/issue-81365-1.stderr similarity index 94% rename from src/test/ui/borrowck/issue-81365.stderr rename to src/test/ui/borrowck/issue-81365-1.stderr index a7dc5366f807e..f680cd629d2fc 100644 --- a/src/test/ui/borrowck/issue-81365.stderr +++ b/src/test/ui/borrowck/issue-81365-1.stderr @@ -1,5 +1,5 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed - --> $DIR/issue-81365.rs:21:9 + --> $DIR/issue-81365-1.rs:21:9 | LL | let first = &self.target_field; | ---- borrow of `self.container_field` occurs here diff --git a/src/test/ui/borrowck/issue-81365-10.rs b/src/test/ui/borrowck/issue-81365-10.rs new file mode 100644 index 0000000000000..7602e184a9f9d --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-10.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &self.deref().target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-10.stderr b/src/test/ui/borrowck/issue-81365-10.stderr new file mode 100644 index 0000000000000..891f70ed7f6b4 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-10.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-10.rs:21:9 + | +LL | let first = &self.deref().target_field; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-11.rs b/src/test/ui/borrowck/issue-81365-11.rs new file mode 100644 index 0000000000000..6b558c65d3d61 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-11.rs @@ -0,0 +1,32 @@ +use std::ops::{Deref, DerefMut}; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl DerefMut for Container { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &mut self.target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-11.stderr b/src/test/ui/borrowck/issue-81365-11.stderr new file mode 100644 index 0000000000000..0770c136632db --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-11.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-11.rs:27:9 + | +LL | let first = &mut self.target_field; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-8.stderr b/src/test/ui/borrowck/issue-81365-8.stderr new file mode 100644 index 0000000000000..0656c65c8232d --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-8.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-8.rs:21:9 + | +LL | let first = &(*self).target_field; + | ------- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-81365-9.rs b/src/test/ui/borrowck/issue-81365-9.rs new file mode 100644 index 0000000000000..cd57afa288df7 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-9.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &Deref::deref(self).target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81365-9.stderr b/src/test/ui/borrowck/issue-81365-9.stderr new file mode 100644 index 0000000000000..c7d48214fd4a8 --- /dev/null +++ b/src/test/ui/borrowck/issue-81365-9.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-9.rs:21:9 + | +LL | let first = &Deref::deref(self).target_field; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. From ef778e796502691ebfb1f3dd5c03248aea6d2ac8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 Feb 2021 18:14:23 +0100 Subject: [PATCH 03/27] Fix span in non_fmt_panic for panic!(some_macro!()). --- compiler/rustc_lint/src/non_fmt_panic.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index e98297b692c92..0c5456cf619d1 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -69,19 +69,30 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc let (span, panic) = panic_call(cx, f); - cx.struct_span_lint(NON_FMT_PANIC, arg.span, |lint| { + // Find the span of the argument to `panic!()`, before expansion in the + // case of `panic!(some_macro!())`. + let mut arg_span = arg.span; + while !span.contains(arg_span) { + let expn = arg_span.ctxt().outer_expn_data(); + if expn.is_root() { + break; + } + arg_span = expn.call_site; + } + + cx.struct_span_lint(NON_FMT_PANIC, arg_span, |lint| { let mut l = lint.build("panic message is not a string literal"); l.note("this is no longer accepted in Rust 2021"); - if span.contains(arg.span) { + if span.contains(arg_span) { l.span_suggestion_verbose( - arg.span.shrink_to_lo(), + arg_span.shrink_to_lo(), "add a \"{}\" format string to Display the message", "\"{}\", ".into(), Applicability::MaybeIncorrect, ); if panic == sym::std_panic_macro { l.span_suggestion_verbose( - span.until(arg.span), + span.until(arg_span), "or use std::panic::panic_any instead", "std::panic::panic_any(".into(), Applicability::MachineApplicable, From 1abc1e2a43c116a87bd430fa14a86e67617b861a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 Feb 2021 18:17:34 +0100 Subject: [PATCH 04/27] Add test for non_fmt_panic lint for panic!(some_macro!()). --- src/test/ui/non-fmt-panic.rs | 6 ++++++ src/test/ui/non-fmt-panic.stderr | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/test/ui/non-fmt-panic.rs b/src/test/ui/non-fmt-panic.rs index 25c53316e1290..ff9e3b497f23d 100644 --- a/src/test/ui/non-fmt-panic.rs +++ b/src/test/ui/non-fmt-panic.rs @@ -29,6 +29,12 @@ fn main() { fancy_panic::fancy_panic!(S); //~^ WARN panic message is not a string literal + macro_rules! a { + () => { 123 }; + } + + panic!(a!()); //~ WARN panic message is not a string literal + // Check that the lint only triggers for std::panic and core::panic, // not any panic macro: macro_rules! panic { diff --git a/src/test/ui/non-fmt-panic.stderr b/src/test/ui/non-fmt-panic.stderr index 45187c518c423..2f33f04cb19f6 100644 --- a/src/test/ui/non-fmt-panic.stderr +++ b/src/test/ui/non-fmt-panic.stderr @@ -183,5 +183,21 @@ LL | fancy_panic::fancy_panic!(S); | = note: this is no longer accepted in Rust 2021 -warning: 14 warnings emitted +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:36:12 + | +LL | panic!(a!()); + | ^^^^ + | + = note: this is no longer accepted in Rust 2021 +help: add a "{}" format string to Display the message + | +LL | panic!("{}", a!()); + | ^^^^^ +help: or use std::panic::panic_any instead + | +LL | std::panic::panic_any(a!()); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: 15 warnings emitted From a428ab17abc310c17ca13eeb6f74b3c5bddff940 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 Feb 2021 18:52:47 +0100 Subject: [PATCH 05/27] Improve suggestion for panic!(format!(..)). --- compiler/rustc_lint/src/non_fmt_panic.rs | 31 +++++++++++++++++++++++- compiler/rustc_span/src/symbol.rs | 1 + library/alloc/src/macros.rs | 1 + 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 0c5456cf619d1..7432f476d7cd0 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -72,18 +72,38 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc // Find the span of the argument to `panic!()`, before expansion in the // case of `panic!(some_macro!())`. let mut arg_span = arg.span; + let mut arg_macro = None; while !span.contains(arg_span) { let expn = arg_span.ctxt().outer_expn_data(); if expn.is_root() { break; } + arg_macro = expn.macro_def_id; arg_span = expn.call_site; } cx.struct_span_lint(NON_FMT_PANIC, arg_span, |lint| { let mut l = lint.build("panic message is not a string literal"); l.note("this is no longer accepted in Rust 2021"); - if span.contains(arg_span) { + if !span.contains(arg_span) { + // No clue where this argument is coming from. + l.emit(); + return; + } + if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { + // A case of `panic!(format!(..))`. + l.note("the panic!() macro supports formatting, so there's no need for the format!() macro here"); + if let Some(inner) = find_inner_span(cx, arg_span) { + l.multipart_suggestion( + "remove the `format!(..)` macro call", + vec![ + (arg_span.until(inner), "".into()), + (inner.between(arg_span.shrink_to_hi()), "".into()), + ], + Applicability::MachineApplicable, + ); + } + } else { l.span_suggestion_verbose( arg_span.shrink_to_lo(), "add a \"{}\" format string to Display the message", @@ -186,6 +206,15 @@ fn check_panic_str<'tcx>( } } +/// Given the span of `some_macro!(args)`, gives the span of `args`. +fn find_inner_span<'tcx>(cx: &LateContext<'tcx>, span: Span) -> Option { + let snippet = cx.sess().parse_sess.source_map().span_to_snippet(span).ok()?; + Some(span.from_inner(InnerSpan { + start: snippet.find(&['(', '{', '['][..])? + 1, + end: snippet.rfind(&[')', '}', ']'][..])?, + })) +} + fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol) { let mut expn = f.span.ctxt().outer_expn_data(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 20e4f7262acb9..831e82559adcc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -554,6 +554,7 @@ symbols! { format_args, format_args_capture, format_args_nl, + format_macro, freeze, freg, frem_fast, diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index a64a8b32ad77f..88a6cec3a8342 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -107,6 +107,7 @@ macro_rules! vec { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "format_macro"] macro_rules! format { ($($arg:tt)*) => {{ let res = $crate::fmt::format($crate::__export::format_args!($($arg)*)); From 9f97a0b364bcbb261f05d6ac62436b6802bfa80b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 Feb 2021 18:53:10 +0100 Subject: [PATCH 06/27] Add test for panic!(format!(..)) lint. --- src/test/ui/non-fmt-panic.rs | 2 ++ src/test/ui/non-fmt-panic.stderr | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/test/ui/non-fmt-panic.rs b/src/test/ui/non-fmt-panic.rs index ff9e3b497f23d..c20df5ffd10a0 100644 --- a/src/test/ui/non-fmt-panic.rs +++ b/src/test/ui/non-fmt-panic.rs @@ -35,6 +35,8 @@ fn main() { panic!(a!()); //~ WARN panic message is not a string literal + panic!(format!("{}", 1)); //~ WARN panic message is not a string literal + // Check that the lint only triggers for std::panic and core::panic, // not any panic macro: macro_rules! panic { diff --git a/src/test/ui/non-fmt-panic.stderr b/src/test/ui/non-fmt-panic.stderr index 2f33f04cb19f6..043c4b0f7506c 100644 --- a/src/test/ui/non-fmt-panic.stderr +++ b/src/test/ui/non-fmt-panic.stderr @@ -199,5 +199,18 @@ help: or use std::panic::panic_any instead LL | std::panic::panic_any(a!()); | ^^^^^^^^^^^^^^^^^^^^^^ -warning: 15 warnings emitted +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:38:12 + | +LL | panic!(format!("{}", 1)); + | ^^^^^^^^^^^^^^^^ + | + = note: this is no longer accepted in Rust 2021 + = note: the panic!() macro supports formatting, so there's no need for the format!() macro here +help: remove the `format!(..)` macro call + | +LL | panic!("{}", 1); + | -- -- + +warning: 16 warnings emitted From 37c532c010cddb8f9283fb50318d8c3816646063 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 Feb 2021 19:43:07 +0100 Subject: [PATCH 07/27] Suggest correct replacement for panic![123]. Before this change, the suggestion was `std::panic::panic_any(123]`, changing the opening brace but not the closing one. --- compiler/rustc_lint/src/non_fmt_panic.rs | 48 ++++++++++++++++-------- src/test/ui/non-fmt-panic.stderr | 8 ++-- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 7432f476d7cd0..c4627745648d3 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -93,12 +93,12 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { // A case of `panic!(format!(..))`. l.note("the panic!() macro supports formatting, so there's no need for the format!() macro here"); - if let Some(inner) = find_inner_span(cx, arg_span) { + if let Some((open, close, _)) = find_delimiters(cx, arg_span) { l.multipart_suggestion( "remove the `format!(..)` macro call", vec![ - (arg_span.until(inner), "".into()), - (inner.between(arg_span.shrink_to_hi()), "".into()), + (arg_span.until(open.shrink_to_hi()), "".into()), + (close.until(arg_span.shrink_to_hi()), "".into()), ], Applicability::MachineApplicable, ); @@ -111,12 +111,20 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc Applicability::MaybeIncorrect, ); if panic == sym::std_panic_macro { - l.span_suggestion_verbose( - span.until(arg_span), - "or use std::panic::panic_any instead", - "std::panic::panic_any(".into(), - Applicability::MachineApplicable, - ); + if let Some((open, close, del)) = find_delimiters(cx, span) { + l.multipart_suggestion( + "or use std::panic::panic_any instead", + if del == '(' { + vec![(span.until(open), "std::panic::panic_any".into())] + } else { + vec![ + (span.until(open.shrink_to_hi()), "std::panic::panic_any(".into()), + (close, ")".into()), + ] + }, + Applicability::MachineApplicable, + ); + } } } l.emit(); @@ -206,13 +214,23 @@ fn check_panic_str<'tcx>( } } -/// Given the span of `some_macro!(args)`, gives the span of `args`. -fn find_inner_span<'tcx>(cx: &LateContext<'tcx>, span: Span) -> Option { +/// Given the span of `some_macro!(args);`, gives the span of `(` and `)`, +/// and the type of (opening) delimiter used. +fn find_delimiters<'tcx>(cx: &LateContext<'tcx>, span: Span) -> Option<(Span, Span, char)> { let snippet = cx.sess().parse_sess.source_map().span_to_snippet(span).ok()?; - Some(span.from_inner(InnerSpan { - start: snippet.find(&['(', '{', '['][..])? + 1, - end: snippet.rfind(&[')', '}', ']'][..])?, - })) + let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?; + let close = snippet.rfind(|c| ")]}".contains(c))?; + Some(( + span.from_inner(InnerSpan { + start: open, + end: open + 1, + }), + span.from_inner(InnerSpan { + start: close, + end: close + 1, + }), + open_ch, + )) } fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol) { diff --git a/src/test/ui/non-fmt-panic.stderr b/src/test/ui/non-fmt-panic.stderr index 043c4b0f7506c..001f066ad212a 100644 --- a/src/test/ui/non-fmt-panic.stderr +++ b/src/test/ui/non-fmt-panic.stderr @@ -93,7 +93,7 @@ LL | panic!("{}", C); help: or use std::panic::panic_any instead | LL | std::panic::panic_any(C); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: panic message is not a string literal --> $DIR/non-fmt-panic.rs:20:12 @@ -109,7 +109,7 @@ LL | panic!("{}", S); help: or use std::panic::panic_any instead | LL | std::panic::panic_any(S); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: panic message is not a string literal --> $DIR/non-fmt-panic.rs:21:17 @@ -125,7 +125,7 @@ LL | std::panic!("{}", 123); help: or use std::panic::panic_any instead | LL | std::panic::panic_any(123); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: panic message is not a string literal --> $DIR/non-fmt-panic.rs:22:18 @@ -197,7 +197,7 @@ LL | panic!("{}", a!()); help: or use std::panic::panic_any instead | LL | std::panic::panic_any(a!()); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: panic message is not a string literal --> $DIR/non-fmt-panic.rs:38:12 From 8ad12bb9b2709678f58e780daca981aafc2810dd Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 Feb 2021 19:44:57 +0100 Subject: [PATCH 08/27] Add ui tests for panic![123] and panic!{123}. --- src/test/ui/non-fmt-panic.rs | 3 +++ src/test/ui/non-fmt-panic.stderr | 34 +++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/test/ui/non-fmt-panic.rs b/src/test/ui/non-fmt-panic.rs index c20df5ffd10a0..c80a90b3eaaac 100644 --- a/src/test/ui/non-fmt-panic.rs +++ b/src/test/ui/non-fmt-panic.rs @@ -37,6 +37,9 @@ fn main() { panic!(format!("{}", 1)); //~ WARN panic message is not a string literal + panic![123]; //~ WARN panic message is not a string literal + panic!{123}; //~ WARN panic message is not a string literal + // Check that the lint only triggers for std::panic and core::panic, // not any panic macro: macro_rules! panic { diff --git a/src/test/ui/non-fmt-panic.stderr b/src/test/ui/non-fmt-panic.stderr index 001f066ad212a..7a333b3e76abe 100644 --- a/src/test/ui/non-fmt-panic.stderr +++ b/src/test/ui/non-fmt-panic.stderr @@ -212,5 +212,37 @@ help: remove the `format!(..)` macro call LL | panic!("{}", 1); | -- -- -warning: 16 warnings emitted +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:40:12 + | +LL | panic![123]; + | ^^^ + | + = note: this is no longer accepted in Rust 2021 +help: add a "{}" format string to Display the message + | +LL | panic!["{}", 123]; + | ^^^^^ +help: or use std::panic::panic_any instead + | +LL | std::panic::panic_any(123); + | ^^^^^^^^^^^^^^^^^^^^^^ ^ + +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:41:12 + | +LL | panic!{123}; + | ^^^ + | + = note: this is no longer accepted in Rust 2021 +help: add a "{}" format string to Display the message + | +LL | panic!{"{}", 123}; + | ^^^^^ +help: or use std::panic::panic_any instead + | +LL | std::panic::panic_any(123); + | ^^^^^^^^^^^^^^^^^^^^^^ ^ + +warning: 18 warnings emitted From 2a0c42450ec34f2c4b3985c159c499560f1c8270 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 Feb 2021 19:51:15 +0100 Subject: [PATCH 09/27] Formatting. --- compiler/rustc_lint/src/non_fmt_panic.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index c4627745648d3..0c7c8b78845cf 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -221,14 +221,8 @@ fn find_delimiters<'tcx>(cx: &LateContext<'tcx>, span: Span) -> Option<(Span, Sp let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?; let close = snippet.rfind(|c| ")]}".contains(c))?; Some(( - span.from_inner(InnerSpan { - start: open, - end: open + 1, - }), - span.from_inner(InnerSpan { - start: close, - end: close + 1, - }), + span.from_inner(InnerSpan { start: open, end: open + 1 }), + span.from_inner(InnerSpan { start: close, end: close + 1 }), open_ch, )) } From daa371d1891f6833ad08542caeb3cf424483a0f9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 Feb 2021 20:03:13 +0100 Subject: [PATCH 10/27] Only define rustc_diagnostic_item format_macro in not(test). --- library/alloc/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 88a6cec3a8342..6a64587a2237f 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -107,7 +107,7 @@ macro_rules! vec { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "format_macro"] +#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")] macro_rules! format { ($($arg:tt)*) => {{ let res = $crate::fmt::format($crate::__export::format_args!($($arg)*)); From ad93f48d770cc8cfe473e809700201c31550bc68 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 17 Feb 2021 10:51:22 +0100 Subject: [PATCH 11/27] Add comment about how we find the right span in non_fmt_panic. --- compiler/rustc_lint/src/non_fmt_panic.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 0c7c8b78845cf..bfe37ce6959e7 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -71,6 +71,9 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc // Find the span of the argument to `panic!()`, before expansion in the // case of `panic!(some_macro!())`. + // We don't use source_callsite(), because this `panic!(..)` might itself + // be expanded from another macro, in which case we want to stop at that + // expansion. let mut arg_span = arg.span; let mut arg_macro = None; while !span.contains(arg_span) { From bf09e0499e30a39426695c149c8a45c0c06bf715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 18 Feb 2021 00:00:00 +0000 Subject: [PATCH 12/27] Implement -Z hir-stats for nested foreign items An attempt to compute HIR stats for crates with nested foreign items results in an ICE. ``` fn main() { extern "C" { fn f(); } } ``` ``` thread 'rustc' panicked at 'visit_nested_xxx must be manually implemented in this visitor' ``` Provide required implementation of visitor method. --- compiler/rustc_passes/src/hir_stats.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index e35ad10968d33..177e4e2d08fa2 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -114,6 +114,11 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { self.visit_impl_item(nested_impl_item) } + fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) { + let nested_foreign_item = self.krate.unwrap().foreign_item(id); + self.visit_foreign_item(nested_foreign_item); + } + fn visit_nested_body(&mut self, body_id: hir::BodyId) { let nested_body = self.krate.unwrap().body(body_id); self.visit_body(nested_body) From 343b67387772dbd068d06a76267288579d3eaed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 19 Feb 2021 00:00:00 +0000 Subject: [PATCH 13/27] Consider auto derefs before warning about write only fields Changes from 81473 extended the dead code lint with an ability to detect fields that are written to but never read from. The implementation skips over fields on the left hand side of an assignment, without marking them as live. A field access might involve an automatic dereference and de-facto read the field. Conservatively mark expressions with deref adjustments as live to avoid generating false positive warnings. --- compiler/rustc_passes/src/dead.rs | 28 ++++++----- .../ui/lint/dead-code/write-only-field.rs | 49 +++++++++++++++++++ .../ui/lint/dead-code/write-only-field.stderr | 20 +++++++- 3 files changed, 85 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d51b501f7ae3d..62a95aa57c29f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -37,15 +37,6 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { ) } -fn base_expr<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - loop { - match expr.kind { - hir::ExprKind::Field(base, ..) => expr = base, - _ => return expr, - } - } -} - struct MarkSymbolVisitor<'tcx> { worklist: Vec, tcx: TyCtxt<'tcx>, @@ -143,6 +134,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } + fn handle_assign(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if self + .typeck_results() + .expr_adjustments(expr) + .iter() + .any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) + { + self.visit_expr(expr); + } else if let hir::ExprKind::Field(base, ..) = expr.kind { + // Ignore write to field + self.handle_assign(base); + } else { + self.visit_expr(expr); + } + } + fn handle_field_pattern_match( &mut self, lhs: &hir::Pat<'_>, @@ -272,8 +279,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.lookup_and_handle_method(expr.hir_id); } hir::ExprKind::Assign(ref left, ref right, ..) => { - // Ignore write to field - self.visit_expr(base_expr(left)); + self.handle_assign(left); self.visit_expr(right); return; } diff --git a/src/test/ui/lint/dead-code/write-only-field.rs b/src/test/ui/lint/dead-code/write-only-field.rs index 78cfcfda8f971..7b3f1e9f5b6cb 100644 --- a/src/test/ui/lint/dead-code/write-only-field.rs +++ b/src/test/ui/lint/dead-code/write-only-field.rs @@ -17,4 +17,53 @@ fn field_write(s: &mut S) { fn main() { let mut s = S { f: 0, sub: Sub { f: 0 } }; field_write(&mut s); + + auto_deref(); + nested_boxes(); +} + +fn auto_deref() { + struct E { + x: bool, + y: bool, //~ ERROR: field is never read + } + + struct P<'a> { + e: &'a mut E + } + + impl P<'_> { + fn f(&mut self) { + self.e.x = true; + self.e.y = true; + } + } + + let mut e = E { x: false, y: false }; + let mut p = P { e: &mut e }; + p.f(); + assert!(e.x); +} + +fn nested_boxes() { + struct A { + b: Box, + } + + struct B { + c: Box, + } + + struct C { + u: u32, //~ ERROR: field is never read + v: u32, //~ ERROR: field is never read + } + + let mut a = A { + b: Box::new(B { + c: Box::new(C { u: 0, v: 0 }), + }), + }; + a.b.c.v = 10; + a.b.c = Box::new(C { u: 1, v: 2 }); } diff --git a/src/test/ui/lint/dead-code/write-only-field.stderr b/src/test/ui/lint/dead-code/write-only-field.stderr index 70d2149665b20..a191d22c8b94c 100644 --- a/src/test/ui/lint/dead-code/write-only-field.stderr +++ b/src/test/ui/lint/dead-code/write-only-field.stderr @@ -22,5 +22,23 @@ error: field is never read: `f` LL | f: i32, | ^^^^^^ -error: aborting due to 3 previous errors +error: field is never read: `y` + --> $DIR/write-only-field.rs:28:9 + | +LL | y: bool, + | ^^^^^^^ + +error: field is never read: `u` + --> $DIR/write-only-field.rs:58:9 + | +LL | u: u32, + | ^^^^^^ + +error: field is never read: `v` + --> $DIR/write-only-field.rs:59:9 + | +LL | v: u32, + | ^^^^^^ + +error: aborting due to 6 previous errors From 99f45732646443253524a3e85cb102d3b9430c6f Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Fri, 19 Feb 2021 13:30:49 +1100 Subject: [PATCH 14/27] Add deref definition location Update conflict_errors.rs Add deref definition location --- .../src/borrow_check/diagnostics/conflict_errors.rs | 1 + src/test/ui/borrowck/issue-81365-1.stderr | 5 +++++ src/test/ui/borrowck/issue-81365-2.stderr | 5 +++++ src/test/ui/borrowck/issue-81365-3.stderr | 5 +++++ src/test/ui/borrowck/issue-81365-4.stderr | 5 +++++ src/test/ui/borrowck/issue-81365-5.stderr | 5 +++++ src/test/ui/borrowck/issue-81365-6.stderr | 5 +++++ src/test/ui/borrowck/issue-81365-7.stderr | 5 +++++ src/test/ui/borrowck/issue-81365-8.stderr | 5 +++++ 9 files changed, 41 insertions(+) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 4bf4df226e172..f5bd497135ff3 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1568,6 +1568,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "borrow occurs due to deref coercion to `{}`", deref_target_ty )); + err.span_note(tcx.def_span(instance.def_id()), "deref defined here"); } } } diff --git a/src/test/ui/borrowck/issue-81365-1.stderr b/src/test/ui/borrowck/issue-81365-1.stderr index f680cd629d2fc..ef88d7f14a39b 100644 --- a/src/test/ui/borrowck/issue-81365-1.stderr +++ b/src/test/ui/borrowck/issue-81365-1.stderr @@ -9,6 +9,11 @@ LL | first; | ----- borrow later used here | = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-1.rs:12:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-2.stderr b/src/test/ui/borrowck/issue-81365-2.stderr index 851cc4b1af29f..e71edb509649f 100644 --- a/src/test/ui/borrowck/issue-81365-2.stderr +++ b/src/test/ui/borrowck/issue-81365-2.stderr @@ -9,6 +9,11 @@ LL | first; | ----- borrow later used here | = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-2.rs:12:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-3.stderr b/src/test/ui/borrowck/issue-81365-3.stderr index eedbed3cfe6c1..70bb6bb93a94b 100644 --- a/src/test/ui/borrowck/issue-81365-3.stderr +++ b/src/test/ui/borrowck/issue-81365-3.stderr @@ -9,6 +9,11 @@ LL | first; | ----- borrow later used here | = note: borrow occurs due to deref coercion to `Container` +note: deref defined here + --> $DIR/issue-81365-3.rs:23:5 + | +LL | type Target = Container; + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-4.stderr b/src/test/ui/borrowck/issue-81365-4.stderr index 82c9fbbc16f6b..e714bb86d1cd2 100644 --- a/src/test/ui/borrowck/issue-81365-4.stderr +++ b/src/test/ui/borrowck/issue-81365-4.stderr @@ -9,6 +9,11 @@ LL | first; | ----- borrow later used here | = note: borrow occurs due to deref coercion to `Container` +note: deref defined here + --> $DIR/issue-81365-4.rs:24:5 + | +LL | type Target = Container; + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-5.stderr b/src/test/ui/borrowck/issue-81365-5.stderr index 8085faf82ed06..7c0e9f43bd0b0 100644 --- a/src/test/ui/borrowck/issue-81365-5.stderr +++ b/src/test/ui/borrowck/issue-81365-5.stderr @@ -9,6 +9,11 @@ LL | first; | ----- borrow later used here | = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-5.rs:19:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-6.stderr b/src/test/ui/borrowck/issue-81365-6.stderr index d35d12b9a8b5d..85ed6acca3d41 100644 --- a/src/test/ui/borrowck/issue-81365-6.stderr +++ b/src/test/ui/borrowck/issue-81365-6.stderr @@ -9,6 +9,11 @@ LL | first; | ----- borrow later used here | = note: borrow occurs due to deref coercion to `[()]` +note: deref defined here + --> $DIR/issue-81365-6.rs:9:5 + | +LL | type Target = [()]; + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-7.stderr b/src/test/ui/borrowck/issue-81365-7.stderr index 0ee9fb8282112..506732ec0c5b4 100644 --- a/src/test/ui/borrowck/issue-81365-7.stderr +++ b/src/test/ui/borrowck/issue-81365-7.stderr @@ -9,6 +9,11 @@ LL | first; | ----- borrow later used here | = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-7.rs:12:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-8.stderr b/src/test/ui/borrowck/issue-81365-8.stderr index 0656c65c8232d..716b6e9b51fd0 100644 --- a/src/test/ui/borrowck/issue-81365-8.stderr +++ b/src/test/ui/borrowck/issue-81365-8.stderr @@ -9,6 +9,11 @@ LL | first; | ----- borrow later used here | = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-8.rs:12:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error From 0fddc2f780b7d075797364386a77b5f2f3bf909b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 21 Oct 2020 00:46:29 +0300 Subject: [PATCH 15/27] Support `pub` on `macro_rules` --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/active.rs | 3 ++ compiler/rustc_parse/src/parser/item.rs | 10 +--- .../rustc_resolve/src/build_reduced_graph.rs | 9 +++- compiler/rustc_span/src/symbol.rs | 1 + src/test/ui/did_you_mean/pub-macro-rules.rs | 16 ------- .../ui/did_you_mean/pub-macro-rules.stderr | 8 ---- .../feature-gate-pub_macro_rules.rs | 10 ++++ .../feature-gate-pub_macro_rules.stderr | 39 +++++++++++++++ .../macro-export-on-modularized-macros.rs | 11 +++++ .../macro-export-on-modularized-macros.stderr | 14 ++++++ src/test/ui/macros/pub-macro-rules-fail.rs | 28 +++++++++++ .../ui/macros/pub-macro-rules-fail.stderr | 48 +++++++++++++++++++ src/test/ui/macros/pub-macro-rules.rs | 20 ++++++++ 14 files changed, 183 insertions(+), 35 deletions(-) delete mode 100644 src/test/ui/did_you_mean/pub-macro-rules.rs delete mode 100644 src/test/ui/did_you_mean/pub-macro-rules.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs create mode 100644 src/test/ui/feature-gates/feature-gate-pub_macro_rules.stderr create mode 100644 src/test/ui/macros/macro-export-on-modularized-macros.rs create mode 100644 src/test/ui/macros/macro-export-on-modularized-macros.stderr create mode 100644 src/test/ui/macros/pub-macro-rules-fail.rs create mode 100644 src/test/ui/macros/pub-macro-rules-fail.stderr create mode 100644 src/test/ui/macros/pub-macro-rules.rs diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 6514de2b81315..474ec2b589b71 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -665,6 +665,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { // involved, so we only emit errors where there are no other parsing errors. gate_all!(destructuring_assignment, "destructuring assignments are unstable"); } + gate_all!(pub_macro_rules, "`pub` on `macro_rules` items is unstable"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 2d0009c225c59..56f5c3b79bef9 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -638,6 +638,9 @@ declare_features! ( /// Allows macro attributes to observe output of `#[derive]`. (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None), + /// Allows `pub` on `macro_rules` items. + (active, pub_macro_rules, "1.49.0", Some(78855), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index cdea82f50ede4..45f6dbca9f048 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1488,15 +1488,7 @@ impl<'a> Parser<'a> { let vstr = pprust::vis_to_string(vis); let vstr = vstr.trim_end(); if macro_rules { - let msg = format!("can't qualify macro_rules invocation with `{}`", vstr); - self.struct_span_err(vis.span, &msg) - .span_suggestion( - vis.span, - "try exporting the macro", - "#[macro_export]".to_owned(), - Applicability::MaybeIncorrect, // speculative - ) - .emit(); + self.sess.gated_spans.gate(sym::pub_macro_rules, vis.span); } else { self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`") .span_suggestion( diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 79ed0b5308dab..65e5b0dddea30 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1230,13 +1230,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }; let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id.to_def_id()); + let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export); self.r.macro_map.insert(def_id.to_def_id(), ext); self.r.local_macro_def_scopes.insert(def_id, parent_scope.module); - if macro_rules { + if macro_rules && matches!(item.vis.kind, ast::VisibilityKind::Inherited) { let ident = ident.normalize_to_macros_2_0(); self.r.macro_names.insert(ident); - let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { ty::Visibility::Public } else { @@ -1261,6 +1261,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }), )) } else { + if is_macro_export { + let what = if macro_rules { "`macro_rules` with `pub`" } else { "`macro` items" }; + let msg = format!("`#[macro_export]` cannot be used on {what}"); + self.r.session.span_err(item.span, &msg); + } let module = parent_scope.module; let vis = match item.kind { // Visibilities must not be resolved non-speculatively twice diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 653d70b6cf244..d4a0f968eee1e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -874,6 +874,7 @@ symbols! { ptr_guaranteed_eq, ptr_guaranteed_ne, ptr_offset_from, + pub_macro_rules, pub_restricted, pure, pushpop_unsafe, diff --git a/src/test/ui/did_you_mean/pub-macro-rules.rs b/src/test/ui/did_you_mean/pub-macro-rules.rs deleted file mode 100644 index c5393703f7091..0000000000000 --- a/src/test/ui/did_you_mean/pub-macro-rules.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[macro_use] mod bleh { - pub macro_rules! foo { //~ ERROR can't qualify macro_rules invocation - ($n:ident) => ( - fn $n () -> i32 { - 1 - } - ) - } - -} - -foo!(meh); - -fn main() { - println!("{}", meh()); -} diff --git a/src/test/ui/did_you_mean/pub-macro-rules.stderr b/src/test/ui/did_you_mean/pub-macro-rules.stderr deleted file mode 100644 index 0bde5783b8cc6..0000000000000 --- a/src/test/ui/did_you_mean/pub-macro-rules.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: can't qualify macro_rules invocation with `pub` - --> $DIR/pub-macro-rules.rs:2:5 - | -LL | pub macro_rules! foo { - | ^^^ help: try exporting the macro: `#[macro_export]` - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs b/src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs new file mode 100644 index 0000000000000..5504ec317ae59 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs @@ -0,0 +1,10 @@ +pub macro_rules! m1 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable + +#[cfg(FALSE)] +pub macro_rules! m2 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable + +pub(crate) macro_rules! m3 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable + +pub(in self) macro_rules! m4 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-pub_macro_rules.stderr b/src/test/ui/feature-gates/feature-gate-pub_macro_rules.stderr new file mode 100644 index 0000000000000..bfaec398d9a97 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-pub_macro_rules.stderr @@ -0,0 +1,39 @@ +error[E0658]: `pub` on `macro_rules` items is unstable + --> $DIR/feature-gate-pub_macro_rules.rs:1:1 + | +LL | pub macro_rules! m1 { () => {} } + | ^^^ + | + = note: see issue #78855 for more information + = help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable + +error[E0658]: `pub` on `macro_rules` items is unstable + --> $DIR/feature-gate-pub_macro_rules.rs:4:1 + | +LL | pub macro_rules! m2 { () => {} } + | ^^^ + | + = note: see issue #78855 for more information + = help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable + +error[E0658]: `pub` on `macro_rules` items is unstable + --> $DIR/feature-gate-pub_macro_rules.rs:6:1 + | +LL | pub(crate) macro_rules! m3 { () => {} } + | ^^^^^^^^^^ + | + = note: see issue #78855 for more information + = help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable + +error[E0658]: `pub` on `macro_rules` items is unstable + --> $DIR/feature-gate-pub_macro_rules.rs:8:1 + | +LL | pub(in self) macro_rules! m4 { () => {} } + | ^^^^^^^^^^^^ + | + = note: see issue #78855 for more information + = help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macros/macro-export-on-modularized-macros.rs b/src/test/ui/macros/macro-export-on-modularized-macros.rs new file mode 100644 index 0000000000000..467c6ba7b78e4 --- /dev/null +++ b/src/test/ui/macros/macro-export-on-modularized-macros.rs @@ -0,0 +1,11 @@ +#![feature(decl_macro)] +#![feature(pub_macro_rules)] + +#[macro_export] +macro m1() {} //~ ERROR `#[macro_export]` cannot be used on `macro` items + +#[macro_export] +pub macro_rules! m2 { () => {} } +//~^ ERROR `#[macro_export]` cannot be used on `macro_rules` with `pub` + +fn main() {} diff --git a/src/test/ui/macros/macro-export-on-modularized-macros.stderr b/src/test/ui/macros/macro-export-on-modularized-macros.stderr new file mode 100644 index 0000000000000..8bb031e12cba2 --- /dev/null +++ b/src/test/ui/macros/macro-export-on-modularized-macros.stderr @@ -0,0 +1,14 @@ +error: `#[macro_export]` cannot be used on `macro` items + --> $DIR/macro-export-on-modularized-macros.rs:5:1 + | +LL | macro m1() {} + | ^^^^^^^^^^^^^ + +error: `#[macro_export]` cannot be used on `macro_rules` with `pub` + --> $DIR/macro-export-on-modularized-macros.rs:8:1 + | +LL | pub macro_rules! m2 { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/macros/pub-macro-rules-fail.rs b/src/test/ui/macros/pub-macro-rules-fail.rs new file mode 100644 index 0000000000000..bdb4c73f18b18 --- /dev/null +++ b/src/test/ui/macros/pub-macro-rules-fail.rs @@ -0,0 +1,28 @@ +#![feature(pub_macro_rules)] + +#[macro_use] +mod m { + pub macro_rules! mac { () => {} } + + // `pub` `macro_rules` cannot be redefined in the same module. + pub macro_rules! mac { () => {} } //~ ERROR the name `mac` is defined multiple times + + pub(self) macro_rules! private_mac { () => {} } +} + +const _: () = { + pub macro_rules! block_mac { () => {} } +}; + +mod n { + // Scope of `pub` `macro_rules` is not extended by `#[macro_use]`. + mac!(); //~ ERROR cannot find macro `mac` in this scope + + // `pub` `macro_rules` doesn't put the macro into the root module, unlike `#[macro_export]`. + crate::mac!(); //~ ERROR failed to resolve: maybe a missing crate `mac` + crate::block_mac!(); //~ ERROR failed to resolve: maybe a missing crate `block_mac` + + crate::m::private_mac!(); //~ ERROR macro `private_mac` is private +} + +fn main() {} diff --git a/src/test/ui/macros/pub-macro-rules-fail.stderr b/src/test/ui/macros/pub-macro-rules-fail.stderr new file mode 100644 index 0000000000000..588d79dd76a4b --- /dev/null +++ b/src/test/ui/macros/pub-macro-rules-fail.stderr @@ -0,0 +1,48 @@ +error[E0428]: the name `mac` is defined multiple times + --> $DIR/pub-macro-rules-fail.rs:8:5 + | +LL | pub macro_rules! mac { () => {} } + | -------------------- previous definition of the macro `mac` here +... +LL | pub macro_rules! mac { () => {} } + | ^^^^^^^^^^^^^^^^^^^^ `mac` redefined here + | + = note: `mac` must be defined only once in the macro namespace of this module + +error[E0433]: failed to resolve: maybe a missing crate `mac`? + --> $DIR/pub-macro-rules-fail.rs:22:12 + | +LL | crate::mac!(); + | ^^^ maybe a missing crate `mac`? + +error[E0433]: failed to resolve: maybe a missing crate `block_mac`? + --> $DIR/pub-macro-rules-fail.rs:23:12 + | +LL | crate::block_mac!(); + | ^^^^^^^^^ maybe a missing crate `block_mac`? + +error: cannot find macro `mac` in this scope + --> $DIR/pub-macro-rules-fail.rs:19:5 + | +LL | mac!(); + | ^^^ + | + = note: consider importing this macro: + m::mac + +error[E0603]: macro `private_mac` is private + --> $DIR/pub-macro-rules-fail.rs:25:15 + | +LL | crate::m::private_mac!(); + | ^^^^^^^^^^^ private macro + | +note: the macro `private_mac` is defined here + --> $DIR/pub-macro-rules-fail.rs:10:5 + | +LL | pub(self) macro_rules! private_mac { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0428, E0433, E0603. +For more information about an error, try `rustc --explain E0428`. diff --git a/src/test/ui/macros/pub-macro-rules.rs b/src/test/ui/macros/pub-macro-rules.rs new file mode 100644 index 0000000000000..cd4a845f7c07d --- /dev/null +++ b/src/test/ui/macros/pub-macro-rules.rs @@ -0,0 +1,20 @@ +// check-pass + +#![feature(pub_macro_rules)] + +mod m { + // `pub` `macro_rules` can be used earlier in item order than they are defined. + foo!(); + + pub macro_rules! foo { () => {} } + + // `pub(...)` works too. + pub(super) macro_rules! bar { () => {} } +} + +// `pub` `macro_rules` are available by module path. +m::foo!(); + +m::bar!(); + +fn main() {} From b3000ec0cdb35b305bfe954db4b14ce32cbc255b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 19 Feb 2021 12:47:53 -0300 Subject: [PATCH 16/27] Update pub_macro_rules since version --- compiler/rustc_feature/src/active.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 56f5c3b79bef9..3f484ab568652 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -639,7 +639,7 @@ declare_features! ( (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None), /// Allows `pub` on `macro_rules` items. - (active, pub_macro_rules, "1.49.0", Some(78855), None), + (active, pub_macro_rules, "1.52.0", Some(78855), None), // ------------------------------------------------------------------------- // feature-group-end: actual feature gates From a00eb7ee1d8f5b38b94410940e87af9c10ed458a Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sat, 20 Feb 2021 00:43:02 +0000 Subject: [PATCH 17/27] Add @is command to jsondocck --- src/test/rustdoc-json/nested.rs | 20 ++++++++++---------- src/tools/jsondocck/src/main.rs | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index 7e705255d983d..f32692b70cd2b 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -1,24 +1,24 @@ // edition:2018 -// @has nested.json "$.index[*][?(@.name=='nested')].kind" \"module\" -// @has - "$.index[*][?(@.name=='nested')].inner.is_crate" true +// @is nested.json "$.index[*][?(@.name=='nested')].kind" \"module\" +// @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true // @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1 -// @has nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" -// @has - "$.index[*][?(@.name=='l1')].inner.is_crate" false +// @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" +// @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2 pub mod l1 { - // @has nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" - // @has - "$.index[*][?(@.name=='l3')].inner.is_crate" false + // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" + // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1 pub mod l3 { - // @has nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" - // @has - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" + // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" + // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" pub struct L4; } - // @has nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\" - // @has - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false + // @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\" + // @is - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false pub use l3::L4; } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 6ec292aba6495..2afb66b969685 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -48,13 +48,14 @@ pub struct Command { pub enum CommandKind { Has, Count, + Is, } impl CommandKind { fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool { let count = match self { CommandKind::Has => (1..=3).contains(&args.len()), - CommandKind::Count => 3 == args.len(), + CommandKind::Count | CommandKind::Is => 3 == args.len(), }; if !count { @@ -83,6 +84,7 @@ impl fmt::Display for CommandKind { let text = match self { CommandKind::Has => "has", CommandKind::Count => "count", + CommandKind::Is => "is", }; write!(f, "{}", text) } @@ -127,6 +129,7 @@ fn get_commands(template: &str) -> Result, ()> { let cmd = match cmd { "has" => CommandKind::Has, "count" => CommandKind::Count, + "is" => CommandKind::Is, _ => { print_err(&format!("Unrecognized command name `@{}`", cmd), lineno); errors = true; @@ -180,6 +183,7 @@ fn get_commands(template: &str) -> Result, ()> { /// Performs the actual work of ensuring a command passes. Generally assumes the command /// is syntactically valid. fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { + // FIXME: Be more granular about why, (eg syntax error, count not equal) let result = match command.kind { CommandKind::Has => { match command.args.len() { @@ -220,6 +224,18 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { Err(_) => false, } } + CommandKind::Is => { + // @has = check *exactly one* item matched by path, and it equals value + assert_eq!(command.args.len(), 3); + let val = cache.get_value(&command.args[0])?; + match select(&val, &command.args[1]) { + Ok(results) => { + let pat: Value = serde_json::from_str(&command.args[2]).unwrap(); + results.len() == 1 && *results[0] == pat + } + Err(_) => false, + } + } }; if result == command.negated { From f0637e4e185e8c3dda694004d1dfd31126ed1fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 19 Feb 2021 17:00:31 -0800 Subject: [PATCH 18/27] Lower condition of `if` expression before it's "then" block Fix #82290, fix #82250. --- compiler/rustc_ast_lowering/src/expr.rs | 3 ++- src/test/ui/pattern/issue-82290.rs | 7 +++++++ src/test/ui/pattern/issue-82290.stderr | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/pattern/issue-82290.rs create mode 100644 src/test/ui/pattern/issue-82290.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b118c0eaed4f3..6d44feec2c496 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -347,8 +347,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { macro_rules! make_if { ($opt:expr) => {{ + let cond = self.lower_expr(cond); let then_expr = self.lower_block_expr(then); - hir::ExprKind::If(self.lower_expr(cond), self.arena.alloc(then_expr), $opt) + hir::ExprKind::If(cond, self.arena.alloc(then_expr), $opt) }}; } if let Some(rslt) = else_opt { diff --git a/src/test/ui/pattern/issue-82290.rs b/src/test/ui/pattern/issue-82290.rs new file mode 100644 index 0000000000000..67f0274fe7436 --- /dev/null +++ b/src/test/ui/pattern/issue-82290.rs @@ -0,0 +1,7 @@ +#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete + +fn main() { + if true && let x = 1 { //~ ERROR `let` expressions are not supported here + let _ = x; + } +} diff --git a/src/test/ui/pattern/issue-82290.stderr b/src/test/ui/pattern/issue-82290.stderr new file mode 100644 index 0000000000000..65ef018dc9737 --- /dev/null +++ b/src/test/ui/pattern/issue-82290.stderr @@ -0,0 +1,20 @@ +error: `let` expressions are not supported here + --> $DIR/issue-82290.rs:4:16 + | +LL | if true && let x = 1 { + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-82290.rs:1:12 + | +LL | #![feature(let_chains)] + | ^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53667 for more information + +error: aborting due to previous error; 1 warning emitted + From cd5f603c314edcf2d75656ac86fc1d303aacfb83 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sat, 20 Feb 2021 01:25:09 +0000 Subject: [PATCH 19/27] Implement @set --- src/test/rustdoc-json/nested.rs | 3 +++ src/tools/jsondocck/src/cache.rs | 2 ++ src/tools/jsondocck/src/main.rs | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index f32692b70cd2b..2e0179113acf4 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -7,15 +7,18 @@ // @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" // @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2 +// @set l1_id = - "$.index[*][?(@.name=='l1')].id" pub mod l1 { // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1 + // @set l3_id = - "$.index[*][?(@.name=='l3')].id" pub mod l3 { // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" + // @set l4_id = - "$.index[*][?(@.name=='L4')].id" pub struct L4; } // @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\" diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs index b742f0eb3ee55..8a6a911321c34 100644 --- a/src/tools/jsondocck/src/cache.rs +++ b/src/tools/jsondocck/src/cache.rs @@ -9,6 +9,7 @@ pub struct Cache { root: PathBuf, files: HashMap, values: HashMap, + pub variables: HashMap, last_path: Option, } @@ -19,6 +20,7 @@ impl Cache { root: Path::new(doc_dir).to_owned(), files: HashMap::new(), values: HashMap::new(), + variables: HashMap::new(), last_path: None, } } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 2afb66b969685..9f231842c60ea 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -49,6 +49,7 @@ pub enum CommandKind { Has, Count, Is, + Set, } impl CommandKind { @@ -56,6 +57,7 @@ impl CommandKind { let count = match self { CommandKind::Has => (1..=3).contains(&args.len()), CommandKind::Count | CommandKind::Is => 3 == args.len(), + CommandKind::Set => 4 == args.len(), }; if !count { @@ -85,6 +87,7 @@ impl fmt::Display for CommandKind { CommandKind::Has => "has", CommandKind::Count => "count", CommandKind::Is => "is", + CommandKind::Set => "set", }; write!(f, "{}", text) } @@ -130,6 +133,7 @@ fn get_commands(template: &str) -> Result, ()> { "has" => CommandKind::Has, "count" => CommandKind::Count, "is" => CommandKind::Is, + "set" => CommandKind::Set, _ => { print_err(&format!("Unrecognized command name `@{}`", cmd), lineno); errors = true; @@ -236,6 +240,23 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { Err(_) => false, } } + // FIXME, Figure out semantics for @!set + CommandKind::Set => { + // @set = + assert_eq!(command.args.len(), 4); + assert_eq!(command.args[1], "=", "Expected an `=`"); + let val = cache.get_value(&command.args[2])?; + + match select(&val, &command.args[3]) { + Ok(results) => { + assert_eq!(results.len(), 1); + let r = cache.variables.insert(command.args[0].clone(), results[0].clone()); + assert!(r.is_none(), "Name collision"); + true + } + Err(_) => false, + } + } }; if result == command.negated { From dd4b938c7f0c7704582a786f973bcfb17e523e94 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sat, 20 Feb 2021 01:47:17 +0000 Subject: [PATCH 20/27] Implement using @set values --- src/test/rustdoc-json/nested.rs | 3 ++- src/tools/jsondocck/src/main.rs | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index 2e0179113acf4..a3d4935f49614 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -7,18 +7,19 @@ // @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" // @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2 -// @set l1_id = - "$.index[*][?(@.name=='l1')].id" pub mod l1 { // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1 // @set l3_id = - "$.index[*][?(@.name=='l3')].id" + // @has - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id pub mod l3 { // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" // @set l4_id = - "$.index[*][?(@.name=='L4')].id" + // @has - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id pub struct L4; } // @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\" diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 9f231842c60ea..8cb9564531a98 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -207,9 +207,15 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; match select(&val, &command.args[1]) { Ok(results) => { - let pat: Value = serde_json::from_str(&command.args[2]).unwrap(); - - !results.is_empty() && results.into_iter().any(|val| *val == pat) + // FIXME: Share the pat getting code with the `Is` branch. + let v_holder; + let pat: &Value = if command.args[2].starts_with("$") { + &cache.variables[&command.args[2][1..]] + } else { + v_holder = serde_json::from_str(&command.args[2]).unwrap(); + &v_holder + }; + !results.is_empty() && results.into_iter().any(|val| val == pat) } Err(_) => false, } @@ -234,8 +240,14 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; match select(&val, &command.args[1]) { Ok(results) => { - let pat: Value = serde_json::from_str(&command.args[2]).unwrap(); - results.len() == 1 && *results[0] == pat + let v_holder; + let pat: &Value = if command.args[2].starts_with("$") { + &cache.variables[&command.args[2][1..]] + } else { + v_holder = serde_json::from_str(&command.args[2]).unwrap(); + &v_holder + }; + results.len() == 1 && results[0] == pat } Err(_) => false, } From a22d948eb0cd509b7ea52c3c615253d03ca9914b Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sun, 21 Feb 2021 19:45:32 +0000 Subject: [PATCH 21/27] Apply suggestions from code review Co-authored-by: Joshua Nelson --- src/tools/jsondocck/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 8cb9564531a98..9c9d49b821f4a 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -187,7 +187,7 @@ fn get_commands(template: &str) -> Result, ()> { /// Performs the actual work of ensuring a command passes. Generally assumes the command /// is syntactically valid. fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { - // FIXME: Be more granular about why, (eg syntax error, count not equal) + // FIXME: Be more granular about why, (e.g. syntax error, count not equal) let result = match command.kind { CommandKind::Has => { match command.args.len() { @@ -215,7 +215,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { v_holder = serde_json::from_str(&command.args[2]).unwrap(); &v_holder }; - !results.is_empty() && results.into_iter().any(|val| val == pat) + results.contains(pat) } Err(_) => false, } @@ -263,7 +263,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { Ok(results) => { assert_eq!(results.len(), 1); let r = cache.variables.insert(command.args[0].clone(), results[0].clone()); - assert!(r.is_none(), "Name collision"); + assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]); true } Err(_) => false, From ba22a69d964283d388a362830e73a992f024a6bf Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sun, 21 Feb 2021 20:10:57 +0000 Subject: [PATCH 22/27] Extract string_to_value to its own function --- src/tools/jsondocck/src/main.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 9c9d49b821f4a..e3334e559db65 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -2,6 +2,7 @@ use jsonpath_lib::select; use lazy_static::lazy_static; use regex::{Regex, RegexBuilder}; use serde_json::Value; +use std::borrow::Cow; use std::{env, fmt, fs}; mod cache; @@ -207,15 +208,8 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; match select(&val, &command.args[1]) { Ok(results) => { - // FIXME: Share the pat getting code with the `Is` branch. - let v_holder; - let pat: &Value = if command.args[2].starts_with("$") { - &cache.variables[&command.args[2][1..]] - } else { - v_holder = serde_json::from_str(&command.args[2]).unwrap(); - &v_holder - }; - results.contains(pat) + let pat = string_to_value(&command.args[2], cache); + results.contains(&pat.as_ref()) } Err(_) => false, } @@ -240,14 +234,8 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; match select(&val, &command.args[1]) { Ok(results) => { - let v_holder; - let pat: &Value = if command.args[2].starts_with("$") { - &cache.variables[&command.args[2][1..]] - } else { - v_holder = serde_json::from_str(&command.args[2]).unwrap(); - &v_holder - }; - results.len() == 1 && results[0] == pat + let pat = string_to_value(&command.args[2], cache); + results.len() == 1 && results[0] == pat.as_ref() } Err(_) => false, } @@ -296,3 +284,11 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { Ok(()) } } + +fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { + if s.starts_with("$") { + Cow::Borrowed(&cache.variables[&s[1..]]) + } else { + Cow::Owned(serde_json::from_str(s).unwrap()) + } +} From 1847a6c0c100f75120d9f41cee22cbab503e081c Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Mon, 22 Feb 2021 19:08:44 +1100 Subject: [PATCH 23/27] Extract deref coercion explanation into method --- .../src/borrow_check/diagnostics/conflict_errors.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index f5bd497135ff3..b0b58a8d00367 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1542,8 +1542,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ); + self.explain_deref_coercion(loan, &mut err); + + err.buffer(&mut self.errors_buffer); + } + + fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) { let tcx = self.infcx.tcx; - // point out implicit deref coercion if let ( Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }), Some((method_did, method_substs)), @@ -1572,8 +1577,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - - err.buffer(&mut self.errors_buffer); } /// Reports an illegal reassignment; for example, an assignment to From dd9ab160a14e8e7b9eee1802482db6a38fa78b80 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Feb 2021 09:41:20 +0100 Subject: [PATCH 24/27] disable atomic_max/min tests in Miri --- library/core/tests/atomic.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index b735957666fc5..539982eb0e49f 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -61,6 +61,7 @@ fn uint_xor() { #[test] #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_min fn uint_min() { let x = AtomicUsize::new(0xf731); assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); @@ -71,6 +72,7 @@ fn uint_min() { #[test] #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_max fn uint_max() { let x = AtomicUsize::new(0x137f); assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); @@ -109,6 +111,7 @@ fn int_xor() { #[test] #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_min fn int_min() { let x = AtomicIsize::new(0xf731); assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); @@ -119,6 +122,7 @@ fn int_min() { #[test] #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_max fn int_max() { let x = AtomicIsize::new(0x137f); assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); From 4c949a455df81924b37dc41f2edf1071ea329fb5 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 22 Feb 2021 10:33:33 +0000 Subject: [PATCH 25/27] Simplify Error Handling. --- src/tools/jsondocck/src/main.rs | 50 ++++++++++++++------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index e3334e559db65..5020a4917a00a 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -197,22 +197,15 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { // @has = check path exists 2 => { let val = cache.get_value(&command.args[0])?; - - match select(&val, &command.args[1]) { - Ok(results) => !results.is_empty(), - Err(_) => false, - } + let results = select(&val, &command.args[1]).unwrap(); + !results.is_empty() } // @has = check *any* item matched by path equals value 3 => { let val = cache.get_value(&command.args[0])?; - match select(&val, &command.args[1]) { - Ok(results) => { - let pat = string_to_value(&command.args[2], cache); - results.contains(&pat.as_ref()) - } - Err(_) => false, - } + let results = select(&val, &command.args[1]).unwrap(); + let pat = string_to_value(&command.args[2], cache); + results.contains(&pat.as_ref()) } _ => unreachable!(), } @@ -223,38 +216,37 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let expected: usize = command.args[2].parse().unwrap(); let val = cache.get_value(&command.args[0])?; - match select(&val, &command.args[1]) { - Ok(results) => results.len() == expected, - Err(_) => false, - } + let results = select(&val, &command.args[1]).unwrap(); + results.len() == expected } CommandKind::Is => { // @has = check *exactly one* item matched by path, and it equals value assert_eq!(command.args.len(), 3); let val = cache.get_value(&command.args[0])?; - match select(&val, &command.args[1]) { - Ok(results) => { - let pat = string_to_value(&command.args[2], cache); - results.len() == 1 && results[0] == pat.as_ref() - } - Err(_) => false, - } + let results = select(&val, &command.args[1]).unwrap(); + let pat = string_to_value(&command.args[2], cache); + results.len() == 1 && results[0] == pat.as_ref() } - // FIXME, Figure out semantics for @!set CommandKind::Set => { // @set = assert_eq!(command.args.len(), 4); assert_eq!(command.args[1], "=", "Expected an `=`"); let val = cache.get_value(&command.args[2])?; - - match select(&val, &command.args[3]) { - Ok(results) => { - assert_eq!(results.len(), 1); + let results = select(&val, &command.args[3]).unwrap(); + assert_eq!(results.len(), 1); + match results.len() { + 0 => false, + 1 => { let r = cache.variables.insert(command.args[0].clone(), results[0].clone()); assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]); true } - Err(_) => false, + _ => { + panic!( + "Got multiple results in `@set` for `{}`: {:?}", + &command.args[3], results + ); + } } } }; From 2145a8770c941f79e28cfdabd524ca2aea8ab2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Sun, 21 Feb 2021 11:15:37 +0300 Subject: [PATCH 26/27] Fix mir-cfg dumps Fixes #81918 Fixes #82326 (duplicate) Fixes #82325 --- compiler/rustc_mir/src/util/graphviz.rs | 23 ++++++++++++++++++----- src/test/ui/issues/issue-81918.rs | 11 +++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-81918.rs diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index 37498e50c0eb1..92c7a358c0a41 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -2,7 +2,7 @@ use gsgdt::GraphvizSettings; use rustc_graphviz as dot; use rustc_hir::def_id::DefId; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; use std::fmt::Debug; use std::io::{self, Write}; @@ -16,14 +16,27 @@ where { let def_ids = dump_mir_def_ids(tcx, single); - let use_subgraphs = def_ids.len() > 1; + let mirs = + def_ids + .iter() + .flat_map(|def_id| { + if tcx.is_const_fn_raw(*def_id) { + vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] + } else { + vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown( + *def_id, + )))] + } + }) + .collect::>(); + + let use_subgraphs = mirs.len() > 1; if use_subgraphs { writeln!(w, "digraph __crate__ {{")?; } - for def_id in def_ids { - let body = &tcx.optimized_mir(def_id); - write_mir_fn_graphviz(tcx, body, use_subgraphs, w)?; + for mir in mirs { + write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?; } if use_subgraphs { diff --git a/src/test/ui/issues/issue-81918.rs b/src/test/ui/issues/issue-81918.rs new file mode 100644 index 0000000000000..8938b8a6f2c52 --- /dev/null +++ b/src/test/ui/issues/issue-81918.rs @@ -0,0 +1,11 @@ +// check-pass +// dont-check-compiler-stdout +// compile-flags: -Z unpretty=mir-cfg + +// This checks that unpretty=mir-cfg does not panic. See #81918. + +const TAG: &'static str = "ABCD"; + +fn main() { + if TAG == "" {} +} From e4ac499b7e5161178a8a38f8ee0390c8b4b95dfa Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 19 Feb 2021 14:27:30 -0800 Subject: [PATCH 27/27] Remove many RefCells from DocContext I left some of them so this change doesn't balloon in size and because removing the RefCell in `DocContext.resolver` would require compiler changes. Thanks to `@jyn514` for making this a lot easier with #82020! --- src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/blanket_impl.rs | 6 ++-- src/librustdoc/clean/inline.rs | 21 ++++++----- src/librustdoc/clean/mod.rs | 14 ++++---- src/librustdoc/clean/utils.rs | 13 ++++--- src/librustdoc/core.rs | 35 +++++++++++-------- .../passes/calculate_doc_coverage.rs | 2 +- src/librustdoc/passes/collect_trait_impls.rs | 5 ++- src/librustdoc/passes/doc_test_lints.rs | 3 +- src/librustdoc/passes/strip_private.rs | 2 +- src/librustdoc/visit_ast.rs | 11 ++---- src/librustdoc/visit_lib.rs | 2 +- 12 files changed, 56 insertions(+), 60 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 711b0298565d7..a24cb0a0f93a1 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -41,7 +41,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { ) -> Option { let tcx = self.cx.tcx; let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) }; - if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) { + if !self.cx.generated_synthetics.insert((ty, trait_def_id)) { debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref); return None; } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index a9d19a725c44f..94b82037e75e9 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -22,8 +22,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { debug!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); for &trait_def_id in self.cx.tcx.all_traits(LOCAL_CRATE).iter() { - if !self.cx.renderinfo.borrow().access_levels.is_public(trait_def_id) - || self.cx.generated_synthetics.borrow_mut().get(&(ty, trait_def_id)).is_some() + if !self.cx.renderinfo.access_levels.is_public(trait_def_id) + || self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some() { continue; } @@ -94,7 +94,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { return; } - self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)); + self.cx.generated_synthetics.insert((ty, trait_def_id)); let provided_trait_methods = self .cx .tcx diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index fded0499ba6a8..ea75d1614bd80 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -122,7 +122,7 @@ crate fn try_inline( let target_attrs = load_attrs(cx, did); let attrs = box merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone); - cx.renderinfo.borrow_mut().inlined.insert(did); + cx.renderinfo.inlined.insert(did); let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name), kind, cx); ret.push(clean::Item { attrs, ..what_rustc_thinks }); Some(ret) @@ -156,7 +156,7 @@ crate fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> { /// /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. -crate fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) { +crate fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: clean::TypeKind) { let crate_name = cx.tcx.crate_name(did.krate).to_string(); let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { @@ -181,9 +181,9 @@ crate fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKin }; if did.is_local() { - cx.renderinfo.borrow_mut().exact_paths.insert(did, fqn); + cx.renderinfo.exact_paths.insert(did, fqn); } else { - cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind)); + cx.renderinfo.external_paths.insert(did, (fqn, kind)); } } @@ -317,7 +317,7 @@ crate fn build_impl( attrs: Option>, ret: &mut Vec, ) { - if !cx.renderinfo.borrow_mut().inlined.insert(did) { + if !cx.renderinfo.inlined.insert(did) { return; } @@ -329,7 +329,7 @@ crate fn build_impl( if !did.is_local() { if let Some(traitref) = associated_trait { let did = traitref.def_id; - if !cx.renderinfo.borrow().access_levels.is_public(did) { + if !cx.renderinfo.access_levels.is_public(did) { return; } @@ -361,7 +361,7 @@ crate fn build_impl( // reachable in rustdoc generated documentation if !did.is_local() { if let Some(did) = for_.def_id() { - if !cx.renderinfo.borrow().access_levels.is_public(did) { + if !cx.renderinfo.access_levels.is_public(did) { return; } @@ -613,20 +613,19 @@ crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { } { - if cx.external_traits.borrow().contains_key(&did) - || cx.active_extern_traits.borrow().contains(&did) + if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.contains(&did) { return; } } { - cx.active_extern_traits.borrow_mut().insert(did); + cx.active_extern_traits.insert(did); } debug!("record_extern_trait: {:?}", did); let trait_ = build_external_trait(cx, did); cx.external_traits.borrow_mut().insert(did, trait_); - cx.active_extern_traits.borrow_mut().remove(&did); + cx.active_extern_traits.remove(&did); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 98e1299df2f26..b6e7046210596 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -357,7 +357,7 @@ impl Clean for hir::Lifetime { | rl::Region::LateBound(_, node_id, _) | rl::Region::Free(_, node_id), ) => { - if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() { + if let Some(lt) = cx.lt_substs.get(&node_id).cloned() { return lt; } } @@ -644,7 +644,7 @@ impl Clean for hir::Generics<'_> { match param.kind { GenericParamDefKind::Lifetime => unreachable!(), GenericParamDefKind::Type { did, ref bounds, .. } => { - cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone()); + cx.impl_trait_bounds.insert(did.into(), bounds.clone()); } GenericParamDefKind::Const { .. } => unreachable!(), } @@ -803,7 +803,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx unreachable!(); } - cx.impl_trait_bounds.borrow_mut().insert(param, bounds); + cx.impl_trait_bounds.insert(param, bounds); } // Now that `cx.impl_trait_bounds` is populated, we can process @@ -1291,10 +1291,10 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { match qpath { hir::QPath::Resolved(None, ref path) => { if let Res::Def(DefKind::TyParam, did) = path.res { - if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() { + if let Some(new_ty) = cx.ty_substs.get(&did).cloned() { return new_ty; } - if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) { + if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) { return ImplTrait(bounds); } } @@ -1304,7 +1304,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { // Substitute private type aliases if let Some(def_id) = def_id.as_local() { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); - if !cx.renderinfo.borrow().access_levels.is_exported(def_id.to_def_id()) { + if !cx.renderinfo.access_levels.is_exported(def_id.to_def_id()) { alias = Some(&cx.tcx.hir().expect_item(hir_id).kind); } } @@ -1651,7 +1651,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Projection(ref data) => data.clean(cx), ty::Param(ref p) => { - if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) { + if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) { ImplTrait(bounds) } else { Generic(p.name) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c7bfd363a129b..d2eee49f0c968 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -23,10 +23,9 @@ crate fn krate(mut cx: &mut DocContext<'_>) -> Crate { let krate = cx.tcx.hir().krate(); let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate); - let mut r = cx.renderinfo.get_mut(); - r.deref_trait_did = cx.tcx.lang_items().deref_trait(); - r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); - r.owned_box_did = cx.tcx.lang_items().owned_box(); + cx.renderinfo.deref_trait_did = cx.tcx.lang_items().deref_trait(); + cx.renderinfo.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); + cx.renderinfo.owned_box_did = cx.tcx.lang_items().owned_box(); let mut externs = Vec::new(); for &cnum in cx.tcx.crates().iter() { @@ -494,10 +493,10 @@ crate fn enter_impl_trait(cx: &mut DocContext<'_>, f: F) -> R where F: FnOnce(&mut DocContext<'_>) -> R, { - let old_bounds = mem::take(&mut *cx.impl_trait_bounds.get_mut()); + let old_bounds = mem::take(&mut cx.impl_trait_bounds); let r = f(cx); - assert!(cx.impl_trait_bounds.borrow().is_empty()); - *cx.impl_trait_bounds.get_mut() = old_bounds; + assert!(cx.impl_trait_bounds.is_empty()); + cx.impl_trait_bounds = old_bounds; r } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index dbf202a732108..8fceb00eeae51 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -42,32 +42,37 @@ crate type ExternalPaths = FxHashMap, clean::TypeKind)>; crate struct DocContext<'tcx> { crate tcx: TyCtxt<'tcx>, + /// Name resolver. Used for intra-doc links. + /// + /// The `Rc>` wrapping is needed because that is what's returned by + /// [`Queries::expansion()`]. + // FIXME: see if we can get rid of this RefCell somehow crate resolver: Rc>, /// Used for normalization. /// /// Most of this logic is copied from rustc_lint::late. crate param_env: ParamEnv<'tcx>, /// Later on moved into `cache` - crate renderinfo: RefCell, + crate renderinfo: RenderInfo, /// Later on moved through `clean::Crate` into `cache` crate external_traits: Rc>>, /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. - crate active_extern_traits: RefCell>, + crate active_extern_traits: FxHashSet, // The current set of type and lifetime substitutions, // for expanding type aliases at the HIR level: /// Table `DefId` of type parameter -> substituted type - crate ty_substs: RefCell>, + crate ty_substs: FxHashMap, /// Table `DefId` of lifetime parameter -> substituted lifetime - crate lt_substs: RefCell>, + crate lt_substs: FxHashMap, /// Table `DefId` of const parameter -> substituted const - crate ct_substs: RefCell>, + crate ct_substs: FxHashMap, /// Table synthetic type parameter for `impl Trait` in argument position -> bounds - crate impl_trait_bounds: RefCell>>, + crate impl_trait_bounds: FxHashMap>, crate fake_def_ids: FxHashMap, /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set. - crate generated_synthetics: RefCell, DefId)>>, + crate generated_synthetics: FxHashSet<(Ty<'tcx>, DefId)>, crate auto_traits: Vec, /// The options given to rustdoc that could be relevant to a pass. crate render_options: RenderOptions, @@ -112,14 +117,14 @@ impl<'tcx> DocContext<'tcx> { F: FnOnce(&mut Self) -> R, { let (old_tys, old_lts, old_cts) = ( - mem::replace(&mut *self.ty_substs.get_mut(), ty_substs), - mem::replace(&mut *self.lt_substs.get_mut(), lt_substs), - mem::replace(&mut *self.ct_substs.get_mut(), ct_substs), + mem::replace(&mut self.ty_substs, ty_substs), + mem::replace(&mut self.lt_substs, lt_substs), + mem::replace(&mut self.ct_substs, ct_substs), ); let r = f(self); - *self.ty_substs.get_mut() = old_tys; - *self.lt_substs.get_mut() = old_lts; - *self.ct_substs.get_mut() = old_cts; + self.ty_substs = old_tys; + self.lt_substs = old_lts; + self.ct_substs = old_cts; r } @@ -509,7 +514,7 @@ crate fn run_global_ctxt( param_env: ParamEnv::empty(), external_traits: Default::default(), active_extern_traits: Default::default(), - renderinfo: RefCell::new(renderinfo), + renderinfo, ty_substs: Default::default(), lt_substs: Default::default(), ct_substs: Default::default(), @@ -642,7 +647,7 @@ crate fn run_global_ctxt( // The main crate doc comments are always collapsed. krate.collapsed = true; - (krate, ctxt.renderinfo.into_inner(), ctxt.render_options) + (krate, ctxt.renderinfo, ctxt.render_options) } /// Due to , diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 542cf6d2c275a..c3365b844ecb8 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -127,7 +127,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { } fn print_results(&self) { - let output_format = self.ctx.renderinfo.borrow().output_format; + let output_format = self.ctx.renderinfo.output_format; if output_format.is_json() { println!("{}", self.to_json()); return; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 0b6d81d1b447e..0271a5b78a7ef 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -48,11 +48,10 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) { let self_ty = cx.tcx.type_of(def_id); let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id); - let mut renderinfo = cx.renderinfo.borrow_mut(); - new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id))); + new_items.extend(impls.filter(|i| cx.renderinfo.inlined.insert(i.def_id))); } - }) + }); } } diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 042a895d2fa2f..e8e1bead84fb6 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -97,8 +97,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { |lint| lint.build("missing code example in this documentation").emit(), ); } - } else if tests.found_tests > 0 && !cx.renderinfo.borrow().access_levels.is_public(item.def_id) - { + } else if tests.found_tests > 0 && !cx.renderinfo.access_levels.is_public(item.def_id) { cx.tcx.struct_span_lint_hir( lint::builtin::PRIVATE_DOC_TESTS, hir_id, diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index c0bb05af3edb5..f83eab6799ee6 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -17,7 +17,7 @@ crate const STRIP_PRIVATE: Pass = Pass { crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = DefIdSet::default(); - let access_levels = cx.renderinfo.borrow().access_levels.clone(); + let access_levels = cx.renderinfo.access_levels.clone(); // strip all private items { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index e92ea55caa737..4d42c181d8cf2 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { assert_eq!(cur_mod_def_id, macro_parent_def_id); cur_mod.macros.push((def, None)); } - self.cx.renderinfo.get_mut().exact_paths = self.exact_paths; + self.cx.renderinfo.exact_paths = self.exact_paths; top_level_module } @@ -199,12 +199,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } else { // All items need to be handled here in case someone wishes to link // to them with intra-doc links - self.cx - .renderinfo - .get_mut() - .access_levels - .map - .insert(did, AccessLevel::Public); + self.cx.renderinfo.access_levels.map.insert(did, AccessLevel::Public); } } } @@ -216,7 +211,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { None => return false, }; - let is_private = !self.cx.renderinfo.borrow().access_levels.is_public(res_did); + let is_private = !self.cx.renderinfo.access_levels.is_public(res_did); let is_hidden = inherits_doc_hidden(self.cx, res_hir_id); // Only inline if requested or if the item would otherwise be stripped. diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 0bf22562eaede..daed5bd107db1 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { crate fn new(cx: &'a mut crate::core::DocContext<'tcx>) -> LibEmbargoVisitor<'a, 'tcx> { LibEmbargoVisitor { tcx: cx.tcx, - access_levels: &mut cx.renderinfo.get_mut().access_levels, + access_levels: &mut cx.renderinfo.access_levels, prev_level: Some(AccessLevel::Public), visited_mods: FxHashSet::default(), }