From ff65bffe2b143528ff90d5226b18ceca750d7c02 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 11 Mar 2020 15:35:46 -0400 Subject: [PATCH 01/23] Fix cycle error when emitting suggestion for mismatched `fn` type Fixes #66667 Previously, we called `tcx.typeck_tables_of` when determining whether or not to emit a suggestion for a type error. However, we might already be type-checking the `DefId` we pass to `typeck_tables_of` (it could be anywhere in the query stack). Fortunately, we only need the function signature, not the entire `TypeckTables`. By using `tcx.fn_sig`, we avoid the possibility of cycle errors while retaining the ability to emit a suggestion. --- src/librustc_typeck/check/op.rs | 26 ++------- .../issues/issue-66667-function-cmp-cycle.rs | 16 ++++++ .../issue-66667-function-cmp-cycle.stderr | 55 +++++++++++++++++++ 3 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/issues/issue-66667-function-cmp-cycle.rs create mode 100644 src/test/ui/issues/issue-66667-function-cmp-cycle.stderr diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index bf3511a26143c..3648a99abc259 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -491,36 +491,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(span, ty.to_string()); if let FnDef(def_id, _) = ty.kind { let source_map = self.tcx.sess.source_map(); - let hir_id = match self.tcx.hir().as_local_hir_id(def_id) { - Some(hir_id) => hir_id, - None => return false, - }; if !self.tcx.has_typeck_tables(def_id) { return false; } - let fn_sig = { - match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { - Some(f) => *f, - None => { - bug!("No fn-sig entry for def_id={:?}", def_id); - } - } - }; + // We're emitting a suggestion, so we can just ignore regions + let fn_sig = *self.tcx.fn_sig(def_id).skip_binder(); let other_ty = if let FnDef(def_id, _) = other_ty.kind { - let hir_id = match self.tcx.hir().as_local_hir_id(def_id) { - Some(hir_id) => hir_id, - None => return false, - }; if !self.tcx.has_typeck_tables(def_id) { return false; } - match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { - Some(f) => f.clone().output(), - None => { - bug!("No fn-sig entry for def_id={:?}", def_id); - } - } + // We're emitting a suggestion, so we can just ignore regions + self.tcx.fn_sig(def_id).skip_binder().output() } else { other_ty }; diff --git a/src/test/ui/issues/issue-66667-function-cmp-cycle.rs b/src/test/ui/issues/issue-66667-function-cmp-cycle.rs new file mode 100644 index 0000000000000..7b025be11a09e --- /dev/null +++ b/src/test/ui/issues/issue-66667-function-cmp-cycle.rs @@ -0,0 +1,16 @@ +fn first() { + second == 1 //~ ERROR binary operation + //~^ ERROR mismatched types +} + +fn second() { + first == 1 //~ ERROR binary operation + //~^ ERROR mismatched types +} + +fn bar() { + bar == 1 //~ ERROR binary operation + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/issues/issue-66667-function-cmp-cycle.stderr b/src/test/ui/issues/issue-66667-function-cmp-cycle.stderr new file mode 100644 index 0000000000000..887699ef5ce85 --- /dev/null +++ b/src/test/ui/issues/issue-66667-function-cmp-cycle.stderr @@ -0,0 +1,55 @@ +error[E0369]: binary operation `==` cannot be applied to type `fn() {second}` + --> $DIR/issue-66667-function-cmp-cycle.rs:2:12 + | +LL | second == 1 + | ------ ^^ - {integer} + | | + | fn() {second} + +error[E0308]: mismatched types + --> $DIR/issue-66667-function-cmp-cycle.rs:2:15 + | +LL | second == 1 + | ^ expected fn item, found integer + | + = note: expected fn item `fn() {second}` + found type `{integer}` + +error[E0369]: binary operation `==` cannot be applied to type `fn() {first}` + --> $DIR/issue-66667-function-cmp-cycle.rs:7:11 + | +LL | first == 1 + | ----- ^^ - {integer} + | | + | fn() {first} + +error[E0308]: mismatched types + --> $DIR/issue-66667-function-cmp-cycle.rs:7:14 + | +LL | first == 1 + | ^ expected fn item, found integer + | + = note: expected fn item `fn() {first}` + found type `{integer}` + +error[E0369]: binary operation `==` cannot be applied to type `fn() {bar}` + --> $DIR/issue-66667-function-cmp-cycle.rs:12:9 + | +LL | bar == 1 + | --- ^^ - {integer} + | | + | fn() {bar} + +error[E0308]: mismatched types + --> $DIR/issue-66667-function-cmp-cycle.rs:12:12 + | +LL | bar == 1 + | ^ expected fn item, found integer + | + = note: expected fn item `fn() {bar}` + found type `{integer}` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. From ef2957de137fb8d6959310e5d8f2fa1d600d7d36 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 13:13:07 -0400 Subject: [PATCH 02/23] allowing getting &mut OsStr from OsString --- src/libstd/ffi/os_str.rs | 21 +++++++++++++++++++++ src/libstd/sys/windows/os_str.rs | 5 +++++ src/libstd/sys_common/os_str_bytes.rs | 5 +++++ 3 files changed, 31 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 77da97219b147..2f921ce7a5fe4 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -379,6 +379,14 @@ impl ops::Index for OsString { } } +#[stable(feature = "mut_osstr", since = "1.44.0")] +impl ops::IndexMut for OsString { + #[inline] + fn index_mut(&mut self, _index: ops::RangeFull) -> &mut OsStr { + OsStr::from_inner_mut(self.inner.as_mut_slice()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for OsString { type Target = OsStr; @@ -389,6 +397,14 @@ impl ops::Deref for OsString { } } +#[stable(feature = "mut_osstr", since = "1.44.0")] +impl ops::DerefMut for OsString { + #[inline] + fn deref_mut(&mut self) -> &mut OsStr { + &mut self[..] + } +} + #[stable(feature = "osstring_default", since = "1.9.0")] impl Default for OsString { /// Constructs an empty `OsString`. @@ -512,6 +528,11 @@ impl OsStr { unsafe { &*(inner as *const Slice as *const OsStr) } } + #[inline] + fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { + unsafe { &mut *(inner as *mut Slice as *mut OsStr) } + } + /// Yields a [`&str`] slice if the `OsStr` is valid Unicode. /// /// This conversion may entail doing a check for UTF-8 validity. diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index ef260f9c5d21f..4cff23b2f4a09 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -80,6 +80,11 @@ impl Buf { unsafe { mem::transmute(self.inner.as_slice()) } } + #[inline] + pub fn as_mut_slice(&mut self) -> &mut Slice { + unsafe { mem::transmute(self.inner.as_mut_slice()) } + } + pub fn into_string(self) -> Result { self.inner.into_string().map_err(|buf| Buf { inner: buf }) } diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs index e965ea79aa039..5767350336dad 100644 --- a/src/libstd/sys_common/os_str_bytes.rs +++ b/src/libstd/sys_common/os_str_bytes.rs @@ -109,6 +109,11 @@ impl Buf { unsafe { mem::transmute(&*self.inner) } } + #[inline] + pub fn as_mut_slice(&mut self) -> &mut Slice { + unsafe { mem::transmute(&mut *self.inner) } + } + pub fn into_string(self) -> Result { String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() }) } From 21975a1aaa682a88266970459f6f67829774d6c4 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 16:12:54 -0400 Subject: [PATCH 03/23] add comments about safety --- src/libstd/ffi/os_str.rs | 4 ++++ src/libstd/sys/windows/os_str.rs | 6 ++++++ src/libstd/sys_common/os_str_bytes.rs | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 2f921ce7a5fe4..45417403c1084 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -525,11 +525,15 @@ impl OsStr { #[inline] fn from_inner(inner: &Slice) -> &OsStr { + // Safety: OsStr is just a wrapper of Slice, + // therefore converting &Slice to &OsStr is safe. unsafe { &*(inner as *const Slice as *const OsStr) } } #[inline] fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { + // Safety: OsStr is just a wrapper of Slice, + // therefore converting &mut Slice to &mut OsStr is safe. unsafe { &mut *(inner as *mut Slice as *mut OsStr) } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 4cff23b2f4a09..e768d9c326b0a 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -77,11 +77,17 @@ impl Buf { } pub fn as_slice(&self) -> &Slice { + // Safety: Slice is just a wrapper for Wtf8, + // and as_slice returns &Wtf8. Therefore, + // transmute &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { + // Safety: Slice is just a wrapper for Wtf8, + // and as_slice returns &Wtf8. Therefore, + // transmute &mut Wtf8 to &mut Slice is safe. unsafe { mem::transmute(self.inner.as_mut_slice()) } } diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs index 5767350336dad..c5d02fb17722f 100644 --- a/src/libstd/sys_common/os_str_bytes.rs +++ b/src/libstd/sys_common/os_str_bytes.rs @@ -106,11 +106,17 @@ impl Buf { #[inline] pub fn as_slice(&self) -> &Slice { + // Safety: Slice just wraps [u8], + // and &*self.inner is &[u8], therefore + // transmuting &[u8] to &Slice is safe. unsafe { mem::transmute(&*self.inner) } } #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { + // Safety: Slice just wraps [u8], + // and &mut *self.inner is &mut [u8], therefore + // transmuting &mut [u8] to &mut Slice is safe. unsafe { mem::transmute(&mut *self.inner) } } From cce8ee8bf7dbf461872d72c8b29302242bb11701 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 16:15:13 -0400 Subject: [PATCH 04/23] remove #[inline] for consistency in windows/os_str --- src/libstd/sys/windows/os_str.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index e768d9c326b0a..cd0eaaef5b669 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -83,7 +83,6 @@ impl Buf { unsafe { mem::transmute(self.inner.as_slice()) } } - #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { // Safety: Slice is just a wrapper for Wtf8, // and as_slice returns &Wtf8. Therefore, From 16712ede6202067d0c1b2e23ad95b87e0afd7191 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 16:18:35 -0400 Subject: [PATCH 05/23] corrections on safety comments --- src/libstd/sys/windows/os_str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index cd0eaaef5b669..9142b42f55858 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -79,14 +79,14 @@ impl Buf { pub fn as_slice(&self) -> &Slice { // Safety: Slice is just a wrapper for Wtf8, // and as_slice returns &Wtf8. Therefore, - // transmute &Wtf8 to &Slice is safe. + // transmuting &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } pub fn as_mut_slice(&mut self) -> &mut Slice { // Safety: Slice is just a wrapper for Wtf8, - // and as_slice returns &Wtf8. Therefore, - // transmute &mut Wtf8 to &mut Slice is safe. + // and as_mut_slice returns &mut Wtf8. Therefore, + // transmuting &mut Wtf8 to &mut Slice is safe. unsafe { mem::transmute(self.inner.as_mut_slice()) } } From e4a65e83e7ce89ce7a015753a4b8d989416ae2a8 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 16:22:49 -0400 Subject: [PATCH 06/23] make safety comments more explicit --- src/libstd/sys/windows/os_str.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 9142b42f55858..2820d2b5fe967 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -78,15 +78,15 @@ impl Buf { pub fn as_slice(&self) -> &Slice { // Safety: Slice is just a wrapper for Wtf8, - // and as_slice returns &Wtf8. Therefore, - // transmuting &Wtf8 to &Slice is safe. + // and self.inner.as_slice() returns &Wtf8. + // Therefore, transmuting &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } pub fn as_mut_slice(&mut self) -> &mut Slice { // Safety: Slice is just a wrapper for Wtf8, - // and as_mut_slice returns &mut Wtf8. Therefore, - // transmuting &mut Wtf8 to &mut Slice is safe. + // and self.inner.as_mut_slice() returns &mut Wtf8. + // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. unsafe { mem::transmute(self.inner.as_mut_slice()) } } From 45416cd91a6bdc493ea62fb3f412713a0fd8e52e Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Fri, 20 Mar 2020 09:00:53 -0400 Subject: [PATCH 07/23] add comment about maintaining OsStr encoding --- src/libstd/ffi/os_str.rs | 2 ++ src/libstd/sys/windows/os_str.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 45417403c1084..0fbe8e5dd83e8 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -534,6 +534,8 @@ impl OsStr { fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { // Safety: OsStr is just a wrapper of Slice, // therefore converting &mut Slice to &mut OsStr is safe. + // Any method that mutates OsStr must be careful not to + // break platform-specific encoding, in particular Wtf8 on Windows. unsafe { &mut *(inner as *mut Slice as *mut OsStr) } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 2820d2b5fe967..ff6885cb27477 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -87,6 +87,8 @@ impl Buf { // Safety: Slice is just a wrapper for Wtf8, // and self.inner.as_mut_slice() returns &mut Wtf8. // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. + // Additionally, care should be taken to ensure the slice + // is always valid Wtf8. unsafe { mem::transmute(self.inner.as_mut_slice()) } } From f07802c0de9091a1f4c728c6b4ee1eca5a49b275 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 23 Mar 2020 11:32:07 +0100 Subject: [PATCH 08/23] decouple rustc_hir::print from crate --- src/librustc_hir/hir.rs | 84 +++-------------------------- src/librustc_hir/print.rs | 25 ++++----- src/librustc_privacy/lib.rs | 16 +++--- src/librustc_typeck/check/_match.rs | 9 ++-- src/librustc_typeck/check/callee.rs | 19 ++++--- src/librustc_typeck/check/expr.rs | 11 ++-- 6 files changed, 52 insertions(+), 112 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index bb864edc99969..2d11bc3dd9784 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2,11 +2,6 @@ use crate::def::{DefKind, Namespace, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; use crate::itemlikevisit; -use crate::print; - -crate use BlockCheckMode::*; -crate use FnRetTy::*; -crate use UnsafeSource::*; use rustc_ast::ast::{self, AsmDialect, CrateSugar, Ident, Name}; use rustc_ast::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy}; @@ -169,12 +164,7 @@ impl fmt::Display for Lifetime { impl fmt::Debug for Lifetime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "lifetime({}: {})", - self.hir_id, - print::to_string(print::NO_ANN, |s| s.print_lifetime(self)) - ) + write!(f, "lifetime({}: {})", self.hir_id, self.name.ident()) } } @@ -191,7 +181,7 @@ impl Lifetime { /// A `Path` is essentially Rust's notion of a name; for instance, /// `std::cmp::PartialEq`. It's represented as a sequence of identifiers, /// along with a bunch of supporting information. -#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)] +#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct Path<'hir> { pub span: Span, /// The resolution for the path. @@ -206,18 +196,6 @@ impl Path<'_> { } } -impl fmt::Debug for Path<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "path({})", self) - } -} - -impl fmt::Display for Path<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", print::to_string(print::NO_ANN, |s| s.print_path(self, false))) - } -} - /// A segment of a path: an identifier, an optional lifetime, and a set of /// types. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] @@ -758,7 +736,7 @@ pub struct Block<'hir> { pub targeted_by_break: bool, } -#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)] +#[derive(Debug, RustcEncodable, RustcDecodable, HashStable_Generic)] pub struct Pat<'hir> { #[stable_hasher(ignore)] pub hir_id: HirId, @@ -766,17 +744,6 @@ pub struct Pat<'hir> { pub span: Span, } -impl fmt::Debug for Pat<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "pat({}: {})", - self.hir_id, - print::to_string(print::NO_ANN, |s| s.print_pat(self)) - ) - } -} - impl Pat<'_> { // FIXME(#19596) this is a workaround, but there should be a better way fn walk_short_(&self, it: &mut impl FnMut(&Pat<'_>) -> bool) -> bool { @@ -1118,26 +1085,15 @@ impl UnOp { } /// A statement. -#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)] +#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct Stmt<'hir> { pub hir_id: HirId, pub kind: StmtKind<'hir>, pub span: Span, } -impl fmt::Debug for Stmt<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "stmt({}: {})", - self.hir_id, - print::to_string(print::NO_ANN, |s| s.print_stmt(self)) - ) - } -} - /// The contents of a statement. -#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)] +#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum StmtKind<'hir> { /// A local (`let`) binding. Local(&'hir Local<'hir>), @@ -1351,7 +1307,7 @@ pub struct AnonConst { } /// An expression. -#[derive(RustcEncodable, RustcDecodable)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub struct Expr<'hir> { pub hir_id: HirId, pub kind: ExprKind<'hir>, @@ -1472,17 +1428,6 @@ impl Expr<'_> { } } -impl fmt::Debug for Expr<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "expr({}: {})", - self.hir_id, - print::to_string(print::NO_ANN, |s| s.print_expr(self)) - ) - } -} - /// Checks if the specified expression is a built-in range literal. /// (See: `LoweringContext::lower_expr()`). /// @@ -1965,19 +1910,13 @@ impl TypeBinding<'_> { } } -#[derive(RustcEncodable, RustcDecodable)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub struct Ty<'hir> { pub hir_id: HirId, pub kind: TyKind<'hir>, pub span: Span, } -impl fmt::Debug for Ty<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "type({})", print::to_string(print::NO_ANN, |s| s.print_type(self))) - } -} - /// Not represented directly in the AST; referred to by name through a `ty_path`. #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(HashStable_Generic)] @@ -2182,15 +2121,6 @@ pub enum FnRetTy<'hir> { Return(&'hir Ty<'hir>), } -impl fmt::Display for FnRetTy<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Return(ref ty) => print::to_string(print::NO_ANN, |s| s.print_type(ty)).fmt(f), - Self::DefaultReturn(_) => "()".fmt(f), - } - } -} - impl FnRetTy<'_> { pub fn span(&self) -> Span { match *self { diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index cd16e451f1db8..f33ed3a72397b 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -1006,10 +1006,10 @@ impl<'a> State<'a> { close_box: bool, ) { match blk.rules { - hir::UnsafeBlock(..) => self.word_space("unsafe"), - hir::PushUnsafeBlock(..) => self.word_space("push_unsafe"), - hir::PopUnsafeBlock(..) => self.word_space("pop_unsafe"), - hir::DefaultBlock => (), + hir::BlockCheckMode::UnsafeBlock(..) => self.word_space("unsafe"), + hir::BlockCheckMode::PushUnsafeBlock(..) => self.word_space("push_unsafe"), + hir::BlockCheckMode::PopUnsafeBlock(..) => self.word_space("pop_unsafe"), + hir::BlockCheckMode::DefaultBlock => (), } self.maybe_print_comment(blk.span.lo()); self.ann.pre(self, AnnNode::Block(blk)); @@ -1848,7 +1848,8 @@ impl<'a> State<'a> { self.print_block_unclosed(&blk); // If it is a user-provided unsafe block, print a comma after it - if let hir::UnsafeBlock(hir::UserProvided) = blk.rules { + if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = blk.rules + { self.s.word(","); } } @@ -1928,18 +1929,18 @@ impl<'a> State<'a> { }); self.s.word("|"); - if let hir::DefaultReturn(..) = decl.output { + if let hir::FnRetTy::DefaultReturn(..) = decl.output { return; } self.space_if_not_bol(); self.word_space("->"); match decl.output { - hir::Return(ref ty) => { + hir::FnRetTy::Return(ref ty) => { self.print_type(&ty); self.maybe_print_comment(ty.span.lo()) } - hir::DefaultReturn(..) => unreachable!(), + hir::FnRetTy::DefaultReturn(..) => unreachable!(), } } @@ -2112,7 +2113,7 @@ impl<'a> State<'a> { } pub fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) { - if let hir::DefaultReturn(..) = decl.output { + if let hir::FnRetTy::DefaultReturn(..) = decl.output { return; } @@ -2120,13 +2121,13 @@ impl<'a> State<'a> { self.ibox(INDENT_UNIT); self.word_space("->"); match decl.output { - hir::DefaultReturn(..) => unreachable!(), - hir::Return(ref ty) => self.print_type(&ty), + hir::FnRetTy::DefaultReturn(..) => unreachable!(), + hir::FnRetTy::Return(ref ty) => self.print_type(&ty), } self.end(); match decl.output { - hir::Return(ref output) => self.maybe_print_comment(output.span.lo()), + hir::FnRetTy::Return(ref output) => self.maybe_print_comment(output.span.lo()), _ => {} } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d680b9e002678..2cc5763a6f54c 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1313,14 +1313,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { let is_local_static = if let DefKind::Static = kind { def_id.is_local() } else { false }; if !self.item_is_accessible(def_id) && !is_local_static { - let name = match *qpath { - hir::QPath::Resolved(_, ref path) => path.to_string(), - hir::QPath::TypeRelative(_, ref segment) => segment.ident.to_string(), + let sess = self.tcx.sess; + let sm = sess.source_map(); + let name = match qpath { + hir::QPath::Resolved(_, path) => sm.span_to_snippet(path.span).ok(), + hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()), }; let kind = kind.descr(def_id); - self.tcx - .sess - .struct_span_err(span, &format!("{} `{}` is private", kind, name)) + let msg = match name { + Some(name) => format!("{} `{}` is private", kind, name), + None => format!("{} is private", kind), + }; + sess.struct_span_err(span, &msg) .span_label(span, &format!("private {}", kind)) .emit(); return; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 20737b44e7c17..f8007b20b3527 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -245,11 +245,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // check that the `if` expr without `else` is the fn body's expr if expr.span == span { - return self.get_fn_decl(hir_id).map(|(fn_decl, _)| { - ( - fn_decl.output.span(), - format!("expected `{}` because of this return type", fn_decl.output), - ) + return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| { + let span = fn_decl.output.span(); + let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?; + Some((span, format!("expected `{}` because of this return type", snippet))) }); } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index ec796043d3ac8..a8751506726a1 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -335,16 +335,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(call_expr.span, "call expression requires function"); if let Some(span) = self.tcx.hir().res_span(def) { + let callee_ty = callee_ty.to_string(); let label = match (unit_variant, inner_callee_path) { - (Some(path), _) => format!("`{}` defined here", path), - (_, Some(hir::QPath::Resolved(_, path))) => format!( - "`{}` defined here returns `{}`", - path, - callee_ty.to_string() - ), - _ => format!("`{}` defined here", callee_ty.to_string()), + (Some(path), _) => Some(format!("`{}` defined here", path)), + (_, Some(hir::QPath::Resolved(_, path))) => { + self.tcx.sess.source_map().span_to_snippet(path.span).ok().map( + |p| format!("`{}` defined here returns `{}`", p, callee_ty), + ) + } + _ => Some(format!("`{}` defined here", callee_ty)), }; - err.span_label(span, label); + if let Some(label) = label { + err.span_label(span, label); + } } err.emit(); } else { diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index dffed9a836c21..4e11246ac7294 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -696,10 +696,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self, &cause, &mut |db| { - db.span_label( - fn_decl.output.span(), - format!("expected `{}` because of this return type", fn_decl.output,), - ); + let span = fn_decl.output.span(); + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + db.span_label( + span, + format!("expected `{}` because of this return type", snippet), + ); + } }, true, ); From b60d732efe924931f377e1f552ce6290b2ba8393 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 23 Mar 2020 20:27:59 +0100 Subject: [PATCH 09/23] rustc_hir: nix rustc_errors dep --- Cargo.lock | 1 - src/librustc_hir/Cargo.toml | 1 - src/librustc_hir/hir.rs | 14 +++--- src/librustc_hir/lib.rs | 1 + .../traits/error_reporting/mod.rs | 3 +- .../traits/object_safety.rs | 45 +++++++++---------- src/librustc_typeck/astconv.rs | 6 +-- src/librustc_typeck/check/coercion.rs | 9 ++-- src/librustc_typeck/check/method/suggest.rs | 2 +- 9 files changed, 40 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22a06151353ba..94305401ee9f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3730,7 +3730,6 @@ dependencies = [ "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", - "rustc_errors", "rustc_index", "rustc_macros", "rustc_span", diff --git a/src/librustc_hir/Cargo.toml b/src/librustc_hir/Cargo.toml index b3682ea5a807c..98598c4bcb5af 100644 --- a/src/librustc_hir/Cargo.toml +++ b/src/librustc_hir/Cargo.toml @@ -16,7 +16,6 @@ rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_index = { path = "../librustc_index" } rustc_span = { path = "../librustc_span" } -rustc_errors = { path = "../librustc_errors" } rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_ast = { path = "../librustc_ast" } lazy_static = "1" diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 2d11bc3dd9784..2054759933f3c 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -11,7 +11,6 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; -use rustc_errors::FatalError; use rustc_macros::HashStable_Generic; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -366,9 +365,9 @@ pub enum GenericBound<'hir> { } impl GenericBound<'_> { - pub fn trait_def_id(&self) -> Option { + pub fn trait_ref(&self) -> Option<&TraitRef<'_>> { match self { - GenericBound::Trait(data, _) => Some(data.trait_ref.trait_def_id()), + GenericBound::Trait(data, _) => Some(&data.trait_ref), _ => None, } } @@ -2204,13 +2203,10 @@ pub struct TraitRef<'hir> { impl TraitRef<'_> { /// Gets the `DefId` of the referenced trait. It _must_ actually be a trait or trait alias. - pub fn trait_def_id(&self) -> DefId { + pub fn trait_def_id(&self) -> Option { match self.path.res { - Res::Def(DefKind::Trait, did) => did, - Res::Def(DefKind::TraitAlias, did) => did, - Res::Err => { - FatalError.raise(); - } + Res::Def(DefKind::Trait | DefKind::TraitAlias, did) => Some(did), + Res::Err => None, _ => unreachable!(), } } diff --git a/src/librustc_hir/lib.rs b/src/librustc_hir/lib.rs index fbb3d6b2af37c..5888bde919d4c 100644 --- a/src/librustc_hir/lib.rs +++ b/src/librustc_hir/lib.rs @@ -7,6 +7,7 @@ #![feature(const_fn)] // For the unsizing cast on `&[]` #![feature(const_panic)] #![feature(in_band_lifetimes)] +#![feature(or_patterns)] #![feature(specialization)] #![recursion_limit = "256"] diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index b9ee991aa0226..52df6d7271b96 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1582,7 +1582,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { for param in generics.params { if param.span == *span && !param.bounds.iter().any(|bound| { - bound.trait_def_id() == self.tcx.lang_items().sized_trait() + bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id()) + == self.tcx.lang_items().sized_trait() }) { let (span, separator) = match param.bounds { diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 5cc1da045fc37..ebeb0e968b0a1 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -15,7 +15,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, Obligation, ObligationCause}; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, FatalError}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; @@ -170,6 +170,24 @@ fn object_safety_violations_for_trait( violations } +fn trait_bound_spans<'tcx>( + tcx: TyCtxt<'tcx>, + bounds: hir::GenericBounds<'tcx>, +) -> impl 'tcx + Iterator { + bounds.iter().filter_map(move |b| match b { + hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) + if trait_has_sized_self( + tcx, + trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), + ) => + { + // Fetch spans for supertraits that are `Sized`: `trait T: Super` + Some(trait_ref.span) + } + _ => None, + }) +} + fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { tcx.hir() .get_if_local(trait_def_id) @@ -189,33 +207,14 @@ fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { // Fetch spans for trait bounds that are Sized: // `trait T where Self: Pred` - Some(pred.bounds.iter().filter_map(|b| match b { - hir::GenericBound::Trait( - trait_ref, - hir::TraitBoundModifier::None, - ) if trait_has_sized_self( - tcx, - trait_ref.trait_ref.trait_def_id(), - ) => - { - Some(trait_ref.span) - } - _ => None, - })) + Some(trait_bound_spans(tcx, pred.bounds)) } _ => None, } }) .flatten() - .chain(bounds.iter().filter_map(|b| match b { - hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) - if trait_has_sized_self(tcx, trait_ref.trait_ref.trait_def_id()) => - { - // Fetch spans for supertraits that are `Sized`: `trait T: Super` - Some(trait_ref.span) - } - _ => None, - })) + // Fetch spans for supertraits that are `Sized`: `trait T: Super`. + .chain(trait_bound_spans(tcx, bounds)) .collect::>(), ), _ => None, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6f558ec9b9508..86737a819a7af 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -16,7 +16,7 @@ use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc_ast::ast; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, FatalError}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; @@ -991,7 +991,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_path_to_mono_trait_ref( trait_ref.path.span, - trait_ref.trait_def_id(), + trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), self_ty, trait_ref.path.segments.last().unwrap(), ) @@ -1007,7 +1007,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bounds: &mut Bounds<'tcx>, speculative: bool, ) -> Result<(), GenericArgCountMismatch> { - let trait_def_id = trait_ref.trait_def_id(); + let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 33fc18b4b6e68..2dc2a48ecbce8 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1402,9 +1402,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { { // Are of this `impl Trait`'s traits object safe? is_object_safe = bounds.iter().all(|bound| { - bound.trait_def_id().map_or(false, |def_id| { - fcx.tcx.object_safety_violations(def_id).is_empty() - }) + bound + .trait_ref() + .and_then(|t| t.trait_def_id()) + .map_or(false, |def_id| { + fcx.tcx.object_safety_violations(def_id).is_empty() + }) }) } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 68996f5aaf973..8a3dc9e8f0279 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -1057,7 +1057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_def_ids: FxHashSet = param .bounds .iter() - .filter_map(|bound| bound.trait_def_id()) + .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?)) .collect(); if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) { err.span_suggestions( From b3866a5c9315d2f882ab9f306df82c5fa66989bf Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 23 Mar 2020 20:59:19 +0100 Subject: [PATCH 10/23] move rustc_hir::print -> rustc_hir_pretty --- Cargo.lock | 17 ++++++++++++++++- src/librustc/Cargo.toml | 1 + src/librustc/hir/map/mod.rs | 8 ++++---- src/librustc_driver/Cargo.toml | 1 + src/librustc_driver/pretty.rs | 2 +- src/librustc_hir/Cargo.toml | 1 - src/librustc_hir/lib.rs | 1 - src/librustc_hir_pretty/Cargo.toml | 18 ++++++++++++++++++ .../print.rs => librustc_hir_pretty/lib.rs} | 11 +++++------ src/librustc_metadata/Cargo.toml | 1 + src/librustc_metadata/rmeta/encoder.rs | 4 ++-- src/librustc_typeck/Cargo.toml | 1 + src/librustc_typeck/astconv.rs | 6 +++--- src/librustc_typeck/check/demand.rs | 13 ++++++++----- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/pat.rs | 2 +- src/librustc_typeck/check_unused.rs | 2 +- 17 files changed, 64 insertions(+), 27 deletions(-) create mode 100644 src/librustc_hir_pretty/Cargo.toml rename src/{librustc_hir/print.rs => librustc_hir_pretty/lib.rs} (99%) diff --git a/Cargo.lock b/Cargo.lock index 94305401ee9f8..02427ecb4b9ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3114,6 +3114,7 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_macros", "rustc_query_system", @@ -3654,6 +3655,7 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_hir", + "rustc_hir_pretty", "rustc_interface", "rustc_lint", "rustc_metadata", @@ -3728,7 +3730,6 @@ dependencies = [ "lazy_static 1.4.0", "log", "rustc_ast", - "rustc_ast_pretty", "rustc_data_structures", "rustc_index", "rustc_macros", @@ -3738,6 +3739,18 @@ dependencies = [ "smallvec 1.0.0", ] +[[package]] +name = "rustc_hir_pretty" +version = "0.0.0" +dependencies = [ + "rustc_ast", + "rustc_ast_pretty", + "rustc_data_structures", + "rustc_hir", + "rustc_span", + "rustc_target", +] + [[package]] name = "rustc_incremental" version = "0.0.0" @@ -3888,6 +3901,7 @@ dependencies = [ "rustc_errors", "rustc_expand", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_session", "rustc_span", @@ -4215,6 +4229,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_session", diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 47b94a2f1a4b4..d4464becb6862 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -22,6 +22,7 @@ rustc_apfloat = { path = "../librustc_apfloat" } rustc_attr = { path = "../librustc_attr" } rustc_feature = { path = "../librustc_feature" } rustc_hir = { path = "../librustc_hir" } +rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_target = { path = "../librustc_target" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index eb8e57743b8f8..7154eb44e01e2 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -12,8 +12,8 @@ pub use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; pub use rustc_hir::definitions::{Definitions, DisambiguatedDefPathData}; use rustc_hir::intravisit; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::print::Nested; use rustc_hir::*; +use rustc_hir_pretty::Nested; use rustc_index::vec::IndexVec; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; @@ -963,7 +963,7 @@ impl<'hir> Map<'hir> { } pub fn hir_to_pretty_string(&self, id: HirId) -> String { - print::to_string(self, |s| s.print_node(self.get(id))) + rustc_hir_pretty::to_string(self, |s| s.print_node(self.get(id))) } } @@ -1048,8 +1048,8 @@ pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> &'tcx Indexe /// Identical to the `PpAnn` implementation for `hir::Crate`, /// except it avoids creating a dependency on the whole crate. -impl<'hir> print::PpAnn for Map<'hir> { - fn nested(&self, state: &mut print::State<'_>, nested: print::Nested) { +impl<'hir> rustc_hir_pretty::PpAnn for Map<'hir> { + fn nested(&self, state: &mut rustc_hir_pretty::State<'_>, nested: rustc_hir_pretty::Nested) { match nested { Nested::Item(id) => state.print_item(self.expect_item(id.id)), Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index aec10ee5ef537..3ca39b24c5276 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -21,6 +21,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_feature = { path = "../librustc_feature" } rustc_hir = { path = "../librustc_hir" } +rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } rustc_parse = { path = "../librustc_parse" } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 1e5cc55a82853..fe006f0e06c1a 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -7,7 +7,7 @@ use rustc_ast::ast; use rustc_ast_pretty::pprust; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::print as pprust_hir; +use rustc_hir_pretty as pprust_hir; use rustc_mir::util::{write_mir_graphviz, write_mir_pretty}; use rustc_session::config::{Input, PpMode, PpSourceMode}; use rustc_session::Session; diff --git a/src/librustc_hir/Cargo.toml b/src/librustc_hir/Cargo.toml index 98598c4bcb5af..811440fdeb987 100644 --- a/src/librustc_hir/Cargo.toml +++ b/src/librustc_hir/Cargo.toml @@ -10,7 +10,6 @@ path = "lib.rs" doctest = false [dependencies] -rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_target = { path = "../librustc_target" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_hir/lib.rs b/src/librustc_hir/lib.rs index 5888bde919d4c..49692c73fad80 100644 --- a/src/librustc_hir/lib.rs +++ b/src/librustc_hir/lib.rs @@ -24,7 +24,6 @@ pub mod intravisit; pub mod itemlikevisit; pub mod lang_items; pub mod pat_util; -pub mod print; mod stable_hash_impls; mod target; pub mod weak_lang_items; diff --git a/src/librustc_hir_pretty/Cargo.toml b/src/librustc_hir_pretty/Cargo.toml new file mode 100644 index 0000000000000..6a9339b4b9cee --- /dev/null +++ b/src/librustc_hir_pretty/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_hir_pretty" +version = "0.0.0" +edition = "2018" + +[lib] +name = "rustc_hir_pretty" +path = "lib.rs" +doctest = false + +[dependencies] +rustc_ast_pretty = { path = "../librustc_ast_pretty" } +rustc_hir = { path = "../librustc_hir" } +rustc_target = { path = "../librustc_target" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_span = { path = "../librustc_span" } +rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_hir/print.rs b/src/librustc_hir_pretty/lib.rs similarity index 99% rename from src/librustc_hir/print.rs rename to src/librustc_hir_pretty/lib.rs index f33ed3a72397b..dc82fb0343348 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -3,15 +3,14 @@ use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::{Comments, PrintState}; +use rustc_hir as hir; +use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node}; +use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier}; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, IdentPrinter}; use rustc_span::{self, BytePos, FileName}; use rustc_target::spec::abi::Abi; -use crate::hir; -use crate::hir::{GenericArg, GenericParam, GenericParamKind, Node}; -use crate::hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier}; - use std::borrow::Cow; use std::cell::Cell; use std::vec; @@ -47,7 +46,7 @@ pub struct NoAnn; impl PpAnn for NoAnn {} pub const NO_ANN: &dyn PpAnn = &NoAnn; -impl PpAnn for hir::Crate<'a> { +impl PpAnn for hir::Crate<'_> { fn try_fetch_item(&self, item: hir::HirId) -> Option<&hir::Item<'_>> { Some(self.item(item)) } @@ -1092,7 +1091,7 @@ impl<'a> State<'a> { &mut self, qpath: &hir::QPath<'_>, fields: &[hir::Field<'_>], - wth: &Option<&'hir hir::Expr<'_>>, + wth: &Option<&hir::Expr<'_>>, ) { self.print_qpath(qpath, true); self.s.word("{"); diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 088cba83ef998..ea439b1f41d42 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -19,6 +19,7 @@ rustc_attr = { path = "../librustc_attr" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } +rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_target = { path = "../librustc_target" } rustc_index = { path = "../librustc_index" } rustc_serialize = { path = "../libserialize", package = "serialize" } diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 52124fd3abb9b..8416550142785 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -830,7 +830,7 @@ impl EncodeContext<'tcx> { record!(self.per_def.kind[def_id] <- match trait_item.kind { ty::AssocKind::Const => { let rendered = - hir::print::to_string(&self.tcx.hir(), |s| s.print_trait_item(ast_item)); + rustc_hir_pretty::to_string(&self.tcx.hir(), |s| s.print_trait_item(ast_item)); let rendered_const = self.lazy(RenderedConst(rendered)); EntryKind::AssocConst( @@ -1048,7 +1048,7 @@ impl EncodeContext<'tcx> { fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> Lazy { let body = self.tcx.hir().body(body_id); - let rendered = hir::print::to_string(&self.tcx.hir(), |s| s.print_expr(&body.value)); + let rendered = rustc_hir_pretty::to_string(&self.tcx.hir(), |s| s.print_expr(&body.value)); let rendered_const = &RenderedConst(rendered); self.lazy(rendered_const) } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index e61a36f844f87..a76f920ce9b51 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -18,6 +18,7 @@ rustc_attr = { path = "../librustc_attr" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } +rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_target = { path = "../librustc_target" } rustc_session = { path = "../librustc_session" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 86737a819a7af..be515d763cc23 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -21,8 +21,8 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_generics, Visitor}; -use rustc_hir::print; use rustc_hir::{Constness, GenericArg, GenericArgs}; +use rustc_hir_pretty::{to_string, NO_ANN}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS}; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -1132,7 +1132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .and_then(|args| args.args.get(0)) .and_then(|arg| match arg { hir::GenericArg::Type(ty) => { - Some(print::to_string(print::NO_ANN, |s| s.print_type(ty))) + Some(to_string(NO_ANN, |s| s.print_type(ty))) } _ => None, }) @@ -1143,7 +1143,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .iter() .filter_map(|b| match (b.ident.as_str() == "Output", &b.kind) { (true, hir::TypeBindingKind::Equality { ty }) => { - Some(print::to_string(print::NO_ANN, |s| s.print_type(ty))) + Some(to_string(NO_ANN, |s| s.print_type(ty))) } _ => None, }) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 0556c80e4f707..40c056a7641ef 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -9,7 +9,8 @@ use rustc::ty::{self, AssocItem, Ty}; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::{is_range_literal, print, Node}; +use rustc_hir::{is_range_literal, Node}; +use rustc_hir_pretty::{to_string, NO_ANN}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -198,10 +199,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .peekable(); if compatible_variants.peek().is_some() { - let expr_text = - self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or_else(|_| { - print::to_string(print::NO_ANN, |s| s.print_expr(expr)) - }); + let expr_text = self + .tcx + .sess + .source_map() + .span_to_snippet(expr.span) + .unwrap_or_else(|_| to_string(NO_ANN, |s| s.print_expr(expr))); let suggestions = compatible_variants.map(|v| format!("{}({})", v, expr_text)); let msg = "try using a variant of the expected enum"; err.span_suggestions(expr.span, msg, suggestions, Applicability::MaybeIncorrect); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 085510452c47e..7855b4b761d56 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2663,7 +2663,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span, qpath: & E0533, "expected unit struct, unit variant or constant, found {} `{}`", res.descr(), - hir::print::to_string(&tcx.hir(), |s| s.print_qpath(qpath, false)) + rustc_hir_pretty::to_string(&tcx.hir(), |s| s.print_qpath(qpath, false)) ) .emit(); } diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 0d38fa98bd7f8..d2290d4a583d9 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -794,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = format!( "expected tuple struct or tuple variant, found {} `{}`", res.descr(), - hir::print::to_string(&tcx.hir(), |s| s.print_qpath(qpath, false)), + rustc_hir_pretty::to_string(&tcx.hir(), |s| s.print_qpath(qpath, false)), ); let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg); match (res, &pat.kind) { diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index d0414af5b2138..fbc8c3327bf83 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::print::visibility_qualified; +use rustc_hir_pretty::visibility_qualified; use rustc_session::lint; use rustc_span::Span; From 92885e3a5bc855c24e302154635107c848f8b585 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 23 Mar 2020 22:39:59 +0100 Subject: [PATCH 11/23] rustc_typeck: remove rustc_hir_pretty usage --- Cargo.lock | 1 - src/librustc_typeck/Cargo.toml | 1 - src/librustc_typeck/astconv.rs | 9 ++--- src/librustc_typeck/check/demand.rs | 20 +++++----- src/librustc_typeck/check/expr.rs | 2 +- src/librustc_typeck/check/mod.rs | 6 +-- src/librustc_typeck/check/pat.rs | 37 ++++++++++--------- src/librustc_typeck/check_unused.rs | 14 +++---- src/librustc_typeck/lib.rs | 1 + .../ui/methods/method-path-in-pattern.stderr | 6 +-- .../privacy/associated-item-privacy-trait.rs | 6 +-- .../associated-item-privacy-trait.stderr | 4 +- .../ui/qualified/qualified-path-params.stderr | 2 +- 13 files changed, 53 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02427ecb4b9ad..549b82e40b2d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4229,7 +4229,6 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_hir", - "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_session", diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index a76f920ce9b51..e61a36f844f87 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -18,7 +18,6 @@ rustc_attr = { path = "../librustc_attr" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_target = { path = "../librustc_target" } rustc_session = { path = "../librustc_session" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index be515d763cc23..432e7545b9ee6 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -20,9 +20,8 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, Fata use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_generics, Visitor}; +use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{Constness, GenericArg, GenericArgs}; -use rustc_hir_pretty::{to_string, NO_ANN}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS}; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -1118,6 +1117,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if !self.tcx().features().unboxed_closures && trait_segment.generic_args().parenthesized != trait_def.paren_sugar { + let sess = &self.tcx().sess.parse_sess; // For now, require that parenthetical notation be used only with `Fn()` etc. let (msg, sugg) = if trait_def.paren_sugar { ( @@ -1132,7 +1132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .and_then(|args| args.args.get(0)) .and_then(|arg| match arg { hir::GenericArg::Type(ty) => { - Some(to_string(NO_ANN, |s| s.print_type(ty))) + sess.source_map().span_to_snippet(ty.span).ok() } _ => None, }) @@ -1143,7 +1143,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .iter() .filter_map(|b| match (b.ident.as_str() == "Output", &b.kind) { (true, hir::TypeBindingKind::Equality { ty }) => { - Some(to_string(NO_ANN, |s| s.print_type(ty))) + sess.source_map().span_to_snippet(ty.span).ok() } _ => None, }) @@ -1154,7 +1154,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { ("parenthetical notation is only stable when used with `Fn`-family traits", None) }; - let sess = &self.tcx().sess.parse_sess; let mut err = feature_err(sess, sym::unboxed_closures, span, msg); if let Some(sugg) = sugg { let msg = "use parenthetical notation instead"; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 40c056a7641ef..f7ffb5a2218ba 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -10,7 +10,6 @@ use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::{is_range_literal, Node}; -use rustc_hir_pretty::{to_string, NO_ANN}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -199,15 +198,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .peekable(); if compatible_variants.peek().is_some() { - let expr_text = self - .tcx - .sess - .source_map() - .span_to_snippet(expr.span) - .unwrap_or_else(|_| to_string(NO_ANN, |s| s.print_expr(expr))); - let suggestions = compatible_variants.map(|v| format!("{}({})", v, expr_text)); - let msg = "try using a variant of the expected enum"; - err.span_suggestions(expr.span, msg, suggestions, Applicability::MaybeIncorrect); + if let Ok(expr_text) = self.tcx.sess.source_map().span_to_snippet(expr.span) { + let suggestions = compatible_variants.map(|v| format!("{}({})", v, expr_text)); + let msg = "try using a variant of the expected enum"; + err.span_suggestions( + expr.span, + msg, + suggestions, + Applicability::MaybeIncorrect, + ); + } } } } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 4e11246ac7294..ae4750f9fd0fa 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -475,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.types.err } Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => { - report_unexpected_variant_res(tcx, res, expr.span, qpath); + report_unexpected_variant_res(tcx, res, expr.span); tcx.types.err } _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7855b4b761d56..754cd7b160acb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2656,14 +2656,14 @@ pub fn check_enum<'tcx>( check_transparent(tcx, sp, def_id); } -fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span, qpath: &QPath<'_>) { +fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) { struct_span_err!( tcx.sess, span, E0533, - "expected unit struct, unit variant or constant, found {} `{}`", + "expected unit struct, unit variant or constant, found {}{}", res.descr(), - rustc_hir_pretty::to_string(&tcx.hir(), |s| s.print_qpath(qpath, false)) + tcx.sess.source_map().span_to_snippet(span).map_or(String::new(), |s| format!(" `{}`", s)), ) .emit(); } diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index d2290d4a583d9..17a6e0544a162 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -171,9 +171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::TupleStruct(ref qpath, subpats, ddpos) => { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) } - PatKind::Path(ref qpath) => { - self.check_pat_path(pat, path_res.unwrap(), qpath, expected, ti) - } + PatKind::Path(_) => self.check_pat_path(pat, path_res.unwrap(), expected, ti), PatKind::Struct(ref qpath, fields, etc) => { self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti) } @@ -694,7 +692,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &Pat<'_>, path_resolution: (Res, Option>, &'b [hir::PathSegment<'b>]), - qpath: &hir::QPath<'_>, expected: Ty<'tcx>, ti: TopInfo<'tcx>, ) -> Ty<'tcx> { @@ -707,17 +704,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); return tcx.types.err; } - Res::Def(DefKind::AssocFn, _) - | Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) - | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { - report_unexpected_variant_res(tcx, res, pat.span, qpath); + Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => { + report_unexpected_variant_res(tcx, res, pat.span); return tcx.types.err; } - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) - | Res::SelfCtor(..) - | Res::Def(DefKind::Const, _) - | Res::Def(DefKind::AssocConst, _) - | Res::Def(DefKind::ConstParam, _) => {} // OK + Res::SelfCtor(..) + | Res::Def( + DefKind::Ctor(_, CtorKind::Const) + | DefKind::Const + | DefKind::AssocConst + | DefKind::ConstParam, + _, + ) => {} // OK _ => bug!("unexpected pattern resolution: {:?}", res), } @@ -791,14 +789,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; let report_unexpected_res = |res: Res| { + let sm = tcx.sess.source_map(); + let path_str = sm + .span_to_snippet(sm.span_until_char(pat.span, '(')) + .map_or(String::new(), |s| format!(" `{}`", s.trim_end())); let msg = format!( - "expected tuple struct or tuple variant, found {} `{}`", + "expected tuple struct or tuple variant, found {}{}", res.descr(), - rustc_hir_pretty::to_string(&tcx.hir(), |s| s.print_qpath(qpath, false)), + path_str ); + let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg); - match (res, &pat.kind) { - (Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::AssocFn, _), _) => { + match res { + Res::Def(DefKind::Fn | DefKind::AssocFn, _) => { err.span_label(pat.span, "`fn` calls are not allowed in patterns"); err.help( "for more information, visit \ diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index fbc8c3327bf83..9d8113e7b3fff 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -5,7 +5,6 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir_pretty::visibility_qualified; use rustc_session::lint; use rustc_span::Span; @@ -176,16 +175,13 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name), None => format!("use {};", item.ident.name), }; - - let replacement = visibility_qualified(&item.vis, base_replacement); - let msg = "`extern crate` is not idiomatic in the new edition"; - let help = format!("convert it to a `{}`", visibility_qualified(&item.vis, "use")); - - lint.build(msg) + let vis = tcx.sess.source_map().span_to_snippet(item.vis.span).unwrap_or_default(); + let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) }; + lint.build("`extern crate` is not idiomatic in the new edition") .span_suggestion_short( extern_crate.span, - &help, - replacement, + &format!("convert it to a `{}`", add_vis("use".to_string())), + add_vis(base_replacement), Applicability::MachineApplicable, ) .emit(); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e487e0d265c3e..fd854c750184e 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -62,6 +62,7 @@ This API is completely unstable and subject to change. #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(or_patterns)] #![feature(try_blocks)] #![feature(never_type)] #![feature(slice_partition_dedup)] diff --git a/src/test/ui/methods/method-path-in-pattern.stderr b/src/test/ui/methods/method-path-in-pattern.stderr index 1d1bdb6b052a8..ed3c0222c7542 100644 --- a/src/test/ui/methods/method-path-in-pattern.stderr +++ b/src/test/ui/methods/method-path-in-pattern.stderr @@ -4,13 +4,13 @@ error[E0533]: expected unit struct, unit variant or constant, found associated f LL | Foo::bar => {} | ^^^^^^^^ -error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `::bar` --> $DIR/method-path-in-pattern.rs:19:9 | LL | ::bar => {} | ^^^^^^^^^^ -error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::trait_bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `::trait_bar` --> $DIR/method-path-in-pattern.rs:23:9 | LL | ::trait_bar => {} @@ -22,7 +22,7 @@ error[E0533]: expected unit struct, unit variant or constant, found associated f LL | if let Foo::bar = 0u32 {} | ^^^^^^^^ -error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `::bar` --> $DIR/method-path-in-pattern.rs:28:12 | LL | if let ::bar = 0u32 {} diff --git a/src/test/ui/privacy/associated-item-privacy-trait.rs b/src/test/ui/privacy/associated-item-privacy-trait.rs index 03347d5b99a31..b1482bc040f53 100644 --- a/src/test/ui/privacy/associated-item-privacy-trait.rs +++ b/src/test/ui/privacy/associated-item-privacy-trait.rs @@ -21,9 +21,9 @@ mod priv_trait { Pub.method(); //~^ ERROR type `for<'r> fn(&'r Self) {::method}` is private ::CONST; - //~^ ERROR associated constant `PrivTr::CONST` is private + //~^ ERROR associated constant `::CONST` is private let _: ::AssocTy; - //~^ ERROR associated type `PrivTr::AssocTy` is private + //~^ ERROR associated type `::AssocTy` is private pub type InSignatureTy = ::AssocTy; //~^ ERROR trait `priv_trait::PrivTr` is private pub trait InSignatureTr: PrivTr {} @@ -115,7 +115,7 @@ mod priv_parent_substs { >::CONST; //~^ ERROR type `priv_parent_substs::Priv` is private - let _: ::AssocTy; // FIXME no longer an error?! + let _: ::AssocTy; // FIXME no longer an error?! let _: >::AssocTy; //~^ ERROR type `priv_parent_substs::Priv` is private let _: >::AssocTy; diff --git a/src/test/ui/privacy/associated-item-privacy-trait.stderr b/src/test/ui/privacy/associated-item-privacy-trait.stderr index c30cc947d4508..b9f3e35d72261 100644 --- a/src/test/ui/privacy/associated-item-privacy-trait.stderr +++ b/src/test/ui/privacy/associated-item-privacy-trait.stderr @@ -31,7 +31,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: associated constant `PrivTr::CONST` is private +error: associated constant `::CONST` is private --> $DIR/associated-item-privacy-trait.rs:23:9 | LL | ::CONST; @@ -42,7 +42,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: associated type `PrivTr::AssocTy` is private +error: associated type `::AssocTy` is private --> $DIR/associated-item-privacy-trait.rs:25:16 | LL | let _: ::AssocTy; diff --git a/src/test/ui/qualified/qualified-path-params.stderr b/src/test/ui/qualified/qualified-path-params.stderr index 7ff43f4404c54..4214e2503c345 100644 --- a/src/test/ui/qualified/qualified-path-params.stderr +++ b/src/test/ui/qualified/qualified-path-params.stderr @@ -1,4 +1,4 @@ -error[E0533]: expected unit struct, unit variant or constant, found associated function `<::A>::f` +error[E0533]: expected unit struct, unit variant or constant, found associated function `::A::f::` --> $DIR/qualified-path-params.rs:20:9 | LL | ::A::f:: => {} From f1701ddef1408ac55f57e332a92371247aae6253 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 24 Mar 2020 02:44:41 +0100 Subject: [PATCH 12/23] rustc: remove rustc_hir_pretty dependency. --- Cargo.lock | 2 +- src/librustc/Cargo.toml | 1 - src/librustc/hir/map/mod.rs | 65 ++++++++++---------------- src/librustc_driver/pretty.rs | 7 +-- src/librustc_hir/intravisit.rs | 5 ++ src/librustc_hir_pretty/lib.rs | 18 +++++++ src/librustc_metadata/rmeta/encoder.rs | 13 ++++-- src/librustc_passes/liveness.rs | 18 ++----- src/librustc_save_analysis/Cargo.toml | 5 +- src/librustc_save_analysis/lib.rs | 7 +-- src/librustc_typeck/check/callee.rs | 3 +- src/librustc_typeck/check/expr.rs | 38 ++++++--------- src/librustc_typeck/collect.rs | 9 +++- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/utils.rs | 2 +- src/librustdoc/lib.rs | 1 + src/librustdoc/test.rs | 2 +- 17 files changed, 101 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 549b82e40b2d0..4b0e78bf2b3c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3114,7 +3114,6 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_hir", - "rustc_hir_pretty", "rustc_index", "rustc_macros", "rustc_query_system", @@ -4086,6 +4085,7 @@ dependencies = [ "rustc_ast_pretty", "rustc_data_structures", "rustc_hir", + "rustc_hir_pretty", "rustc_parse", "rustc_session", "rustc_span", diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index d4464becb6862..47b94a2f1a4b4 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -22,7 +22,6 @@ rustc_apfloat = { path = "../librustc_apfloat" } rustc_attr = { path = "../librustc_attr" } rustc_feature = { path = "../librustc_feature" } rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_target = { path = "../librustc_target" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 7154eb44e01e2..221efedd1d75d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -13,7 +13,6 @@ pub use rustc_hir::definitions::{Definitions, DisambiguatedDefPathData}; use rustc_hir::intravisit; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::*; -use rustc_hir_pretty::Nested; use rustc_index::vec::IndexVec; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; @@ -954,20 +953,18 @@ impl<'hir> Map<'hir> { } } + /// Get a representation of this `id` for debugging purposes. + /// NOTE: Do NOT use this in diagnostics! pub fn node_to_string(&self, id: HirId) -> String { - hir_id_to_string(self, id, true) - } - - pub fn hir_to_user_string(&self, id: HirId) -> String { - hir_id_to_string(self, id, false) - } - - pub fn hir_to_pretty_string(&self, id: HirId) -> String { - rustc_hir_pretty::to_string(self, |s| s.print_node(self.get(id))) + hir_id_to_string(self, id) } } impl<'hir> intravisit::Map<'hir> for Map<'hir> { + fn find(&self, hir_id: HirId) -> Option> { + self.find(hir_id) + } + fn body(&self, id: BodyId) -> &'hir Body<'hir> { self.body(id) } @@ -1046,23 +1043,8 @@ pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> &'tcx Indexe tcx.arena.alloc(IndexedHir { crate_hash, map }) } -/// Identical to the `PpAnn` implementation for `hir::Crate`, -/// except it avoids creating a dependency on the whole crate. -impl<'hir> rustc_hir_pretty::PpAnn for Map<'hir> { - fn nested(&self, state: &mut rustc_hir_pretty::State<'_>, nested: rustc_hir_pretty::Nested) { - match nested { - Nested::Item(id) => state.print_item(self.expect_item(id.id)), - Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), - Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), - Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat), - } - } -} - -fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { +fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { let id_str = format!(" (hir_id={})", id); - let id_str = if include_id { &id_str[..] } else { "" }; let path_str = || { // This functionality is used for debugging, try to use `TyCtxt` to get @@ -1083,6 +1065,9 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { }) }; + let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default(); + let node_str = |prefix| format!("{} {}{}", prefix, span_str(), id_str); + match map.find(id) { Some(Node::Item(item)) => { let item_str = match item.kind { @@ -1133,22 +1118,20 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { Some(Node::Field(ref field)) => { format!("field {} in {}{}", field.ident, path_str(), id_str) } - Some(Node::AnonConst(_)) => format!("const {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Expr(_)) => format!("expr {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Stmt(_)) => format!("stmt {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::PathSegment(_)) => { - format!("path segment {}{}", map.hir_to_pretty_string(id), id_str) - } - Some(Node::Ty(_)) => format!("type {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::TraitRef(_)) => format!("trait_ref {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Binding(_)) => format!("local {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Pat(_)) => format!("pat {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Param(_)) => format!("param {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Arm(_)) => format!("arm {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Block(_)) => format!("block {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Local(_)) => format!("local {}{}", map.hir_to_pretty_string(id), id_str), + Some(Node::AnonConst(_)) => node_str("const"), + Some(Node::Expr(_)) => node_str("expr"), + Some(Node::Stmt(_)) => node_str("stmt"), + Some(Node::PathSegment(_)) => node_str("path segment"), + Some(Node::Ty(_)) => node_str("type"), + Some(Node::TraitRef(_)) => node_str("trait ref"), + Some(Node::Binding(_)) => node_str("local"), + Some(Node::Pat(_)) => node_str("pat"), + Some(Node::Param(_)) => node_str("param"), + Some(Node::Arm(_)) => node_str("arm"), + Some(Node::Block(_)) => node_str("block"), + Some(Node::Local(_)) => node_str("local"), Some(Node::Ctor(..)) => format!("ctor {}{}", path_str(), id_str), - Some(Node::Lifetime(_)) => format!("lifetime {}{}", map.hir_to_pretty_string(id), id_str), + Some(Node::Lifetime(_)) => node_str("lifetime"), Some(Node::GenericParam(ref param)) => format!("generic_param {:?}{}", param, id_str), Some(Node::Visibility(ref vis)) => format!("visibility {:?}{}", vis, id_str), Some(Node::MacroDef(_)) => format!("macro {}{}", path_str(), id_str), diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index fe006f0e06c1a..a57a70e6b8ca7 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -155,7 +155,7 @@ impl<'hir> pprust::PpAnn for NoAnn<'hir> {} impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { if let Some(tcx) = self.tcx { - pprust_hir::PpAnn::nested(&tcx.hir(), state, nested) + pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) } } } @@ -228,7 +228,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { if let Some(ref tcx) = self.tcx { - pprust_hir::PpAnn::nested(&tcx.hir(), state, nested) + pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) } } fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { @@ -334,7 +334,8 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { if let pprust_hir::Nested::Body(id) = nested { self.tables.set(self.tcx.body_tables(id)); } - pprust_hir::PpAnn::nested(&self.tcx.hir(), state, nested); + let pp_ann = &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>); + pprust_hir::PpAnn::nested(pp_ann, state, nested); self.tables.set(old_tables); } fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 11749cf996b44..08b4ef1b918e1 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -121,6 +121,8 @@ impl<'a> FnKind<'a> { /// An abstract representation of the HIR `rustc::hir::map::Map`. pub trait Map<'hir> { + /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. + fn find(&self, hir_id: HirId) -> Option>; fn body(&self, id: BodyId) -> &'hir Body<'hir>; fn item(&self, id: HirId) -> &'hir Item<'hir>; fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>; @@ -132,6 +134,9 @@ pub trait Map<'hir> { pub struct ErasedMap<'hir>(&'hir dyn Map<'hir>); impl<'hir> Map<'hir> for ErasedMap<'hir> { + fn find(&self, _: HirId) -> Option> { + None + } fn body(&self, id: BodyId) -> &'hir Body<'hir> { self.0.body(id) } diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index dc82fb0343348..06f338af9e92b 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -15,6 +15,10 @@ use std::borrow::Cow; use std::cell::Cell; use std::vec; +pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: hir::HirId) -> String { + to_string(&map, |s| s.print_node(map.find(hir_id).unwrap())) +} + pub enum AnnNode<'a> { Name(&'a ast::Name), Block(&'a hir::Block<'a>), @@ -61,6 +65,20 @@ impl PpAnn for hir::Crate<'_> { } } +/// Identical to the `PpAnn` implementation for `hir::Crate`, +/// except it avoids creating a dependency on the whole crate. +impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { + fn nested(&self, state: &mut State<'_>, nested: Nested) { + match nested { + Nested::Item(id) => state.print_item(self.item(id.id)), + Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), + Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), + Nested::Body(id) => state.print_expr(&self.body(id).value), + Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat), + } + } +} + pub struct State<'a> { pub s: pp::Printer, comments: Option>, diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 8416550142785..6c86dfe39e2a6 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -829,8 +829,10 @@ impl EncodeContext<'tcx> { record!(self.per_def.kind[def_id] <- match trait_item.kind { ty::AssocKind::Const => { - let rendered = - rustc_hir_pretty::to_string(&self.tcx.hir(), |s| s.print_trait_item(ast_item)); + let rendered = rustc_hir_pretty::to_string( + &(&self.tcx.hir() as &dyn intravisit::Map<'_>), + |s| s.print_trait_item(ast_item) + ); let rendered_const = self.lazy(RenderedConst(rendered)); EntryKind::AssocConst( @@ -1047,8 +1049,11 @@ impl EncodeContext<'tcx> { } fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> Lazy { - let body = self.tcx.hir().body(body_id); - let rendered = rustc_hir_pretty::to_string(&self.tcx.hir(), |s| s.print_expr(&body.value)); + let hir = self.tcx.hir(); + let body = hir.body(body_id); + let rendered = rustc_hir_pretty::to_string(&(&hir as &dyn intravisit::Map<'_>), |s| { + s.print_expr(&body.value) + }); let rendered_const = &RenderedConst(rendered); self.lazy(rendered_const) } diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 97f6457d39736..e729c2d517fea 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -903,10 +903,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn compute(&mut self, body: &hir::Expr<'_>) -> LiveNode { - debug!( - "compute: using id for body, {}", - self.ir.tcx.hir().hir_to_pretty_string(body.hir_id) - ); + debug!("compute: using id for body, {:?}", body); // the fallthrough exit is only for those cases where we do not // explicitly return: @@ -979,7 +976,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode { - debug!("propagate_through_expr: {}", self.ir.tcx.hir().hir_to_pretty_string(expr.hir_id)); + debug!("propagate_through_expr: {:?}", expr); match expr.kind { // Interesting cases with control flow or which gen/kill @@ -990,10 +987,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ), hir::ExprKind::Closure(..) => { - debug!( - "{} is an ExprKind::Closure", - self.ir.tcx.hir().hir_to_pretty_string(expr.hir_id) - ); + debug!("{:?} is an ExprKind::Closure", expr); // the construction of a closure itself is not important, // but we have to consider the closed over variables. @@ -1344,11 +1338,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut first_merge = true; let ln = self.live_node(expr.hir_id, expr.span); self.init_empty(ln, succ); - debug!( - "propagate_through_loop: using id for loop body {} {}", - expr.hir_id, - self.ir.tcx.hir().hir_to_pretty_string(body.hir_id) - ); + debug!("propagate_through_loop: using id for loop body {} {:?}", expr.hir_id, body); self.break_ln.insert(expr.hir_id, succ); diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index de851d9772727..623da1ddcb425 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -11,13 +11,14 @@ path = "lib.rs" [dependencies] log = "0.4" rustc = { path = "../librustc" } +rustc_ast = { path = "../librustc_ast" } rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_data_structures = { path = "../librustc_data_structures" } -rustc_session = { path = "../librustc_session" } rustc_hir = { path = "../librustc_hir" } +rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_parse = { path = "../librustc_parse" } serde_json = "1" -rustc_ast = { path = "../librustc_ast" } +rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } rls-data = "0.19" rls-span = "0.5" diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 024633c3b3dec..21551eeddb927 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -404,14 +404,15 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { Some(impl_id) => match self.tcx.hir().get_if_local(impl_id) { Some(Node::Item(item)) => match item.kind { hir::ItemKind::Impl { ref self_ty, .. } => { + let hir = self.tcx.hir(); + let mut qualname = String::from("<"); - qualname.push_str(&self.tcx.hir().hir_to_pretty_string(self_ty.hir_id)); + qualname.push_str(&rustc_hir_pretty::id_to_string(&hir, self_ty.hir_id)); let trait_id = self.tcx.trait_id_of_impl(impl_id); let mut docs = String::new(); let mut attrs = vec![]; - let hir_id = self.tcx.hir().node_to_hir_id(id); - if let Some(Node::ImplItem(item)) = self.tcx.hir().find(hir_id) { + if let Some(Node::ImplItem(item)) = hir.find(hir.node_to_hir_id(id)) { docs = self.docs_for_attrs(&item.attrs); attrs = item.attrs.to_vec(); } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index a8751506726a1..074951684ef06 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -265,7 +265,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let &ty::Adt(adt_def, ..) = t { if adt_def.is_enum() { if let hir::ExprKind::Call(ref expr, _) = call_expr.kind { - unit_variant = Some(self.tcx.hir().hir_to_pretty_string(expr.hir_id)) + unit_variant = + self.tcx.sess.source_map().span_to_snippet(expr.span).ok(); } } } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index ae4750f9fd0fa..53a20d9e86788 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1671,20 +1671,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let (Some(len), Ok(user_index)) = (len.try_eval_usize(self.tcx, self.param_env), field.as_str().parse::()) { - let base = self - .tcx - .sess - .source_map() - .span_to_snippet(base.span) - .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id)); - let help = "instead of using tuple indexing, use array indexing"; - let suggestion = format!("{}[{}]", base, field); - let applicability = if len < user_index { - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - err.span_suggestion(expr.span, help, suggestion, applicability); + if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) { + let help = "instead of using tuple indexing, use array indexing"; + let suggestion = format!("{}[{}]", base, field); + let applicability = if len < user_index { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + err.span_suggestion(expr.span, help, suggestion, applicability); + } } } @@ -1695,15 +1691,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &hir::Expr<'_>, field: ast::Ident, ) { - let base = self - .tcx - .sess - .source_map() - .span_to_snippet(base.span) - .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id)); - let msg = format!("`{}` is a raw pointer; try dereferencing it", base); - let suggestion = format!("(*{}).{}", base, field); - err.span_suggestion(expr.span, &msg, suggestion, Applicability::MaybeIncorrect); + if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) { + let msg = format!("`{}` is a raw pointer; try dereferencing it", base); + let suggestion = format!("(*{}).{}", base, field); + err.span_suggestion(expr.span, &msg, suggestion, Applicability::MaybeIncorrect); + } } fn no_such_field_err( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8136417de0387..e602c3a30645d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2139,13 +2139,18 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( { let check = |ast_ty: &hir::Ty<'_>, ty: Ty<'_>| { if ty.is_simd() { + let snip = tcx + .sess + .source_map() + .span_to_snippet(ast_ty.span) + .map_or(String::new(), |s| format!(" `{}`", s)); tcx.sess .struct_span_err( ast_ty.span, &format!( - "use of SIMD type `{}` in FFI is highly experimental and \ + "use of SIMD type{} in FFI is highly experimental and \ may result in invalid code", - tcx.hir().hir_to_pretty_string(ast_ty.hir_id) + snip ), ) .help("add `#![feature(simd_ffi)]` to the crate attributes to enable") diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 153f7af9f97ca..510eae82834c8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -482,8 +482,8 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet) } pub fn print_inlined_const(cx: &DocContext<'_>, did: DefId) -> String { - if let Some(node_id) = cx.tcx.hir().as_local_hir_id(did) { - cx.tcx.hir().hir_to_pretty_string(node_id) + if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(did) { + rustc_hir_pretty::id_to_string(&cx.tcx.hir(), hir_id) } else { cx.tcx.rendered_const(did) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 82e34710f0cbf..b3bfb559749cb 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -578,7 +578,7 @@ pub fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String { None }; - snippet.unwrap_or_else(|| cx.tcx.hir().hir_to_pretty_string(body.hir_id)) + snippet.unwrap_or_else(|| rustc_hir_pretty::id_to_string(&cx.tcx.hir(), body.hir_id)) } /// Given a type Path, resolve it to a Type using the TyCtxt diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 33cabad9193c4..3c5df0247c1e8 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -26,6 +26,7 @@ extern crate rustc_errors; extern crate rustc_expand; extern crate rustc_feature; extern crate rustc_hir; +extern crate rustc_hir_pretty; extern crate rustc_index; extern crate rustc_infer; extern crate rustc_interface; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index c5aa4677d5659..93305a1f87a16 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -910,7 +910,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { fn visit_item(&mut self, item: &'hir hir::Item) { let name = if let hir::ItemKind::Impl { ref self_ty, .. } = item.kind { - self.map.hir_to_pretty_string(self_ty.hir_id) + rustc_hir_pretty::id_to_string(&self.map, self_ty.hir_id) } else { item.ident.to_string() }; From b514c42e7baad3dec7dcce9e734df2e0b402391e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 26 Mar 2020 09:59:07 +0100 Subject: [PATCH 13/23] trait_bound_spans -> sized_trait_bound_spans --- src/librustc_trait_selection/traits/object_safety.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index ebeb0e968b0a1..7d4ad61902a92 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -170,7 +170,7 @@ fn object_safety_violations_for_trait( violations } -fn trait_bound_spans<'tcx>( +fn sized_trait_bound_spans<'tcx>( tcx: TyCtxt<'tcx>, bounds: hir::GenericBounds<'tcx>, ) -> impl 'tcx + Iterator { @@ -207,14 +207,14 @@ fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { // Fetch spans for trait bounds that are Sized: // `trait T where Self: Pred` - Some(trait_bound_spans(tcx, pred.bounds)) + Some(sized_trait_bound_spans(tcx, pred.bounds)) } _ => None, } }) .flatten() // Fetch spans for supertraits that are `Sized`: `trait T: Super`. - .chain(trait_bound_spans(tcx, bounds)) + .chain(sized_trait_bound_spans(tcx, bounds)) .collect::>(), ), _ => None, From b2f7a9502bafebfa9ce0b61ff24a19c26e66c93b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 26 Mar 2020 13:50:02 +0100 Subject: [PATCH 14/23] rustc_hir_pretty: bump recursion_limit --- src/librustc_hir_pretty/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index 06f338af9e92b..88b1288848f4f 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -1,3 +1,5 @@ +#![recursion_limit = "256"] + use rustc_ast::ast; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; From 40a0fdcb1840b01c5ac2c58b48df0ed5bc33a7af Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 26 Mar 2020 16:10:58 +0000 Subject: [PATCH 15/23] Add regression test for #66706 --- src/test/ui/issues/issue-66706.rs | 13 +++++++++++ src/test/ui/issues/issue-66706.stderr | 32 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/test/ui/issues/issue-66706.rs create mode 100644 src/test/ui/issues/issue-66706.stderr diff --git a/src/test/ui/issues/issue-66706.rs b/src/test/ui/issues/issue-66706.rs new file mode 100644 index 0000000000000..5e64f63d53395 --- /dev/null +++ b/src/test/ui/issues/issue-66706.rs @@ -0,0 +1,13 @@ +fn a() { + [0; [|_: _ &_| ()].len()] + //~^ ERROR expected `,`, found `&` + //~| ERROR type annotations needed + //~| ERROR mismatched types +} + +fn b() { + [0; [|f @ &ref _| {} ; 0 ].len() ]; + //~^ ERROR expected identifier, found reserved identifier `_` +} + +fn main() {} diff --git a/src/test/ui/issues/issue-66706.stderr b/src/test/ui/issues/issue-66706.stderr new file mode 100644 index 0000000000000..6d290bccc7d0d --- /dev/null +++ b/src/test/ui/issues/issue-66706.stderr @@ -0,0 +1,32 @@ +error: expected `,`, found `&` + --> $DIR/issue-66706.rs:2:16 + | +LL | [0; [|_: _ &_| ()].len()] + | -^ expected `,` + | | + | help: missing `,` + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-66706.rs:9:20 + | +LL | [0; [|f @ &ref _| {} ; 0 ].len() ]; + | ^ expected identifier, found reserved identifier + +error[E0282]: type annotations needed + --> $DIR/issue-66706.rs:2:11 + | +LL | [0; [|_: _ &_| ()].len()] + | ^ consider giving this closure parameter a type + +error[E0308]: mismatched types + --> $DIR/issue-66706.rs:2:5 + | +LL | fn a() { + | - help: try adding a return type: `-> [{integer}; _]` +LL | [0; [|_: _ &_| ()].len()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. From 15346ed53ca1b248b8063dc29928d2e0876e825d Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 28 Feb 2020 21:42:20 -0800 Subject: [PATCH 16/23] Remove `BitDenotation` framework --- src/librustc_mir/dataflow/at_location.rs | 169 ----- src/librustc_mir/dataflow/mod.rs | 850 +---------------------- 2 files changed, 2 insertions(+), 1017 deletions(-) delete mode 100644 src/librustc_mir/dataflow/at_location.rs diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs deleted file mode 100644 index e4eb8506846c0..0000000000000 --- a/src/librustc_mir/dataflow/at_location.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! A nice wrapper to consume dataflow results at several CFG -//! locations. - -use rustc::mir::{BasicBlock, Location}; -use rustc_index::bit_set::{BitIter, BitSet, HybridBitSet}; - -use crate::dataflow::{BitDenotation, DataflowResults, GenKillSet}; - -use std::borrow::Borrow; -use std::iter; - -/// A trait for "cartesian products" of multiple FlowAtLocation. -/// -/// There's probably a way to auto-impl this, but I think -/// it is cleaner to have manual visitor impls. -pub trait FlowsAtLocation { - /// Reset the state bitvector to represent the entry to block `bb`. - fn reset_to_entry_of(&mut self, bb: BasicBlock); - - /// Reset the state bitvector to represent the exit of the - /// terminator of block `bb`. - /// - /// **Important:** In the case of a `Call` terminator, these - /// effects do *not* include the result of storing the destination - /// of the call, since that is edge-dependent (in other words, the - /// effects don't apply to the unwind edge). - fn reset_to_exit_of(&mut self, bb: BasicBlock); - - /// Builds gen and kill sets for statement at `loc`. - /// - /// Note that invoking this method alone does not change the - /// `curr_state` -- you must invoke `apply_local_effect` - /// afterwards. - fn reconstruct_statement_effect(&mut self, loc: Location); - - /// Builds gen and kill sets for terminator for `loc`. - /// - /// Note that invoking this method alone does not change the - /// `curr_state` -- you must invoke `apply_local_effect` - /// afterwards. - fn reconstruct_terminator_effect(&mut self, loc: Location); - - /// Apply current gen + kill sets to `flow_state`. - /// - /// (`loc` parameters can be ignored if desired by - /// client. For the terminator, the `stmt_idx` will be the number - /// of statements in the block.) - fn apply_local_effect(&mut self, loc: Location); -} - -/// Represents the state of dataflow at a particular -/// CFG location, both before and after it is -/// executed. -/// -/// Data flow results are typically computed only as basic block -/// boundaries. A `FlowInProgress` allows you to reconstruct the -/// effects at any point in the control-flow graph by starting with -/// the state at the start of the basic block (`reset_to_entry_of`) -/// and then replaying the effects of statements and terminators -/// (e.g., via `reconstruct_statement_effect` and -/// `reconstruct_terminator_effect`; don't forget to call -/// `apply_local_effect`). -pub struct FlowAtLocation<'tcx, BD, DR = DataflowResults<'tcx, BD>> -where - BD: BitDenotation<'tcx>, - DR: Borrow>, -{ - base_results: DR, - curr_state: BitSet, - stmt_trans: GenKillSet, -} - -impl<'tcx, BD, DR> FlowAtLocation<'tcx, BD, DR> -where - BD: BitDenotation<'tcx>, - DR: Borrow>, -{ - /// Iterate over each bit set in the current state. - pub fn each_state_bit(&self, f: F) - where - F: FnMut(BD::Idx), - { - self.curr_state.iter().for_each(f) - } - - /// Iterate over each `gen` bit in the current effect (invoke - /// `reconstruct_statement_effect` or - /// `reconstruct_terminator_effect` first). - pub fn each_gen_bit(&self, f: F) - where - F: FnMut(BD::Idx), - { - self.stmt_trans.gen_set.iter().for_each(f) - } - - pub fn new(results: DR) -> Self { - let bits_per_block = results.borrow().sets().bits_per_block(); - let curr_state = BitSet::new_empty(bits_per_block); - let stmt_trans = GenKillSet::from_elem(HybridBitSet::new_empty(bits_per_block)); - FlowAtLocation { base_results: results, curr_state, stmt_trans } - } - - /// Access the underlying operator. - pub fn operator(&self) -> &BD { - self.base_results.borrow().operator() - } - - pub fn contains(&self, x: BD::Idx) -> bool { - self.curr_state.contains(x) - } - - /// Returns an iterator over the elements present in the current state. - pub fn iter_incoming(&self) -> iter::Peekable> { - self.curr_state.iter().peekable() - } - - /// Creates a clone of the current state and applies the local - /// effects to the clone (leaving the state of self intact). - /// Invokes `f` with an iterator over the resulting state. - pub fn with_iter_outgoing(&self, f: F) - where - F: FnOnce(BitIter<'_, BD::Idx>), - { - let mut curr_state = self.curr_state.clone(); - self.stmt_trans.apply(&mut curr_state); - f(curr_state.iter()); - } - - /// Returns a bitset of the elements present in the current state. - pub fn as_dense(&self) -> &BitSet { - &self.curr_state - } -} - -impl<'tcx, BD, DR> FlowsAtLocation for FlowAtLocation<'tcx, BD, DR> -where - BD: BitDenotation<'tcx>, - DR: Borrow>, -{ - fn reset_to_entry_of(&mut self, bb: BasicBlock) { - self.curr_state.overwrite(self.base_results.borrow().sets().entry_set_for(bb.index())); - } - - fn reset_to_exit_of(&mut self, bb: BasicBlock) { - self.reset_to_entry_of(bb); - let trans = self.base_results.borrow().sets().trans_for(bb.index()); - trans.apply(&mut self.curr_state) - } - - fn reconstruct_statement_effect(&mut self, loc: Location) { - self.stmt_trans.clear(); - self.base_results.borrow().operator().before_statement_effect(&mut self.stmt_trans, loc); - self.stmt_trans.apply(&mut self.curr_state); - - self.base_results.borrow().operator().statement_effect(&mut self.stmt_trans, loc); - } - - fn reconstruct_terminator_effect(&mut self, loc: Location) { - self.stmt_trans.clear(); - self.base_results.borrow().operator().before_terminator_effect(&mut self.stmt_trans, loc); - self.stmt_trans.apply(&mut self.curr_state); - - self.base_results.borrow().operator().terminator_effect(&mut self.stmt_trans, loc); - } - - fn apply_local_effect(&mut self, _loc: Location) { - self.stmt_trans.apply(&mut self.curr_state) - } -} diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index c98a5e84729ab..b7189f60984ea 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -1,21 +1,9 @@ -use rustc::mir::traversal; -use rustc::mir::{self, BasicBlock, BasicBlockData, Body, Location, Statement, Terminator}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty; use rustc_ast::ast::{self, MetaItem}; -use rustc_ast_pretty::pprust; -use rustc_data_structures::work_queue::WorkQueue; -use rustc_hir::def_id::DefId; -use rustc_index::bit_set::{BitSet, HybridBitSet}; +use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; -use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; -use std::borrow::Borrow; -use std::fmt; -use std::io; -use std::path::PathBuf; - -pub use self::at_location::{FlowAtLocation, FlowsAtLocation}; pub(crate) use self::drop_flag_effects::*; pub use self::impls::borrows::Borrows; pub use self::impls::DefinitelyInitializedPlaces; @@ -26,10 +14,8 @@ pub use self::impls::{MaybeRequiresStorage, MaybeStorageLive}; use self::move_paths::MoveData; -mod at_location; pub mod drop_flag_effects; pub mod generic; -mod graphviz; mod impls; pub mod move_paths; @@ -40,76 +26,6 @@ pub(crate) mod indexes { }; } -pub(crate) struct DataflowBuilder<'a, 'tcx, BD> -where - BD: BitDenotation<'tcx>, -{ - def_id: DefId, - flow_state: DataflowAnalysis<'a, 'tcx, BD>, - print_preflow_to: Option, - print_postflow_to: Option, -} - -/// `DebugFormatted` encapsulates the "{:?}" rendering of some -/// arbitrary value. This way: you pay cost of allocating an extra -/// string (as well as that of rendering up-front); in exchange, you -/// don't have to hand over ownership of your value or deal with -/// borrowing it. -pub struct DebugFormatted(String); - -impl DebugFormatted { - pub fn new(input: &dyn fmt::Debug) -> DebugFormatted { - DebugFormatted(format!("{:?}", input)) - } -} - -impl fmt::Debug for DebugFormatted { - fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(w, "{}", self.0) - } -} - -pub trait Dataflow<'tcx, BD: BitDenotation<'tcx>> { - /// Sets up and runs the dataflow problem, using `p` to render results if - /// implementation so chooses. - fn dataflow

