From 768e7078785dd418968f26d79b1ff323403999ef Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:08:52 -0400 Subject: [PATCH 01/18] kill the `CheckLoops` DepNode --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc_passes/loops.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 5aea2bcaa4f5c..5142fd3c028db 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -60,7 +60,6 @@ pub enum DepNode { CheckStaticRecursion, ResolveLifetimes, RegionResolveCrate, - CheckLoops, PluginRegistrar, StabilityIndex, CollectItem(D), @@ -219,7 +218,6 @@ impl DepNode { CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), RegionResolveCrate => Some(RegionResolveCrate), - CheckLoops => Some(CheckLoops), PluginRegistrar => Some(PluginRegistrar), StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 421181c68c4cd..2ea235af10378 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -11,7 +11,6 @@ use self::Context::*; use rustc::session::Session; -use rustc::dep_graph::DepNode; use rustc::hir::map::Map; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir; @@ -50,7 +49,6 @@ struct CheckLoopVisitor<'a, 'hir: 'a> { } pub fn check_crate(sess: &Session, map: &Map) { - let _task = map.dep_graph.in_task(DepNode::CheckLoops); let krate = map.krate(); krate.visit_all_item_likes(&mut CheckLoopVisitor { sess: sess, From f3b876c4b2dec93ead8ebdcbf5eb5a0be4fa46a0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:09:12 -0400 Subject: [PATCH 02/18] kill `CheckStaticRecursion` --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc_passes/static_recursion.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 5142fd3c028db..0521b50df4d2d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -57,7 +57,6 @@ pub enum DepNode { // Represents different phases in the compiler. CollectLanguageItems, - CheckStaticRecursion, ResolveLifetimes, RegionResolveCrate, PluginRegistrar, @@ -215,7 +214,6 @@ impl DepNode { MirKrate => Some(MirKrate), TypeckBodiesKrate => Some(TypeckBodiesKrate), CollectLanguageItems => Some(CollectLanguageItems), - CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), RegionResolveCrate => Some(RegionResolveCrate), PluginRegistrar => Some(PluginRegistrar), diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index fc05471ead30b..d0bf49b7b337d 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -11,7 +11,6 @@ // This compiler pass detects constants that refer to themselves // recursively. -use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::session::{CompileResult, Session}; use rustc::hir::def::{Def, CtorKind}; @@ -88,8 +87,6 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> { } pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) -> CompileResult { - let _task = hir_map.dep_graph.in_task(DepNode::CheckStaticRecursion); - let mut visitor = CheckCrateVisitor { sess: sess, hir_map: hir_map, From a83734dd96e303f484972dba9b446b3dda478f2e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:19:36 -0400 Subject: [PATCH 03/18] remove `EffectCheck` --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc/middle/effect.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 0521b50df4d2d..b3878819378f7 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -64,7 +64,6 @@ pub enum DepNode { CollectItem(D), CollectItemSig(D), Coherence, - EffectCheck, Liveness, Resolve, EntryPoint, @@ -219,7 +218,6 @@ impl DepNode { PluginRegistrar => Some(PluginRegistrar), StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), - EffectCheck => Some(EffectCheck), Liveness => Some(Liveness), Resolve => Some(Resolve), EntryPoint => Some(EntryPoint), diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5af8e7e52d888..d2b8ed8c29707 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -12,7 +12,6 @@ //! `unsafe`. use self::RootUnsafeContext::*; -use dep_graph::DepNode; use ty::{self, Ty, TyCtxt}; use ty::MethodCall; use lint; @@ -241,8 +240,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::EffectCheck); - let mut visitor = EffectCheckVisitor { tcx: tcx, tables: &ty::TypeckTables::empty(), From a2a4fad6f787869bc3ae96e02082938e0a6dbef9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:28:48 -0400 Subject: [PATCH 04/18] kill `Liveness` --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc/middle/liveness.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index b3878819378f7..59d04ea8c771c 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -64,7 +64,6 @@ pub enum DepNode { CollectItem(D), CollectItemSig(D), Coherence, - Liveness, Resolve, EntryPoint, CheckEntryFn, @@ -218,7 +217,6 @@ impl DepNode { PluginRegistrar => Some(PluginRegistrar), StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), - Liveness => Some(Liveness), Resolve => Some(Resolve), EntryPoint => Some(EntryPoint), CheckEntryFn => Some(CheckEntryFn), diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 7cae08efc0de0..b7da8480c1cef 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -109,7 +109,6 @@ use self::LoopKind::*; use self::LiveNodeKind::*; use self::VarKind::*; -use dep_graph::DepNode; use hir::def::*; use ty::{self, TyCtxt, ParameterEnvironment}; use traits::{self, Reveal}; @@ -196,7 +195,6 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::Liveness); tcx.hir.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor()); tcx.sess.abort_if_errors(); } From a4d7c1fec361219d237f39b5e32c09c72ca69fac Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 12:06:35 -0400 Subject: [PATCH 05/18] push `borrowck` into its own task --- src/librustc/hir/map/mod.rs | 21 ++++++++++++++++++ src/librustc/ty/maps.rs | 2 ++ src/librustc_borrowck/borrowck/mod.rs | 32 +++++++++++++-------------- src/librustc_borrowck/lib.rs | 2 ++ src/librustc_driver/driver.rs | 1 + 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index d7aa36b24f942..cfafec00ae20d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -442,6 +442,27 @@ impl<'hir> Map<'hir> { self.local_def_id(self.body_owner(id)) } + /// Given a body owner's id, returns the `BodyId` associated with it. + pub fn body_owned_by(&self, id: NodeId) -> BodyId { + if let Some(entry) = self.find_entry(id) { + if let Some(body_id) = entry.associated_body() { + // For item-like things and closures, the associated + // body has its own distinct id, and that is returned + // by `associated_body`. + body_id + } else { + // For some expressions, the expression is its own body. + if let EntryExpr(_, expr) = entry { + BodyId { node_id: expr.id } + } else { + span_bug!(self.span(id), "id `{}` has no associated body", id); + } + } + } else { + bug!("no entry for id `{}`", id) + } + } + pub fn ty_param_owner(&self, id: NodeId) -> NodeId { match self.get(id) { NodeItem(&Item { node: ItemTrait(..), .. }) => id, diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4a183191cef29..219dbc4998e04 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -423,6 +423,8 @@ define_maps! { <'tcx> pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), + pub borrowck: BorrowCheck(DefId) -> (), + /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. /// (Defined only for LOCAL_CRATE) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0915c57b588eb..e0b4a23010d2f 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -22,7 +22,6 @@ pub use self::mir::elaborate_drops::ElaborateDrops; use self::InteriorKind::*; -use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; use rustc::cfg; @@ -37,12 +36,13 @@ use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::ImmutabilityBlame; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; +use rustc::ty::maps::Providers; use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; -use syntax_pos::{MultiSpan, Span}; +use syntax_pos::{DUMMY_SP, MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; @@ -62,16 +62,16 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task); - - fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { - tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| { - tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), - tcx, - body_id, - borrowck_fn); - }); - } + tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { + ty::queries::borrowck::get(tcx, DUMMY_SP, body_owner_def_id); + }); +} + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + borrowck: borrowck, + ..*providers + }; } /// Collection of conclusions determined via borrow checker analyses. @@ -81,11 +81,11 @@ pub struct AnalysisData<'a, 'tcx: 'a> { pub move_data: move_data::FlowedMoveData<'a, 'tcx>, } -fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { - debug!("borrowck_fn(body_id={:?})", body_id); +fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { + debug!("borrowck(body_owner_def_id={:?})", owner_def_id); - let owner_id = tcx.hir.body_owner(body_id); - let owner_def_id = tcx.hir.local_def_id(owner_id); + let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap(); + let body_id = tcx.hir.body_owned_by(owner_id); let attributes = tcx.get_attrs(owner_def_id); let tables = tcx.item_tables(owner_def_id); diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index d3b22884a3d8c..a1d3357faf566 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -51,4 +51,6 @@ mod borrowck; pub mod graphviz; +pub use borrowck::provide; + __build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 977382b33adf7..13486d898cff3 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -887,6 +887,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut local_providers = ty::maps::Providers::default(); mir::provide(&mut local_providers); rustc_privacy::provide(&mut local_providers); + borrowck::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); From 44e414c4770ff0800c375ddbb8e0f46ee00bcab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Apr 2017 09:50:04 -0700 Subject: [PATCH 06/18] Use proper span for tuple index parsed as float Fix diagnostic suggestion from: ```rust help: try parenthesizing the first index | (1, (2, 3)).((1, (2, 3)).1).1; ``` to the correct: ```rust help: try parenthesizing the first index | ((1, (2, 3)).1).1; ``` --- src/libsyntax/parse/parser.rs | 6 +++--- .../suggestions}/tuple-float-index.rs | 4 +--- src/test/ui/suggestions/tuple-float-index.stderr | 11 +++++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) rename src/test/{parse-fail => ui/suggestions}/tuple-float-index.rs (75%) create mode 100644 src/test/ui/suggestions/tuple-float-index.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855af..0d2c9b92ed759 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2498,10 +2498,10 @@ impl<'a> Parser<'a> { } token::Literal(token::Float(n), _suf) => { self.bump(); - let prev_span = self.prev_span; let fstr = n.as_str(); - let mut err = self.diagnostic().struct_span_err(prev_span, + let mut err = self.diagnostic().struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); + err.span_label(self.prev_span, &"unexpected token"); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::().ok() { Some(f) => f, @@ -2519,7 +2519,7 @@ impl<'a> Parser<'a> { word(&mut s.s, fstr.splitn(2, ".").last().unwrap()) }); err.span_suggestion( - prev_span, + lo.to(self.prev_span), "try parenthesizing the first index", sugg); } diff --git a/src/test/parse-fail/tuple-float-index.rs b/src/test/ui/suggestions/tuple-float-index.rs similarity index 75% rename from src/test/parse-fail/tuple-float-index.rs rename to src/test/ui/suggestions/tuple-float-index.rs index 57ad89ad37404..8bfbd0e74db22 100644 --- a/src/test/parse-fail/tuple-float-index.rs +++ b/src/test/ui/suggestions/tuple-float-index.rs @@ -11,7 +11,5 @@ // compile-flags: -Z parse-only fn main () { - (1, (2, 3)).1.1; //~ ERROR unexpected token - //~^ HELP try parenthesizing the first index - //~| SUGGESTION ((1, (2, 3)).1).1 + (1, (2, 3)).1.1; } diff --git a/src/test/ui/suggestions/tuple-float-index.stderr b/src/test/ui/suggestions/tuple-float-index.stderr new file mode 100644 index 0000000000000..abe04dc1aa210 --- /dev/null +++ b/src/test/ui/suggestions/tuple-float-index.stderr @@ -0,0 +1,11 @@ +error: unexpected token: `1.1` + --> $DIR/tuple-float-index.rs:14:17 + | +14 | (1, (2, 3)).1.1; + | ^^^ unexpected token + | +help: try parenthesizing the first index + | ((1, (2, 3)).1).1; + +error: aborting due to previous error + From d94f2c928c2c41dc0efd4122157e604788141b03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 8 Apr 2017 13:10:08 -0700 Subject: [PATCH 07/18] Update cargo submodules Brings in a fix for #40955 through rust-lang/cargo#3898. Closes #40955 --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index 4729175045b41..c416fb60b11ec 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 +Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 From 0303a3364b68e412539634617c734192760a7df4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 11 Apr 2017 01:04:33 +0300 Subject: [PATCH 08/18] Fix pairs of doubles using an illegal <8 x i8> vector. --- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/cabi_x86_64.rs | 17 +++++++++-------- .../extern-fn-struct-passing-abi/test.c | 19 +++++++++++++++++++ .../extern-fn-struct-passing-abi/test.rs | 11 +++++++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 7be80a757ca01..c4fdc46d030c9 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -283,7 +283,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> { Layout::Vector { .. } => { Some(Reg { - kind: RegKind::Integer, + kind: RegKind::Vector, size: self.size(ccx) }) } diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index cbe170d85834c..2daebf5cf3d6b 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -173,14 +173,15 @@ fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option { Class::Sse => { let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count(); *i += vec_len; - Some(match size { - 4 => Reg::f32(), - 8 => Reg::f64(), - _ => { - Reg { - kind: RegKind::Vector, - size: Size::from_bytes(vec_len as u64 * 8) - } + Some(if vec_len == 1 { + match size { + 4 => Reg::f32(), + _ => Reg::f64() + } + } else { + Reg { + kind: RegKind::Vector, + size: Size::from_bytes(vec_len as u64 * 8) } }) } diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c index 4253767ee76a9..4e09928edc6d1 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.c +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c @@ -38,6 +38,11 @@ struct Huge { int32_t e; }; +struct FloatPoint { + double x; + double y; +}; + // System V x86_64 ABI: // a, b, c, d, e should be in registers // s should be byval pointer @@ -258,3 +263,17 @@ struct Huge huge_struct(struct Huge s) { return s; } + +// System V x86_64 ABI: +// p should be in registers +// return should be in registers +// +// Win64 ABI: +// p should be a byval pointer +// return should be in a hidden sret pointer +struct FloatPoint float_point(struct FloatPoint p) { + assert(p.x == 5.); + assert(p.y == -3.); + + return p; +} diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs index b91362b8edccb..ff845a644b114 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.rs +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs @@ -46,6 +46,13 @@ struct Huge { e: i32 } +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +struct FloatPoint { + x: f64, + y: f64 +} + #[link(name = "test", kind = "static")] extern { fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect); @@ -72,6 +79,8 @@ extern { fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect; fn huge_struct(s: Huge) -> Huge; + + fn float_point(p: FloatPoint) -> FloatPoint; } fn main() { @@ -79,6 +88,7 @@ fn main() { let t = BiggerRect { s: s, a: 27834, b: 7657 }; let u = FloatRect { a: 3489, b: 3490, c: 8. }; let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 }; + let p = FloatPoint { x: 5., y: -3. }; unsafe { byval_rect(1, 2, 3, 4, 5, s); @@ -94,5 +104,6 @@ fn main() { assert_eq!(split_ret_byval_struct(1, 2, s), s); assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t); assert_eq!(sret_split_struct(1, 2, s), t); + assert_eq!(float_point(p), p); } } From 384ec80d2b3dd61a5f9910dc660bffea8710002e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 11 Apr 2017 23:52:51 +0300 Subject: [PATCH 09/18] store Spans for all MIR locals --- src/librustc/ich/impls_mir.rs | 3 +- src/librustc/mir/mod.rs | 40 +++++++++++-------- src/librustc/mir/visit.rs | 5 +-- .../borrowck/mir/elaborate_drops.rs | 6 +-- src/librustc_mir/build/expr/as_lvalue.rs | 3 +- src/librustc_mir/build/expr/as_rvalue.rs | 14 +++---- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 3 +- src/librustc_mir/build/matches/test.rs | 13 +++--- src/librustc_mir/build/misc.rs | 6 +-- src/librustc_mir/build/mod.rs | 12 ++++-- src/librustc_mir/shim.rs | 23 ++++++----- src/librustc_mir/transform/inline.rs | 15 +++---- src/librustc_mir/transform/promote_consts.rs | 6 ++- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/util/elaborate_drops.rs | 2 +- src/librustc_mir/util/patch.rs | 5 ++- src/librustc_mir/util/pretty.rs | 4 +- .../debuginfo/create_scope_map.rs | 2 +- src/librustc_trans/mir/mod.rs | 5 +-- 21 files changed, 96 insertions(+), 77 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 401f7e1921ab4..3ff8ffb35054a 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -22,7 +22,8 @@ impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); -impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info }); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info, +is_user_variable}); impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index aea4684e526ce..9ff64b295b765 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -197,10 +197,10 @@ impl<'tcx> Mir<'tcx> { pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].source_info.is_none() { - Some(local) - } else { + if self.local_decls[local].is_user_variable { None + } else { + Some(local) } }) } @@ -210,10 +210,10 @@ impl<'tcx> Mir<'tcx> { pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].source_info.is_none() { - None - } else { + if self.local_decls[local].is_user_variable { Some(local) + } else { + None } }) } @@ -370,6 +370,9 @@ pub struct LocalDecl<'tcx> { /// Temporaries and the return pointer are always mutable. pub mutability: Mutability, + /// True if this corresponds to a user-declared local variable. + pub is_user_variable: bool, + /// Type of this local. pub ty: Ty<'tcx>, @@ -379,24 +382,23 @@ pub struct LocalDecl<'tcx> { /// to generate better debuginfo. pub name: Option, - /// For user-declared variables, stores their source information. - /// - /// For temporaries, this is `None`. - /// - /// This is the primary way to differentiate between user-declared - /// variables and compiler-generated temporaries. - pub source_info: Option, + /// Source info of the local. + pub source_info: SourceInfo, } impl<'tcx> LocalDecl<'tcx> { /// Create a new `LocalDecl` for a temporary. #[inline] - pub fn new_temp(ty: Ty<'tcx>) -> Self { + pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { LocalDecl { mutability: Mutability::Mut, ty: ty, name: None, - source_info: None, + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, + is_user_variable: false } } @@ -404,12 +406,16 @@ impl<'tcx> LocalDecl<'tcx> { /// /// This must be inserted into the `local_decls` list as the first local. #[inline] - pub fn new_return_pointer(return_ty: Ty) -> LocalDecl { + pub fn new_return_pointer(return_ty: Ty, span: Span) -> LocalDecl { LocalDecl { mutability: Mutability::Mut, ty: return_ty, - source_info: None, + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, name: None, // FIXME maybe we do want some name here? + is_user_variable: false } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 733ad36de90e3..83963de8b0014 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -630,12 +630,11 @@ macro_rules! make_mir_visitor { ref $($mutability)* ty, name: _, ref $($mutability)* source_info, + is_user_variable: _, } = *local_decl; self.visit_ty(ty); - if let Some(ref $($mutability)* info) = *source_info { - self.visit_source_info(info); - } + self.visit_source_info(source_info); } fn super_visibility_scope(&mut self, diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 713e656666271..ca313622a3afd 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -307,12 +307,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { data } - fn create_drop_flag(&mut self, index: MovePathIndex) { + fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { let tcx = self.tcx; let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.mir.span); self.drop_flags.entry(index).or_insert_with(|| { - patch.new_temp(tcx.types.bool) + patch.new_temp(tcx.types.bool, span) }); } @@ -374,7 +374,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", child, location, path, (maybe_live, maybe_dead)); if maybe_live && maybe_dead { - self.create_drop_flag(child) + self.create_drop_flag(child, terminator.source_info.span) } }); } diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 1cd9a1b25bade..df2841a668269 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -62,7 +62,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let idx = unpack!(block = this.as_operand(block, None, index)); // bounds check: - let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty)); + let (len, lt) = (this.temp(usize_ty.clone(), expr_span), + this.temp(bool_ty, expr_span)); this.cfg.push_assign(block, source_info, // len = len(slice) &len, Rvalue::Len(slice.clone())); this.cfg.push_assign(block, source_info, // lt = idx < len diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6694107a8d485..fb547332c5f58 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bool_ty = this.hir.bool_ty(); let minval = this.minval_literal(expr_span, expr.ty); - let is_min = this.temp(bool_ty); + let is_min = this.temp(bool_ty, expr_span); this.cfg.push_assign(block, source_info, &is_min, Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval)); @@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } ExprKind::Box { value, value_extents } => { let value = this.hir.mirror(value); - let result = this.temp(expr.ty); + let result = this.temp(expr.ty, expr_span); // to start, malloc some memory of suitable type (thus far, uninitialized): this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty)); this.in_scope(value_extents, block, |this| { @@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bool_ty = self.hir.bool_ty(); if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() { let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty], false); - let result_value = self.temp(result_tup); + let result_value = self.temp(result_tup, span); self.cfg.push_assign(block, source_info, &result_value, Rvalue::CheckedBinaryOp(op, @@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; // Check for / 0 - let is_zero = self.temp(bool_ty); + let is_zero = self.temp(bool_ty, span); let zero = self.zero_literal(span, ty); self.cfg.push_assign(block, source_info, &is_zero, Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero)); @@ -315,9 +315,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let neg_1 = self.neg_1_literal(span, ty); let min = self.minval_literal(span, ty); - let is_neg_1 = self.temp(bool_ty); - let is_min = self.temp(bool_ty); - let of = self.temp(bool_ty); + let is_neg_1 = self.temp(bool_ty, span); + let is_min = self.temp(bool_ty, span); + let of = self.temp(bool_ty, span); // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 42d9ab4d2bf27..e4598b4143871 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -44,8 +44,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let expr_ty = expr.ty.clone(); - let temp = this.temp(expr_ty.clone()); let expr_span = expr.span; + let temp = this.temp(expr_ty.clone(), expr_span); let source_info = this.source_info(expr_span); if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) { diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 7336da654c184..c03432312b0ab 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => { let expr_ty = expr.ty; - let temp = this.temp(expr.ty.clone()); + let temp = this.temp(expr.ty.clone(), expr_span); unpack!(block = this.into(&temp, block, expr)); unpack!(block = this.build_drop(block, expr_span, temp, expr_ty)); block.unit() diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 705eb1f56608e..ddeec1fe6d0ba 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -710,7 +710,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mutability: mutability, ty: var_ty.clone(), name: Some(name), - source_info: Some(source_info), + source_info: source_info, + is_user_variable: true, }); self.var_indices.insert(var_id, var); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index f4fdf8ade900a..5fece4d6a5d23 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", num_enum_variants, values, variants); let discr_ty = adt_def.repr.discr_type().to_ty(tcx); - let discr = self.temp(discr_ty); + let discr = self.temp(discr_ty, test.span); self.cfg.push_assign(block, source_info, &discr, Rvalue::Discriminant(lvalue.clone())); assert_eq!(values.len() + 1, targets.len()); @@ -270,7 +270,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let ty::TyRef(region, mt) = ty.sty { if let ty::TyArray(_, _) = mt.ty.sty { ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); - let val_slice = self.temp(ty); + let val_slice = self.temp(ty, test.span); self.cfg.push_assign(block, source_info, &val_slice, Rvalue::Cast(CastKind::Unsize, val, ty)); val = Operand::Consume(val_slice); @@ -285,7 +285,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: value.clone() }); - let slice = self.temp(ty); + let slice = self.temp(ty, test.span); self.cfg.push_assign(block, source_info, &slice, Rvalue::Cast(CastKind::Unsize, array, ty)); Operand::Consume(slice) @@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let bool_ty = self.hir.bool_ty(); - let eq_result = self.temp(bool_ty); + let eq_result = self.temp(bool_ty, test.span); let eq_block = self.cfg.start_new_block(); let cleanup = self.diverge_cleanup(); self.cfg.terminate(block, source_info, TerminatorKind::Call { @@ -349,7 +349,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TestKind::Len { len, op } => { let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty()); - let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty)); + let (actual, result) = (self.temp(usize_ty, test.span), + self.temp(bool_ty, test.span)); // actual = len(lvalue) self.cfg.push_assign(block, source_info, @@ -383,7 +384,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { left: Operand<'tcx>, right: Operand<'tcx>) -> BasicBlock { let bool_ty = self.hir.bool_ty(); - let result = self.temp(bool_ty); + let result = self.temp(bool_ty, span); // result = op(left, right) let source_info = self.source_info(span); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 99aa5cb0fa86e..35a8b245f2bb6 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -27,8 +27,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// /// NB: **No cleanup is scheduled for this temporary.** You should /// call `schedule_drop` once the temporary is initialized. - pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> { - let temp = self.local_decls.push(LocalDecl::new_temp(ty)); + pub fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Lvalue<'tcx> { + let temp = self.local_decls.push(LocalDecl::new_temp(ty, span)); let lvalue = Lvalue::Local(temp); debug!("temp: created temp {:?} with type {:?}", lvalue, self.local_decls[temp].ty); @@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: u64) -> Lvalue<'tcx> { let usize_ty = self.hir.usize_ty(); - let temp = self.temp(usize_ty); + let temp = self.temp(usize_ty, source_info.span); self.cfg.push_assign_constant( block, source_info, &temp, Constant { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index db03a1c68f715..ef3fa23500b34 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -249,7 +249,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, breakable_scopes: vec![], - local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1), + local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty, + span), 1), var_indices: NodeMap(), unit_temp: None, cached_resume_block: None, @@ -304,8 +305,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.local_decls.push(LocalDecl { mutability: Mutability::Not, ty: ty, - source_info: None, + source_info: SourceInfo { + scope: ARGUMENT_VISIBILITY_SCOPE, + span: pattern.map_or(self.fn_span, |pat| pat.span) + }, name: name, + is_user_variable: false, }); } @@ -341,7 +346,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Some(ref tmp) => tmp.clone(), None => { let ty = self.hir.unit_ty(); - let tmp = self.temp(ty); + let fn_span = self.fn_span; + let tmp = self.temp(ty, fn_span); self.unit_temp = Some(tmp.clone()); tmp } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 63d20be88feee..0cec84d16a81c 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -137,16 +137,20 @@ enum CallKind { Direct(DefId), } -fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl { - LocalDecl { mutability, ty, name: None, source_info: None } +fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl { + LocalDecl { + mutability, ty, name: None, + source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span }, + is_user_variable: false + } } -fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) +fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span) -> IndexVec> { - iter::once(temp_decl(Mutability::Mut, sig.output())) + iter::once(temp_decl(Mutability::Mut, sig.output(), span)) .chain(sig.inputs().iter().map( - |ity| temp_decl(Mutability::Not, ity))) + |ity| temp_decl(Mutability::Not, ity, span))) .collect() } @@ -188,7 +192,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ), IndexVec::new(), sig.output(), - local_decls_for_sig(&sig), + local_decls_for_sig(&sig, span), sig.inputs().len(), vec![], span @@ -297,7 +301,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, debug!("build_call_shim: sig={:?}", sig); - let mut local_decls = local_decls_for_sig(&sig); + let mut local_decls = local_decls_for_sig(&sig, span); let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }; let rcvr_arg = Local::new(1+0); @@ -317,7 +321,8 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, tcx.mk_ref(re_erased, ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::MutMutable - }) + }), + span )); statements.push(Statement { source_info: source_info, @@ -442,7 +447,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields); - let local_decls = local_decls_for_sig(&sig); + let local_decls = local_decls_for_sig(&sig, span); let source_info = SourceInfo { span: span, diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 80a9c06f11b28..ac2bdaad24f76 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -461,11 +461,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { for loc in callee_mir.vars_and_temps_iter() { let mut local = callee_mir.local_decls[loc].clone(); - if let Some(ref mut source_info) = local.source_info { - source_info.scope = scope_map[source_info.scope]; - - source_info.span = callsite.location.span; - } + local.source_info.scope = scope_map[local.source_info.scope]; + local.source_info.span = callsite.location.span; let idx = caller_mir.local_decls.push(local); local_map.push(idx); @@ -506,7 +503,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let ty = dest.ty(caller_mir, self.tcx); - let temp = LocalDecl::new_temp(ty); + let temp = LocalDecl::new_temp(ty, callsite.location.span); let tmp = caller_mir.local_decls.push(temp); let tmp = Lvalue::Local(tmp); @@ -590,7 +587,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { arg.deref()); let ty = arg.ty(caller_mir, self.tcx); - let ref_tmp = LocalDecl::new_temp(ty); + let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span); let ref_tmp = caller_mir.local_decls.push(ref_tmp); let ref_tmp = Lvalue::Local(ref_tmp); @@ -611,7 +608,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty); - let cast_tmp = LocalDecl::new_temp(ptr_ty); + let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span); let cast_tmp = caller_mir.local_decls.push(cast_tmp); let cast_tmp = Lvalue::Local(cast_tmp); @@ -645,7 +642,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let ty = arg.ty(caller_mir, tcx); - let arg_tmp = LocalDecl::new_temp(ty); + let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span); let arg_tmp = caller_mir.local_decls.push(arg_tmp); let arg_tmp = Lvalue::Local(arg_tmp); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 57cf4b1e8b02b..ed9a0d3809f24 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -208,7 +208,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let no_stmts = self.source[loc.block].statements.len(); let new_temp = self.promoted.local_decls.push( - LocalDecl::new_temp(self.source.local_decls[temp].ty)); + LocalDecl::new_temp(self.source.local_decls[temp].ty, + self.source.local_decls[temp].source_info.span)); debug!("promote({:?} @ {:?}/{:?}, {:?})", temp, loc, no_stmts, self.keep_original); @@ -379,7 +380,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, }; // Declare return pointer local - let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect(); + let initial_locals = iter::once(LocalDecl::new_return_pointer(ty, span)) + .collect(); let mut promoter = Promoter { promoted: Mir::new( diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8eabe92fb98c0..1313b24fa74f5 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -881,7 +881,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Avoid a generic error for other uses of arguments. if self.qualif.intersects(Qualif::FN_ARGUMENT) { let decl = &self.mir.local_decls[index]; - span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022, + span_err!(self.tcx.sess, decl.source_info.span, E0022, "arguments of constant functions can only \ be immutable by-value bindings"); return; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index ccbc6700d89c1..04a1fc891cf1e 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -686,7 +686,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> } fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { - self.elaborator.patch().new_temp(ty) + self.elaborator.patch().new_temp(ty, self.source_info.span) } fn terminator_loc(&mut self, bb: BasicBlock) -> Location { diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 19f240da73059..7898d93c22e3b 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -11,6 +11,7 @@ use rustc::ty::Ty; use rustc::mir::*; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use syntax_pos::Span; /// This struct represents a patch to MIR, which can add /// new statements and basic blocks and patch over block @@ -92,10 +93,10 @@ impl<'tcx> MirPatch<'tcx> { } } - pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { + pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; - self.new_locals.push(LocalDecl::new_temp(ty)); + self.new_locals.push(LocalDecl::new_temp(ty, span)); Local::new(index as usize) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index ef2bf6e543420..b202e1495104e 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -196,8 +196,8 @@ fn write_scope_tree(tcx: TyCtxt, // User variable types (including the user's name in a comment). for local in mir.vars_iter() { let var = &mir.local_decls[local]; - let (name, source_info) = if var.source_info.unwrap().scope == child { - (var.name.unwrap(), var.source_info.unwrap()) + let (name, source_info) = if var.source_info.scope == child { + (var.name.unwrap(), var.source_info) } else { // Not a variable or not declared in this scope. continue; diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index c6f8ba7b6dc78..3d074c31c8a32 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -65,7 +65,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function let mut has_variables = BitVector::new(mir.visibility_scopes.len()); for var in mir.vars_iter() { let decl = &mir.local_decls[var]; - has_variables.insert(decl.source_info.unwrap().scope.index()); + has_variables.insert(decl.source_info.scope.index()); } // Instantiate all scopes. diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c8d15d28708f4..892a27e4550a7 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -255,8 +255,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( if let Some(name) = decl.name { // User variable - let source_info = decl.source_info.unwrap(); - let debug_scope = mircx.scopes[source_info.scope]; + let debug_scope = mircx.scopes[decl.source_info.scope]; let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo; if !lvalue_locals.contains(local.index()) && !dbg { @@ -268,7 +267,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( assert!(!ty.has_erasable_regions()); let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str()); if dbg { - let (scope, span) = mircx.debug_loc(source_info); + let (scope, span) = mircx.debug_loc(decl.source_info); declare_local(&bcx, &mircx.debug_context, name, ty, scope, VariableAccess::DirectVariable { alloca: lvalue.llval }, VariableKind::LocalVariable, span); From 0144613078b8210a774f51d7bf6282812bef1e91 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 11 Apr 2017 23:53:20 +0300 Subject: [PATCH 10/18] Move rvalue checking to MIR Fixes #41139. --- src/librustc_driver/driver.rs | 8 +- src/librustc_mir/diagnostics.rs | 33 ++++++++ src/librustc_mir/transform/type_check.rs | 48 ++++++++++- src/librustc_passes/diagnostics.rs | 33 -------- src/librustc_passes/lib.rs | 1 - src/librustc_passes/rvalues.rs | 103 ----------------------- src/test/compile-fail/issue-41139.rs | 18 ++++ 7 files changed, 97 insertions(+), 147 deletions(-) delete mode 100644 src/librustc_passes/rvalues.rs create mode 100644 src/test/compile-fail/issue-41139.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bdb05d06b0b10..4dfffe7fd5c98 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -35,7 +35,7 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, +use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats, mir_stats}; use rustc_const_eval::check_match; use super::Compilation; @@ -957,10 +957,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "liveness checking", || middle::liveness::check_crate(tcx)); - time(time_passes, - "rvalue checking", - || rvalues::check_crate(tcx)); - time(time_passes, "MIR dump", || mir::mir_map::build_mir_for_crate(tcx)); @@ -976,8 +972,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // in stage 4 below. passes.push_hook(box mir::transform::dump_mir::DumpMir); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial")); - passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass(box mir::transform::type_check::TypeckMir); + passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass( box mir::transform::simplify_branches::SimplifyBranches::new("initial")); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts")); diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index eb16812af9b02..bb07081fe433b 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -244,6 +244,39 @@ let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; ``` "##, +E0161: r##" +A value was moved. However, its size was not known at compile time, and only +values of a known size can be moved. + +Erroneous code example: + +```compile_fail +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<[isize]> = box *array; + // error: cannot move a value of type [isize]: the size of [isize] cannot + // be statically determined +} +``` + +In Rust, you can only move a value when its size is known at compile time. + +To work around this restriction, consider "hiding" the value behind a reference: +either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move +it around as usual. Example: + +``` +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<&[isize]> = box array; // ok! +} +``` +"##, + E0396: r##" The value behind a raw pointer can't be determined at compile-time (or even link-time), which means it can't be used in a constant diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 3d604affbfea9..f209b93cee18f 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -24,6 +24,7 @@ use std::fmt; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { @@ -87,6 +88,11 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { self.sanitize_type(rvalue, rval_ty); } + fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) { + self.super_local_decl(local_decl); + self.sanitize_type(local_decl, local_decl.ty); + } + fn visit_mir(&mut self, mir: &Mir<'tcx>) { self.sanitize_type(&"return type", mir.return_ty); for local_decl in &mir.local_decls { @@ -317,6 +323,7 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fulfillment_cx: traits::FulfillmentContext<'tcx>, last_span: Span, body_id: ast::NodeId, + reported_errors: FxHashSet<(Ty<'tcx>, Span)>, } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { @@ -326,6 +333,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fulfillment_cx: traits::FulfillmentContext::new(), last_span: DUMMY_SP, body_id: body_id, + reported_errors: FxHashSet(), } } @@ -641,9 +649,39 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn typeck_mir(&mut self, mir: &Mir<'tcx>) { + fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) { + match mir.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Arg => { + // return values of normal functions are required to be + // sized by typeck, but return values of ADT constructors are + // not because we don't include a `Self: Sized` bounds on them. + // + // Unbound parts of arguments were never required to be Sized + // - maybe we should make that a warning. + return + } + LocalKind::Var | LocalKind::Temp => {} + } + + let span = local_decl.source_info.span; + let ty = local_decl.ty; + if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) { + if let None = self.reported_errors.replace((ty, span)) { + span_err!(self.tcx().sess, span, E0161, + "cannot move a value of type {0}: the size of {0} \ + cannot be statically determined", ty); + } + } + } + + fn typeck_mir(&mut self, mir: &Mir<'gcx>) { self.last_span = mir.span; debug!("run_on_mir: {:?}", mir.span); + + for (local, local_decl) in mir.local_decls.iter_enumerated() { + self.check_local(mir, local, local_decl); + } + for block in mir.basic_blocks() { for stmt in &block.statements { if stmt.source_info.span != DUMMY_SP { @@ -698,16 +736,18 @@ impl TypeckMir { impl<'tcx> MirPass<'tcx> for TypeckMir { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { - debug!("run_pass: {}", tcx.node_path_str(src.item_id())); + let item_id = src.item_id(); + let def_id = tcx.hir.local_def_id(item_id); + debug!("run_pass: {}", tcx.item_path_str(def_id)); if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. return; } - let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id()); + let param_env = ty::ParameterEnvironment::for_item(tcx, item_id); tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { - let mut checker = TypeChecker::new(&infcx, src.item_id()); + let mut checker = TypeChecker::new(&infcx, item_id); { let mut verifier = TypeVerifier::new(&mut checker, mir); verifier.visit_mir(mir); diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 5f06eadb84a92..036a52d5a3db3 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -82,39 +82,6 @@ extern { ``` "##, -E0161: r##" -A value was moved. However, its size was not known at compile time, and only -values of a known size can be moved. - -Erroneous code example: - -```compile_fail -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<[isize]> = box *array; - // error: cannot move a value of type [isize]: the size of [isize] cannot - // be statically determined -} -``` - -In Rust, you can only move a value when its size is known at compile time. - -To work around this restriction, consider "hiding" the value behind a reference: -either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move -it around as usual. Example: - -``` -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<&[isize]> = box array; // ok! -} -``` -"##, - E0265: r##" This error indicates that a static or constant references itself. All statics and constants need to resolve to a value in an acyclic manner. diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 7a465f0ec4239..22566c813d86a 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -47,5 +47,4 @@ pub mod hir_stats; pub mod loops; pub mod mir_stats; pub mod no_asm; -pub mod rvalues; pub mod static_recursion; diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs deleted file mode 100644 index c367e71fcd246..0000000000000 --- a/src/librustc_passes/rvalues.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Checks that all rvalues in a crate have statically known size. check_crate -// is the public starting point. - -use rustc::dep_graph::DepNode; -use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization as mc; -use rustc::ty::{self, TyCtxt}; -use rustc::traits::Reveal; - -use rustc::hir; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use syntax::ast; -use syntax_pos::Span; - -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut rvcx = RvalueContext { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor()); -} - -struct RvalueContext<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - - fn visit_nested_body(&mut self, body_id: hir::BodyId) { - let body = self.tcx.hir.body(body_id); - self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { - let mut delegate = RvalueContextDelegate { - tcx: infcx.tcx, - param_env: &infcx.parameter_environment - }; - euv::ExprUseVisitor::new(&mut delegate, &infcx).consume_body(body); - }); - self.visit_body(body); - } -} - -struct RvalueContextDelegate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - param_env: &'a ty::ParameterEnvironment<'gcx>, -} - -impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tcx> { - fn consume(&mut self, - _: ast::NodeId, - span: Span, - cmt: mc::cmt<'tcx>, - _: euv::ConsumeMode) { - debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty); - let ty = self.tcx.lift_to_global(&cmt.ty).unwrap(); - if !ty.is_sized(self.tcx.global_tcx(), self.param_env, span) { - span_err!(self.tcx.sess, span, E0161, - "cannot move a value of type {0}: the size of {0} cannot be statically determined", - ty); - } - } - - fn matched_pat(&mut self, - _matched_pat: &hir::Pat, - _cmt: mc::cmt, - _mode: euv::MatchMode) {} - - fn consume_pat(&mut self, - _consume_pat: &hir::Pat, - _cmt: mc::cmt, - _mode: euv::ConsumeMode) { - } - - fn borrow(&mut self, - _borrow_id: ast::NodeId, - _borrow_span: Span, - _cmt: mc::cmt, - _loan_region: &'tcx ty::Region, - _bk: ty::BorrowKind, - _loan_cause: euv::LoanCause) { - } - - fn decl_without_init(&mut self, - _id: ast::NodeId, - _span: Span) { - } - - fn mutate(&mut self, - _assignment_id: ast::NodeId, - _assignment_span: Span, - _assignee_cmt: mc::cmt, - _mode: euv::MutateMode) { - } -} diff --git a/src/test/compile-fail/issue-41139.rs b/src/test/compile-fail/issue-41139.rs new file mode 100644 index 0000000000000..15ca151c49a79 --- /dev/null +++ b/src/test/compile-fail/issue-41139.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait {} + +fn get_function<'a>() -> &'a Fn() -> Trait { panic!("") } + +fn main() { + let t : &Trait = &get_function()(); + //~^ ERROR cannot move a value of type Trait + 'static +} From 540a069761c1184ee2998f23a24b76c97c274043 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 12 Apr 2017 00:44:17 +0300 Subject: [PATCH 11/18] address review comments --- src/librustc_mir/transform/type_check.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index f209b93cee18f..bfb08de56d8bb 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -666,6 +666,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let span = local_decl.source_info.span; let ty = local_decl.ty; if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) { + // in current MIR construction, all non-control-flow rvalue + // expressions evaluate through `as_temp` or `into` a return + // slot or local, so to find all unsized rvalues it is enough + // to check all temps, return slots and locals. if let None = self.reported_errors.replace((ty, span)) { span_err!(self.tcx().sess, span, E0161, "cannot move a value of type {0}: the size of {0} \ From 2389830deaf39b736e35c471e39543d30f708972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 Feb 2017 14:31:59 -0800 Subject: [PATCH 12/18] Highlight and simplify mismatched types Shorten mismatched types errors by replacing subtypes that are not different with `_`, and highlighting only the subtypes that are different. Given a file ```rust struct X { x: T1, y: T2, } fn foo() -> X, String> { X { x: X {x: "".to_string(), y: 2}, y: "".to_string()} } fn bar() -> Option { "".to_string() } ``` provide the following output ```rust error[E0308]: mismatched types --> file.rs:6:5 | 6 | X { x: X {x: "".to_string(), y: 2}, y: "".to_string()} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found {integer} | = note: expected type `X, _>` ^^^^^^^^^^^^^^^^^^^ // < highlighted found type `X, _>` ^^^^^^^^^ // < highlighted error[E0308]: mismatched types --> file.rs:6:5 | 10 | "".to_string() | ^^^^^^^^^^^^^^ expected struct `std::option::Option`, found `std::string::String` | = note: expected type `Option` ^^^^^^^ ^ // < highlighted found type `std::string::String` ``` --- src/librustc/infer/error_reporting/mod.rs | 288 +++++++++++++++++- src/librustc/infer/error_reporting/note.rs | 2 + src/librustc/ty/mod.rs | 2 +- src/librustc_errors/diagnostic.rs | 72 ++++- src/librustc_errors/diagnostic_builder.rs | 10 +- src/librustc_errors/lib.rs | 2 +- .../ex2a-push-one-existing-name.stderr | 4 +- .../ex2b-push-no-existing-names.stderr | 4 +- .../ex2c-push-inference-variable.stderr | 2 +- src/test/ui/mismatched_types/abridged.rs | 61 ++++ src/test/ui/mismatched_types/abridged.stderr | 70 +++++ 11 files changed, 485 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/mismatched_types/abridged.rs create mode 100644 src/test/ui/mismatched_types/abridged.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 9fa2bc8a2a7a9..dcbe50de2e9b2 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -70,7 +70,7 @@ use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, Issue32330}; use ty::error::TypeError; use syntax_pos::{Pos, Span}; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, DiagnosticStyledString}; mod note; @@ -365,6 +365,262 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` + /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and + /// populate `other_value` with `other_ty`. + /// + /// ```text + /// Foo> + /// ^^^^--------^ this is highlighted + /// | | + /// | this type argument is exactly the same as the other type, not highlighted + /// this is highlighted + /// Bar + /// -------- this type is the same as a type argument in the other type, not highlighted + /// ``` + fn highlight_outer(&self, + mut value: &mut DiagnosticStyledString, + mut other_value: &mut DiagnosticStyledString, + name: String, + sub: &ty::subst::Substs<'tcx>, + pos: usize, + other_ty: &ty::Ty<'tcx>) { + // `value` and `other_value` hold two incomplete type representation for display. + // `name` is the path of both types being compared. `sub` + value.push_highlighted(name); + let len = sub.len(); + if len > 0 { + value.push_highlighted("<"); + } + + // Output the lifetimes fot the first type + let lifetimes = sub.regions().map(|lifetime| { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + }).collect::>().join(", "); + if !lifetimes.is_empty() { + if sub.regions().count() < len { + value.push_normal(lifetimes + &", "); + } else { + value.push_normal(lifetimes); + } + } + + // Highlight all the type arguments that aren't at `pos` and compare the type argument at + // `pos` and `other_ty`. + for (i, type_arg) in sub.types().enumerate() { + if i == pos { + let values = self.cmp(type_arg, other_ty); + value.0.extend((values.0).0); + other_value.0.extend((values.1).0); + } else { + value.push_highlighted(format!("{}", type_arg)); + } + + if len > 0 && i != len - 1 { + value.push_normal(", "); + } + //self.push_comma(&mut value, &mut other_value, len, i); + } + if len > 0 { + value.push_highlighted(">"); + } + } + + /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, + /// as that is the difference to the other type. + /// + /// For the following code: + /// + /// ```norun + /// let x: Foo> = foo::>(); + /// ``` + /// + /// The type error output will behave in the following way: + /// + /// ```text + /// Foo> + /// ^^^^--------^ this is highlighted + /// | | + /// | this type argument is exactly the same as the other type, not highlighted + /// this is highlighted + /// Bar + /// -------- this type is the same as a type argument in the other type, not highlighted + /// ``` + fn cmp_type_arg(&self, + mut t1_out: &mut DiagnosticStyledString, + mut t2_out: &mut DiagnosticStyledString, + path: String, + sub: &ty::subst::Substs<'tcx>, + other_path: String, + other_ty: &ty::Ty<'tcx>) -> Option<()> { + for (i, ta) in sub.types().enumerate() { + if &ta == other_ty { + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + return Some(()); + } + if let &ty::TyAdt(def, _) = &ta.sty { + let path_ = self.tcx.item_path_str(def.did.clone()); + if path_ == other_path { + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + return Some(()); + } + } + } + None + } + + /// Add a `,` to the type representation only if it is appropriate. + fn push_comma(&self, + value: &mut DiagnosticStyledString, + other_value: &mut DiagnosticStyledString, + len: usize, + pos: usize) { + if len > 0 && pos != len - 1 { + value.push_normal(", "); + other_value.push_normal(", "); + } + } + + /// Compare two given types, eliding parts that are the same between them and highlighting + /// relevant differences, and return two representation of those types for highlighted printing. + fn cmp(&self, t1: ty::Ty<'tcx>, t2: ty::Ty<'tcx>) + -> (DiagnosticStyledString, DiagnosticStyledString) + { + match (&t1.sty, &t2.sty) { + (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { + let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); + let path1 = self.tcx.item_path_str(def1.did.clone()); + let path2 = self.tcx.item_path_str(def2.did.clone()); + if def1.did == def2.did { + // Easy case. Replace same types with `_` to shorten the output and highlight + // the differing ones. + // let x: Foo = y::>(); + // Foo + // Foo + // --- ^ type argument elided + // | + // highlighted in output + values.0.push_normal(path1); + values.1.push_normal(path2); + + // Only draw `<...>` if there're lifetime/type arguments. + let len = sub1.len(); + if len > 0 { + values.0.push_normal("<"); + values.1.push_normal("<"); + } + + fn lifetime_display(lifetime: &Region) -> String { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + } + // At one point we'd like to elide all lifetimes here, they are irrelevant for + // all diagnostics that use this output + // + // Foo<'x, '_, Bar> + // Foo<'y, '_, Qux> + // ^^ ^^ --- type arguments are not elided + // | | + // | elided as they were the same + // not elided, they were different, but irrelevant + let lifetimes = sub1.regions().zip(sub2.regions()); + for (i, lifetimes) in lifetimes.enumerate() { + let l1 = lifetime_display(lifetimes.0); + let l2 = lifetime_display(lifetimes.1); + if l1 == l2 { + values.0.push_normal("'_"); + values.1.push_normal("'_"); + } else { + values.0.push_highlighted(l1); + values.1.push_highlighted(l2); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + + // We're comparing two types with the same path, so we compare the type + // arguments for both. If they are the same, do not highlight and elide from the + // output. + // Foo<_, Bar> + // Foo<_, Qux> + // ^ elided type as this type argument was the same in both sides + let type_arguments = sub1.types().zip(sub2.types()); + let regions_len = sub1.regions().collect::>().len(); + for (i, (ta1, ta2)) in type_arguments.enumerate() { + let i = i + regions_len; + if ta1 == ta2 { + values.0.push_normal("_"); + values.1.push_normal("_"); + } else { + let (x1, x2) = self.cmp(ta1, ta2); + (values.0).0.extend(x1.0); + (values.1).0.extend(x2.0); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + + // Close the type argument bracket. + // Only draw `<...>` if there're lifetime/type arguments. + if len > 0 { + values.0.push_normal(">"); + values.1.push_normal(">"); + } + values + } else { + // Check for case: + // let x: Foo = foo::>(); + // Foo + // ------- this type argument is exactly the same as the other type + // Bar + if self.cmp_type_arg(&mut values.0, + &mut values.1, + path1.clone(), + sub1, + path2.clone(), + &t2).is_some() { + return values; + } + // Check for case: + // let x: Bar = y:>>(); + // Bar + // Foo> + // ------- this type argument is exactly the same as the other type + if self.cmp_type_arg(&mut values.1, + &mut values.0, + path2, + sub2, + path1, + &t1).is_some() { + return values; + } + + // We couldn't find anything in common, highlight everything. + // let x: Bar = y::>(); + (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2))) + } + } + _ => { + if t1 == t2 { + // The two types are the same, elide and don't highlight. + (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) + } else { + // We couldn't find anything in common, highlight everything. + (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2))) + } + } + } + } + pub fn note_type_err(&self, diag: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>, @@ -397,14 +653,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { - (&TypeError::Sorts(ref values), false, true) => { + (&TypeError::Sorts(ref values), false, true) => { diag.note_expected_found_extra( - &"type", &expected, &found, + &"type", expected, found, &format!(" ({})", values.expected.sort_string(self.tcx)), &format!(" ({})", values.found.sort_string(self.tcx))); } (_, false, _) => { - diag.note_expected_found(&"type", &expected, &found); + diag.note_expected_found(&"type", expected, found); } _ => (), } @@ -472,26 +728,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag } - /// Returns a string of the form "expected `{}`, found `{}`". - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { + fn values_str(&self, values: &ValuePairs<'tcx>) + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> + { match *values { - infer::Types(ref exp_found) => self.expected_found_str(exp_found), + infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } } + fn expected_found_str_ty(&self, + exp_found: &ty::error::ExpectedFound>) + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { + let exp_found = self.resolve_type_vars_if_possible(exp_found); + if exp_found.references_error() { + return None; + } + + Some(self.cmp(exp_found.expected, exp_found.found)) + } + + /// Returns a string of the form "expected `{}`, found `{}`". fn expected_found_str>( &self, exp_found: &ty::error::ExpectedFound) - -> Option<(String, String)> + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_type_vars_if_possible(exp_found); if exp_found.references_error() { return None; } - Some((format!("{}", exp_found.expected), format!("{}", exp_found.found))) + Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), + DiagnosticStyledString::highlighted(format!("{}", exp_found.found)))) } fn report_generic_bound_failure(&self, diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 8f8b2603dad84..8b753e0d22be7 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -20,6 +20,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match *origin { infer::Subtype(ref trace) => { if let Some((expected, found)) = self.values_str(&trace.values) { + let expected = expected.content(); + let found = found.content(); // FIXME: do we want a "the" here? err.span_note(trace.cause.span, &format!("...so that {} (expected {}, found {})", diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f1..3c51fd546c7c2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2218,7 +2218,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// `DefId` is really just an interned def-path). /// /// Note that if `id` is not local to this crate, the result will - // be a non-local `DefPath`. + /// be a non-local `DefPath`. pub fn def_path(self, id: DefId) -> hir_map::DefPath { if id.is_local() { self.hir.def_path(id) diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 1b77ead92deb6..9715ace3e2e2e 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -35,6 +35,46 @@ pub struct SubDiagnostic { pub render_span: Option, } +#[derive(PartialEq, Eq)] +pub struct DiagnosticStyledString(pub Vec); + +impl DiagnosticStyledString { + pub fn new() -> DiagnosticStyledString { + DiagnosticStyledString(vec![]) + } + pub fn push_normal>(&mut self, t: S) { + self.0.push(StringPart::Normal(t.into())); + } + pub fn push_highlighted>(&mut self, t: S) { + self.0.push(StringPart::Highlighted(t.into())); + } + pub fn normal>(t: S) -> DiagnosticStyledString { + DiagnosticStyledString(vec![StringPart::Normal(t.into())]) + } + + pub fn highlighted>(t: S) -> DiagnosticStyledString { + DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) + } + + pub fn content(&self) -> String { + self.0.iter().map(|x| x.content()).collect::() + } +} + +#[derive(PartialEq, Eq)] +pub enum StringPart { + Normal(String), + Highlighted(String), +} + +impl StringPart { + pub fn content(&self) -> String { + match self { + &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned() + } + } +} + impl Diagnostic { pub fn new(level: Level, message: &str) -> Self { Diagnostic::new_with_code(level, None, message) @@ -81,8 +121,8 @@ impl Diagnostic { pub fn note_expected_found(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) + expected: DiagnosticStyledString, + found: DiagnosticStyledString) -> &mut Self { self.note_expected_found_extra(label, expected, found, &"", &"") @@ -90,21 +130,29 @@ impl Diagnostic { pub fn note_expected_found_extra(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, expected_extra: &fmt::Display, found_extra: &fmt::Display) -> &mut Self { + let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)]; + msg.extend(expected.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`{}\n", expected_extra), Style::NoStyle)); + msg.push((format!(" found {} `", label), Style::NoStyle)); + msg.extend(found.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`{}", found_extra), Style::NoStyle)); + // For now, just attach these as notes - self.highlighted_note(vec![ - (format!("expected {} `", label), Style::NoStyle), - (format!("{}", expected), Style::Highlight), - (format!("`{}\n", expected_extra), Style::NoStyle), - (format!(" found {} `", label), Style::NoStyle), - (format!("{}", found), Style::Highlight), - (format!("`{}", found_extra), Style::NoStyle), - ]); + self.highlighted_note(msg); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7dfea6b8951b0..7b27f13951b61 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -9,6 +9,8 @@ // except according to those terms. use Diagnostic; +use DiagnosticStyledString; + use Level; use Handler; use std::fmt::{self, Debug}; @@ -115,14 +117,14 @@ impl<'a> DiagnosticBuilder<'a> { forward!(pub fn note_expected_found(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) + expected: DiagnosticStyledString, + found: DiagnosticStyledString) -> &mut Self); forward!(pub fn note_expected_found_extra(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, expected_extra: &fmt::Display, found_extra: &fmt::Display) -> &mut Self); diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 2efdaa57fba36..da29e354a7014 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -203,7 +203,7 @@ impl error::Error for ExplicitBug { } } -pub use diagnostic::{Diagnostic, SubDiagnostic}; +pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, StringPart}; pub use diagnostic_builder::DiagnosticBuilder; /// A handler deals with errors; certain errors diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr index 6f42a9f679a6a..6956a043cc694 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 16 | x.push(y); | ^ lifetime mismatch | - = note: expected type `Ref<'a, i32>` - found type `Ref<'_, i32>` + = note: expected type `Ref<'a, _>` + found type `Ref<'_, _>` note: the anonymous lifetime #2 defined on the body at 15:51... --> $DIR/ex2a-push-one-existing-name.rs:15:52 | diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr index edc1c2362de57..990ae65ba9854 100644 --- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 16 | x.push(y); | ^ lifetime mismatch | - = note: expected type `Ref<'_, i32>` - found type `Ref<'_, i32>` + = note: expected type `Ref<'_, _>` + found type `Ref<'_, _>` note: the anonymous lifetime #3 defined on the body at 15:43... --> $DIR/ex2b-push-no-existing-names.rs:15:44 | diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr index 755b71d4a1d9e..82f6c71ec1c2e 100644 --- a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr +++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr @@ -27,7 +27,7 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body 17 | | x.push(z); 18 | | } | |_^ ...ending here -note: ...so that expression is assignable (expected Ref<'b, i32>, found Ref<'_, i32>) +note: ...so that expression is assignable (expected Ref<'b, _>, found Ref<'_, _>) --> $DIR/ex2c-push-inference-variable.rs:17:12 | 17 | x.push(z); diff --git a/src/test/ui/mismatched_types/abridged.rs b/src/test/ui/mismatched_types/abridged.rs new file mode 100644 index 0000000000000..c448ad955fab4 --- /dev/null +++ b/src/test/ui/mismatched_types/abridged.rs @@ -0,0 +1,61 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Bar { + Qux, + Zar, +} + +struct Foo { + bar: usize, +} + +struct X { + x: T1, + y: T2, +} + +fn a() -> Foo { + Some(Foo { bar: 1 }) +} + +fn a2() -> Foo { + Ok(Foo { bar: 1}) +} + +fn b() -> Option { + Foo { bar: 1 } +} + +fn c() -> Result { + Foo { bar: 1 } +} + +fn d() -> X, String> { + X { + x: X { + x: "".to_string(), + y: 2, + }, + y: 3, + } +} + +fn e() -> X, String> { + X { + x: X { + x: "".to_string(), + y: 2, + }, + y: "".to_string(), + } +} + +fn main() {} diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr new file mode 100644 index 0000000000000..c67c6113d17c5 --- /dev/null +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -0,0 +1,70 @@ +error[E0308]: mismatched types + --> $DIR/abridged.rs:26:5 + | +26 | Some(Foo { bar: 1 }) + | ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option` + | + = note: expected type `Foo` + found type `std::option::Option` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:30:5 + | +30 | Ok(Foo { bar: 1}) + | ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result` + | + = note: expected type `Foo` + found type `std::result::Result` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:34:5 + | +34 | Foo { bar: 1 } + | ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo` + | + = note: expected type `std::option::Option` + found type `Foo` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:38:5 + | +38 | Foo { bar: 1 } + | ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo` + | + = note: expected type `std::result::Result` + found type `Foo` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:42:5 + | +42 | X { + | _____^ starting here... +43 | | x: X { +44 | | x: "".to_string(), +45 | | y: 2, +46 | | }, +47 | | y: 3, +48 | | } + | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | + = note: expected type `X, std::string::String>` + found type `X, {integer}>` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:52:5 + | +52 | X { + | _____^ starting here... +53 | | x: X { +54 | | x: "".to_string(), +55 | | y: 2, +56 | | }, +57 | | y: "".to_string(), +58 | | } + | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | + = note: expected type `X, _>` + found type `X, _>` + +error: aborting due to 6 previous errors + From ed7b6c3724be948bc04aaf3ed4311c877bde6dd3 Mon Sep 17 00:00:00 2001 From: projektir Date: Wed, 12 Apr 2017 00:10:36 -0400 Subject: [PATCH 13/18] Minor nits in primitive str --- src/libcollections/str.rs | 37 +++++++++++++++++++++++------------- src/libstd/primitive_docs.rs | 8 ++++---- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c37a4fa6b5572..f85336b8afbf4 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -318,8 +318,10 @@ impl str { /// Returns a subslice of `str`. /// - /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever - /// equivalent indexing operation would panic. + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None /// /// # Examples /// @@ -339,8 +341,10 @@ impl str { /// Returns a mutable subslice of `str`. /// - /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever - /// equivalent indexing operation would panic. + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None /// /// # Examples /// @@ -563,7 +567,7 @@ impl str { core_str::StrExt::split_at_mut(self, mid) } - /// Returns an iterator over the `char`s of a string slice. + /// Returns an iterator over the [`char`]s of a string slice. /// /// As a string slice consists of valid UTF-8, we can iterate through a /// string slice by [`char`]. This method returns such an iterator. @@ -1650,13 +1654,13 @@ impl str { /// Parses this string slice into another type. /// - /// Because `parse()` is so general, it can cause problems with type - /// inference. As such, `parse()` is one of the few times you'll see + /// Because `parse` is so general, it can cause problems with type + /// inference. As such, `parse` is one of the few times you'll see /// the syntax affectionately known as the 'turbofish': `::<>`. This /// helps the inference algorithm understand specifically which type /// you're trying to parse into. /// - /// `parse()` can parse any type that implements the [`FromStr`] trait. + /// `parse` can parse any type that implements the [`FromStr`] trait. /// /// [`FromStr`]: str/trait.FromStr.html /// @@ -1739,7 +1743,7 @@ impl str { /// /// `replacen` creates a new [`String`], and copies the data from this string slice into it. /// While doing so, it attempts to find matches of a pattern. If it finds any, it - /// replaces them with the replacement string slice at most `N` times. + /// replaces them with the replacement string slice at most `count` times. /// /// [`String`]: string/struct.String.html /// @@ -1885,7 +1889,9 @@ impl str { return s; } - /// Escapes each char in `s` with `char::escape_debug`. + /// Escapes each char in `s` with [`char::escape_debug`]. + /// + /// [`char::escape_debug`]: primitive.char.html#method.escape_debug #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1893,7 +1899,9 @@ impl str { self.chars().flat_map(|c| c.escape_debug()).collect() } - /// Escapes each char in `s` with `char::escape_default`. + /// Escapes each char in `s` with [`char::escape_default`]. + /// + /// [`char::escape_default`]: primitive.char.html#method.escape_default #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1901,7 +1909,9 @@ impl str { self.chars().flat_map(|c| c.escape_default()).collect() } - /// Escapes each char in `s` with `char::escape_unicode`. + /// Escapes each char in `s` with [`char::escape_unicode`]. + /// + /// [`char::escape_unicode`]: primitive.char.html#method.escape_unicode #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1909,9 +1919,10 @@ impl str { self.chars().flat_map(|c| c.escape_unicode()).collect() } - /// Converts a `Box` into a [`String`] without copying or allocating. + /// Converts a [`Box`] into a [`String`] without copying or allocating. /// /// [`String`]: string/struct.String.html + /// [`Box`]: boxed/struct.Box.html /// /// # Examples /// diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5b2053e929a10..8ae987557dd0f 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -406,7 +406,7 @@ mod prim_slice { } /// /// This documentation describes a number of methods and trait implementations /// on the `str` type. For technical reasons, there is additional, separate -/// documentation in [the `std::str` module](str/index.html) as well. +/// documentation in the [`std::str`](str/index.html) module as well. /// /// # Examples /// @@ -425,7 +425,7 @@ mod prim_slice { } /// # Representation /// /// A `&str` is made up of two components: a pointer to some bytes, and a -/// length. You can look at these with the [`.as_ptr`] and [`len`] methods: +/// length. You can look at these with the [`as_ptr`] and [`len`] methods: /// /// ``` /// use std::slice; @@ -452,11 +452,11 @@ mod prim_slice { } /// assert_eq!(s, Ok(story)); /// ``` /// -/// [`.as_ptr`]: #method.as_ptr +/// [`as_ptr`]: #method.as_ptr /// [`len`]: #method.len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. Use `.as_slice()` +/// used to get a string slice under normal circumstances. Use `as_slice` /// instead. #[stable(feature = "rust1", since = "1.0.0")] mod prim_str { } From f39145169f24cc6dd4c17f5529fc02169d8fea0d Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Mon, 10 Apr 2017 20:53:20 +0800 Subject: [PATCH 14/18] COPYRIGHT: remove hoedown license Hoedown was removed in b96fef8411f Also cleanup src/tools/tidy/src/main.rs Signed-off-by: NODA, Kai --- COPYRIGHT | 22 ---------------------- src/tools/tidy/src/main.rs | 2 -- 2 files changed, 24 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index abe8998030871..19559fa2950ea 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -197,28 +197,6 @@ their own copyright notices and license terms: USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* Hoedown, the markdown parser, under src/rt/hoedown, is - licensed as follows. - - Copyright (c) 2008, Natacha Porté - Copyright (c) 2011, Vicent Martí - Copyright (c) 2013, Devin Torres and the Hoedown authors - - Permission to use, copy, modify, and distribute this - software for any purpose with or without fee is hereby - granted, provided that the above copyright notice and - this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR - ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA - OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * libbacktrace, under src/libbacktrace: Copyright (C) 2012-2014 Free Software Foundation, Inc. diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index dee37341051ed..17f8b62117ad4 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -82,11 +82,9 @@ fn filter_dirs(path: &Path) -> bool { "src/llvm", "src/libbacktrace", "src/compiler-rt", - "src/rt/hoedown", "src/rustllvm", "src/rust-installer", "src/liblibc", - "src/tools/cargo", "src/vendor", ]; skip.iter().any(|p| path.ends_with(p)) From 2e327a668e0f37fa9663ede580d354e28fc016bf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Apr 2017 05:42:02 -0400 Subject: [PATCH 15/18] fix nit --- src/librustc_borrowck/borrowck/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e0b4a23010d2f..142286bd834d0 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -69,7 +69,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn provide(providers: &mut Providers) { *providers = Providers { - borrowck: borrowck, + borrowck, ..*providers }; } From c008cd70f5cb20cf22eb2cc9ae12f978296e8a45 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 6 Apr 2017 16:56:09 +0200 Subject: [PATCH 16/18] Make compiletest write test output to different files for different revisions. --- src/tools/compiletest/src/runtest.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 2865fa6a79253..7fb296c19f6ed 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1589,8 +1589,14 @@ actual:\n\ } fn dump_output(&self, out: &str, err: &str) { - self.dump_output_file(out, "out"); - self.dump_output_file(err, "err"); + let revision = if let Some(r) = self.revision { + format!("{}.", r) + } else { + String::new() + }; + + self.dump_output_file(out, &format!("{}out", revision)); + self.dump_output_file(err, &format!("{}err", revision)); self.maybe_dump_to_stdout(out, err); } From bc7af816f3b8712efa4e6643f9cdeb1d5ba5c78a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 5 Apr 2017 13:00:17 +0200 Subject: [PATCH 17/18] ICH: Hash everything that gets encoded into crate metadata. --- src/librustc/ich/hcx.rs | 52 ++++ src/librustc/ich/impls_ty.rs | 291 +++++++++++++++++- src/librustc/ich/mod.rs | 4 +- src/librustc/lib.rs | 1 + src/librustc/middle/free_region.rs | 4 + src/librustc_data_structures/array_vec.rs | 6 + .../transitive_relation.rs | 46 +++ src/librustc_metadata/astencode.rs | 42 +-- src/librustc_metadata/encoder.rs | 60 ++-- src/librustc_metadata/index_builder.rs | 77 ++++- src/librustc_metadata/lib.rs | 1 + src/librustc_metadata/schema.rs | 58 ++++ 12 files changed, 576 insertions(+), 66 deletions(-) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 5ef30550f1155..3a6367c353c1e 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -13,8 +13,10 @@ use hir::def_id::DefId; use ich::{self, CachingCodemapView}; use session::config::DebugInfoLevel::NoDebugInfo; use ty; +use util::nodemap::NodeMap; use std::hash as std_hash; +use std::collections::{HashMap, HashSet}; use syntax::ast; use syntax::attr; @@ -296,3 +298,53 @@ impl<'a, 'tcx> HashStable> for Span { } } } + +pub fn hash_stable_hashmap<'a, 'tcx, K, V, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + map: &HashMap, + extract_stable_key: F) + where K: Eq + std_hash::Hash, + V: HashStable>, + R: std_hash::BuildHasher, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + W: StableHasherResult, +{ + let mut keys: Vec<_> = map.keys() + .map(|k| (extract_stable_key(hcx, k), k)) + .collect(); + keys.sort_unstable_by_key(|&(ref stable_key, _)| stable_key.clone()); + keys.len().hash_stable(hcx, hasher); + for (stable_key, key) in keys { + stable_key.hash_stable(hcx, hasher); + map[key].hash_stable(hcx, hasher); + } +} + +pub fn hash_stable_hashset<'a, 'tcx, K, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + set: &HashSet, + extract_stable_key: F) + where K: Eq + std_hash::Hash, + R: std_hash::BuildHasher, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + W: StableHasherResult, +{ + let mut keys: Vec<_> = set.iter() + .map(|k| extract_stable_key(hcx, k)) + .collect(); + keys.sort_unstable(); + keys.hash_stable(hcx, hasher); +} + +pub fn hash_stable_nodemap<'a, 'tcx, V, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + map: &NodeMap) + where V: HashStable>, + W: StableHasherResult, +{ + hash_stable_hashmap(hcx, hasher, map, |hcx, node_id| { + hcx.tcx.hir.definitions().node_to_hir_id(*node_id).local_id + }); +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b6f3af2a11ec..c682f6b8668c3 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -11,31 +11,37 @@ //! This module contains `HashStable` implementations for various data types //! from rustc::ty in no particular order. -use ich::StableHashingContext; +use ich::{self, StableHashingContext, NodeIdHashingMode}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::hash as std_hash; use std::mem; use ty; - -impl<'a, 'tcx> HashStable> for ty::Ty<'tcx> { +impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { - let type_hash = hcx.tcx().type_id_hash(*self); - type_hash.hash_stable(hcx, hasher); + let ty::TyS { + ref sty, + + // The other fields just provide fast access to information that is + // also contained in `sty`, so no need to hash them. + .. + } = *self; + + sty.hash_stable(hcx, hasher); } } impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); -impl<'a, 'tcx, T> HashStable> for ty::Slice +impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice where T: HashStable> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { - (&**self).hash_stable(hcx, hasher); + (&self[..]).hash_stable(hcx, hasher); } } @@ -67,9 +73,13 @@ impl<'a, 'tcx> HashStable> for ty::Region { index.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } + ty::ReScope(code_extent) => { + code_extent.hash_stable(hcx, hasher); + } + ty::ReFree(ref free_region) => { + free_region.hash_stable(hcx, hasher); + } ty::ReLateBound(..) | - ty::ReFree(..) | - ty::ReScope(..) | ty::ReVar(..) | ty::ReSkolemized(..) => { bug!("TypeIdHasher: unexpected region {:?}", *self) @@ -127,7 +137,6 @@ impl_stable_hash_for!(enum ty::BorrowKind { MutBorrow }); - impl<'a, 'tcx> HashStable> for ty::UpvarCapture<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, @@ -223,7 +232,6 @@ impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx } } - impl<'a, 'tcx> HashStable> for ty::AdtFlags { fn hash_stable(&self, _: &mut StableHashingContext<'a, 'tcx>, @@ -303,7 +311,6 @@ for ::middle::const_val::ConstVal<'tcx> { impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); - impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { parent, predicates @@ -413,3 +420,263 @@ impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData { impl_stable_hash_for!(struct ty::DebruijnIndex { depth }); + +impl_stable_hash_for!(enum ty::cast::CastKind { + CoercionCast, + PtrPtrCast, + PtrAddrCast, + AddrPtrCast, + NumericCast, + EnumCast, + PrimIntCast, + U8CharCast, + ArrayPtrCast, + FnPtrPtrCast, + FnPtrAddrCast +}); + +impl<'a, 'tcx> HashStable> for ::middle::region::CodeExtent +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + hcx.tcx().region_maps.code_extent_data(*self).hash_stable(hcx, hasher); + }); + } +} + +impl<'a, 'tcx> HashStable> for ::middle::region::CodeExtentData +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::region::CodeExtentData; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + CodeExtentData::Misc(node_id) | + CodeExtentData::DestructionScope(node_id) => { + node_id.hash_stable(hcx, hasher); + } + CodeExtentData::CallSiteScope { fn_id, body_id } | + CodeExtentData::ParameterScope { fn_id, body_id } => { + fn_id.hash_stable(hcx, hasher); + body_id.hash_stable(hcx, hasher); + } + CodeExtentData::Remainder(block_remainder) => { + block_remainder.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::middle::region::BlockRemainder { + block, + first_statement_index +}); + +impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo { + custom_kind +}); + +impl_stable_hash_for!(struct ty::FreeRegion { + scope, + bound_region +}); + +impl_stable_hash_for!(enum ty::BoundRegion { + BrAnon(index), + BrNamed(def_id, name), + BrFresh(index), + BrEnv +}); + +impl<'a, 'tcx> HashStable> for ty::TypeVariants<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use ty::TypeVariants::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + TyBool | + TyChar | + TyStr | + TyNever => { + // Nothing more to hash. + } + TyInt(int_ty) => { + int_ty.hash_stable(hcx, hasher); + } + TyUint(uint_ty) => { + uint_ty.hash_stable(hcx, hasher); + } + TyFloat(float_ty) => { + float_ty.hash_stable(hcx, hasher); + } + TyAdt(adt_def, substs) => { + adt_def.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + TyArray(inner_ty, len) => { + inner_ty.hash_stable(hcx, hasher); + len.hash_stable(hcx, hasher); + } + TySlice(inner_ty) => { + inner_ty.hash_stable(hcx, hasher); + } + TyRawPtr(pointee_ty) => { + pointee_ty.hash_stable(hcx, hasher); + } + TyRef(region, pointee_ty) => { + region.hash_stable(hcx, hasher); + pointee_ty.hash_stable(hcx, hasher); + } + TyFnDef(def_id, substs, ref sig) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + sig.hash_stable(hcx, hasher); + } + TyFnPtr(ref sig) => { + sig.hash_stable(hcx, hasher); + } + TyDynamic(ref existential_predicates, region) => { + existential_predicates.hash_stable(hcx, hasher); + region.hash_stable(hcx, hasher); + } + TyClosure(def_id, closure_substs) => { + def_id.hash_stable(hcx, hasher); + closure_substs.hash_stable(hcx, hasher); + } + TyTuple(inner_tys, from_diverging_type_var) => { + inner_tys.hash_stable(hcx, hasher); + from_diverging_type_var.hash_stable(hcx, hasher); + } + TyProjection(ref projection_ty) => { + projection_ty.hash_stable(hcx, hasher); + } + TyAnon(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + TyParam(param_ty) => { + param_ty.hash_stable(hcx, hasher); + } + + TyError | + TyInfer(..) => { + bug!("ty::TypeVariants::hash_stable() - Unexpected variant.") + } + } + } +} + +impl_stable_hash_for!(struct ty::ParamTy { + idx, + name +}); + +impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> { + ty, + mutbl +}); + +impl<'a, 'tcx> HashStable> for ty::ExistentialPredicate<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ExistentialPredicate::Trait(ref trait_ref) => { + trait_ref.hash_stable(hcx, hasher); + } + ty::ExistentialPredicate::Projection(ref projection) => { + projection.hash_stable(hcx, hasher); + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + def_id.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ExistentialTraitRef<'tcx> { + def_id, + substs +}); + +impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> { + trait_ref, + item_name, + ty +}); + + +impl<'a, 'tcx> HashStable> for ty::TypeckTables<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::TypeckTables { + ref type_relative_path_defs, + ref node_types, + ref item_substs, + ref adjustments, + ref method_map, + ref upvar_capture_map, + ref closure_tys, + ref closure_kinds, + ref liberated_fn_sigs, + ref fru_field_types, + + ref cast_kinds, + lints: _, + ref used_trait_imports, + tainted_by_errors, + ref free_region_map, + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs); + ich::hash_stable_nodemap(hcx, hasher, node_types); + ich::hash_stable_nodemap(hcx, hasher, item_substs); + ich::hash_stable_nodemap(hcx, hasher, adjustments); + + ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| { + let ty::MethodCall { + expr_id, + autoderef + } = *method_call; + + let def_id = hcx.tcx().hir.local_def_id(expr_id); + (hcx.def_path_hash(def_id), autoderef) + }); + + ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { + let ty::UpvarId { + var_id, + closure_expr_id + } = *up_var_id; + + let var_def_id = hcx.tcx().hir.local_def_id(var_id); + let closure_def_id = hcx.tcx().hir.local_def_id(closure_expr_id); + (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id)) + }); + + ich::hash_stable_nodemap(hcx, hasher, closure_tys); + ich::hash_stable_nodemap(hcx, hasher, closure_kinds); + ich::hash_stable_nodemap(hcx, hasher, liberated_fn_sigs); + ich::hash_stable_nodemap(hcx, hasher, fru_field_types); + ich::hash_stable_nodemap(hcx, hasher, cast_kinds); + + ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { + hcx.tcx().def_path_hash(*def_id) + }); + + tainted_by_errors.hash_stable(hcx, hasher); + free_region_map.hash_stable(hcx, hasher); + }) + } +} diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index f932c90a331e1..d70ed051ac410 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -12,8 +12,8 @@ pub use self::fingerprint::Fingerprint; pub use self::caching_codemap_view::CachingCodemapView; -pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; - +pub use self::hcx::{StableHashingContext, NodeIdHashingMode, hash_stable_hashmap, + hash_stable_hashset, hash_stable_nodemap}; mod fingerprint; mod caching_codemap_view; mod hcx; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3b002fd4dfc1a..1f96330d51da5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -42,6 +42,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(discriminant_value)] +#![feature(sort_unstable)] extern crate arena; extern crate core; diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cdb081ab40098..a8eb6a1074383 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -180,3 +180,7 @@ fn lub() { map.relate_free_regions(frs[1], frs[2]); assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2])); } + +impl_stable_hash_for!(struct FreeRegionMap { + relation +}); diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index adb2219722602..848e5a076bb9a 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -40,6 +40,12 @@ unsafe impl Array for [T; 8] { const LEN: usize = 8; } +unsafe impl Array for [T; 32] { + type Element = T; + type PartialStorage = [ManuallyDrop; 32]; + const LEN: usize = 32; +} + pub struct ArrayVec { count: usize, values: A::PartialStorage diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 2bce7faf08cec..2631108aeb5fa 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,11 +9,14 @@ // except according to those terms. use bitvec::BitMatrix; +use stable_hasher::{HashStable, StableHasher, StableHasherResult}; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use std::cell::RefCell; use std::fmt::Debug; use std::mem; + + #[derive(Clone)] pub struct TransitiveRelation { // List of elements. This is used to map from a T to a usize. We @@ -334,6 +337,49 @@ impl Decodable for TransitiveRelation } } +impl HashStable for TransitiveRelation + where T: HashStable + PartialEq + Debug +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + // We are assuming here that the relation graph has been built in a + // deterministic way and we can just hash it the way it is. + let TransitiveRelation { + ref elements, + ref edges, + // "closure" is just a copy of the data above + closure: _ + } = *self; + + elements.hash_stable(hcx, hasher); + edges.hash_stable(hcx, hasher); + } +} + +impl HashStable for Edge { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + let Edge { + ref source, + ref target, + } = *self; + + source.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + } +} + +impl HashStable for Index { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + let Index(idx) = *self; + idx.hash_stable(hcx, hasher); + } +} + #[test] fn test_one_step() { let mut relation = TransitiveRelation::new(); diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 459132eb9c613..d9008ce555cc1 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -10,14 +10,12 @@ use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use encoder::EncodeContext; +use index_builder::EntryBuilder; use schema::*; use rustc::hir; use rustc::ty; -use rustc_serialize::Encodable; - #[derive(RustcEncodable, RustcDecodable)] pub struct Ast<'tcx> { pub body: Lazy, @@ -26,7 +24,14 @@ pub struct Ast<'tcx> { pub rvalue_promotable_to_static: bool, } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl_stable_hash_for!(struct Ast<'tcx> { + body, + tables, + nested_bodies, + rvalue_promotable_to_static +}); + +impl<'a, 'b, 'tcx> EntryBuilder<'a, 'b, 'tcx> { pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy> { let body = self.tcx.hir.body(body_id); let lazy_body = self.lazy(body); @@ -34,15 +39,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tables = self.tcx.body_tables(body_id); let lazy_tables = self.lazy(tables); - let nested_pos = self.position(); - let nested_count = { - let mut visitor = NestedBodyEncodingVisitor { - ecx: self, - count: 0, - }; - visitor.visit_body(body); - visitor.count + let mut visitor = NestedBodyCollector { + tcx: self.tcx, + bodies_found: Vec::new(), }; + visitor.visit_body(body); + let lazy_nested_bodies = self.lazy_seq_ref_from_slice(&visitor.bodies_found); let rvalue_promotable_to_static = self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id]; @@ -50,27 +52,25 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(&Ast { body: lazy_body, tables: lazy_tables, - nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count), + nested_bodies: lazy_nested_bodies, rvalue_promotable_to_static: rvalue_promotable_to_static }) } } -struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> { - ecx: &'a mut EncodeContext<'b, 'tcx>, - count: usize, +struct NestedBodyCollector<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + bodies_found: Vec<&'tcx hir::Body>, } -impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> { +impl<'a, 'tcx: 'a> Visitor<'tcx> for NestedBodyCollector<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } fn visit_nested_body(&mut self, body: hir::BodyId) { - let body = self.ecx.tcx.hir.body(body); - body.encode(self.ecx).unwrap(); - self.count += 1; - + let body = self.tcx.hir.body(body); + self.bodies_found.push(body); self.visit_body(body); } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 38d774992a551..a74ce3f650226 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -15,6 +15,7 @@ use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; +use rustc::ich; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; use rustc::mir; @@ -42,7 +43,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use rustc::hir::intravisit; -use super::index_builder::{FromId, IndexBuilder, Untracked}; +use super::index_builder::{FromId, IndexBuilder, Untracked, EntryBuilder}; pub struct EncodeContext<'a, 'tcx: 'a> { opaque: opaque::Encoder<'a>, @@ -54,6 +55,8 @@ pub struct EncodeContext<'a, 'tcx: 'a> { lazy_state: LazyState, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, + + pub metadata_hashes: Vec<(DefIndex, ich::Fingerprint)>, } macro_rules! encoder_methods { @@ -172,7 +175,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn lazy_seq(&mut self, iter: I) -> LazySeq + pub fn lazy_seq(&mut self, iter: I) -> LazySeq where I: IntoIterator, T: Encodable { @@ -184,7 +187,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq + pub fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq where I: IntoIterator, T: 'b + Encodable { @@ -233,10 +236,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Ok(()) } +} +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { let tcx = self.tcx; - self.lazy_seq(tcx.item_variances(def_id).iter().cloned()) + self.lazy_seq_from_slice(&tcx.item_variances(def_id)) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { @@ -305,7 +310,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = ModData { reexports: match tcx.export_map.get(&id) { - Some(exports) if *vis == hir::Public => self.lazy_seq_ref(exports), + Some(exports) if *vis == hir::Public => { + self.lazy_seq_from_slice(exports.as_slice()) + } _ => LazySeq::empty(), }, }; @@ -339,14 +346,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, - EncodeContext::encode_field, + EntryBuilder::encode_field, (adt_def_id, Untracked((variant_index, field_index)))); } } } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { /// Encode data for the given field of the given variant of the /// given ADT. The indices of the variant/field are untracked: /// this is ok because we will have to lookup the adt-def by its @@ -907,7 +914,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let def = self.tcx.lookup_adt_def(def_id); for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, - EncodeContext::encode_enum_variant_info, + EntryBuilder::encode_enum_variant_info, (def_id, Untracked(i))); } } @@ -918,7 +925,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { if !struct_def.is_struct() { let ctor_def_id = self.tcx.hir.local_def_id(struct_def.id()); self.record(ctor_def_id, - EncodeContext::encode_struct_ctor, + EntryBuilder::encode_struct_ctor, (def_id, ctor_def_id)); } } @@ -928,14 +935,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemImpl(..) => { for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(trait_item_def_id, - EncodeContext::encode_info_for_impl_item, + EntryBuilder::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(item_def_id, - EncodeContext::encode_info_for_trait_item, + EntryBuilder::encode_info_for_trait_item, item_def_id); } } @@ -943,7 +950,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_foreign_item(&mut self, (def_id, nitem): (DefId, &hir::ForeignItem)) -> Entry<'tcx> { @@ -1002,7 +1009,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { match item.node { hir::ItemExternCrate(_) | hir::ItemUse(..) => (), // ignore these - _ => self.index.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)), + _ => self.index.record(def_id, EntryBuilder::encode_info_for_item, (def_id, item)), } self.index.encode_addl_info_for_item(item); } @@ -1010,7 +1017,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { intravisit::walk_foreign_item(self, ni); let def_id = self.index.tcx.hir.local_def_id(ni.id); self.index.record(def_id, - EncodeContext::encode_info_for_foreign_item, + EntryBuilder::encode_info_for_foreign_item, (def_id, ni)); } fn visit_generics(&mut self, generics: &'tcx hir::Generics) { @@ -1023,7 +1030,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { } fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) { let def_id = self.index.tcx.hir.local_def_id(macro_def.id); - self.index.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def); + self.index.record(def_id, EntryBuilder::encode_info_for_macro_def, macro_def); } } @@ -1032,14 +1039,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { for ty_param in &generics.ty_params { let def_id = self.tcx.hir.local_def_id(ty_param.id); let has_default = Untracked(ty_param.default.is_some()); - self.record(def_id, EncodeContext::encode_info_for_ty_param, (def_id, has_default)); + self.record(def_id, EntryBuilder::encode_info_for_ty_param, (def_id, has_default)); } } fn encode_info_for_ty(&mut self, ty: &hir::Ty) { if let hir::TyImplTrait(_) = ty.node { let def_id = self.tcx.hir.local_def_id(ty.id); - self.record(def_id, EncodeContext::encode_info_for_anon_ty, def_id); + self.record(def_id, EntryBuilder::encode_info_for_anon_ty, def_id); } } @@ -1047,14 +1054,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { match expr.node { hir::ExprClosure(..) => { let def_id = self.tcx.hir.local_def_id(expr.id); - self.record(def_id, EncodeContext::encode_info_for_closure, def_id); + self.record(def_id, EntryBuilder::encode_info_for_closure, def_id); } _ => {} } } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty_param(&mut self, (def_id, Untracked(has_default)): (DefId, Untracked)) -> Entry<'tcx> { @@ -1133,11 +1140,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { + self.lazy_seq_from_slice(attrs) + } +} + +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_items(&mut self) -> Index { let krate = self.tcx.hir.krate(); let mut index = IndexBuilder::new(self); index.record(DefId::local(CRATE_DEF_INDEX), - EncodeContext::encode_info_for_mod, + EntryBuilder::encode_info_for_mod, FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); let mut visitor = EncodeVisitor { index: index }; krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); @@ -1147,10 +1160,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { visitor.index.into_items() } - fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { - self.lazy_seq_ref(attrs) - } - fn encode_crate_deps(&mut self) -> LazySeq { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc)> { // Pull the cnums and name,vers,hash out of cstore @@ -1298,7 +1307,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { None => LazySeq::empty(), } } +} +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_crate_root(&mut self) -> Lazy { let mut i = self.position(); let crate_deps = self.encode_crate_deps(); @@ -1448,6 +1459,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), + metadata_hashes: Vec::new(), }; // Encode the rustc version string in a predictable location. diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index a811f72bc956c..389ada12da81e 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -59,14 +59,19 @@ use encoder::EncodeContext; use index::Index; use schema::*; -use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::ich::{StableHashingContext, Fingerprint}; use rustc::ty::TyCtxt; use syntax::ast; use std::ops::{Deref, DerefMut}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; +use rustc_serialize::Encodable; + +use rustc::dep_graph::DepNode; + /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { @@ -112,16 +117,29 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { /// holds, and that it is therefore not gaining "secret" access to /// bits of HIR or other state that would not be trackd by the /// content system. - pub fn record(&mut self, - id: DefId, - op: fn(&mut EncodeContext<'b, 'tcx>, DATA) -> Entry<'tcx>, - data: DATA) + pub fn record<'x, DATA>(&'x mut self, + id: DefId, + op: fn(&mut EntryBuilder<'x, 'b, 'tcx>, DATA) -> Entry<'tcx>, + data: DATA) where DATA: DepGraphRead { let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); data.read(self.tcx); - let entry = op(&mut self.ecx, data); - self.items.record(id, self.ecx.lazy(&entry)); + + assert!(id.is_local()); + let tcx: TyCtxt<'b, 'tcx, 'tcx> = self.ecx.tcx; + let ecx: &'x mut EncodeContext<'b, 'tcx> = &mut *self.ecx; + let mut entry_builder = EntryBuilder { + tcx: tcx, + ecx: ecx, + hasher: StableHasher::new(), + hcx: StableHashingContext::new(tcx), + }; + + let entry = op(&mut entry_builder, data); + let entry = entry_builder.ecx.lazy(&entry); + entry_builder.finish(id); + self.items.record(id, entry); } pub fn into_items(self) -> Index { @@ -223,3 +241,48 @@ impl DepGraphRead for FromId { tcx.hir.read(self.0); } } + +pub struct EntryBuilder<'a, 'b: 'a, 'tcx: 'b> { + pub tcx: TyCtxt<'b, 'tcx, 'tcx>, + ecx: &'a mut EncodeContext<'b, 'tcx>, + hasher: StableHasher, + hcx: StableHashingContext<'b, 'tcx>, +} + +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { + + pub fn finish(self, def_id: DefId) { + let hash = self.hasher.finish(); + self.ecx.metadata_hashes.push((def_id.index, hash)); + } + + pub fn lazy(&mut self, value: &T) -> Lazy + where T: Encodable + HashStable> + { + value.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy(value) + } + + pub fn lazy_seq(&mut self, iter: I) -> LazySeq + where I: IntoIterator, + T: Encodable + HashStable> + { + let items: Vec = iter.into_iter().collect(); + items.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq(items) + } + + pub fn lazy_seq_from_slice(&mut self, slice: &[T]) -> LazySeq + where T: Encodable + HashStable> + { + slice.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq_ref(slice.iter()) + } + + pub fn lazy_seq_ref_from_slice(&mut self, slice: &[&T]) -> LazySeq + where T: Encodable + HashStable> + { + slice.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq_ref(slice.iter().map(|x| *x)) + } +} diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 2fbdb8c0de676..b9e142ac65072 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -27,6 +27,7 @@ #![feature(rustc_private)] #![feature(specialization)] #![feature(staged_api)] +#![feature(discriminant_value)] #[macro_use] extern crate log; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index abb482a50ebc2..6ffa31c072709 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -28,6 +28,9 @@ use syntax_pos::{self, Span}; use std::marker::PhantomData; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable, + StableHasherResult}; + pub fn rustc_version() -> String { format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) @@ -100,6 +103,15 @@ impl Clone for Lazy { impl serialize::UseSpecializedEncodable for Lazy {} impl serialize::UseSpecializedDecodable for Lazy {} +impl HashStable for Lazy { + fn hash_stable(&self, + _: &mut CTX, + _: &mut StableHasher) { + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. + } +} + /// A sequence of type T referred to by its absolute position /// in the metadata and length, and which can be decoded lazily. /// The sequence is a single node for the purposes of `Lazy`. @@ -148,6 +160,15 @@ impl Clone for LazySeq { impl serialize::UseSpecializedEncodable for LazySeq {} impl serialize::UseSpecializedDecodable for LazySeq {} +impl HashStable for LazySeq { + fn hash_stable(&self, + _: &mut CTX, + _: &mut StableHasher) { + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. + } +} + /// Encoding / decoding state for `Lazy` and `LazySeq`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum LazyState { @@ -251,17 +272,23 @@ pub struct ModData { pub reexports: LazySeq, } +impl_stable_hash_for!(struct ModData { reexports }); + #[derive(RustcEncodable, RustcDecodable)] pub struct MacroDef { pub body: String, } +impl_stable_hash_for!(struct MacroDef { body }); + #[derive(RustcEncodable, RustcDecodable)] pub struct FnData { pub constness: hir::Constness, pub arg_names: LazySeq, } +impl_stable_hash_for!(struct FnData { constness, arg_names }); + #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData<'tcx> { pub ctor_kind: CtorKind, @@ -273,6 +300,13 @@ pub struct VariantData<'tcx> { pub struct_ctor: Option, } +impl_stable_hash_for!(struct VariantData<'tcx> { + ctor_kind, + discr, + evaluated_discr, + struct_ctor +}); + #[derive(RustcEncodable, RustcDecodable)] pub struct TraitData<'tcx> { pub unsafety: hir::Unsafety, @@ -281,6 +315,13 @@ pub struct TraitData<'tcx> { pub super_predicates: Lazy>, } +impl_stable_hash_for!(struct TraitData<'tcx> { + unsafety, + paren_sugar, + has_default_impl, + super_predicates +}); + #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, @@ -291,6 +332,14 @@ pub struct ImplData<'tcx> { pub trait_ref: Option>>, } +impl_stable_hash_for!(struct ImplData<'tcx> { + polarity, + parent_impl, + coerce_unsized_info, + trait_ref +}); + + /// Describes whether the container of an associated item /// is a trait or an impl and whether, in a trait, it has /// a default, or an in impl, whether it's marked "default". @@ -302,6 +351,13 @@ pub enum AssociatedContainer { ImplFinal, } +impl_stable_hash_for!(enum ::schema::AssociatedContainer { + TraitRequired, + TraitWithDefault, + ImplDefault, + ImplFinal +}); + impl AssociatedContainer { pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer { match *self { @@ -335,9 +391,11 @@ pub struct MethodData { pub container: AssociatedContainer, pub has_self: bool, } +impl_stable_hash_for!(struct MethodData { fn_data, container, has_self }); #[derive(RustcEncodable, RustcDecodable)] pub struct ClosureData<'tcx> { pub kind: ty::ClosureKind, pub ty: Lazy>, } +impl_stable_hash_for!(struct ClosureData<'tcx> { kind, ty }); From ca2dce9b48e65ae2b286fbd10e459536ecccb2d8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 5 Apr 2017 23:39:02 +0200 Subject: [PATCH 18/18] ICH: Replace old, transitive metadata hashing with direct hashing approach. Instead of collecting all potential inputs to some metadata entry and hashing those, we directly hash the values we are storing in metadata. This is more accurate and doesn't suffer from quadratic blow-up when many entries have the same dependencies. --- src/librustc/ich/impls_ty.rs | 32 ++--- src/librustc/middle/cstore.rs | 23 +++- src/librustc/ty/mod.rs | 17 +++ src/librustc/ty/util.rs | 30 +++-- src/librustc_data_structures/blake2b.rs | 34 ++++- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/stable_hasher.rs | 7 +- src/librustc_driver/driver.rs | 1 + src/librustc_incremental/persist/data.rs | 14 +- .../persist/dirty_clean.rs | 64 ++++++--- src/librustc_incremental/persist/preds/mod.rs | 28 +++- src/librustc_incremental/persist/save.rs | 81 ++---------- src/librustc_metadata/cstore_impl.rs | 8 +- src/librustc_metadata/encoder.rs | 48 +++++-- src/librustc_metadata/index_builder.rs | 93 +++++++++++--- src/librustc_metadata/schema.rs | 90 ++++++++++++- src/librustc_trans/back/link.rs | 5 +- src/librustc_trans/base.rs | 11 +- src/librustc_trans/lib.rs | 2 +- src/test/incremental/hashes/enum_defs.rs | 92 ++++++++++--- src/test/incremental/hashes/extern_mods.rs | 40 ++++-- .../incremental/hashes/function_interfaces.rs | 10 +- src/test/incremental/hashes/inherent_impls.rs | 20 ++- src/test/incremental/hashes/struct_defs.rs | 90 ++++++++++--- src/test/incremental/hashes/trait_defs.rs | 121 +++++++++++------- src/test/incremental/hashes/trait_impls.rs | 58 +++------ .../unchecked_dirty_clean_metadata.rs | 10 -- 27 files changed, 689 insertions(+), 341 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index c682f6b8668c3..46d1e7ef0c7c4 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -16,24 +16,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::hash as std_hash; use std::mem; +use syntax_pos::symbol::InternedString; use ty; -impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, - hasher: &mut StableHasher) { - let ty::TyS { - ref sty, - - // The other fields just provide fast access to information that is - // also contained in `sty`, so no need to hash them. - .. - } = *self; - - sty.hash_stable(hcx, hasher); - } -} - impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice @@ -288,9 +273,14 @@ for ::middle::const_val::ConstVal<'tcx> { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } - ConstVal::Struct(ref _name_value_map) => { - // BTreeMap>), - panic!("Ordering still unstable") + ConstVal::Struct(ref name_value_map) => { + let mut values: Vec<(InternedString, &ConstVal)> = + name_value_map.iter() + .map(|(name, val)| (name.as_str(), val)) + .collect(); + + values.sort_unstable_by_key(|&(ref name, _)| name.clone()); + values.hash_stable(hcx, hasher); } ConstVal::Tuple(ref value) => { value.hash_stable(hcx, hasher); @@ -632,6 +622,8 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' ref fru_field_types, ref cast_kinds, + + // FIXME(#41184): This is still ignored at the moment. lints: _, ref used_trait_imports, tainted_by_errors, @@ -672,7 +664,7 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' ich::hash_stable_nodemap(hcx, hasher, cast_kinds); ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { - hcx.tcx().def_path_hash(*def_id) + hcx.def_path_hash(*def_id) }); tainted_by_errors.hash_stable(hcx, hasher); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 694321812836b..81cf24e58dda4 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -27,6 +27,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::map as hir_map; use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData}; use hir::svh::Svh; +use ich; use middle::lang_items; use ty::{self, TyCtxt}; use session::Session; @@ -161,6 +162,20 @@ pub struct ExternCrate { pub path_len: usize, } +pub struct EncodedMetadata { + pub raw_data: Vec, + pub hashes: Vec, +} + +/// The hash for some metadata that (when saving) will be exported +/// from this crate, or which (when importing) was exported by an +/// upstream crate. +#[derive(Debug, RustcEncodable, RustcDecodable, Copy, Clone)] +pub struct EncodedMetadataHash { + pub def_index: DefIndex, + pub hash: ich::Fingerprint, +} + /// A store of Rust crates, through with their metadata /// can be accessed. pub trait CrateStore { @@ -258,7 +273,8 @@ pub trait CrateStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec; + reachable: &NodeSet) + -> EncodedMetadata; fn metadata_encoding_version(&self) -> &[u8]; } @@ -417,7 +433,10 @@ impl CrateStore for DummyCrateStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec { vec![] } + reachable: &NodeSet) + -> EncodedMetadata { + bug!("encode_metadata") + } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a2c356c20db09..23f35d3bdd792 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -452,6 +452,23 @@ impl<'tcx> Hash for TyS<'tcx> { } } +impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::TyS { + ref sty, + + // The other fields just provide fast access to information that is + // also contained in `sty`, so no need to hash them. + flags: _, + region_depth: _, + } = *self; + + sty.hash_stable(hcx, hasher); + } +} + pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fd8191303a9a6..c650ffe302762 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -13,7 +13,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use infer::InferCtxt; -// use hir::map as hir_map; +use ich::{StableHashingContext, NodeIdHashingMode}; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::ParameterEnvironment; @@ -25,8 +25,8 @@ use util::nodemap::FxHashMap; use middle::lang_items; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult}; - +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use std::cell::RefCell; use std::cmp; use std::hash::Hash; @@ -187,6 +187,22 @@ impl<'tcx> ParameterEnvironment<'tcx> { } } +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Creates a hash of the type `Ty` which will be the same no matter what crate + /// context it's calculated within. This is used by the `type_id` intrinsic. + pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { + let mut hasher = StableHasher::new(); + let mut hcx = StableHashingContext::new(self); + + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ty.hash_stable(hcx, &mut hasher); + }); + }); + hasher.finish() + } +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { @@ -339,14 +355,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect() } - /// Creates a hash of the type `Ty` which will be the same no matter what crate - /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { - let mut hasher = TypeIdHasher::new(self); - hasher.visit_ty(ty); - hasher.finish() - } - /// Calculate the destructor of a given type. pub fn calculate_dtor( self, diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs index 9d97a83f693c3..bdef9fefd41e4 100644 --- a/src/librustc_data_structures/blake2b.rs +++ b/src/librustc_data_structures/blake2b.rs @@ -29,16 +29,23 @@ pub struct Blake2bCtx { t: [u64; 2], c: usize, outlen: u16, - finalized: bool + finalized: bool, + + #[cfg(debug_assertions)] + fnv_hash: u64, } +#[cfg(debug_assertions)] impl ::std::fmt::Debug for Blake2bCtx { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - try!(write!(fmt, "hash: ")); - for v in &self.h { - try!(write!(fmt, "{:x}", v)); - } - Ok(()) + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "{:x}", self.fnv_hash) + } +} + +#[cfg(not(debug_assertions))] +impl ::std::fmt::Debug for Blake2bCtx { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "Enable debug_assertions() for more info.") } } @@ -157,6 +164,9 @@ fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx { c: 0, outlen: outlen as u16, finalized: false, + + #[cfg(debug_assertions)] + fnv_hash: 0xcbf29ce484222325, }; ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64); @@ -194,6 +204,16 @@ fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) { checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy); ctx.c += bytes_to_copy; } + + #[cfg(debug_assertions)] + { + // compute additional FNV hash for simpler to read debug output + const MAGIC_PRIME: u64 = 0x00000100000001b3; + + for &byte in data { + ctx.fnv_hash = (ctx.fnv_hash ^ byte as u64).wrapping_mul(MAGIC_PRIME); + } + } } fn blake2b_final(ctx: &mut Blake2bCtx) diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 72c533a74618b..00c46d992bfd5 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -40,6 +40,7 @@ #![feature(discriminant_value)] #![feature(specialization)] #![feature(manually_drop)] +#![feature(struct_field_attributes)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index dc412a0763ef7..95f063976d491 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -40,13 +40,18 @@ fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize { /// This hasher currently always uses the stable Blake2b algorithm /// and allows for variable output lengths through its type /// parameter. -#[derive(Debug)] pub struct StableHasher { state: Blake2bHasher, bytes_hashed: u64, width: PhantomData, } +impl ::std::fmt::Debug for StableHasher { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{:?}", self.state) + } +} + pub trait StableHasherResult: Sized { fn finish(hasher: StableHasher) -> Self; } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bdb05d06b0b10..eeacf79514a87 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1083,6 +1083,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "serialize dep graph", || rustc_incremental::save_dep_graph(tcx, &incremental_hashes_map, + &translation.metadata.hashes, translation.link.crate_hash)); translation } diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index d900907395656..8a1af5dd08d74 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -13,6 +13,7 @@ use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; use rustc::ich::Fingerprint; +use rustc::middle::cstore::EncodedMetadataHash; use std::sync::Arc; use rustc_data_structures::fx::FxHashMap; @@ -98,7 +99,7 @@ pub struct SerializedMetadataHashes { /// where `X` refers to some item in this crate. That `X` will be /// a `DefPathIndex` that gets retracted to the current `DefId` /// (matching the one found in this structure). - pub hashes: Vec, + pub hashes: Vec, /// For each DefIndex (as it occurs in SerializedMetadataHash), this /// map stores the DefPathIndex (as it occurs in DefIdDirectory), so @@ -112,14 +113,3 @@ pub struct SerializedMetadataHashes { /// the DefIndex. pub index_map: FxHashMap } - -/// The hash for some metadata that (when saving) will be exported -/// from this crate, or which (when importing) was exported by an -/// upstream crate. -#[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct SerializedMetadataHash { - pub def_index: DefIndex, - - /// the hash itself, computed by `calculate_item_hash` - pub hash: Fingerprint, -} diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index d931f64d579e1..af5c1f05bd1fc 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -215,9 +215,11 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { } } -pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &FxHashMap, - current_metadata_hashes: &FxHashMap) { +pub fn check_dirty_clean_metadata<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + prev_metadata_hashes: &FxHashMap, + current_metadata_hashes: &FxHashMap) +{ if !tcx.sess.opts.debugging_opts.query_dep_graph { return; } @@ -230,7 +232,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, current_metadata_hashes: current_metadata_hashes, checked_attrs: FxHashSet(), }; - krate.visit_all_item_likes(&mut dirty_clean_visitor); + intravisit::walk_crate(&mut dirty_clean_visitor, krate); let mut all_attrs = FindAllAttrs { tcx: tcx, @@ -246,30 +248,58 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); } -pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { +pub struct DirtyCleanMetadataVisitor<'a, 'tcx: 'a, 'm> { tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_metadata_hashes: &'m FxHashMap, current_metadata_hashes: &'m FxHashMap, checked_attrs: FxHashSet, } -impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { +impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { + + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::All(&self.tcx.hir) + } + fn visit_item(&mut self, item: &'tcx hir::Item) { self.check_item(item.id, item.span); + intravisit::walk_item(self, item); + } - if let hir::ItemEnum(ref def, _) = item.node { - for v in &def.variants { - self.check_item(v.node.data.id(), v.span); - } + fn visit_variant_data(&mut self, + variant_data: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + _parent_id: ast::NodeId, + span: Span) { + if self.tcx.hir.find(variant_data.id()).is_some() { + // VariantData that represent structs or tuples don't have a + // separate entry in the HIR map and checking them would error, + // so only check if this is an enum or union variant. + self.check_item(variant_data.id(), span); } + + intravisit::walk_struct_def(self, variant_data); } - fn visit_trait_item(&mut self, item: &hir::TraitItem) { + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) { self.check_item(item.id, item.span); + intravisit::walk_trait_item(self, item); } - fn visit_impl_item(&mut self, item: &hir::ImplItem) { + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) { self.check_item(item.id, item.span); + intravisit::walk_impl_item(self, item); + } + + fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) { + self.check_item(i.id, i.span); + intravisit::walk_foreign_item(self, i); + } + + fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { + self.check_item(s.id, s.span); + intravisit::walk_struct_field(self, s); } } @@ -281,13 +311,15 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { for attr in self.tcx.get_attrs(def_id).iter() { if attr.check_name(ATTR_DIRTY_METADATA) { if check_config(self.tcx, attr) { - self.checked_attrs.insert(attr.id); - self.assert_state(false, def_id, item_span); + if self.checked_attrs.insert(attr.id) { + self.assert_state(false, def_id, item_span); + } } } else if attr.check_name(ATTR_CLEAN_METADATA) { if check_config(self.tcx, attr) { - self.checked_attrs.insert(attr.id); - self.assert_state(true, def_id, item_span); + if self.checked_attrs.insert(attr.id) { + self.assert_state(true, def_id, item_span); + } } } } diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs index fe8cf72996e15..e769641a4cadf 100644 --- a/src/librustc_incremental/persist/preds/mod.rs +++ b/src/librustc_incremental/persist/preds/mod.rs @@ -44,16 +44,18 @@ impl<'q> Predecessors<'q> { pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self { let tcx = hcx.tcx; - let collect_for_metadata = tcx.sess.opts.debugging_opts.incremental_cc || - tcx.sess.opts.debugging_opts.query_dep_graph; - // Find the set of "start nodes". These are nodes that we will // possibly query later. let is_output = |node: &DepNode| -> bool { match *node { DepNode::WorkProduct(_) => true, - DepNode::MetaData(ref def_id) => collect_for_metadata && def_id.is_local(), - + DepNode::MetaData(ref def_id) => { + // We do *not* create dep-nodes for the current crate's + // metadata anymore, just for metadata that we import/read + // from other crates. + debug_assert!(!def_id.is_local()); + false + } // if -Z query-dep-graph is passed, save more extended data // to enable better unit testing DepNode::TypeckTables(_) | @@ -75,6 +77,22 @@ impl<'q> Predecessors<'q> { .or_insert_with(|| hcx.hash(input).unwrap()); } + if tcx.sess.opts.debugging_opts.query_dep_graph { + // Not all inputs might have been reachable from an output node, + // but we still want their hash for our unit tests. + let hir_nodes = query.graph.all_nodes().iter().filter_map(|node| { + match node.data { + DepNode::Hir(_) => Some(&node.data), + _ => None, + } + }); + + for node in hir_nodes { + hashes.entry(node) + .or_insert_with(|| hcx.hash(node).unwrap()); + } + } + let bootstrap_outputs: Vec<&'q DepNode> = (0 .. graph.len_nodes()) .map(NodeIndex) diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 1591503865e81..1864009fbdf21 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -12,13 +12,12 @@ use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::ich::Fingerprint; +use rustc::middle::cstore::EncodedMetadataHash; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::{NodeIndex, INCOMING}; use rustc_serialize::Encodable as RustcEncodable; use rustc_serialize::opaque::Encoder; -use std::hash::Hash; use std::io::{self, Cursor, Write}; use std::fs::{self, File}; use std::path::PathBuf; @@ -32,10 +31,10 @@ use super::fs::*; use super::dirty_clean; use super::file_format; use super::work_product; -use calculate_svh::IchHasher; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap, + metadata_hashes: &[EncodedMetadataHash], svh: Svh) { debug!("save_dep_graph()"); let _ignore = tcx.dep_graph.in_ignore(); @@ -56,16 +55,16 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let preds = Predecessors::new(&query, &mut hcx); let mut current_metadata_hashes = FxHashMap(); + // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, + // since metadata-encoding might add new entries to the + // DefIdDirectory (which is saved in the dep-graph file). if sess.opts.debugging_opts.incremental_cc || sess.opts.debugging_opts.query_dep_graph { - // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, - // since metadata-encoding might add new entries to the - // DefIdDirectory (which is saved in the dep-graph file). save_in(sess, metadata_hash_export_path(sess), |e| encode_metadata_hashes(tcx, svh, - &preds, + metadata_hashes, &mut builder, &mut current_metadata_hashes, e)); @@ -241,80 +240,16 @@ pub fn encode_dep_graph(preds: &Predecessors, pub fn encode_metadata_hashes(tcx: TyCtxt, svh: Svh, - preds: &Predecessors, + metadata_hashes: &[EncodedMetadataHash], builder: &mut DefIdDirectoryBuilder, current_metadata_hashes: &mut FxHashMap, encoder: &mut Encoder) -> io::Result<()> { - // For each `MetaData(X)` node where `X` is local, accumulate a - // hash. These are the metadata items we export. Downstream - // crates will want to see a hash that tells them whether we might - // have changed the metadata for a given item since they last - // compiled. - // - // (I initially wrote this with an iterator, but it seemed harder to read.) let mut serialized_hashes = SerializedMetadataHashes { - hashes: vec![], + hashes: metadata_hashes.to_vec(), index_map: FxHashMap() }; - for (index, target) in preds.reduced_graph.all_nodes().iter().enumerate() { - let index = NodeIndex(index); - let def_id = match *target.data { - DepNode::MetaData(def_id) if def_id.is_local() => def_id, - _ => continue, - }; - - // To create the hash for each item `X`, we don't hash the raw - // bytes of the metadata (though in principle we - // could). Instead, we walk the predecessors of `MetaData(X)` - // from the dep-graph. This corresponds to all the inputs that - // were read to construct the metadata. To create the hash for - // the metadata, we hash (the hash of) all of those inputs. - debug!("save: computing metadata hash for {:?}", def_id); - - // Create a vector containing a pair of (source-id, hash). - // The source-id is stored as a `DepNode`, where the u64 - // is the det. hash of the def-path. This is convenient - // because we can sort this to get a stable ordering across - // compilations, even if the def-ids themselves have changed. - let mut hashes: Vec<(DepNode, Fingerprint)> = - preds.reduced_graph - .depth_traverse(index, INCOMING) - .map(|index| preds.reduced_graph.node_data(index)) - .filter(|dep_node| HashContext::is_hashable(dep_node)) - .map(|dep_node| { - let hash_dep_node = dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))) - .unwrap(); - let hash = preds.hashes[dep_node]; - (hash_dep_node, hash) - }) - .collect(); - - hashes.sort(); - let mut state = IchHasher::new(); - hashes.hash(&mut state); - let hash = state.finish(); - - debug!("save: metadata hash for {:?} is {}", def_id, hash); - - if tcx.sess.opts.debugging_opts.incremental_dump_hash { - println!("metadata hash for {:?} is {}", def_id, hash); - for pred_index in preds.reduced_graph.depth_traverse(index, INCOMING) { - let dep_node = preds.reduced_graph.node_data(pred_index); - if HashContext::is_hashable(&dep_node) { - println!("metadata hash for {:?} depends on {:?} with hash {}", - def_id, dep_node, preds.hashes[dep_node]); - } - } - } - - serialized_hashes.hashes.push(SerializedMetadataHash { - def_index: def_id.index, - hash: hash, - }); - } - if tcx.sess.opts.debugging_opts.query_dep_graph { for serialized_hash in &serialized_hashes.hashes { let def_id = DefId::local(serialized_hash.def_index); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 37984e4c3718f..3239dfb937b5e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -14,8 +14,9 @@ use locator; use schema; use rustc::dep_graph::DepTrackingMapConfig; -use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate}; -use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; +use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, + ExternCrate, NativeLibrary, LinkMeta, + LinkagePreference, LoadedMacro, EncodedMetadata}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; use rustc::session::Session; @@ -498,7 +499,8 @@ impl CrateStore for cstore::CStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec + reachable: &NodeSet) + -> EncodedMetadata { encoder::encode_metadata(tcx, self, link_meta, reachable) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a74ce3f650226..ffe68094c6afc 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -12,10 +12,10 @@ use cstore; use index::Index; use schema::*; -use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary}; +use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, + EncodedMetadata, EncodedMetadataHash}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; -use rustc::ich; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; use rustc::mir; @@ -56,7 +56,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, - pub metadata_hashes: Vec<(DefIndex, ich::Fingerprint)>, + pub metadata_hashes: Vec, } macro_rules! encoder_methods { @@ -240,13 +240,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { + debug!("EntryBuilder::encode_item_variances({:?})", def_id); let tcx = self.tcx; self.lazy_seq_from_slice(&tcx.item_variances(def_id)) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(&tcx.item_type(def_id)) + let ty = tcx.item_type(def_id); + debug!("EntryBuilder::encode_item_type({:?}) => {:?}", def_id, ty); + self.lazy(&ty) } /// Encode data for the given variant of the given ADT. The @@ -261,6 +264,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let def = tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; let def_id = variant.did; + debug!("EntryBuilder::encode_enum_variant_info({:?})", def_id); let data = VariantData { ctor_kind: variant.ctor_kind, @@ -307,6 +311,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { -> Entry<'tcx> { let tcx = self.tcx; let def_id = tcx.hir.local_def_id(id); + debug!("EntryBuilder::encode_info_for_mod({:?})", def_id); let data = ModData { reexports: match tcx.export_map.get(&id) { @@ -370,6 +375,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let field = &variant.fields[field_index]; let def_id = field.did; + debug!("EntryBuilder::encode_field({:?})", def_id); + let variant_id = tcx.hir.as_local_node_id(variant.did).unwrap(); let variant_data = tcx.hir.expect_variant_data(variant_id); @@ -394,6 +401,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> { + debug!("EntryBuilder::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; let variant = tcx.lookup_adt_def(adt_def_id).struct_variant(); @@ -436,16 +444,19 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_generics(&mut self, def_id: DefId) -> Lazy { + debug!("EntryBuilder::encode_generics({:?})", def_id); let tcx = self.tcx; self.lazy(tcx.item_generics(def_id)) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { + debug!("EntryBuilder::encode_predicates({:?})", def_id); let tcx = self.tcx; self.lazy(&tcx.item_predicates(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_trait_item({:?})", def_id); let tcx = self.tcx; let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); @@ -528,6 +539,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_impl_item({:?})", def_id); let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let ast_item = self.tcx.hir.expect_impl_item(node_id); let impl_item = self.tcx.associated_item(def_id); @@ -614,11 +626,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_mir(&mut self, def_id: DefId) -> Option>> { + debug!("EntryBuilder::encode_mir({:?})", def_id); self.tcx.maps.mir.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow())) } // Encodes the inherent implementations of a structure, enumeration, or trait. fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq { + debug!("EntryBuilder::encode_inherent_implementations({:?})", def_id); match self.tcx.maps.inherent_impls.borrow().get(&def_id) { None => LazySeq::empty(), Some(implementations) => { @@ -631,18 +645,19 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_stability(&mut self, def_id: DefId) -> Option> { + debug!("EntryBuilder::encode_stability({:?})", def_id); self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab)) } fn encode_deprecation(&mut self, def_id: DefId) -> Option> { + debug!("EntryBuilder::encode_deprecation({:?})", def_id); self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr)) } fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> { let tcx = self.tcx; - debug!("encoding info for item at {}", - tcx.sess.codemap().span_to_string(item.span)); + debug!("EntryBuilder::encode_info_for_item({:?})", def_id); let kind = match item.node { hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic, @@ -956,7 +971,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { -> Entry<'tcx> { let tcx = self.tcx; - debug!("writing foreign item {}", tcx.node_path_str(nitem.id)); + debug!("EntryBuilder::encode_info_for_foreign_item({:?})", def_id); let kind = match nitem.node { hir::ForeignItemFn(_, ref names, _) => { @@ -1065,6 +1080,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty_param(&mut self, (def_id, Untracked(has_default)): (DefId, Untracked)) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_ty_param({:?})", def_id); let tcx = self.tcx; Entry { kind: EntryKind::Type, @@ -1091,6 +1107,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_anon_ty({:?})", def_id); let tcx = self.tcx; Entry { kind: EntryKind::Type, @@ -1113,6 +1130,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_closure({:?})", def_id); let tcx = self.tcx; let data = ClosureData { @@ -1141,6 +1159,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { + // NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because + // we really on the HashStable specialization for [Attribute] + // to properly filter things out. self.lazy_seq_from_slice(attrs) } } @@ -1442,14 +1463,15 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, link_meta: &LinkMeta, exported_symbols: &NodeSet) - -> Vec { + -> EncodedMetadata +{ let mut cursor = Cursor::new(vec![]); cursor.write_all(METADATA_HEADER).unwrap(); // Will be filed with the root position after encoding everything. cursor.write_all(&[0, 0, 0, 0]).unwrap(); - let root = { + let (root, metadata_hashes) = { let mut ecx = EncodeContext { opaque: opaque::Encoder::new(&mut cursor), tcx: tcx, @@ -1467,7 +1489,8 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Encode all the entries and extra information in the crate, // culminating in the `CrateRoot` which points to all of it. - ecx.encode_crate_root() + let root = ecx.encode_crate_root(); + (root, ecx.metadata_hashes) }; let mut result = cursor.into_inner(); @@ -1479,7 +1502,10 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result[header + 2] = (pos >> 8) as u8; result[header + 3] = (pos >> 0) as u8; - result + EncodedMetadata { + raw_data: result, + hashes: metadata_hashes, + } } pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions { diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 389ada12da81e..01f948866b850 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -62,16 +62,16 @@ use schema::*; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ich::{StableHashingContext, Fingerprint}; +use rustc::middle::cstore::EncodedMetadataHash; use rustc::ty::TyCtxt; use syntax::ast; use std::ops::{Deref, DerefMut}; +use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_serialize::Encodable; -use rustc::dep_graph::DepNode; - /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { @@ -123,20 +123,36 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { data: DATA) where DATA: DepGraphRead { - let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); - data.read(self.tcx); - assert!(id.is_local()); let tcx: TyCtxt<'b, 'tcx, 'tcx> = self.ecx.tcx; + + // We don't track this since we are explicitly computing the incr. comp. + // hashes anyway. In theory we could do some tracking here and use it to + // avoid rehashing things (and instead cache the hashes) but it's + // unclear whether that would be a win since hashing is cheap enough. + let _task = tcx.dep_graph.in_ignore(); + + let compute_ich = (tcx.sess.opts.debugging_opts.query_dep_graph || + tcx.sess.opts.debugging_opts.incremental_cc) && + tcx.sess.opts.build_dep_graph(); + let ecx: &'x mut EncodeContext<'b, 'tcx> = &mut *self.ecx; let mut entry_builder = EntryBuilder { tcx: tcx, ecx: ecx, - hasher: StableHasher::new(), - hcx: StableHashingContext::new(tcx), + hcx: if compute_ich { + Some((StableHashingContext::new(tcx), StableHasher::new())) + } else { + None + } }; let entry = op(&mut entry_builder, data); + + if let Some((ref mut hcx, ref mut hasher)) = entry_builder.hcx { + entry.hash_stable(hcx, hasher); + } + let entry = entry_builder.ecx.lazy(&entry); entry_builder.finish(id); self.items.record(id, entry); @@ -245,21 +261,28 @@ impl DepGraphRead for FromId { pub struct EntryBuilder<'a, 'b: 'a, 'tcx: 'b> { pub tcx: TyCtxt<'b, 'tcx, 'tcx>, ecx: &'a mut EncodeContext<'b, 'tcx>, - hasher: StableHasher, - hcx: StableHashingContext<'b, 'tcx>, + hcx: Option<(StableHashingContext<'b, 'tcx>, StableHasher)>, } impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { pub fn finish(self, def_id: DefId) { - let hash = self.hasher.finish(); - self.ecx.metadata_hashes.push((def_id.index, hash)); + if let Some((_, hasher)) = self.hcx { + let hash = hasher.finish(); + self.ecx.metadata_hashes.push(EncodedMetadataHash { + def_index: def_id.index, + hash: hash, + }); + } } pub fn lazy(&mut self, value: &T) -> Lazy where T: Encodable + HashStable> { - value.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + value.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy(value) } @@ -267,22 +290,58 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { where I: IntoIterator, T: Encodable + HashStable> { - let items: Vec = iter.into_iter().collect(); - items.hash_stable(&mut self.hcx, &mut self.hasher); - self.ecx.lazy_seq(items) + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + let iter = iter.into_iter(); + let (lower_bound, upper_bound) = iter.size_hint(); + + if upper_bound == Some(lower_bound) { + lower_bound.hash_stable(hcx, hasher); + let mut num_items_hashed = 0; + let ret = self.ecx.lazy_seq(iter.inspect(|item| { + item.hash_stable(hcx, hasher); + num_items_hashed += 1; + })); + + // Sometimes items in a sequence are filtered out without being + // hashed (e.g. for &[ast::Attribute]) and this code path cannot + // handle that correctly, so we want to make sure we didn't hit + // it by accident. + if lower_bound != num_items_hashed { + bug!("Hashed a different number of items ({}) than expected ({})", + num_items_hashed, + lower_bound); + } + debug!("metadata-hash: {:?}", hasher); + ret + } else { + // Collect into a vec so we know the length of the sequence + let items: AccumulateVec<[T; 32]> = iter.collect(); + items.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + self.ecx.lazy_seq(items) + } + } else { + self.ecx.lazy_seq(iter) + } } pub fn lazy_seq_from_slice(&mut self, slice: &[T]) -> LazySeq where T: Encodable + HashStable> { - slice.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + slice.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy_seq_ref(slice.iter()) } pub fn lazy_seq_ref_from_slice(&mut self, slice: &[&T]) -> LazySeq where T: Encodable + HashStable> { - slice.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + slice.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy_seq_ref(slice.iter().map(|x| *x)) } } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 6ffa31c072709..53d6a9ec10df2 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -14,6 +14,7 @@ use index; use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; +use rustc::ich::StableHashingContext; use rustc::middle::const_val::ConstVal; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; @@ -27,6 +28,7 @@ use syntax::symbol::Symbol; use syntax_pos::{self, Span}; use std::marker::PhantomData; +use std::mem; use rustc_data_structures::stable_hasher::{StableHasher, HashStable, StableHasherResult}; @@ -107,8 +109,8 @@ impl HashStable for Lazy { fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // There's nothing to do. Whatever got encoded within this Lazy<> - // wrapper has already been hashed. + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. } } @@ -164,8 +166,8 @@ impl HashStable for LazySeq { fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // There's nothing to do. Whatever got encoded within this Lazy<> - // wrapper has already been hashed. + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. } } @@ -240,6 +242,23 @@ pub struct Entry<'tcx> { pub mir: Option>>, } +impl_stable_hash_for!(struct Entry<'tcx> { + kind, + visibility, + span, + attributes, + children, + stability, + deprecation, + ty, + inherent_impls, + variances, + generics, + predicates, + ast, + mir +}); + #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub enum EntryKind<'tcx> { Const(u8), @@ -267,6 +286,69 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer, u8), } +impl<'a, 'tcx> HashStable> for EntryKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + EntryKind::ImmStatic | + EntryKind::MutStatic | + EntryKind::ForeignImmStatic | + EntryKind::ForeignMutStatic | + EntryKind::ForeignMod | + EntryKind::Field | + EntryKind::Type => { + // Nothing else to hash here. + } + EntryKind::Const(qualif) => { + qualif.hash_stable(hcx, hasher); + } + EntryKind::Enum(ref repr_options) => { + repr_options.hash_stable(hcx, hasher); + } + EntryKind::Variant(ref variant_data) => { + variant_data.hash_stable(hcx, hasher); + } + EntryKind::Struct(ref variant_data, ref repr_options) | + EntryKind::Union(ref variant_data, ref repr_options) => { + variant_data.hash_stable(hcx, hasher); + repr_options.hash_stable(hcx, hasher); + } + EntryKind::Fn(ref fn_data) | + EntryKind::ForeignFn(ref fn_data) => { + fn_data.hash_stable(hcx, hasher); + } + EntryKind::Mod(ref mod_data) => { + mod_data.hash_stable(hcx, hasher); + } + EntryKind::MacroDef(ref macro_def) => { + macro_def.hash_stable(hcx, hasher); + } + EntryKind::Closure(closure_data) => { + closure_data.hash_stable(hcx, hasher); + } + EntryKind::Trait(ref trait_data) => { + trait_data.hash_stable(hcx, hasher); + } + EntryKind::DefaultImpl(ref impl_data) | + EntryKind::Impl(ref impl_data) => { + impl_data.hash_stable(hcx, hasher); + } + EntryKind::Method(ref method_data) => { + method_data.hash_stable(hcx, hasher); + } + EntryKind::AssociatedType(associated_container) => { + associated_container.hash_stable(hcx, hasher); + } + EntryKind::AssociatedConst(associated_container, qualif) => { + associated_container.hash_stable(hcx, hasher); + qualif.hash_stable(hcx, hasher); + } + } + } +} + #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { pub reexports: LazySeq, diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 66380079a8b29..0ffa7a79408e1 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -443,7 +443,10 @@ fn archive_config<'a>(sess: &'a Session, } fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: &Path) { - let result = fs::File::create(out_filename).and_then(|mut f| f.write_all(&trans.metadata)); + let result = fs::File::create(out_filename).and_then(|mut f| { + f.write_all(&trans.metadata.raw_data) + }); + if let Err(e) = result { sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 574b345218be9..f76e816bcf0c9 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -36,6 +36,7 @@ use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; +use middle::cstore::EncodedMetadata; use rustc::ty::{self, Ty, TyCtxt}; use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; @@ -724,7 +725,8 @@ fn contains_null(s: &str) -> bool { } fn write_metadata(cx: &SharedCrateContext, - exported_symbols: &NodeSet) -> Vec { + exported_symbols: &NodeSet) + -> EncodedMetadata { use flate; #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -748,7 +750,10 @@ fn write_metadata(cx: &SharedCrateContext, }).max().unwrap(); if kind == MetadataKind::None { - return Vec::new(); + return EncodedMetadata { + raw_data: vec![], + hashes: vec![], + }; } let cstore = &cx.tcx().sess.cstore; @@ -761,7 +766,7 @@ fn write_metadata(cx: &SharedCrateContext, assert!(kind == MetadataKind::Compressed); let mut compressed = cstore.metadata_encoding_version().to_vec(); - compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); + compressed.extend_from_slice(&flate::deflate_bytes(&metadata.raw_data)); let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 5c3b17c889760..628d46f8e7059 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -168,7 +168,7 @@ pub struct CrateTranslation { pub modules: Vec, pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, - pub metadata: Vec, + pub metadata: middle::cstore::EncodedMetadata, pub exported_symbols: back::symbol_export::ExportedSymbols, pub no_builtins: bool, pub windows_subsystem: Option, diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index 048ccb529a24f..37c6ef58f5e56 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -38,8 +38,13 @@ enum EnumVisibility { A } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -pub enum EnumVisibility { A } +pub enum EnumVisibility { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + A +} @@ -56,7 +61,10 @@ enum EnumChangeNameCStyleVariant { #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeNameCStyleVariant { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] Variant1, + #[rustc_metadata_clean(cfg="cfail3")] Variant2Changed, } @@ -259,10 +267,13 @@ enum EnumChangeFieldTypeTupleStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldTypeTupleStyleVariant { - Variant1(u32, u64), + Variant1(u32, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u64), } @@ -277,11 +288,16 @@ enum EnumChangeFieldTypeStructStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldTypeStructStyleVariant { Variant1, - Variant2 { a: u32, b: u64 }, + Variant2 { + a: u32, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + b: u64 + }, } @@ -312,10 +328,16 @@ enum EnumChangeOrderTupleStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeOrderTupleStyleVariant { - Variant1(u64, u32), + Variant1( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u64, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u32), } @@ -611,11 +633,23 @@ enum EnumSwapUsageTypeParameters { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumSwapUsageTypeParameters { - Variant1 { a: B }, - Variant2 { a: A }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: B + }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant2 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: A + }, } @@ -630,11 +664,23 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumSwapUsageLifetimeParameters<'a, 'b> { - Variant1 { a: &'b u32 }, - Variant2 { b: &'a u32 }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: &'b u32 + }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant2 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + b: &'a u32 + }, } @@ -653,10 +699,16 @@ mod change_field_type_indirectly_tuple_style { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum TupleStyle { - Variant1(FieldType) + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + FieldType + ) } } @@ -671,10 +723,16 @@ mod change_field_type_indirectly_struct_style { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum StructStyle { - Variant1 { a: FieldType } + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: FieldType + } } } diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs index 03e621fedbeb4..1d26e6c07d15b 100644 --- a/src/test/incremental/hashes/extern_mods.rs +++ b/src/test/incremental/hashes/extern_mods.rs @@ -53,9 +53,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_parameter_name(d: i64) -> i32; } @@ -70,9 +72,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_parameter_type(c: i32) -> i32; } @@ -87,9 +91,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_return_type(c: i32) -> i8; } @@ -104,9 +110,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn add_parameter(c: i32, d: i32) -> i32; } @@ -121,9 +129,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn add_return_type(c: i32) -> i32; } @@ -138,9 +148,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn make_function_variadic(c: i32, ...); } @@ -155,9 +167,11 @@ extern "C" { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern "rust-call" { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_calling_convention(c: i32); } @@ -172,9 +186,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn make_function_public(c: i32); } @@ -246,9 +262,11 @@ mod indirectly_change_parameter_type { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn indirectly_change_parameter_type(c: c_int); } } @@ -264,9 +282,11 @@ mod indirectly_change_return_type { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn indirectly_change_return_type() -> c_int; } } diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index 93d94cd1a19c4..2fe3f0d5d1fe0 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -50,7 +50,7 @@ fn add_return_type() {} #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] // The type doesn't change, so metadata is the same #[rustc_metadata_clean(cfg="cfail3")] fn add_return_type() -> () {} @@ -154,7 +154,7 @@ fn lifetime_parameter() {} #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +// #[rustc_metadata_dirty(cfg="cfail2")] -- Unused lifetime params don't show up in the type? #[rustc_metadata_clean(cfg="cfail3")] fn lifetime_parameter<'a>() {} @@ -315,16 +315,16 @@ fn return_impl_trait() -> impl Clone { #[cfg(cfail1)] fn change_return_impl_trait() -> impl Clone { - 0 + 0u32 } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] // The actual type is the same, so: clean #[rustc_metadata_clean(cfg="cfail3")] fn change_return_impl_trait() -> impl Copy { - 0 + 0u32 } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index fd9ac61046e3a..899aefa24a033 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -107,7 +107,7 @@ impl Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -126,7 +126,7 @@ impl Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -171,7 +171,7 @@ impl Foo { impl Foo { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_method_to_impl1(&self) { } @@ -219,9 +219,7 @@ impl Foo { #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_dirty(label="HirBody", cfg="cfail2")] #[rustc_clean(label="HirBody", cfg="cfail3")] - // At the moment we explicitly ignore argument names in metadata, since they - // are not used in downstream crates (except in rustdoc) - #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_parameter_name(&self, b: i64) { } } @@ -287,9 +285,7 @@ impl Foo { #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_dirty(label="HirBody", cfg="cfail2")] #[rustc_clean(label="HirBody", cfg="cfail3")] - // At the moment we explicitly ignore argument names in metadata, since they - // are not used in downstream crates (except in rustdoc) - #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_parameter_order(&self, b: i64, a: i64) { } } @@ -373,7 +369,7 @@ impl Foo { impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] // Apparently unused lifetimes don't show up in the type. #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } @@ -544,7 +540,7 @@ impl Bar { impl Bar { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_impl_parameter(&self) { } } @@ -565,7 +561,7 @@ impl Bar { impl Bar { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_trait_bound_to_impl_parameter(&self) { } } diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs index 2d79987823f20..17a5dc1678367 100644 --- a/src/test/incremental/hashes/struct_defs.rs +++ b/src/test/incremental/hashes/struct_defs.rs @@ -62,9 +62,13 @@ struct TupleStructFieldType(i32); #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct TupleStructFieldType(u32); +struct TupleStructFieldType( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u32 +); // Tuple Struct Add Field ------------------------------------------------------ @@ -77,7 +81,13 @@ struct TupleStructAddField(i32); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct TupleStructAddField(i32, u32); +struct TupleStructAddField( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + i32, + #[rustc_metadata_clean(cfg="cfail3")] + u32 +); // Tuple Struct Field Visibility ----------------------------------------------- @@ -101,9 +111,13 @@ struct RecordStructFieldType { x: f32 } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructFieldType { x: u64 } +struct RecordStructFieldType { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + x: u64 +} // Record Struct Field Name ---------------------------------------------------- @@ -129,7 +143,12 @@ struct RecordStructAddField { x: f32 } #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructAddField { x: f32, y: () } +struct RecordStructAddField { + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + x: f32, + #[rustc_metadata_clean(cfg="cfail3")] + y: () } // Record Struct Field Visibility ---------------------------------------------- @@ -142,7 +161,11 @@ struct RecordStructFieldVisibility { x: f32 } #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructFieldVisibility { pub x: f32 } +struct RecordStructFieldVisibility { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub x: f32 +} // Add Lifetime Parameter ------------------------------------------------------ @@ -168,7 +191,14 @@ struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddLifetimeParameterBound<'a, 'b: 'a>(&'a f32, &'b f64); +struct AddLifetimeParameterBound<'a, 'b: 'a>( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'a f32, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'b f64 +); #[cfg(cfail1)] struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); @@ -178,7 +208,13 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64) +struct AddLifetimeParameterBoundWhereClause<'a, 'b>( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'a f32, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'b f64) where 'b: 'a; @@ -192,7 +228,16 @@ struct AddTypeParameter(T1, T1); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameter(T1, T2); +struct AddTypeParameter( + // The field contains the parent's Generics, so it's dirty even though its + // type hasn't changed. + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T1, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T2 +); // Add Type Parameter Bound ---------------------------------------------------- @@ -205,7 +250,11 @@ struct AddTypeParameterBound(T); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameterBound(T); +struct AddTypeParameterBound( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T +); #[cfg(cfail1)] @@ -216,7 +265,11 @@ struct AddTypeParameterBoundWhereClause(T); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameterBoundWhereClause(T) where T: Sync; +struct AddTypeParameterBoundWhereClause( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T +) where T: Sync; // Empty struct ---------------------------------------------------------------- @@ -234,6 +287,7 @@ struct Visibility; #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub struct Visibility; @@ -252,9 +306,13 @@ mod tuple_struct_change_field_type_indirectly { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - struct TupleStruct(FieldType); + struct TupleStruct( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + FieldType + ); } @@ -267,9 +325,11 @@ mod record_struct_change_field_type_indirectly { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] struct RecordStruct { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] _x: FieldType } } diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 94698506ec53f..61a2be054a51a 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -100,7 +100,7 @@ trait TraitAddReturnType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -121,7 +121,7 @@ trait TraitChangeReturnType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -142,7 +142,7 @@ trait TraitAddParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -164,7 +164,7 @@ trait TraitChangeMethodParameterName { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. @@ -194,7 +194,7 @@ trait TraitChangeMethodParameterType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -215,7 +215,7 @@ trait TraitChangeMethodParameterTypeRef { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterTypeRef { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -236,7 +236,7 @@ trait TraitChangeMethodParametersOrder { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParametersOrder { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -257,9 +257,13 @@ trait TraitAddMethodDefaultImplementation { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddMethodDefaultImplementation { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] fn method() { } } @@ -293,7 +297,7 @@ trait TraitChangeModeSelfRefToMut { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeModeSelfRefToMut { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -335,7 +339,7 @@ trait TraitChangeModeSelfOwnToRef { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeModeSelfOwnToRef { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -356,7 +360,7 @@ trait TraitAddUnsafeModifier { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddUnsafeModifier { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -377,7 +381,7 @@ trait TraitAddExternModifier { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddExternModifier { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -398,7 +402,7 @@ trait TraitChangeExternCToRustIntrinsic { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeExternCToRustIntrinsic { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -419,7 +423,7 @@ trait TraitAddTypeParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddTypeParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -440,12 +444,12 @@ trait TraitAddLifetimeParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddLifetimeParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] // Unused lifetimes don't seem to show up in type? #[rustc_metadata_clean(cfg="cfail3")] fn method<'a>(); } @@ -465,7 +469,7 @@ trait TraitAddTraitBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddTraitBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -486,7 +490,7 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddBuiltinBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -507,7 +511,7 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -528,7 +532,7 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondTraitBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -549,7 +553,7 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -570,7 +574,7 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -585,7 +589,12 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { // Add associated type ------------------------------------------------------------ #[cfg(cfail1)] trait TraitAddAssociatedType { - fn mathod(); + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } #[cfg(not(cfail1))] @@ -596,7 +605,7 @@ trait TraitAddAssociatedType { trait TraitAddAssociatedType { type Associated; - fn mathod(); + fn method(); } @@ -606,9 +615,12 @@ trait TraitAddAssociatedType { trait TraitAddTraitBoundToAssociatedType { type Associated; - fn mathod(); + fn method(); } + +// Apparently the type bound contributes to the predicates of the trait, but +// does not change the associated item itself. #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] @@ -617,11 +629,11 @@ trait TraitAddTraitBoundToAssociatedType { trait TraitAddTraitBoundToAssociatedType { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] type Associated: ReferencedTrait0; - fn mathod(); + fn method(); } @@ -631,7 +643,7 @@ trait TraitAddTraitBoundToAssociatedType { trait TraitAddLifetimeBoundToAssociatedType<'a> { type Associated; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] @@ -642,11 +654,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { trait TraitAddLifetimeBoundToAssociatedType<'a> { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] type Associated: 'a; - fn mathod(); + fn method(); } @@ -656,18 +668,22 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { trait TraitAddDefaultToAssociatedType { type Associated; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddDefaultToAssociatedType { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] type Associated = ReferenceType0; - fn mathod(); + fn method(); } @@ -675,7 +691,7 @@ trait TraitAddDefaultToAssociatedType { // Add associated constant -------------------------------------------------------- #[cfg(cfail1)] trait TraitAddAssociatedConstant { - fn mathod(); + fn method(); } #[cfg(not(cfail1))] @@ -686,7 +702,7 @@ trait TraitAddAssociatedConstant { trait TraitAddAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } @@ -696,18 +712,26 @@ trait TraitAddAssociatedConstant { trait TraitAddInitializerToAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddInitializerToAssociatedConstant { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] const Value: u32 = 1; - fn mathod(); + #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } @@ -717,13 +741,13 @@ trait TraitAddInitializerToAssociatedConstant { trait TraitChangeTypeOfAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeTypeOfAssociatedConstant { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -732,7 +756,11 @@ trait TraitChangeTypeOfAssociatedConstant { #[rustc_metadata_clean(cfg="cfail3")] const Value: f64; - fn mathod(); + #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } @@ -1111,9 +1139,6 @@ trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } - -// EDIT: Some more cases ---------------------------------------------------------- - // Change return type of method indirectly by modifying a use statement------------ mod change_return_type_of_method_indirectly_use { #[cfg(cfail1)] @@ -1123,7 +1148,7 @@ mod change_return_type_of_method_indirectly_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1145,7 +1170,7 @@ mod change_method_parameter_type_indirectly_by_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeArgType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1167,7 +1192,7 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1190,7 +1215,7 @@ mod change_method_parameter_type_bound_indirectly_by_use_where { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameterWhere { #[rustc_dirty(label="Hir", cfg="cfail2")] diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs index 30e376f04fb87..06c8eb6a878f0 100644 --- a/src/test/incremental/hashes/trait_impls.rs +++ b/src/test/incremental/hashes/trait_impls.rs @@ -120,7 +120,7 @@ impl ChangeMethodBodyTraitInlined for Foo { #[rustc_metadata_clean(cfg="cfail3")] #[inline] fn method_name() { - () + panic!() } } @@ -144,7 +144,7 @@ pub trait ChangeMethodSelfnessTrait { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeMethodSelfnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -176,16 +176,14 @@ pub trait RemoveMethodSelfnessTrait { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl RemoveMethodSelfnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn method_name() { - () - } + fn method_name() {} } // Change Method Selfmutness ----------------------------------------------------------- @@ -208,16 +206,14 @@ pub trait ChangeMethodSelfmutnessTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeMethodSelfmutnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn method_name(&mut self) { - () - } + fn method_name(&mut self) {} } // Change item kind ----------------------------------------------------------- @@ -317,16 +313,20 @@ impl ChangeHasValueTrait for Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub trait ChangeHasValueTrait { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] fn method_name() { } } #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeHasValueTrait for Foo { fn method_name() { } @@ -346,32 +346,16 @@ impl AddDefaultTrait for Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl AddDefaultTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] default fn method_name() { } } -// Remove default - -pub trait RemoveDefaultTrait { - fn method_name(); -} - -#[cfg(cfail1)] -impl RemoveDefaultTrait for Foo { - default fn method_name() { } -} - -#[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] -#[rustc_metadata_clean(cfg="cfail3")] -impl RemoveDefaultTrait for Foo { - fn method_name() { } -} - // Add arguments #[cfg(cfail1)] @@ -392,7 +376,7 @@ pub trait AddArgumentTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl AddArgumentTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -422,7 +406,7 @@ pub trait ChangeArgumentTypeTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeArgumentTypeTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -504,7 +488,7 @@ impl AddLifetimeBoundToImplParameter for T { impl AddLifetimeBoundToImplParameter for T { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn id(self) -> Self { self } } @@ -529,7 +513,7 @@ impl AddTraitBoundToImplParameter for T { impl AddTraitBoundToImplParameter for T { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn id(self) -> Self { self } } diff --git a/src/test/incremental/unchecked_dirty_clean_metadata.rs b/src/test/incremental/unchecked_dirty_clean_metadata.rs index 4017b4d4ba9ae..917c2c9dbce4f 100644 --- a/src/test/incremental/unchecked_dirty_clean_metadata.rs +++ b/src/test/incremental/unchecked_dirty_clean_metadata.rs @@ -33,13 +33,3 @@ fn main() { } } -struct _Struct { - #[rustc_metadata_dirty(cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked #[rustc_dirty]/#[rustc_clean] attribute - _field1: i32, - - #[rustc_metadata_clean(cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked #[rustc_dirty]/#[rustc_clean] attribute - _field2: i32, -} -