(&mut self, p: P) - where - P: Fn(&BD, BD::Idx) -> DebugFormatted, - { - let _ = p; // default implementation does not instrument process. - self.build_sets(); - self.propagate(); - } - - /// Sets up the entry, gen, and kill sets for this instance of a dataflow problem. - fn build_sets(&mut self); - - /// Finds a fixed-point solution to this instance of a dataflow problem. - fn propagate(&mut self); -} - -impl<'a, 'tcx, BD> Dataflow<'tcx, BD> for DataflowBuilder<'a, 'tcx, BD> -where - BD: BitDenotation<'tcx>, -{ - fn dataflow

(&mut self, p: P) - where - P: Fn(&BD, BD::Idx) -> DebugFormatted, - { - self.flow_state.build_sets(); - self.pre_dataflow_instrumentation(|c, i| p(c, i)).unwrap(); - self.flow_state.propagate(); - self.post_dataflow_instrumentation(|c, i| p(c, i)).unwrap(); - } - - fn build_sets(&mut self) { - self.flow_state.build_sets(); - } - fn propagate(&mut self) { - self.flow_state.propagate(); - } -} - pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option { for attr in attrs { if attr.check_name(sym::rustc_mir) { @@ -130,525 +46,6 @@ pub struct MoveDataParamEnv<'tcx> { pub(crate) param_env: ty::ParamEnv<'tcx>, } -pub fn do_dataflow<'a, 'tcx, BD, P>( - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - def_id: DefId, - attributes: &[ast::Attribute], - dead_unwinds: &BitSet, - bd: BD, - p: P, -) -> DataflowResults<'tcx, BD> -where - BD: BitDenotation<'tcx>, - P: Fn(&BD, BD::Idx) -> DebugFormatted, -{ - let flow_state = DataflowAnalysis::new(body, dead_unwinds, bd); - flow_state.run(tcx, def_id, attributes, p) -} - -impl<'a, 'tcx, BD> DataflowAnalysis<'a, 'tcx, BD> -where - BD: BitDenotation<'tcx>, -{ - pub(crate) fn run

( - self, - tcx: TyCtxt<'tcx>, - def_id: DefId, - attributes: &[ast::Attribute], - p: P, - ) -> DataflowResults<'tcx, BD> - where - P: Fn(&BD, BD::Idx) -> DebugFormatted, - { - let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option { - if let Some(item) = has_rustc_mir_with(attrs, name) { - if let Some(s) = item.value_str() { - return Some(s.to_string()); - } else { - let path = pprust::path_to_string(&item.path); - sess.span_err(item.span, &format!("{} attribute requires a path", path)); - return None; - } - } - None - }; - - let print_preflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_preflow); - let print_postflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_postflow); - - let mut mbcx = - DataflowBuilder { def_id, print_preflow_to, print_postflow_to, flow_state: self }; - - mbcx.dataflow(p); - mbcx.flow_state.results() - } -} - -struct PropagationContext<'b, 'a, 'tcx, O> -where - O: BitDenotation<'tcx>, -{ - builder: &'b mut DataflowAnalysis<'a, 'tcx, O>, -} - -impl<'a, 'tcx, BD> DataflowAnalysis<'a, 'tcx, BD> -where - BD: BitDenotation<'tcx>, -{ - fn propagate(&mut self) { - let mut temp = BitSet::new_empty(self.flow_state.sets.bits_per_block); - let mut propcx = PropagationContext { builder: self }; - propcx.walk_cfg(&mut temp); - } - - fn build_sets(&mut self) { - // Build the transfer function for each block. - for (bb, data) in self.body.basic_blocks().iter_enumerated() { - let &mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = data; - - let trans = self.flow_state.sets.trans_mut_for(bb.index()); - for j_stmt in 0..statements.len() { - let location = Location { block: bb, statement_index: j_stmt }; - self.flow_state.operator.before_statement_effect(trans, location); - self.flow_state.operator.statement_effect(trans, location); - } - - if terminator.is_some() { - let location = Location { block: bb, statement_index: statements.len() }; - self.flow_state.operator.before_terminator_effect(trans, location); - self.flow_state.operator.terminator_effect(trans, location); - } - } - - // Initialize the flow state at entry to the start block. - let on_entry = self.flow_state.sets.entry_set_mut_for(mir::START_BLOCK.index()); - self.flow_state.operator.start_block_effect(on_entry); - } -} - -impl<'b, 'a, 'tcx, BD> PropagationContext<'b, 'a, 'tcx, BD> -where - BD: BitDenotation<'tcx>, -{ - fn walk_cfg(&mut self, in_out: &mut BitSet) { - let body = self.builder.body; - - // Initialize the dirty queue in reverse post-order. This makes it more likely that the - // entry state for each basic block will have the effects of its predecessors applied - // before it is processed. In fact, for CFGs without back edges, this guarantees that - // dataflow will converge in exactly `N` iterations, where `N` is the number of basic - // blocks. - let mut dirty_queue: WorkQueue = - WorkQueue::with_none(body.basic_blocks().len()); - for (bb, _) in traversal::reverse_postorder(body) { - dirty_queue.insert(bb); - } - - // Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will - // be processed after the ones added above. - for bb in body.basic_blocks().indices() { - dirty_queue.insert(bb); - } - - while let Some(bb) = dirty_queue.pop() { - let (on_entry, trans) = self.builder.flow_state.sets.get_mut(bb.index()); - debug_assert!(in_out.words().len() == on_entry.words().len()); - in_out.overwrite(on_entry); - trans.apply(in_out); - - let bb_data = &body[bb]; - self.builder.propagate_bits_into_graph_successors_of( - in_out, - (bb, bb_data), - &mut dirty_queue, - ); - } - } -} - -fn dataflow_path(context: &str, path: &str) -> PathBuf { - let mut path = PathBuf::from(path); - let new_file_name = { - let orig_file_name = path.file_name().unwrap().to_str().unwrap(); - format!("{}_{}", context, orig_file_name) - }; - path.set_file_name(new_file_name); - path -} - -impl<'a, 'tcx, BD> DataflowBuilder<'a, 'tcx, BD> -where - BD: BitDenotation<'tcx>, -{ - fn pre_dataflow_instrumentation

(&self, p: P) -> io::Result<()> - where - P: Fn(&BD, BD::Idx) -> DebugFormatted, - { - if let Some(ref path_str) = self.print_preflow_to { - let path = dataflow_path(BD::name(), path_str); - graphviz::print_borrowck_graph_to(self, &path, p) - } else { - Ok(()) - } - } - - fn post_dataflow_instrumentation

(&self, p: P) -> io::Result<()> - where - P: Fn(&BD, BD::Idx) -> DebugFormatted, - { - if let Some(ref path_str) = self.print_postflow_to { - let path = dataflow_path(BD::name(), path_str); - graphviz::print_borrowck_graph_to(self, &path, p) - } else { - Ok(()) - } - } -} - -/// DataflowResultsConsumer abstracts over walking the MIR with some -/// already constructed dataflow results. -/// -/// It abstracts over the FlowState and also completely hides the -/// underlying flow analysis results, because it needs to handle cases -/// where we are combining the results of *multiple* flow analyses -/// (e.g., borrows + inits + uninits). -pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> { - type FlowState: FlowsAtLocation; - - // Observation Hooks: override (at least one of) these to get analysis feedback. - fn visit_block_entry(&mut self, _bb: BasicBlock, _flow_state: &Self::FlowState) {} - - fn visit_statement_entry( - &mut self, - _loc: Location, - _stmt: &'a Statement<'tcx>, - _flow_state: &Self::FlowState, - ) { - } - - fn visit_terminator_entry( - &mut self, - _loc: Location, - _term: &'a Terminator<'tcx>, - _flow_state: &Self::FlowState, - ) { - } - - // Main entry point: this drives the processing of results. - - fn analyze_results(&mut self, flow_uninit: &mut Self::FlowState) { - let flow = flow_uninit; - for (bb, _) in traversal::reverse_postorder(self.body()) { - flow.reset_to_entry_of(bb); - self.process_basic_block(bb, flow); - } - } - - fn process_basic_block(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowState) { - self.visit_block_entry(bb, flow_state); - - let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = self.body()[bb]; - let mut location = Location { block: bb, statement_index: 0 }; - for stmt in statements.iter() { - flow_state.reconstruct_statement_effect(location); - self.visit_statement_entry(location, stmt, flow_state); - flow_state.apply_local_effect(location); - location.statement_index += 1; - } - - if let Some(ref term) = *terminator { - flow_state.reconstruct_terminator_effect(location); - self.visit_terminator_entry(location, term, flow_state); - - // We don't need to apply the effect of the terminator, - // since we are only visiting dataflow state on control - // flow entry to the various nodes. (But we still need to - // reconstruct the effect, because the visit method might - // inspect it.) - } - } - - // Delegated Hooks: Provide access to the MIR and process the flow state. - - fn body(&self) -> &'a Body<'tcx>; -} - -/// Allows iterating dataflow results in a flexible and reasonably fast way. -pub struct DataflowResultsCursor<'mir, 'tcx, BD, DR = DataflowResults<'tcx, BD>> -where - BD: BitDenotation<'tcx>, - DR: Borrow>, -{ - flow_state: FlowAtLocation<'tcx, BD, DR>, - - // The statement (or terminator) whose effect has been reconstructed in - // flow_state. - curr_loc: Option, - - body: &'mir Body<'tcx>, -} - -pub type DataflowResultsRefCursor<'mir, 'tcx, BD> = - DataflowResultsCursor<'mir, 'tcx, BD, &'mir DataflowResults<'tcx, BD>>; - -impl<'mir, 'tcx, BD, DR> DataflowResultsCursor<'mir, 'tcx, BD, DR> -where - BD: BitDenotation<'tcx>, - DR: Borrow>, -{ - pub fn new(result: DR, body: &'mir Body<'tcx>) -> Self { - DataflowResultsCursor { flow_state: FlowAtLocation::new(result), curr_loc: None, body } - } - - /// Seek to the given location in MIR. This method is fast if you are - /// traversing your MIR statements in order. - /// - /// After calling `seek`, the current state will reflect all effects up to - /// and including the `before_statement_effect` of the statement at location - /// `loc`. The `statement_effect` of the statement at `loc` will be - /// available as the current effect (see e.g. `each_gen_bit`). - /// - /// If `loc.statement_index` equals the number of statements in the block, - /// we will reconstruct the terminator effect in the same way as described - /// above. - pub fn seek(&mut self, loc: Location) { - if self.curr_loc.map(|cur| loc == cur).unwrap_or(false) { - return; - } - - let start_index; - let should_reset = match self.curr_loc { - None => true, - Some(cur) if loc.block != cur.block || loc.statement_index < cur.statement_index => { - true - } - _ => false, - }; - if should_reset { - self.flow_state.reset_to_entry_of(loc.block); - start_index = 0; - } else { - let curr_loc = self.curr_loc.unwrap(); - start_index = curr_loc.statement_index; - // Apply the effect from the last seek to the current state. - self.flow_state.apply_local_effect(curr_loc); - } - - for stmt in start_index..loc.statement_index { - let mut stmt_loc = loc; - stmt_loc.statement_index = stmt; - self.flow_state.reconstruct_statement_effect(stmt_loc); - self.flow_state.apply_local_effect(stmt_loc); - } - - if loc.statement_index == self.body[loc.block].statements.len() { - self.flow_state.reconstruct_terminator_effect(loc); - } else { - self.flow_state.reconstruct_statement_effect(loc); - } - self.curr_loc = Some(loc); - } - - /// Return whether the current state contains bit `x`. - pub fn contains(&self, x: BD::Idx) -> bool { - self.flow_state.contains(x) - } - - /// Iterate over each `gen` bit in the current effect (invoke `seek` first). - pub fn each_gen_bit(&self, f: F) - where - F: FnMut(BD::Idx), - { - self.flow_state.each_gen_bit(f) - } - - pub fn get(&self) -> &BitSet { - self.flow_state.as_dense() - } -} - -pub struct DataflowAnalysis<'a, 'tcx, O> -where - O: BitDenotation<'tcx>, -{ - flow_state: DataflowState<'tcx, O>, - dead_unwinds: &'a BitSet, - body: &'a Body<'tcx>, -} - -impl<'a, 'tcx, O> DataflowAnalysis<'a, 'tcx, O> -where - O: BitDenotation<'tcx>, -{ - pub fn results(self) -> DataflowResults<'tcx, O> { - DataflowResults(self.flow_state) - } - - pub fn body(&self) -> &'a Body<'tcx> { - self.body - } -} - -pub struct DataflowResults<'tcx, O>(pub(crate) DataflowState<'tcx, O>) -where - O: BitDenotation<'tcx>; - -impl<'tcx, O: BitDenotation<'tcx>> DataflowResults<'tcx, O> { - pub fn sets(&self) -> &AllSets { - &self.0.sets - } - - pub fn operator(&self) -> &O { - &self.0.operator - } -} - -/// State of a dataflow analysis; couples a collection of bit sets -/// with operator used to initialize and merge bits during analysis. -pub struct DataflowState<'tcx, O: BitDenotation<'tcx>> { - /// All the sets for the analysis. (Factored into its - /// own structure so that we can borrow it mutably - /// on its own separate from other fields.) - pub sets: AllSets, - - /// operator used to initialize, combine, and interpret bits. - pub(crate) operator: O, -} - -impl<'tcx, O: BitDenotation<'tcx>> DataflowState<'tcx, O> { - pub(crate) fn interpret_set<'c, P>( - &self, - o: &'c O, - set: &BitSet, - render_idx: &P, - ) -> Vec - where - P: Fn(&O, O::Idx) -> DebugFormatted, - { - set.iter().map(|i| render_idx(o, i)).collect() - } - - pub(crate) fn interpret_hybrid_set<'c, P>( - &self, - o: &'c O, - set: &HybridBitSet, - render_idx: &P, - ) -> Vec - where - P: Fn(&O, O::Idx) -> DebugFormatted, - { - set.iter().map(|i| render_idx(o, i)).collect() - } -} - -/// A 2-tuple representing the "gen" and "kill" bitsets during -/// dataflow analysis. -/// -/// It is best to ensure that the intersection of `gen_set` and -/// `kill_set` is empty; otherwise the results of the dataflow will -/// have a hidden dependency on what order the bits are generated and -/// killed during the iteration. (This is such a good idea that the -/// `fn gen` and `fn kill` methods that set their state enforce this -/// for you.) -#[derive(Debug, Clone, Copy)] -pub struct GenKill { - pub(crate) gen_set: T, - pub(crate) kill_set: T, -} - -pub type GenKillSet = GenKill>; - -impl GenKill { - /// Creates a new tuple where `gen_set == kill_set == elem`. - pub(crate) fn from_elem(elem: T) -> Self - where - T: Clone, - { - GenKill { gen_set: elem.clone(), kill_set: elem } - } -} - -impl GenKillSet { - pub fn clear(&mut self) { - self.gen_set.clear(); - self.kill_set.clear(); - } - - pub fn gen(&mut self, e: E) { - self.gen_set.insert(e); - self.kill_set.remove(e); - } - - pub fn gen_all(&mut self, i: impl IntoIterator>) { - for j in i { - self.gen(*j.borrow()); - } - } - - pub fn kill(&mut self, e: E) { - self.gen_set.remove(e); - self.kill_set.insert(e); - } - - pub fn kill_all(&mut self, i: impl IntoIterator>) { - for j in i { - self.kill(*j.borrow()); - } - } - - /// Computes `(set ∪ gen) - kill` and assigns the result to `set`. - pub(crate) fn apply(&self, set: &mut BitSet) { - set.union(&self.gen_set); - set.subtract(&self.kill_set); - } -} - -#[derive(Debug)] -pub struct AllSets { - /// Analysis bitwidth for each block. - bits_per_block: usize, - - /// For each block, bits valid on entry to the block. - on_entry: Vec>, - - /// The transfer function of each block expressed as the set of bits - /// generated and killed by executing the statements + terminator in the - /// block -- with one caveat. In particular, for *call terminators*, the - /// effect of storing the destination is not included, since that only takes - /// effect on the **success** edge (and not the unwind edge). - trans: Vec>, -} - -impl AllSets { - pub fn bits_per_block(&self) -> usize { - self.bits_per_block - } - - pub fn get_mut(&mut self, block_idx: usize) -> (&mut BitSet, &mut GenKillSet) { - (&mut self.on_entry[block_idx], &mut self.trans[block_idx]) - } - - pub fn trans_for(&self, block_idx: usize) -> &GenKillSet { - &self.trans[block_idx] - } - pub fn trans_mut_for(&mut self, block_idx: usize) -> &mut GenKillSet { - &mut self.trans[block_idx] - } - pub fn entry_set_for(&self, block_idx: usize) -> &BitSet { - &self.on_entry[block_idx] - } - pub fn entry_set_mut_for(&mut self, block_idx: usize) -> &mut BitSet { - &mut self.on_entry[block_idx] - } - pub fn gen_set_for(&self, block_idx: usize) -> &HybridBitSet { - &self.trans_for(block_idx).gen_set - } - pub fn kill_set_for(&self, block_idx: usize) -> &HybridBitSet { - &self.trans_for(block_idx).kill_set - } -} - /// Parameterization for the precise form of data flow that is used. /// /// `BottomValue` determines whether the initial entry set for each basic block is empty or full. @@ -689,246 +86,3 @@ pub trait BottomValue { if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) } } } - -/// A specific flavor of dataflow analysis. -/// -/// To run a dataflow analysis, one sets up an initial state for the -/// `START_BLOCK` via `start_block_effect` and a transfer function (`trans`) -/// for each block individually. The entry set for all other basic blocks is -/// initialized to `Self::BOTTOM_VALUE`. The dataflow analysis then -/// iteratively modifies the various entry sets (but leaves the the transfer -/// function unchanged). `BottomValue::join` is used to merge the bitsets from -/// two blocks (e.g. when two blocks' terminator jumps to a single block, that -/// target block's state is the merged state of both incoming blocks). -pub trait BitDenotation<'tcx>: BottomValue { - /// Specifies what index type is used to access the bitvector. - type Idx: Idx; - - /// A name describing the dataflow analysis that this - /// `BitDenotation` is supporting. The name should be something - /// suitable for plugging in as part of a filename (i.e., avoid - /// space-characters or other things that tend to look bad on a - /// file system, like slashes or periods). It is also better for - /// the name to be reasonably short, again because it will be - /// plugged into a filename. - fn name() -> &'static str; - - /// Size of each bitvector allocated for each block in the analysis. - fn bits_per_block(&self) -> usize; - - /// Mutates the entry set according to the effects that - /// have been established *prior* to entering the start - /// block. This can't access the gen/kill sets, because - /// these won't be accounted for correctly. - /// - /// (For example, establishing the call arguments.) - fn start_block_effect(&self, entry_set: &mut BitSet); - - /// Similar to `statement_effect`, except it applies - /// *just before* the statement rather than *just after* it. - /// - /// This matters for "dataflow at location" APIs, because the - /// before-statement effect is visible while visiting the - /// statement, while the after-statement effect only becomes - /// visible at the next statement. - /// - /// Both the before-statement and after-statement effects are - /// applied, in that order, before moving for the next - /// statement. - fn before_statement_effect(&self, _trans: &mut GenKillSet, _location: Location) {} - - /// Mutates the block-sets (the flow sets for the given - /// basic block) according to the effects of evaluating statement. - /// - /// This is used, in particular, for building up the - /// "transfer-function" representing the overall-effect of the - /// block, represented via GEN and KILL sets. - /// - /// The statement is identified as `bb_data[idx_stmt]`, where - /// `bb_data` is the sequence of statements identified by `bb` in - /// the MIR. - fn statement_effect(&self, trans: &mut GenKillSet, location: Location); - - /// Similar to `terminator_effect`, except it applies - /// *just before* the terminator rather than *just after* it. - /// - /// This matters for "dataflow at location" APIs, because the - /// before-terminator effect is visible while visiting the - /// terminator, while the after-terminator effect only becomes - /// visible at the terminator's successors. - /// - /// Both the before-terminator and after-terminator effects are - /// applied, in that order, before moving for the next - /// terminator. - fn before_terminator_effect(&self, _trans: &mut GenKillSet, _location: Location) {} - - /// Mutates the block-sets (the flow sets for the given - /// basic block) according to the effects of evaluating - /// the terminator. - /// - /// This is used, in particular, for building up the - /// "transfer-function" representing the overall-effect of the - /// block, represented via GEN and KILL sets. - /// - /// The effects applied here cannot depend on which branch the - /// terminator took. - fn terminator_effect(&self, trans: &mut GenKillSet, location: Location); - - /// Mutates the block-sets according to the (flow-dependent) - /// effect of a successful return from a Call terminator. - /// - /// If basic-block BB_x ends with a call-instruction that, upon - /// successful return, flows to BB_y, then this method will be - /// called on the exit flow-state of BB_x in order to set up the - /// entry flow-state of BB_y. - /// - /// This is used, in particular, as a special case during the - /// "propagate" loop where all of the basic blocks are repeatedly - /// visited. Since the effects of a Call terminator are - /// flow-dependent, the current MIR cannot encode them via just - /// GEN and KILL sets attached to the block, and so instead we add - /// this extra machinery to represent the flow-dependent effect. - // - // FIXME: right now this is a bit of a wart in the API. It might - // be better to represent this as an additional gen- and - // kill-sets associated with each edge coming out of the basic - // block. - fn propagate_call_return( - &self, - in_out: &mut BitSet, - call_bb: mir::BasicBlock, - dest_bb: mir::BasicBlock, - dest_place: &mir::Place<'tcx>, - ); -} - -impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> -where - D: BitDenotation<'tcx>, -{ - pub fn new( - body: &'a Body<'tcx>, - dead_unwinds: &'a BitSet, - denotation: D, - ) -> Self { - let bits_per_block = denotation.bits_per_block(); - let num_blocks = body.basic_blocks().len(); - - let on_entry = if D::BOTTOM_VALUE { - vec![BitSet::new_filled(bits_per_block); num_blocks] - } else { - vec![BitSet::new_empty(bits_per_block); num_blocks] - }; - let nop = GenKill::from_elem(HybridBitSet::new_empty(bits_per_block)); - - DataflowAnalysis { - body, - dead_unwinds, - flow_state: DataflowState { - sets: AllSets { bits_per_block, on_entry, trans: vec![nop; num_blocks] }, - operator: denotation, - }, - } - } -} - -impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> -where - D: BitDenotation<'tcx>, -{ - /// Propagates the bits of `in_out` into all the successors of `bb`, - /// using bitwise operator denoted by `self.operator`. - /// - /// For most blocks, this is entirely uniform. However, for blocks - /// that end with a call terminator, the effect of the call on the - /// dataflow state may depend on whether the call returned - /// successfully or unwound. - /// - /// To reflect this, the `propagate_call_return` method of the - /// `BitDenotation` mutates `in_out` when propagating `in_out` via - /// a call terminator; such mutation is performed *last*, to - /// ensure its side-effects do not leak elsewhere (e.g., into - /// unwind target). - fn propagate_bits_into_graph_successors_of( - &mut self, - in_out: &mut BitSet, - (bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData<'tcx>), - dirty_list: &mut WorkQueue, - ) { - match bb_data.terminator().kind { - mir::TerminatorKind::Return - | mir::TerminatorKind::Resume - | mir::TerminatorKind::Abort - | mir::TerminatorKind::GeneratorDrop - | mir::TerminatorKind::Unreachable => {} - mir::TerminatorKind::Goto { target } - | mir::TerminatorKind::Assert { target, cleanup: None, .. } - | mir::TerminatorKind::Yield { resume: target, drop: None, .. } - | mir::TerminatorKind::Drop { target, location: _, unwind: None } - | mir::TerminatorKind::DropAndReplace { target, value: _, location: _, unwind: None } => - { - self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); - } - mir::TerminatorKind::Yield { resume: target, drop: Some(drop), .. } => { - self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); - self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list); - } - mir::TerminatorKind::Assert { target, cleanup: Some(unwind), .. } - | mir::TerminatorKind::Drop { target, location: _, unwind: Some(unwind) } - | mir::TerminatorKind::DropAndReplace { - target, - value: _, - location: _, - unwind: Some(unwind), - } => { - self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); - if !self.dead_unwinds.contains(bb) { - self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); - } - } - mir::TerminatorKind::SwitchInt { ref targets, .. } => { - for target in targets { - self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list); - } - } - mir::TerminatorKind::Call { cleanup, ref destination, .. } => { - if let Some(unwind) = cleanup { - if !self.dead_unwinds.contains(bb) { - self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); - } - } - if let Some((ref dest_place, dest_bb)) = *destination { - // N.B.: This must be done *last*, after all other - // propagation, as documented in comment above. - self.flow_state.operator.propagate_call_return(in_out, bb, dest_bb, dest_place); - self.propagate_bits_into_entry_set_for(in_out, dest_bb, dirty_list); - } - } - mir::TerminatorKind::FalseEdges { real_target, imaginary_target } => { - self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list); - self.propagate_bits_into_entry_set_for(in_out, imaginary_target, dirty_list); - } - mir::TerminatorKind::FalseUnwind { real_target, unwind } => { - self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list); - if let Some(unwind) = unwind { - if !self.dead_unwinds.contains(bb) { - self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list); - } - } - } - } - } - - fn propagate_bits_into_entry_set_for( - &mut self, - in_out: &BitSet, - bb: mir::BasicBlock, - dirty_queue: &mut WorkQueue, - ) { - let entry_set = self.flow_state.sets.entry_set_mut_for(bb.index()); - let set_changed = self.flow_state.operator.join(entry_set, &in_out); - if set_changed { - dirty_queue.insert(bb); - } - } -} From 9978afb5d6e851d8cc37e657daf68b3902af93b5 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 28 Feb 2020 21:47:36 -0800 Subject: [PATCH 17/23] Move `MoveDataParamEnv` to beginning of module --- src/librustc_mir/dataflow/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index b7189f60984ea..2c64108d7c20c 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -26,6 +26,11 @@ pub(crate) mod indexes { }; } +pub struct MoveDataParamEnv<'tcx> { + pub(crate) move_data: MoveData<'tcx>, + pub(crate) param_env: ty::ParamEnv<'tcx>, +} + pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option { for attr in attrs { if attr.check_name(sym::rustc_mir) { @@ -41,11 +46,6 @@ pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Opti None } -pub struct MoveDataParamEnv<'tcx> { - pub(crate) move_data: MoveData<'tcx>, - pub(crate) param_env: ty::ParamEnv<'tcx>, -} - /// Parameterization for the precise form of data flow that is used. /// /// `BottomValue` determines whether the initial entry set for each basic block is empty or full. From bae1114e750f93741e8881a49d30594759684144 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 28 Feb 2020 21:49:33 -0800 Subject: [PATCH 18/23] Rename `dataflow::generic` to `dataflow::framework` --- src/librustc_mir/dataflow/{generic => framework}/cursor.rs | 0 src/librustc_mir/dataflow/{generic => framework}/engine.rs | 0 src/librustc_mir/dataflow/{generic => framework}/graphviz.rs | 0 src/librustc_mir/dataflow/{generic => framework}/mod.rs | 0 src/librustc_mir/dataflow/{generic => framework}/tests.rs | 0 src/librustc_mir/dataflow/{generic => framework}/visitor.rs | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/librustc_mir/dataflow/{generic => framework}/cursor.rs (100%) rename src/librustc_mir/dataflow/{generic => framework}/engine.rs (100%) rename src/librustc_mir/dataflow/{generic => framework}/graphviz.rs (100%) rename src/librustc_mir/dataflow/{generic => framework}/mod.rs (100%) rename src/librustc_mir/dataflow/{generic => framework}/tests.rs (100%) rename src/librustc_mir/dataflow/{generic => framework}/visitor.rs (100%) diff --git a/src/librustc_mir/dataflow/generic/cursor.rs b/src/librustc_mir/dataflow/framework/cursor.rs similarity index 100% rename from src/librustc_mir/dataflow/generic/cursor.rs rename to src/librustc_mir/dataflow/framework/cursor.rs diff --git a/src/librustc_mir/dataflow/generic/engine.rs b/src/librustc_mir/dataflow/framework/engine.rs similarity index 100% rename from src/librustc_mir/dataflow/generic/engine.rs rename to src/librustc_mir/dataflow/framework/engine.rs diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/framework/graphviz.rs similarity index 100% rename from src/librustc_mir/dataflow/generic/graphviz.rs rename to src/librustc_mir/dataflow/framework/graphviz.rs diff --git a/src/librustc_mir/dataflow/generic/mod.rs b/src/librustc_mir/dataflow/framework/mod.rs similarity index 100% rename from src/librustc_mir/dataflow/generic/mod.rs rename to src/librustc_mir/dataflow/framework/mod.rs diff --git a/src/librustc_mir/dataflow/generic/tests.rs b/src/librustc_mir/dataflow/framework/tests.rs similarity index 100% rename from src/librustc_mir/dataflow/generic/tests.rs rename to src/librustc_mir/dataflow/framework/tests.rs diff --git a/src/librustc_mir/dataflow/generic/visitor.rs b/src/librustc_mir/dataflow/framework/visitor.rs similarity index 100% rename from src/librustc_mir/dataflow/generic/visitor.rs rename to src/librustc_mir/dataflow/framework/visitor.rs From 93ce5ff5874c1a6b31bef120ffa4a8824e3d9216 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 28 Feb 2020 21:55:41 -0800 Subject: [PATCH 19/23] Update use statements in `dataflow/mod.rs` --- src/librustc_mir/dataflow/mod.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 2c64108d7c20c..737183f8dc330 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -5,17 +5,20 @@ use rustc_index::vec::Idx; use rustc_span::symbol::{sym, Symbol}; pub(crate) use self::drop_flag_effects::*; -pub use self::impls::borrows::Borrows; -pub use self::impls::DefinitelyInitializedPlaces; -pub use self::impls::EverInitializedPlaces; -pub use self::impls::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; -pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; -pub use self::impls::{MaybeRequiresStorage, MaybeStorageLive}; +pub use self::framework::{ + visit_results, Analysis, AnalysisDomain, BorrowckFlowState, BorrowckResults, Engine, GenKill, + GenKillAnalysis, Results, ResultsCursor, ResultsRefCursor, ResultsVisitor, +}; +pub use self::impls::{ + borrows::Borrows, DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeBorrowedLocals, + MaybeInitializedPlaces, MaybeMutBorrowedLocals, MaybeRequiresStorage, MaybeStorageLive, + MaybeUninitializedPlaces, +}; use self::move_paths::MoveData; pub mod drop_flag_effects; -pub mod generic; +pub mod framework; mod impls; pub mod move_paths; From a8cc89f97566521cd54ea424eea09099b2531b03 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 28 Feb 2020 22:02:20 -0800 Subject: [PATCH 20/23] Update imports from `dataflow::generic` to `dataflow` --- src/librustc_mir/borrow_check/mod.rs | 6 +++--- src/librustc_mir/borrow_check/nll.rs | 2 +- src/librustc_mir/borrow_check/type_check/liveness/mod.rs | 2 +- src/librustc_mir/borrow_check/type_check/liveness/trace.rs | 2 +- src/librustc_mir/borrow_check/type_check/mod.rs | 2 +- src/librustc_mir/dataflow/impls/borrowed_locals.rs | 2 +- src/librustc_mir/dataflow/impls/borrows.rs | 6 +++--- src/librustc_mir/dataflow/impls/mod.rs | 3 +-- src/librustc_mir/dataflow/impls/storage_liveness.rs | 2 +- src/librustc_mir/transform/check_consts/resolver.rs | 4 ++-- src/librustc_mir/transform/check_consts/validation.rs | 2 +- src/librustc_mir/transform/elaborate_drops.rs | 2 +- src/librustc_mir/transform/generator.rs | 2 +- src/librustc_mir/transform/rustc_peek.rs | 2 +- 14 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 6c1901455fda9..882c6bd0333ee 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -29,12 +29,12 @@ use std::mem; use std::rc::Rc; use crate::dataflow; -use crate::dataflow::generic::{Analysis, BorrowckFlowState as Flows, BorrowckResults}; use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex}; use crate::dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveError}; use crate::dataflow::Borrows; use crate::dataflow::EverInitializedPlaces; use crate::dataflow::MoveDataParamEnv; +use crate::dataflow::{Analysis, BorrowckFlowState as Flows, BorrowckResults}; use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use crate::transform::MirSource; @@ -298,7 +298,7 @@ fn do_mir_borrowck<'a, 'tcx>( mbcx.report_move_errors(errors); } - dataflow::generic::visit_results( + dataflow::visit_results( &*body, traversal::reverse_postorder(&*body).map(|(bb, _)| bb), &results, @@ -509,7 +509,7 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { // 2. loans made in overlapping scopes do not conflict // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -impl<'cx, 'tcx> dataflow::generic::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> { +impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> { type FlowState = Flows<'cx, 'tcx>; fn visit_statement( diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 077ed49ed2cac..8e929a4fa22f4 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -21,9 +21,9 @@ use std::str::FromStr; use self::mir_util::PassWhere; use polonius_engine::{Algorithm, Output}; -use crate::dataflow::generic::ResultsCursor; use crate::dataflow::move_paths::{InitKind, InitLocation, MoveData}; use crate::dataflow::MaybeInitializedPlaces; +use crate::dataflow::ResultsCursor; use crate::transform::MirSource; use crate::util as mir_util; use crate::util::pretty; diff --git a/src/librustc_mir/borrow_check/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs index cdf962ee31a6e..a55529ed0ef12 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs @@ -3,9 +3,9 @@ use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use std::rc::Rc; -use crate::dataflow::generic::ResultsCursor; use crate::dataflow::move_paths::MoveData; use crate::dataflow::MaybeInitializedPlaces; +use crate::dataflow::ResultsCursor; use crate::borrow_check::{ constraints::OutlivesConstraintSet, diff --git a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs index 0c49ee44f9a50..75b269c79b96e 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs @@ -8,10 +8,10 @@ use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::TypeOp; use std::rc::Rc; -use crate::dataflow::generic::ResultsCursor; use crate::dataflow::indexes::MovePathIndex; use crate::dataflow::move_paths::{HasMoveData, MoveData}; use crate::dataflow::MaybeInitializedPlaces; +use crate::dataflow::ResultsCursor; use crate::borrow_check::{ region_infer::values::{self, PointIndex, RegionValueElements}, diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index f94160cc08a19..02f6bcade23a2 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -39,9 +39,9 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}; -use crate::dataflow::generic::ResultsCursor; use crate::dataflow::move_paths::MoveData; use crate::dataflow::MaybeInitializedPlaces; +use crate::dataflow::ResultsCursor; use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute; use crate::borrow_check::{ diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index 95a676c0892c5..955021d83aa09 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -1,6 +1,6 @@ pub use super::*; -use crate::dataflow::generic::{AnalysisDomain, GenKill, GenKillAnalysis}; +use crate::dataflow::{AnalysisDomain, GenKill, GenKillAnalysis}; use rustc::mir::visit::Visitor; use rustc::mir::*; use rustc::ty::{ParamEnv, TyCtxt}; diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index a7c0efd63b1a8..9e9e414ad648b 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -8,8 +8,8 @@ use rustc_index::bit_set::BitSet; use crate::borrow_check::{ places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, }; -use crate::dataflow::generic::{self, GenKill}; use crate::dataflow::BottomValue; +use crate::dataflow::{self, GenKill}; use std::rc::Rc; @@ -226,7 +226,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } } -impl<'tcx> generic::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { +impl<'tcx> dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { type Idx = BorrowIndex; const NAME: &'static str = "borrows"; @@ -245,7 +245,7 @@ impl<'tcx> generic::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { } } -impl<'tcx> generic::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { +impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { fn before_statement_effect( &self, trans: &mut impl GenKill, diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 87d8e9e411c6f..180094e412b15 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -12,9 +12,8 @@ use super::MoveDataParamEnv; use crate::util::elaborate_drops::DropFlagState; -use super::generic::{AnalysisDomain, GenKill, GenKillAnalysis}; use super::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; -use super::BottomValue; +use super::{AnalysisDomain, BottomValue, GenKill, GenKillAnalysis}; use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_location; diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 5341d661b1db6..f8d1efabd33c0 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -1,7 +1,7 @@ pub use super::*; -use crate::dataflow::generic::{self as dataflow, GenKill, Results, ResultsRefCursor}; use crate::dataflow::BottomValue; +use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; use rustc::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc::mir::*; use std::cell::RefCell; diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index e42f64b5c7384..5f761ce344880 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -9,7 +9,7 @@ use rustc_index::bit_set::BitSet; use std::marker::PhantomData; use super::{qualifs, Item, Qualif}; -use crate::dataflow::{self as old_dataflow, generic as dataflow}; +use crate::dataflow; /// A `Visitor` that propagates qualifs between locals. This defines the transfer function of /// `FlowSensitiveAnalysis`. @@ -165,7 +165,7 @@ where } } -impl old_dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> { +impl dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> { const BOTTOM_VALUE: bool = false; } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index be461c0e03d86..7f4714e9f9c19 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -22,8 +22,8 @@ use super::qualifs::{self, HasMutInterior, NeedsDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, ConstKind, Item, Qualif}; use crate::const_eval::{is_const_fn, is_unstable_const_fn}; -use crate::dataflow::generic::{self as dataflow, Analysis}; use crate::dataflow::MaybeMutBorrowedLocals; +use crate::dataflow::{self, Analysis}; // We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated // through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals` diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 5d02074aaaa6b..4ec4ef0206105 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -1,9 +1,9 @@ use crate::dataflow; -use crate::dataflow::generic::{Analysis, ResultsCursor}; use crate::dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use crate::dataflow::on_lookup_result_bits; use crate::dataflow::MoveDataParamEnv; use crate::dataflow::{on_all_children_bits, on_all_drop_children_bits}; +use crate::dataflow::{Analysis, ResultsCursor}; use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use crate::transform::{MirPass, MirSource}; use crate::util::elaborate_drops::{elaborate_drop, DropFlagState, Unwind}; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 349cda831053f..1945efb6bf7cc 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -49,7 +49,7 @@ //! For generators with state 1 (returned) and state 2 (poisoned) it does nothing. //! Otherwise it drops all the values in scope at the last suspension point. -use crate::dataflow::generic::{self as dataflow, Analysis}; +use crate::dataflow::{self, Analysis}; use crate::dataflow::{MaybeBorrowedLocals, MaybeRequiresStorage, MaybeStorageLive}; use crate::transform::no_landing_pads::no_landing_pads; use crate::transform::simplify; diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 22ac3410a75ab..c9a00166f0f9c 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -9,11 +9,11 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; -use crate::dataflow::generic::{Analysis, Results, ResultsCursor}; use crate::dataflow::move_paths::{HasMoveData, MoveData}; use crate::dataflow::move_paths::{LookupResult, MovePathIndex}; use crate::dataflow::MaybeMutBorrowedLocals; use crate::dataflow::MoveDataParamEnv; +use crate::dataflow::{Analysis, Results, ResultsCursor}; use crate::dataflow::{ DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, }; From 7108cea14ee1517898cbfcb71f59706f30a4cf18 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 2 Mar 2020 09:32:12 -0800 Subject: [PATCH 21/23] Move `BottomValue` into `framework/mod.rs` --- src/librustc_mir/dataflow/framework/mod.rs | 43 +++++++++++++++++++- src/librustc_mir/dataflow/mod.rs | 47 +--------------------- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/librustc_mir/dataflow/framework/mod.rs b/src/librustc_mir/dataflow/framework/mod.rs index fb4b7b9c5be31..345fb665b32d6 100644 --- a/src/librustc_mir/dataflow/framework/mod.rs +++ b/src/librustc_mir/dataflow/framework/mod.rs @@ -41,8 +41,6 @@ use rustc_hir::def_id::DefId; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_index::vec::{Idx, IndexVec}; -use crate::dataflow::BottomValue; - mod cursor; mod engine; mod graphviz; @@ -95,6 +93,47 @@ where } } +/// Parameterization for the precise form of data flow that is used. +/// +/// `BottomValue` determines whether the initial entry set for each basic block is empty or full. +/// This also determines the semantics of the lattice `join` operator used to merge dataflow +/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed +/// point. +/// +/// This means, for propagation across the graph, that you either want to start at all-zeroes and +/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect +/// as your merge when propagating. +pub trait BottomValue { + /// Specifies the initial value for each bit in the entry set for each basic block. + const BOTTOM_VALUE: bool; + + /// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed. + /// + /// It is almost certainly wrong to override this, since it automatically applies + /// * `inout_set & in_set` if `BOTTOM_VALUE == true` + /// * `inout_set | in_set` if `BOTTOM_VALUE == false` + /// + /// This means that if a bit is not `BOTTOM_VALUE`, it is propagated into all target blocks. + /// For clarity, the above statement again from a different perspective: + /// A bit in the block's entry set is `!BOTTOM_VALUE` if *any* predecessor block's bit value is + /// `!BOTTOM_VALUE`. + /// + /// There are situations where you want the opposite behaviour: propagate only if *all* + /// predecessor blocks's value is `!BOTTOM_VALUE`. + /// E.g. if you want to know whether a bit is *definitely* set at a specific location. This + /// means that all code paths leading to the location must have set the bit, instead of any + /// code path leading there. + /// + /// If you want this kind of "definitely set" analysis, you need to + /// 1. Invert `BOTTOM_VALUE` + /// 2. Reset the `entry_set` in `start_block_effect` to `!BOTTOM_VALUE` + /// 3. Override `join` to do the opposite from what it's doing now. + #[inline] + fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { + if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) } + } +} + /// Define the domain of a dataflow problem. /// /// This trait specifies the lattice on which this analysis operates. For now, this must be a diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 737183f8dc330..d13dfb2698033 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -1,13 +1,11 @@ use rustc::ty; use rustc_ast::ast::{self, MetaItem}; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::Idx; use rustc_span::symbol::{sym, Symbol}; pub(crate) use self::drop_flag_effects::*; pub use self::framework::{ - visit_results, Analysis, AnalysisDomain, BorrowckFlowState, BorrowckResults, Engine, GenKill, - GenKillAnalysis, Results, ResultsCursor, ResultsRefCursor, ResultsVisitor, + visit_results, Analysis, AnalysisDomain, BorrowckFlowState, BorrowckResults, BottomValue, + Engine, GenKill, GenKillAnalysis, Results, ResultsCursor, ResultsRefCursor, ResultsVisitor, }; pub use self::impls::{ borrows::Borrows, DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeBorrowedLocals, @@ -48,44 +46,3 @@ pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Opti } None } - -/// Parameterization for the precise form of data flow that is used. -/// -/// `BottomValue` determines whether the initial entry set for each basic block is empty or full. -/// This also determines the semantics of the lattice `join` operator used to merge dataflow -/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed -/// point. -/// -/// This means, for propagation across the graph, that you either want to start at all-zeroes and -/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect -/// as your merge when propagating. -pub trait BottomValue { - /// Specifies the initial value for each bit in the entry set for each basic block. - const BOTTOM_VALUE: bool; - - /// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed. - /// - /// It is almost certainly wrong to override this, since it automatically applies - /// * `inout_set & in_set` if `BOTTOM_VALUE == true` - /// * `inout_set | in_set` if `BOTTOM_VALUE == false` - /// - /// This means that if a bit is not `BOTTOM_VALUE`, it is propagated into all target blocks. - /// For clarity, the above statement again from a different perspective: - /// A bit in the block's entry set is `!BOTTOM_VALUE` if *any* predecessor block's bit value is - /// `!BOTTOM_VALUE`. - /// - /// There are situations where you want the opposite behaviour: propagate only if *all* - /// predecessor blocks's value is `!BOTTOM_VALUE`. - /// E.g. if you want to know whether a bit is *definitely* set at a specific location. This - /// means that all code paths leading to the location must have set the bit, instead of any - /// code path leading there. - /// - /// If you want this kind of "definitely set" analysis, you need to - /// 1. Invert `BOTTOM_VALUE` - /// 2. Reset the `entry_set` in `start_block_effect` to `!BOTTOM_VALUE` - /// 3. Override `join` to do the opposite from what it's doing now. - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) } - } -} From fe0e7c3cba6c8742f4e29920f4e7a52f88284a42 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 2 Mar 2020 09:40:58 -0800 Subject: [PATCH 22/23] Update `framework` module docs --- src/librustc_mir/dataflow/framework/mod.rs | 32 ++++++++++------------ 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/dataflow/framework/mod.rs b/src/librustc_mir/dataflow/framework/mod.rs index 345fb665b32d6..8556be7e74062 100644 --- a/src/librustc_mir/dataflow/framework/mod.rs +++ b/src/librustc_mir/dataflow/framework/mod.rs @@ -1,26 +1,25 @@ //! A framework that can express both [gen-kill] and generic dataflow problems. //! -//! There is another interface for dataflow in the compiler in `librustc_mir/dataflow/mod.rs`. The -//! interface in this module will eventually [replace that one][design-meeting]. +//! To actually use this framework, you must implement either the `Analysis` or the +//! `GenKillAnalysis` trait. If your transfer function can be expressed with only gen/kill +//! operations, prefer `GenKillAnalysis` since it will run faster while iterating to fixpoint. The +//! `impls` module contains several examples of gen/kill dataflow analyses. //! -//! To actually use this framework, you must implement either the `Analysis` or the `GenKillAnalysis` -//! trait. If your transfer function can be expressed with only gen/kill operations, prefer -//! `GenKillAnalysis` since it will run faster while iterating to fixpoint. Create an `Engine` using -//! the appropriate constructor and call `iterate_to_fixpoint`. You can use a `ResultsCursor` to -//! inspect the fixpoint solution to your dataflow problem. +//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait, +//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the +//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use +//! `visit_results`. The following example uses the `ResultsCursor` approach. //! //! ```ignore(cross-crate-imports) -//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, did: DefId) { -//! let analysis = MyAnalysis::new(); -//! -//! // If `MyAnalysis` implements `GenKillAnalysis`. -//! let results = Engine::new_gen_kill(tcx, body, did, analysis).iterate_to_fixpoint(); +//! use rustc_mir::dataflow::Analysis; // Makes `into_engine` available. //! -//! // If `MyAnalysis` implements `Analysis`. -//! // let results = Engine::new_generic(tcx, body, did, analysis).iterate_to_fixpoint(); -//! -//! let mut cursor = ResultsCursor::new(body, results); +//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, did: DefId) { +//! let analysis = MyAnalysis::new() +//! .into_engine(tcx, body, did) +//! .iterate_to_fixpoint() +//! .into_results_cursor(body); //! +//! // Print the dataflow state *after* each statement in the start block. //! for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() { //! cursor.seek_after(Location { block: START_BLOCK, statement_index }); //! let state = cursor.get(); @@ -30,7 +29,6 @@ //! ``` //! //! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems -//! [design-meeting]https://github.com/rust-lang/compiler-team/issues/202 use std::io; From 89d6009461918a5939520fe5424ee499ed6d504d Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 2 Mar 2020 09:43:18 -0800 Subject: [PATCH 23/23] Make `framework` a private module --- src/librustc_mir/dataflow/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index d13dfb2698033..96e5b6936a191 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -16,7 +16,7 @@ pub use self::impls::{ use self::move_paths::MoveData; pub mod drop_flag_effects; -pub mod framework; +mod framework; mod impls; pub mod move_paths;