From 5b66f27ed34849a849bd93ce662bffeec2e56947 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 17 Mar 2020 16:07:29 -0700 Subject: Use `const_eval_limit` instead of infinite loop detector --- src/librustc/mir/interpret/error.rs | 12 +++--- src/librustc_mir/const_eval/machine.rs | 67 ++++++++++------------------------ src/librustc_mir/interpret/memory.rs | 19 ---------- 3 files changed, 25 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 0b33408edf0..4b1fad5d0b3 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -565,8 +565,10 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { pub enum ResourceExhaustionInfo { /// The stack grew too big. StackFrameLimitReached, - /// The program ran into an infinite loop. - InfiniteLoop, + /// The program ran for too long. + /// + /// The exact limit is set by the `const_eval_limit` attribute. + TimeLimitReached, } impl fmt::Debug for ResourceExhaustionInfo { @@ -576,11 +578,7 @@ impl fmt::Debug for ResourceExhaustionInfo { StackFrameLimitReached => { write!(f, "reached the configured maximum number of stack frames") } - InfiniteLoop => write!( - f, - "duplicate interpreter state observed here, const evaluation will never \ - terminate" - ), + TimeLimitReached => write!(f, "exceeded interpreter time limit"), } } } diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index bb661d3d2a3..22b01be299b 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -3,7 +3,6 @@ use rustc::ty::layout::HasTyCtxt; use rustc::ty::{self, Ty}; use std::borrow::{Borrow, Cow}; use std::collections::hash_map::Entry; -use std::convert::TryFrom; use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; @@ -13,13 +12,13 @@ use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; use crate::interpret::{ - self, snapshot, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory, - MemoryKind, OpTy, PlaceTy, Pointer, Scalar, + self, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory, MemoryKind, OpTy, + PlaceTy, Pointer, Scalar, }; use super::error::*; -impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { +impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter> { /// Evaluate a const function where all arguments (if any) are zero-sized types. /// The evaluation is memoized thanks to the query system. /// @@ -86,22 +85,13 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { } } -/// The number of steps between loop detector snapshots. -/// Should be a power of two for performance reasons. -const DETECTOR_SNAPSHOT_PERIOD: isize = 256; - -// Extra machine state for CTFE, and the Machine instance -pub struct CompileTimeInterpreter<'mir, 'tcx> { - /// When this value is negative, it indicates the number of interpreter - /// steps *until* the loop detector is enabled. When it is positive, it is - /// the number of steps after the detector has been enabled modulo the loop - /// detector period. - pub(super) steps_since_detector_enabled: isize, - - pub(super) is_detector_enabled: bool, - - /// Extra state to detect loops. - pub(super) loop_detector: snapshot::InfiniteLoopDetector<'mir, 'tcx>, +/// Extra machine state for CTFE, and the Machine instance +pub struct CompileTimeInterpreter { + /// For now, the number of terminators that can be evaluated before we throw a resource + /// exhuastion error. + /// + /// Setting this to `0` disables the limit and allows the interpreter to run forever. + pub steps_remaining: usize, } #[derive(Copy, Clone, Debug)] @@ -110,16 +100,9 @@ pub struct MemoryExtra { pub(super) can_access_statics: bool, } -impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { +impl CompileTimeInterpreter { pub(super) fn new(const_eval_limit: usize) -> Self { - let steps_until_detector_enabled = - isize::try_from(const_eval_limit).unwrap_or(std::isize::MAX); - - CompileTimeInterpreter { - loop_detector: Default::default(), - steps_since_detector_enabled: -steps_until_detector_enabled, - is_detector_enabled: const_eval_limit != 0, - } + CompileTimeInterpreter { steps_remaining: const_eval_limit } } } @@ -173,8 +156,7 @@ impl interpret::AllocMap for FxHashMap { } } -crate type CompileTimeEvalContext<'mir, 'tcx> = - InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; +crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter>; impl interpret::MayLeak for ! { #[inline(always)] @@ -184,7 +166,7 @@ impl interpret::MayLeak for ! { } } -impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { +impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter { type MemoryKinds = !; type PointerTag = (); type ExtraFnVal = !; @@ -346,26 +328,17 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if !ecx.machine.is_detector_enabled { + // The step limit has already been hit in a previous call to `before_terminator`. + if ecx.machine.steps_remaining == 0 { return Ok(()); } - { - let steps = &mut ecx.machine.steps_since_detector_enabled; - - *steps += 1; - if *steps < 0 { - return Ok(()); - } - - *steps %= DETECTOR_SNAPSHOT_PERIOD; - if *steps != 0 { - return Ok(()); - } + ecx.machine.steps_remaining -= 1; + if ecx.machine.steps_remaining == 0 { + throw_exhaust!(TimeLimitReached) } - let span = ecx.frame().span; - ecx.machine.loop_detector.observe_and_analyze(*ecx.tcx, span, &ecx.memory, &ecx.stack[..]) + Ok(()) } #[inline(always)] diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 82a467c7ba9..03be71f6174 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -112,25 +112,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> } } -// FIXME: Really we shouldn't clone memory, ever. Snapshot machinery should instead -// carefully copy only the reachable parts. -impl<'mir, 'tcx, M> Clone for Memory<'mir, 'tcx, M> -where - M: Machine<'mir, 'tcx, PointerTag = (), AllocExtra = ()>, - M::MemoryExtra: Copy, - M::MemoryMap: AllocMap, Allocation)>, -{ - fn clone(&self) -> Self { - Memory { - alloc_map: self.alloc_map.clone(), - extra_fn_ptr_map: self.extra_fn_ptr_map.clone(), - dead_alloc_map: self.dead_alloc_map.clone(), - extra: self.extra, - tcx: self.tcx, - } - } -} - impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { pub fn new(tcx: TyCtxtAt<'tcx>, extra: M::MemoryExtra) -> Self { Memory { -- cgit 1.4.1-3-g733a5 From e15c48672850c0a0b7936df3dfa861bfa34db4bd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 17 Mar 2020 16:08:13 -0700 Subject: Remove infinite loop detector --- src/librustc_mir/interpret/mod.rs | 1 - src/librustc_mir/interpret/snapshot.rs | 420 --------------------------------- 2 files changed, 421 deletions(-) delete mode 100644 src/librustc_mir/interpret/snapshot.rs (limited to 'src') diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index c3fd9682765..3063a99886b 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -9,7 +9,6 @@ mod memory; mod operand; mod operator; mod place; -pub(crate) mod snapshot; // for const_eval mod step; mod terminator; mod traits; diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs deleted file mode 100644 index ee45179fd8b..00000000000 --- a/src/librustc_mir/interpret/snapshot.rs +++ /dev/null @@ -1,420 +0,0 @@ -//! This module contains the machinery necessary to detect infinite loops -//! during const-evaluation by taking snapshots of the state of the interpreter -//! at regular intervals. - -// This lives in `interpret` because it needs access to all sots of private state. However, -// it is not used by the general miri engine, just by CTFE. - -use std::hash::{Hash, Hasher}; - -use rustc::ich::StableHashingContextProvider; -use rustc::mir; -use rustc::mir::interpret::{ - AllocId, Allocation, InterpResult, Pointer, Relocations, Scalar, UndefMask, -}; - -use rustc::ty::layout::{Align, Size}; -use rustc::ty::{self, TyCtxt}; -use rustc_ast::ast::Mutability; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_index::vec::IndexVec; -use rustc_macros::HashStable; -use rustc_span::source_map::Span; - -use super::eval_context::{LocalState, StackPopCleanup}; -use super::{ - Frame, Immediate, LocalValue, MemPlace, MemPlaceMeta, Memory, Operand, Place, ScalarMaybeUndef, -}; -use crate::const_eval::CompileTimeInterpreter; - -#[derive(Default)] -pub(crate) struct InfiniteLoopDetector<'mir, 'tcx> { - /// The set of all `InterpSnapshot` *hashes* observed by this detector. - /// - /// When a collision occurs in this table, we store the full snapshot in - /// `snapshots`. - hashes: FxHashSet, - - /// The set of all `InterpSnapshot`s observed by this detector. - /// - /// An `InterpSnapshot` will only be fully cloned once it has caused a - /// collision in `hashes`. As a result, the detector must observe at least - /// *two* full cycles of an infinite loop before it triggers. - snapshots: FxHashSet>, -} - -impl<'mir, 'tcx> InfiniteLoopDetector<'mir, 'tcx> { - pub fn observe_and_analyze( - &mut self, - tcx: TyCtxt<'tcx>, - span: Span, - memory: &Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - stack: &[Frame<'mir, 'tcx>], - ) -> InterpResult<'tcx, ()> { - // Compute stack's hash before copying anything - let mut hcx = tcx.get_stable_hashing_context(); - let mut hasher = StableHasher::new(); - stack.hash_stable(&mut hcx, &mut hasher); - let hash = hasher.finish::(); - - // Check if we know that hash already - if self.hashes.is_empty() { - // FIXME(#49980): make this warning a lint - tcx.sess.span_warn( - span, - "Constant evaluating a complex constant, this might take some time", - ); - } - if self.hashes.insert(hash) { - // No collision - return Ok(()); - } - - // We need to make a full copy. NOW things that to get really expensive. - info!("snapshotting the state of the interpreter"); - - if self.snapshots.insert(InterpSnapshot::new(memory, stack)) { - // Spurious collision or first cycle - return Ok(()); - } - - // Second cycle - throw_exhaust!(InfiniteLoop) - } -} - -trait SnapshotContext<'a> { - fn resolve(&'a self, id: &AllocId) -> Option<&'a Allocation>; -} - -/// Taking a snapshot of the evaluation context produces a view of -/// the state of the interpreter that is invariant to `AllocId`s. -trait Snapshot<'a, Ctx: SnapshotContext<'a>> { - type Item; - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item; -} - -macro_rules! __impl_snapshot_field { - ($field:ident, $ctx:expr) => { - $field.snapshot($ctx) - }; - ($field:ident, $ctx:expr, $delegate:expr) => { - $delegate - }; -} - -// This assumes the type has two type parameters, first for the tag (set to `()`), -// then for the id -macro_rules! impl_snapshot_for { - (enum $enum_name:ident { - $( $variant:ident $( ( $($field:ident $(-> $delegate:expr)?),* ) )? ),* $(,)? - }) => { - - impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name - where Ctx: self::SnapshotContext<'a>, - { - type Item = $enum_name<(), AllocIdSnapshot<'a>>; - - #[inline] - fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item { - match *self { - $( - $enum_name::$variant $( ( $(ref $field),* ) )? => { - $enum_name::$variant $( - ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* ) - )? - } - )* - } - } - } - }; - - (struct $struct_name:ident { $($field:ident $(-> $delegate:expr)?),* $(,)? }) => { - impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name - where Ctx: self::SnapshotContext<'a>, - { - type Item = $struct_name<(), AllocIdSnapshot<'a>>; - - #[inline] - fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item { - let $struct_name { - $(ref $field),* - } = *self; - - $struct_name { - $( $field: __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* - } - } - } - }; -} - -impl<'a, Ctx, T> Snapshot<'a, Ctx> for Option -where - Ctx: SnapshotContext<'a>, - T: Snapshot<'a, Ctx>, -{ - type Item = Option<>::Item>; - - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - match self { - Some(x) => Some(x.snapshot(ctx)), - None => None, - } - } -} - -#[derive(Eq, PartialEq)] -struct AllocIdSnapshot<'a>(Option>); - -impl<'a, Ctx> Snapshot<'a, Ctx> for AllocId -where - Ctx: SnapshotContext<'a>, -{ - type Item = AllocIdSnapshot<'a>; - - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - AllocIdSnapshot(ctx.resolve(self).map(|alloc| alloc.snapshot(ctx))) - } -} - -impl_snapshot_for!(struct Pointer { - alloc_id, - offset -> *offset, // just copy offset verbatim - tag -> *tag, // just copy tag -}); - -impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar -where - Ctx: SnapshotContext<'a>, -{ - type Item = Scalar<(), AllocIdSnapshot<'a>>; - - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - match self { - Scalar::Ptr(p) => Scalar::Ptr(p.snapshot(ctx)), - Scalar::Raw { size, data } => Scalar::Raw { data: *data, size: *size }, - } - } -} - -impl_snapshot_for!( - enum ScalarMaybeUndef { - Scalar(s), - Undef, - } -); - -impl_snapshot_for!( - enum MemPlaceMeta { - Meta(s), - None, - Poison, - } -); - -impl_snapshot_for!(struct MemPlace { - ptr, - meta, - align -> *align, // just copy alignment verbatim -}); - -impl<'a, Ctx> Snapshot<'a, Ctx> for Place -where - Ctx: SnapshotContext<'a>, -{ - type Item = Place<(), AllocIdSnapshot<'a>>; - - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - match self { - Place::Ptr(p) => Place::Ptr(p.snapshot(ctx)), - - Place::Local { frame, local } => Place::Local { frame: *frame, local: *local }, - } - } -} - -impl_snapshot_for!( - enum Immediate { - Scalar(s), - ScalarPair(s, t), - } -); - -impl_snapshot_for!( - enum Operand { - Immediate(v), - Indirect(m), - } -); - -impl_snapshot_for!( - enum LocalValue { - Dead, - Uninitialized, - Live(v), - } -); - -impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations -where - Ctx: SnapshotContext<'a>, -{ - type Item = Relocations<(), AllocIdSnapshot<'a>>; - - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - Relocations::from_presorted( - self.iter().map(|(size, ((), id))| (*size, ((), id.snapshot(ctx)))).collect(), - ) - } -} - -#[derive(Eq, PartialEq)] -struct AllocationSnapshot<'a> { - bytes: &'a [u8], - relocations: Relocations<(), AllocIdSnapshot<'a>>, - undef_mask: &'a UndefMask, - align: &'a Align, - size: &'a Size, - mutability: &'a Mutability, -} - -impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation -where - Ctx: SnapshotContext<'a>, -{ - type Item = AllocationSnapshot<'a>; - - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - let Allocation { size, align, mutability, extra: (), .. } = self; - - let all_bytes = 0..self.len(); - // This 'inspect' is okay since following access respects undef and relocations. This does - // influence interpreter exeuction, but only to detect the error of cycles in evaluation - // dependencies. - let bytes = self.inspect_with_undef_and_ptr_outside_interpreter(all_bytes); - - let undef_mask = self.undef_mask(); - let relocations = self.relocations(); - - AllocationSnapshot { - bytes, - undef_mask, - align, - size, - mutability, - relocations: relocations.snapshot(ctx), - } - } -} - -#[derive(Eq, PartialEq)] -struct FrameSnapshot<'a, 'tcx> { - instance: ty::Instance<'tcx>, - span: Span, - return_to_block: &'a StackPopCleanup, - return_place: Option>>, - locals: IndexVec>>, - block: Option, - stmt: usize, -} - -impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx> -where - Ctx: SnapshotContext<'a>, -{ - type Item = FrameSnapshot<'a, 'tcx>; - - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - let Frame { - body: _, - instance, - span, - return_to_block, - return_place, - locals, - block, - stmt, - extra: _, - } = self; - - FrameSnapshot { - instance: *instance, - span: *span, - return_to_block, - block: *block, - stmt: *stmt, - return_place: return_place.map(|r| r.snapshot(ctx)), - locals: locals.iter().map(|local| local.snapshot(ctx)).collect(), - } - } -} - -impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx> -where - Ctx: SnapshotContext<'a>, -{ - type Item = LocalValue<(), AllocIdSnapshot<'a>>; - - fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - let LocalState { value, layout: _ } = self; - value.snapshot(ctx) - } -} - -impl<'b, 'mir, 'tcx> SnapshotContext<'b> - for Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> -{ - fn resolve(&'b self, id: &AllocId) -> Option<&'b Allocation> { - self.get_raw(*id).ok() - } -} - -/// The virtual machine state during const-evaluation at a given point in time. -/// We assume the `CompileTimeInterpreter` has no interesting extra state that -/// is worth considering here. -#[derive(HashStable)] -struct InterpSnapshot<'mir, 'tcx> { - // Not hashing memory: Avoid hashing memory all the time during execution - #[stable_hasher(ignore)] - memory: Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - stack: Vec>, -} - -impl InterpSnapshot<'mir, 'tcx> { - fn new( - memory: &Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - stack: &[Frame<'mir, 'tcx>], - ) -> Self { - InterpSnapshot { memory: memory.clone(), stack: stack.into() } - } - - // Used to compare two snapshots - fn snapshot(&'b self) -> Vec> { - // Start with the stack, iterate and recursively snapshot - self.stack.iter().map(|frame| frame.snapshot(&self.memory)).collect() - } -} - -impl<'mir, 'tcx> Hash for InterpSnapshot<'mir, 'tcx> { - fn hash(&self, state: &mut H) { - // Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2) - let mut hcx = self.memory.tcx.get_stable_hashing_context(); - let mut hasher = StableHasher::new(); - self.hash_stable(&mut hcx, &mut hasher); - hasher.finish::().hash(state) - } -} - -impl<'mir, 'tcx> Eq for InterpSnapshot<'mir, 'tcx> {} - -impl<'mir, 'tcx> PartialEq for InterpSnapshot<'mir, 'tcx> { - fn eq(&self, other: &Self) -> bool { - // FIXME: This looks to be a *ridiculously expensive* comparison operation. - // Doesn't this make tons of copies? Either `snapshot` is very badly named, - // or it does! - self.snapshot() == other.snapshot() - } -} -- cgit 1.4.1-3-g733a5 From 044dc6e8dd435eb9c3b6f1dc0c85d0a6e70dae82 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 17 Mar 2020 16:08:28 -0700 Subject: Update const-eval tests --- src/test/ui/consts/const-eval/infinite_loop.rs | 1 - src/test/ui/consts/const-eval/infinite_loop.stderr | 21 ++++------------- src/test/ui/consts/const-eval/issue-52475.rs | 1 - src/test/ui/consts/const-eval/issue-52475.stderr | 19 +++------------ .../const_limit/const_eval_limit_not_reached.rs | 22 +++++++++++------- .../consts/const_limit/const_eval_limit_reached.rs | 27 ++++++++++------------ .../const_limit/const_eval_limit_reached.stderr | 25 ++++++++++---------- 7 files changed, 46 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/test/ui/consts/const-eval/infinite_loop.rs b/src/test/ui/consts/const-eval/infinite_loop.rs index af5e7658d48..c8de259354e 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.rs +++ b/src/test/ui/consts/const-eval/infinite_loop.rs @@ -2,7 +2,6 @@ fn main() { // Tests the Collatz conjecture with an incorrect base case (0 instead of 1). // The value of `n` will loop indefinitely (4 - 2 - 1 - 4). let _ = [(); { - //~^ WARNING Constant evaluating a complex constant, this might take some time let mut n = 113383; // #20 in https://oeis.org/A006884 while n != 0 { //~^ ERROR `while` is not allowed in a `const` diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr index e04c31cf397..9b56457ea5f 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.stderr +++ b/src/test/ui/consts/const-eval/infinite_loop.stderr @@ -1,5 +1,5 @@ error[E0658]: `while` is not allowed in a `const` - --> $DIR/infinite_loop.rs:7:9 + --> $DIR/infinite_loop.rs:6:9 | LL | / while n != 0 { LL | | @@ -14,7 +14,7 @@ LL | | } = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0658]: `if` is not allowed in a `const` - --> $DIR/infinite_loop.rs:9:17 + --> $DIR/infinite_loop.rs:8:17 | LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,24 +22,11 @@ LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; = note: see issue #49146 for more information = help: add `#![feature(const_if_match)]` to the crate attributes to enable -warning: Constant evaluating a complex constant, this might take some time - --> $DIR/infinite_loop.rs:4:18 - | -LL | let _ = [(); { - | __________________^ -LL | | -LL | | let mut n = 113383; // #20 in https://oeis.org/A006884 -LL | | while n != 0 { -... | -LL | | n -LL | | }]; - | |_____^ - error[E0080]: evaluation of constant value failed - --> $DIR/infinite_loop.rs:9:20 + --> $DIR/infinite_loop.rs:8:20 | LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; - | ^^^^^^^^^^ duplicate interpreter state observed here, const evaluation will never terminate + | ^^^^^^^^^^ exceeded interpreter time limit error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-eval/issue-52475.rs b/src/test/ui/consts/const-eval/issue-52475.rs index 3788167f449..869f0b981af 100644 --- a/src/test/ui/consts/const-eval/issue-52475.rs +++ b/src/test/ui/consts/const-eval/issue-52475.rs @@ -1,6 +1,5 @@ fn main() { let _ = [(); { - //~^ WARNING Constant evaluating a complex constant, this might take some time let mut x = &0; let mut n = 0; while n < 5 { diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr index 31d87925b2c..8d6168a7f86 100644 --- a/src/test/ui/consts/const-eval/issue-52475.stderr +++ b/src/test/ui/consts/const-eval/issue-52475.stderr @@ -1,5 +1,5 @@ error[E0658]: `while` is not allowed in a `const` - --> $DIR/issue-52475.rs:6:9 + --> $DIR/issue-52475.rs:5:9 | LL | / while n < 5 { LL | | @@ -12,24 +12,11 @@ LL | | } = help: add `#![feature(const_loop)]` to the crate attributes to enable = help: add `#![feature(const_if_match)]` to the crate attributes to enable -warning: Constant evaluating a complex constant, this might take some time - --> $DIR/issue-52475.rs:2:18 - | -LL | let _ = [(); { - | __________________^ -LL | | -LL | | let mut x = &0; -LL | | let mut n = 0; -... | -LL | | 0 -LL | | }]; - | |_____^ - error[E0080]: evaluation of constant value failed - --> $DIR/issue-52475.rs:8:17 + --> $DIR/issue-52475.rs:7:17 | LL | n = (n + 1) % 5; - | ^^^^^^^^^^^ duplicate interpreter state observed here, const evaluation will never terminate + | ^^^^^^^^^^^ exceeded interpreter time limit error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs index 4ed908312fb..34abcdf08da 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs +++ b/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs @@ -1,15 +1,21 @@ // check-pass + #![feature(const_eval_limit)] -#![const_eval_limit="1000"] +#![feature(const_loop, const_if_match)] -const CONSTANT: usize = limit(); +// This needs to be higher than the number of loop iterations since each pass through the loop may +// hit more than one terminator. +#![const_eval_limit="4000"] -fn main() { - assert_eq!(CONSTANT, 1764); -} +const X: usize = { + let mut x = 0; + while x != 1000 { + x += 1; + } -const fn limit() -> usize { - let x = 42; + x +}; - x * 42 +fn main() { + assert_eq!(X, 1000); } diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs index d962398d413..b45aca0b13e 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_reached.rs +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs @@ -1,21 +1,18 @@ -// ignore-tidy-linelength -// only-x86_64 -// check-pass -// NOTE: We always compile this test with -Copt-level=0 because higher opt-levels -// optimize away the const function -// compile-flags:-Copt-level=0 #![feature(const_eval_limit)] -#![const_eval_limit="2"] +#![feature(const_loop, const_if_match)] -const CONSTANT: usize = limit(); -//~^ WARNING Constant evaluating a complex constant, this might take some time +#![const_eval_limit="500"] -fn main() { - assert_eq!(CONSTANT, 1764); -} +const X: usize = { + let mut x = 0; + while x != 1000 { + //~^ ERROR any use of this value will cause an error + x += 1; + } -const fn limit() -> usize { //~ WARNING Constant evaluating a complex constant, this might take some time - let x = 42; + x +}; - x * 42 +fn main() { + assert_eq!(X, 1000); } diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr index e0871ff7185..ca8fbef9072 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -1,16 +1,17 @@ -warning: Constant evaluating a complex constant, this might take some time - --> $DIR/const_eval_limit_reached.rs:17:1 +error: any use of this value will cause an error + --> $DIR/const_eval_limit_reached.rs:8:11 | -LL | / const fn limit() -> usize { -LL | | let x = 42; +LL | / const X: usize = { +LL | | let mut x = 0; +LL | | while x != 1000 { + | | ^^^^^^^^^ exceeded interpreter time limit LL | | -LL | | x * 42 -LL | | } - | |_^ - -warning: Constant evaluating a complex constant, this might take some time - --> $DIR/const_eval_limit_reached.rs:10:1 +... | +LL | | x +LL | | }; + | |__- | -LL | const CONSTANT: usize = limit(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 2daaf2b252040ff542eb42d66043f62c360c4db5 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sun, 15 Mar 2020 21:48:09 -0500 Subject: replace some adhoc logic with article_and_descr --- src/librustc_lint/builtin.rs | 45 +++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 88f2284cd61..14ad35767b9 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -349,7 +349,7 @@ impl MissingDoc { id: Option, attrs: &[ast::Attribute], sp: Span, - desc: &'static str, + desc: &str, ) { // If we're building a test harness, then warning about // documentation is probably not really relevant right now. @@ -413,12 +413,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) { - let desc = match it.kind { - hir::ItemKind::Fn(..) => "a function", - hir::ItemKind::Mod(..) => "a module", - hir::ItemKind::Enum(..) => "an enum", - hir::ItemKind::Struct(..) => "a struct", - hir::ItemKind::Union(..) => "a union", + match it.kind { hir::ItemKind::Trait(.., trait_item_refs) => { // Issue #11592: traits are always considered exported, even when private. if let hir::VisibilityKind::Inherited = it.vis.node { @@ -428,33 +423,45 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } return; } - "a trait" } - hir::ItemKind::TyAlias(..) => "a type alias", hir::ItemKind::Impl { of_trait: Some(ref trait_ref), items, .. } => { // If the trait is private, add the impl items to `private_traits` so they don't get // reported for missing docs. let real_trait = trait_ref.path.res.def_id(); if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) { - match cx.tcx.hir().find(hir_id) { - Some(Node::Item(item)) => { - if let hir::VisibilityKind::Inherited = item.vis.node { - for impl_item_ref in items { - self.private_traits.insert(impl_item_ref.id.hir_id); - } + if let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) { + if let hir::VisibilityKind::Inherited = item.vis.node { + for impl_item_ref in items { + self.private_traits.insert(impl_item_ref.id.hir_id); } } - _ => {} } } return; } - hir::ItemKind::Const(..) => "a constant", - hir::ItemKind::Static(..) => "a static", + + hir::ItemKind::TyAlias(..) + | hir::ItemKind::Fn(..) + | hir::ItemKind::Mod(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..) + | hir::ItemKind::Const(..) + | hir::ItemKind::Static(..) => {} + _ => return, }; - self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, desc); + let def_id = cx.tcx.hir().local_def_id(it.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id); + + self.check_missing_docs_attrs( + cx, + Some(it.hir_id), + &it.attrs, + it.span, + &format!("{} {}", article, desc), + ); } fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::TraitItem<'_>) { -- cgit 1.4.1-3-g733a5 From 99ae42876b1e99b558c392d7912b826d32c39476 Mon Sep 17 00:00:00 2001 From: DeeDeeG Date: Sat, 21 Mar 2020 15:33:06 -0400 Subject: Improve E0308 error message wording --- src/librustc_error_codes/error_codes/E0308.md | 8 +++---- src/test/ui/json-bom-plus-crlf-multifile.stderr | 32 ++++++++++++------------- src/test/ui/json-bom-plus-crlf.stderr | 32 ++++++++++++------------- 3 files changed, 36 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/librustc_error_codes/error_codes/E0308.md b/src/librustc_error_codes/error_codes/E0308.md index 7d87d54194e..b2c84370490 100644 --- a/src/librustc_error_codes/error_codes/E0308.md +++ b/src/librustc_error_codes/error_codes/E0308.md @@ -13,7 +13,7 @@ let x: i32 = "I am not a number!"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json-bom-plus-crlf-multifile.stderr index 026943669f8..99f91cc8816 100644 --- a/src/test/ui/json-bom-plus-crlf-multifile.stderr +++ b/src/test/ui/json-bom-plus-crlf-multifile.stderr @@ -13,10 +13,10 @@ let x: i32 = \"I am not a number!\"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -34,10 +34,10 @@ let x: i32 = \"I am not a number!\"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -55,10 +55,10 @@ let x: i32 = \"I am not a number!\"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -76,10 +76,10 @@ let x: i32 = \"I am not a number!\"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json-bom-plus-crlf.stderr index 735a46b8c87..3e84f5ef54d 100644 --- a/src/test/ui/json-bom-plus-crlf.stderr +++ b/src/test/ui/json-bom-plus-crlf.stderr @@ -13,10 +13,10 @@ let x: i32 = \"I am not a number!\"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -34,10 +34,10 @@ let x: i32 = \"I am not a number!\"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -55,10 +55,10 @@ let x: i32 = \"I am not a number!\"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -76,10 +76,10 @@ let x: i32 = \"I am not a number!\"; ``` This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +variable. It can happen in several cases, the most common being a mismatch +between the type that the compiler inferred for a variable based on its +initializing expression, on the one hand, and the type the author explicitly +assigned to the variable, on the other hand. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 1661a0a99ba09ff0b2cce8ad99c4f18150165b80 Mon Sep 17 00:00:00 2001 From: mark Date: Sat, 21 Mar 2020 19:47:23 -0500 Subject: convert a couple more errors --- src/librustc_lint/builtin.rs | 19 ++++++------------- src/test/ui/lint/lint-missing-doc.rs | 6 +++--- src/test/ui/lint/lint-missing-doc.stderr | 6 +++--- .../ui/privacy/private-in-public-non-principal.rs | 2 +- .../ui/privacy/private-in-public-non-principal.stderr | 2 +- 5 files changed, 14 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 14ad35767b9..9a02bebb235 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -469,18 +469,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { return; } - let desc = match trait_item.kind { - hir::TraitItemKind::Const(..) => "an associated constant", - hir::TraitItemKind::Fn(..) => "a trait method", - hir::TraitItemKind::Type(..) => "an associated type", - }; + let def_id = cx.tcx.hir().local_def_id(trait_item.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id); self.check_missing_docs_attrs( cx, Some(trait_item.hir_id), &trait_item.attrs, trait_item.span, - desc, + &format!("{} {}", article, desc), ); } @@ -490,18 +487,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { return; } - let desc = match impl_item.kind { - hir::ImplItemKind::Const(..) => "an associated constant", - hir::ImplItemKind::Fn(..) => "a method", - hir::ImplItemKind::TyAlias(_) => "an associated type", - hir::ImplItemKind::OpaqueTy(_) => "an associated `impl Trait` type", - }; + let def_id = cx.tcx.hir().local_def_id(impl_item.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id); self.check_missing_docs_attrs( cx, Some(impl_item.hir_id), &impl_item.attrs, impl_item.span, - desc, + &format!("{} {}", article, desc), ); } diff --git a/src/test/ui/lint/lint-missing-doc.rs b/src/test/ui/lint/lint-missing-doc.rs index 77f9a3770a3..bab6f4e9e5e 100644 --- a/src/test/ui/lint/lint-missing-doc.rs +++ b/src/test/ui/lint/lint-missing-doc.rs @@ -50,8 +50,8 @@ trait B { } pub trait C { //~ ERROR: missing documentation for a trait - fn foo(&self); //~ ERROR: missing documentation for a trait method - fn foo_with_impl(&self) {} //~ ERROR: missing documentation for a trait method + fn foo(&self); //~ ERROR: missing documentation for an associated function + fn foo_with_impl(&self) {} //~ ERROR: missing documentation for an associated function } #[allow(missing_docs)] @@ -78,7 +78,7 @@ impl Foo { } impl PubFoo { - pub fn foo() {} //~ ERROR: missing documentation for a method + pub fn foo() {} //~ ERROR: missing documentation for an associated function /// dox pub fn foo1() {} fn foo2() {} diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr index a18a97e5f7f..21da4fae4c1 100644 --- a/src/test/ui/lint/lint-missing-doc.stderr +++ b/src/test/ui/lint/lint-missing-doc.stderr @@ -40,13 +40,13 @@ error: missing documentation for a trait LL | pub trait C { | ^^^^^^^^^^^ -error: missing documentation for a trait method +error: missing documentation for an associated function --> $DIR/lint-missing-doc.rs:53:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ -error: missing documentation for a trait method +error: missing documentation for an associated function --> $DIR/lint-missing-doc.rs:54:5 | LL | fn foo_with_impl(&self) {} @@ -64,7 +64,7 @@ error: missing documentation for an associated type LL | type AssociatedTypeDef = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: missing documentation for a method +error: missing documentation for an associated function --> $DIR/lint-missing-doc.rs:81:5 | LL | pub fn foo() {} diff --git a/src/test/ui/privacy/private-in-public-non-principal.rs b/src/test/ui/privacy/private-in-public-non-principal.rs index 5d89d8105b1..b306849ac8e 100644 --- a/src/test/ui/privacy/private-in-public-non-principal.rs +++ b/src/test/ui/privacy/private-in-public-non-principal.rs @@ -10,7 +10,7 @@ pub fn leak_dyn_nonprincipal() -> Box { loo #[deny(missing_docs)] fn container() { impl dyn PubPrincipal { - pub fn check_doc_lint() {} //~ ERROR missing documentation for a method + pub fn check_doc_lint() {} //~ ERROR missing documentation for an associated function } impl dyn PubPrincipal + PrivNonPrincipal { pub fn check_doc_lint() {} // OK, no missing doc lint diff --git a/src/test/ui/privacy/private-in-public-non-principal.stderr b/src/test/ui/privacy/private-in-public-non-principal.stderr index 2a41fae43c6..778c98671ad 100644 --- a/src/test/ui/privacy/private-in-public-non-principal.stderr +++ b/src/test/ui/privacy/private-in-public-non-principal.stderr @@ -8,7 +8,7 @@ LL | pub fn leak_dyn_nonprincipal() -> Box = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 -error: missing documentation for a method +error: missing documentation for an associated function --> $DIR/private-in-public-non-principal.rs:13:9 | LL | pub fn check_doc_lint() {} -- cgit 1.4.1-3-g733a5 From cdb2c3c36819870e155f4711e67e8b417356c8a4 Mon Sep 17 00:00:00 2001 From: mark Date: Sat, 21 Mar 2020 21:32:35 -0500 Subject: use static strs --- src/librustc_lint/builtin.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 9a02bebb235..24529db48aa 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -349,7 +349,8 @@ impl MissingDoc { id: Option, attrs: &[ast::Attribute], sp: Span, - desc: &str, + article: &'static str, + desc: &'static str, ) { // If we're building a test harness, then warning about // documentation is probably not really relevant right now. @@ -374,7 +375,7 @@ impl MissingDoc { let has_doc = attrs.iter().any(|a| has_doc(a)); if !has_doc { cx.struct_span_lint(MISSING_DOCS, cx.tcx.sess.source_map().def_span(sp), |lint| { - lint.build(&format!("missing documentation for {}", desc)).emit() + lint.build(&format!("missing documentation for {} {}", article, desc)).emit() }); } } @@ -398,7 +399,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } fn check_crate(&mut self, cx: &LateContext<'_, '_>, krate: &hir::Crate<'_>) { - self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "crate"); + self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "a", "crate"); for macro_def in krate.exported_macros { let has_doc = macro_def.attrs.iter().any(|a| has_doc(a)); @@ -455,13 +456,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { let def_id = cx.tcx.hir().local_def_id(it.hir_id); let (article, desc) = cx.tcx.article_and_description(def_id); - self.check_missing_docs_attrs( - cx, - Some(it.hir_id), - &it.attrs, - it.span, - &format!("{} {}", article, desc), - ); + self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, article, desc); } fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::TraitItem<'_>) { @@ -477,7 +472,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { Some(trait_item.hir_id), &trait_item.attrs, trait_item.span, - &format!("{} {}", article, desc), + article, + desc, ); } @@ -494,18 +490,26 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { Some(impl_item.hir_id), &impl_item.attrs, impl_item.span, - &format!("{} {}", article, desc), + article, + desc, ); } fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, sf: &hir::StructField<'_>) { if !sf.is_positional() { - self.check_missing_docs_attrs(cx, Some(sf.hir_id), &sf.attrs, sf.span, "a struct field") + self.check_missing_docs_attrs( + cx, + Some(sf.hir_id), + &sf.attrs, + sf.span, + "a", + "struct field", + ) } } fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant<'_>) { - self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, v.span, "a variant"); + self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, v.span, "a", "variant"); } } -- cgit 1.4.1-3-g733a5 From 1e5d81de1d8485e9ce2995bc6b1559f25c4d86e5 Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Sun, 22 Mar 2020 18:02:18 +0900 Subject: Fix invalid suggestion on `&mut` iterators yielding `&` references --- .../borrow_check/diagnostics/mutability_errors.rs | 82 ++++++++++++++++------ .../issue-69789-iterator-mut-suggestion.rs | 11 +++ .../issue-69789-iterator-mut-suggestion.stderr | 12 ++++ 3 files changed, 82 insertions(+), 23 deletions(-) create mode 100644 src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.rs create mode 100644 src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr (limited to 'src') diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index c462f934148..ee654431d88 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -1,9 +1,10 @@ -use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache}; +use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location}; use rustc::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; use rustc_hir::Node; use rustc_index::vec::Idx; +use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; @@ -338,10 +339,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match self.local_names[local] { Some(name) if !local_decl.from_compiler_desugaring() => { - let suggestion = match local_decl.local_info { + let label = match local_decl.local_info { LocalInfo::User(ClearCrossCrate::Set( mir::BindingForm::ImplicitSelf(_), - )) => Some(suggest_ampmut_self(self.infcx.tcx, local_decl)), + )) => { + let (span, suggestion) = + suggest_ampmut_self(self.infcx.tcx, local_decl); + Some((true, span, suggestion)) + } LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( mir::VarBindingForm { @@ -349,13 +354,38 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { opt_ty_info, .. }, - ))) => Some(suggest_ampmut( - self.infcx.tcx, - self.body, - local, - local_decl, - opt_ty_info, - )), + ))) => { + // check if the RHS is from desugaring + let locations = self.body.find_assignments(local); + let opt_assignment_rhs_span = locations + .first() + .map(|&location| self.body.source_info(location).span); + let opt_desugaring_kind = + opt_assignment_rhs_span.and_then(|span| span.desugaring_kind()); + match opt_desugaring_kind { + // on for loops, RHS points to the iterator part + Some(DesugaringKind::ForLoop) => Some(( + false, + opt_assignment_rhs_span.unwrap(), + format!( + "this iterator yields `{SIGIL}` {DESC}s", + SIGIL = pointer_sigil, + DESC = pointer_desc + ), + )), + // don't create labels for compiler-generated spans + Some(_) => None, + None => { + let (span, suggestion) = suggest_ampmut( + self.infcx.tcx, + local_decl, + opt_assignment_rhs_span, + opt_ty_info, + ); + Some((true, span, suggestion)) + } + } + } LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( mir::VarBindingForm { @@ -365,7 +395,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ))) => { let pattern_span = local_decl.source_info.span; suggest_ref_mut(self.infcx.tcx, pattern_span) - .map(|replacement| (pattern_span, replacement)) + .map(|replacement| (true, pattern_span, replacement)) } LocalInfo::User(ClearCrossCrate::Clear) => { @@ -375,13 +405,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _ => unreachable!(), }; - if let Some((err_help_span, suggested_code)) = suggestion { - err.span_suggestion( - err_help_span, - &format!("consider changing this to be a mutable {}", pointer_desc), - suggested_code, - Applicability::MachineApplicable, - ); + match label { + Some((true, err_help_span, suggested_code)) => { + err.span_suggestion( + err_help_span, + &format!( + "consider changing this to be a mutable {}", + pointer_desc + ), + suggested_code, + Applicability::MachineApplicable, + ); + } + Some((false, err_label_span, message)) => { + err.span_label(err_label_span, &message); + } + None => {} } err.span_label( span, @@ -581,14 +620,11 @@ fn suggest_ampmut_self<'tcx>( // by trying (3.), then (2.) and finally falling back on (1.). fn suggest_ampmut<'tcx>( tcx: TyCtxt<'tcx>, - body: ReadOnlyBodyAndCache<'_, 'tcx>, - local: Local, local_decl: &mir::LocalDecl<'tcx>, + opt_assignment_rhs_span: Option, opt_ty_info: Option, ) -> (Span, String) { - let locations = body.find_assignments(local); - if !locations.is_empty() { - let assignment_rhs_span = body.source_info(locations[0]).span; + if let Some(assignment_rhs_span) = opt_assignment_rhs_span { if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) { if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(|c: char| -> bool { c.is_whitespace() })) diff --git a/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.rs b/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.rs new file mode 100644 index 00000000000..f6d0e9e04d3 --- /dev/null +++ b/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.rs @@ -0,0 +1,11 @@ +// Regression test for #69789: rustc generated an invalid suggestion +// when `&` reference from `&mut` iterator is mutated. + +fn main() { + for item in &mut std::iter::empty::<&'static ()>() { + //~^ NOTE this iterator yields `&` references + *item = (); + //~^ ERROR cannot assign + //~| NOTE cannot be written + } +} diff --git a/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr b/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr new file mode 100644 index 00000000000..d2865ffd196 --- /dev/null +++ b/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr @@ -0,0 +1,12 @@ +error[E0594]: cannot assign to `*item` which is behind a `&` reference + --> $DIR/issue-69789-iterator-mut-suggestion.rs:7:9 + | +LL | for item in &mut std::iter::empty::<&'static ()>() { + | -------------------------------------- this iterator yields `&` references +LL | +LL | *item = (); + | ^^^^^^^^^^ `item` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. -- cgit 1.4.1-3-g733a5 From 82f4a1a9b98ef7f16b25de44150d004c3b1b528a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 11:41:07 +0100 Subject: get rid of ConstPropUnsupported; use ZST marker structs instead --- src/libcore/any.rs | 2 +- src/librustc/mir/interpret/error.rs | 49 +++++++++++++++++++++++++------- src/librustc/mir/interpret/mod.rs | 4 +-- src/librustc_mir/transform/const_prop.rs | 32 ++++++++++++++------- 4 files changed, 63 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 97ef513cbcc..39df803bbea 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -164,7 +164,7 @@ impl dyn Any { // Get `TypeId` of the type this function is instantiated with. let t = TypeId::of::(); - // Get `TypeId` of the type in the trait object. + // Get `TypeId` of the type in the trait object (`self`). let concrete = self.type_id(); // Compare both `TypeId`s on equality. diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index ff107a5f1e2..fd7f5361214 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -14,7 +14,10 @@ use rustc_hir as hir; use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::{def_id::DefId, Pos, Span}; -use std::{any::Any, fmt}; +use std::{ + any::{Any, TypeId}, + fmt, mem, +}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)] pub enum ErrorHandled { @@ -451,9 +454,6 @@ impl fmt::Debug for UndefinedBehaviorInfo { pub enum UnsupportedOpInfo { /// Free-form case. Only for errors that are never caught! Unsupported(String), - /// When const-prop encounters a situation it does not support, it raises this error. - /// This must not allocate for performance reasons (hence `str`, not `String`). - ConstPropUnsupported(&'static str), /// Accessing an unsupported foreign static. ReadForeignStatic(DefId), /// Could not find MIR for a function. @@ -472,9 +472,6 @@ impl fmt::Debug for UnsupportedOpInfo { use UnsupportedOpInfo::*; match self { Unsupported(ref msg) => write!(f, "{}", msg), - ConstPropUnsupported(ref msg) => { - write!(f, "Constant propagation encountered an unsupported situation: {}", msg) - } ReadForeignStatic(did) => { write!(f, "tried to read from foreign (extern) static {:?}", did) } @@ -516,6 +513,35 @@ impl fmt::Debug for ResourceExhaustionInfo { } } +/// A trait for machine-specific errors (or other "machine stop" conditions). +pub trait MachineStopType: Any + fmt::Debug + Send {} +impl MachineStopType for String {} + +// Copy-pasted from `any.rs`; there does not seem to be a way to re-use that. +impl dyn MachineStopType { + pub fn is(&self) -> bool { + // Get `TypeId` of the type this function is instantiated with. + let t = TypeId::of::(); + + // Get `TypeId` of the type in the trait object (`self`). + let concrete = self.type_id(); + + // Compare both `TypeId`s on equality. + t == concrete + } + + pub fn downcast_ref(&self) -> Option<&T> { + if self.is::() { + // SAFETY: just checked whether we are pointing to the correct type, and we can rely on + // that check for memory safety because `Any` is implemented for all types; no other + // impls can exist as they would conflict with our impl. + unsafe { Some(&*(self as *const dyn MachineStopType as *const T)) } + } else { + None + } + } +} + pub enum InterpError<'tcx> { /// The program caused undefined behavior. UndefinedBehavior(UndefinedBehaviorInfo), @@ -529,7 +555,7 @@ pub enum InterpError<'tcx> { ResourceExhaustion(ResourceExhaustionInfo), /// Stop execution for a machine-controlled reason. This is never raised by /// the core engine itself. - MachineStop(Box), + MachineStop(Box), } pub type InterpResult<'tcx, T = ()> = Result>; @@ -549,7 +575,7 @@ impl fmt::Debug for InterpError<'_> { InvalidProgram(ref msg) => write!(f, "{:?}", msg), UndefinedBehavior(ref msg) => write!(f, "{:?}", msg), ResourceExhaustion(ref msg) => write!(f, "{:?}", msg), - MachineStop(_) => bug!("unhandled MachineStop"), + MachineStop(ref msg) => write!(f, "{:?}", msg), } } } @@ -560,8 +586,9 @@ impl InterpError<'_> { /// waste of resources. pub fn allocates(&self) -> bool { match self { - InterpError::MachineStop(_) - | InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) + // Zero-sized boxes to not allocate. + InterpError::MachineStop(b) => mem::size_of_val(&**b) > 0, + InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true, diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index dfe5adb1bbf..35876c8e95a 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -92,8 +92,8 @@ mod value; pub use self::error::{ struct_error, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled, FrameInfo, - InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, ResourceExhaustionInfo, - UndefinedBehaviorInfo, UnsupportedOpInfo, + InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, + ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUndef}; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 8d7cafc34b3..687bacfdc1b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use std::cell::Cell; -use rustc::mir::interpret::{InterpResult, Scalar}; +use rustc::mir::interpret::{InterpResult, MachineStopType, Scalar}; use rustc::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; @@ -192,7 +192,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _ret: Option<(PlaceTy<'tcx>, BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { - throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp")) + #[derive(Debug)] + struct ConstPropIntrinsic; + impl MachineStopType for ConstPropIntrinsic {} + throw_machine_stop!(ConstPropIntrinsic) } fn assert_panic( @@ -204,7 +207,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { } fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> { - throw_unsup!(ConstPropUnsupported("ptr-to-int casts aren't supported in ConstProp")) + throw_unsup!(ReadPointerAsBytes) } fn binary_ptr_op( @@ -213,11 +216,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _left: ImmTy<'tcx>, _right: ImmTy<'tcx>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + #[derive(Debug)] + struct ConstPropPtrOp; + impl MachineStopType for ConstPropPtrOp {} // We can't do this because aliasing of memory can differ between const eval and llvm - throw_unsup!(ConstPropUnsupported( - "pointer arithmetic or comparisons aren't supported \ - in ConstProp" - )) + throw_machine_stop!(ConstPropPtrOp) } #[inline(always)] @@ -240,7 +243,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _ecx: &mut InterpCx<'mir, 'tcx, Self>, _dest: PlaceTy<'tcx>, ) -> InterpResult<'tcx> { - throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword")) + #[derive(Debug)] + struct ConstPropBox; + impl MachineStopType for ConstPropBox {} + throw_machine_stop!(ConstPropBox) } fn access_local( @@ -251,7 +257,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { let l = &frame.locals[local]; if l.value == LocalValue::Uninitialized { - throw_unsup!(ConstPropUnsupported("tried to access an uninitialized local")); + #[derive(Debug)] + struct ConstPropUninitLocal; + impl MachineStopType for ConstPropUninitLocal {} + throw_machine_stop!(ConstPropUninitLocal) } l.access() @@ -261,10 +270,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _memory_extra: &(), allocation: &Allocation, ) -> InterpResult<'tcx> { + #[derive(Debug)] + struct ConstPropGlobalMem; + impl MachineStopType for ConstPropGlobalMem {} // if the static allocation is mutable or if it has relocations (it may be legal to mutate // the memory behind that in the future), then we can't const prop it if allocation.mutability == Mutability::Mut || allocation.relocations().len() > 0 { - throw_unsup!(ConstPropUnsupported("can't eval mutable statics in ConstProp")); + throw_machine_stop!(ConstPropGlobalMem) } Ok(()) -- cgit 1.4.1-3-g733a5 From d40dff9cbbabfdb1477dfbb71f45ca4f36c1d596 Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 22 Mar 2020 14:37:51 -0500 Subject: the crate and tests --- src/librustc_lint/builtin.rs | 2 +- src/test/ui/issues/issue-10656.rs | 2 +- src/test/ui/issues/issue-10656.stderr | 2 +- src/test/ui/lint/lints-in-foreign-macros.rs | 2 +- src/test/ui/lint/lints-in-foreign-macros.stderr | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 24529db48aa..66d9fe7e149 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -399,7 +399,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } fn check_crate(&mut self, cx: &LateContext<'_, '_>, krate: &hir::Crate<'_>) { - self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "a", "crate"); + self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "the", "crate"); for macro_def in krate.exported_macros { let has_doc = macro_def.attrs.iter().any(|a| has_doc(a)); diff --git a/src/test/ui/issues/issue-10656.rs b/src/test/ui/issues/issue-10656.rs index 8918dadb47a..250c4bc442f 100644 --- a/src/test/ui/issues/issue-10656.rs +++ b/src/test/ui/issues/issue-10656.rs @@ -1,3 +1,3 @@ #![deny(missing_docs)] #![crate_type="lib"] -//~^^ ERROR missing documentation for crate +//~^^ ERROR missing documentation for the crate diff --git a/src/test/ui/issues/issue-10656.stderr b/src/test/ui/issues/issue-10656.stderr index 2e91a598dce..2e4365f1ed7 100644 --- a/src/test/ui/issues/issue-10656.stderr +++ b/src/test/ui/issues/issue-10656.stderr @@ -1,4 +1,4 @@ -error: missing documentation for crate +error: missing documentation for the crate --> $DIR/issue-10656.rs:1:1 | LL | / #![deny(missing_docs)] diff --git a/src/test/ui/lint/lints-in-foreign-macros.rs b/src/test/ui/lint/lints-in-foreign-macros.rs index c96b8f1a5cf..1e8b6788a60 100644 --- a/src/test/ui/lint/lints-in-foreign-macros.rs +++ b/src/test/ui/lint/lints-in-foreign-macros.rs @@ -1,7 +1,7 @@ // aux-build:lints-in-foreign-macros.rs // check-pass -#![warn(unused_imports)] //~ missing documentation for crate [missing_docs] +#![warn(unused_imports)] //~ missing documentation for the crate [missing_docs] #![warn(missing_docs)] #[macro_use] diff --git a/src/test/ui/lint/lints-in-foreign-macros.stderr b/src/test/ui/lint/lints-in-foreign-macros.stderr index 207d85a89c7..dcea5adb863 100644 --- a/src/test/ui/lint/lints-in-foreign-macros.stderr +++ b/src/test/ui/lint/lints-in-foreign-macros.stderr @@ -26,7 +26,7 @@ warning: unused import: `std::string::ToString` LL | mod d { baz2!(use std::string::ToString;); } | ^^^^^^^^^^^^^^^^^^^^^ -warning: missing documentation for crate +warning: missing documentation for the crate --> $DIR/lints-in-foreign-macros.rs:4:1 | LL | / #![warn(unused_imports)] -- cgit 1.4.1-3-g733a5 From b5636b8437feecc3474e607f60891f3ebc098ded Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 22 Mar 2020 12:49:58 -0700 Subject: Rename `TimeLimitReached` -> `StepLimitReached` --- src/librustc/mir/interpret/error.rs | 6 ++++-- src/librustc_mir/const_eval/machine.rs | 2 +- src/test/ui/consts/const-eval/infinite_loop.stderr | 2 +- src/test/ui/consts/const-eval/issue-52475.stderr | 2 +- src/test/ui/consts/const_limit/const_eval_limit_reached.stderr | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 4b1fad5d0b3..54d48e83d03 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -568,7 +568,7 @@ pub enum ResourceExhaustionInfo { /// The program ran for too long. /// /// The exact limit is set by the `const_eval_limit` attribute. - TimeLimitReached, + StepLimitReached, } impl fmt::Debug for ResourceExhaustionInfo { @@ -578,7 +578,9 @@ impl fmt::Debug for ResourceExhaustionInfo { StackFrameLimitReached => { write!(f, "reached the configured maximum number of stack frames") } - TimeLimitReached => write!(f, "exceeded interpreter time limit"), + StepLimitReached => { + write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)") + } } } } diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 22b01be299b..123fc80021f 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -335,7 +335,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter { ecx.machine.steps_remaining -= 1; if ecx.machine.steps_remaining == 0 { - throw_exhaust!(TimeLimitReached) + throw_exhaust!(StepLimitReached) } Ok(()) diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr index 9b56457ea5f..ebdb73c4467 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.stderr +++ b/src/test/ui/consts/const-eval/infinite_loop.stderr @@ -26,7 +26,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/infinite_loop.rs:8:20 | LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; - | ^^^^^^^^^^ exceeded interpreter time limit + | ^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr index 8d6168a7f86..b069537ead9 100644 --- a/src/test/ui/consts/const-eval/issue-52475.stderr +++ b/src/test/ui/consts/const-eval/issue-52475.stderr @@ -16,7 +16,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-52475.rs:7:17 | LL | n = (n + 1) % 5; - | ^^^^^^^^^^^ exceeded interpreter time limit + | ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr index ca8fbef9072..be522dd6d5d 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const X: usize = { LL | | let mut x = 0; LL | | while x != 1000 { - | | ^^^^^^^^^ exceeded interpreter time limit + | | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) LL | | ... | LL | | x -- cgit 1.4.1-3-g733a5 From bd1df4405785a34ac494007f185744d51ddd9138 Mon Sep 17 00:00:00 2001 From: CDirkx Date: Sun, 22 Mar 2020 22:04:05 +0100 Subject: Add regression test for #70155. With #70166 merged, `RangeInclusive` now derives `PartialEq` and `Eq`, implementing structural equality and as a side effect the range is now usable with const generics, closing #70155. A test is added to avoid a change to the private fields or the equality implementation of the range from subtly reverting #70155. --- src/test/ui/const-generics/issues/issue-70155.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-70155.rs (limited to 'src') diff --git a/src/test/ui/const-generics/issues/issue-70155.rs b/src/test/ui/const-generics/issues/issue-70155.rs new file mode 100644 index 00000000000..be71b347590 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-70155.rs @@ -0,0 +1,12 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +// Regression test for #70155: +// `RangeInclusive` should be usable with const generics + +struct S>; + +const C : S<{ 0 ..= 999 }> = S; + +pub fn main() {} -- cgit 1.4.1-3-g733a5 From cda81da6ea4c037ef036067d9cb98e80208ee525 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 20:24:22 +0100 Subject: avoid unsafe code, use upcasting-trait instead (trick by oli) --- src/librustc/mir/interpret/error.rs | 41 +++++++++++++++---------------------- 1 file changed, 16 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index fd7f5361214..d00eb7921a0 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -14,10 +14,7 @@ use rustc_hir as hir; use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::{def_id::DefId, Pos, Span}; -use std::{ - any::{Any, TypeId}, - fmt, mem, -}; +use std::{any::Any, fmt, mem}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)] pub enum ErrorHandled { @@ -513,32 +510,26 @@ impl fmt::Debug for ResourceExhaustionInfo { } } +/// A trait to work around not having trait object upcasting. +pub trait AsAny: Any { + fn as_any(&self) -> &dyn Any; +} + +impl AsAny for T { + #[inline(always)] + fn as_any(&self) -> &dyn Any { + self + } +} + /// A trait for machine-specific errors (or other "machine stop" conditions). -pub trait MachineStopType: Any + fmt::Debug + Send {} +pub trait MachineStopType: AsAny + fmt::Debug + Send {} impl MachineStopType for String {} -// Copy-pasted from `any.rs`; there does not seem to be a way to re-use that. impl dyn MachineStopType { - pub fn is(&self) -> bool { - // Get `TypeId` of the type this function is instantiated with. - let t = TypeId::of::(); - - // Get `TypeId` of the type in the trait object (`self`). - let concrete = self.type_id(); - - // Compare both `TypeId`s on equality. - t == concrete - } - + #[inline(always)] pub fn downcast_ref(&self) -> Option<&T> { - if self.is::() { - // SAFETY: just checked whether we are pointing to the correct type, and we can rely on - // that check for memory safety because `Any` is implemented for all types; no other - // impls can exist as they would conflict with our impl. - unsafe { Some(&*(self as *const dyn MachineStopType as *const T)) } - } else { - None - } + self.as_any().downcast_ref() } } -- cgit 1.4.1-3-g733a5 From 5e8b795552fed746ec1bbd1d397d7fb11a0faacd Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 22 Mar 2020 17:18:30 -0500 Subject: fix one more test --- src/test/rustdoc-ui/deny-missing-docs-crate.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr index f0a13b70b97..821e6b99f7b 100644 --- a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr +++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr @@ -1,4 +1,4 @@ -error: missing documentation for crate +error: missing documentation for the crate --> $DIR/deny-missing-docs-crate.rs:1:1 | LL | / #![deny(missing_docs)] -- cgit 1.4.1-3-g733a5 From 410385dfd0532f3e8867afaaa4b89c315b0e84b1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 10:58:43 +0100 Subject: add macro to reduce boilerplate and keep readable messages --- src/librustc/mir/interpret/error.rs | 2 +- src/librustc_mir/transform/const_prop.rs | 45 +++++++++++++++++--------------- 2 files changed, 25 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index d00eb7921a0..010b73db9ac 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -577,7 +577,7 @@ impl InterpError<'_> { /// waste of resources. pub fn allocates(&self) -> bool { match self { - // Zero-sized boxes to not allocate. + // Zero-sized boxes do not allocate. InterpError::MachineStop(b) => mem::size_of_val(&**b) > 0, InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_)) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 687bacfdc1b..74140a1fc6d 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use std::cell::Cell; -use rustc::mir::interpret::{InterpResult, MachineStopType, Scalar}; +use rustc::mir::interpret::{InterpResult, Scalar}; use rustc::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; @@ -39,6 +39,24 @@ use crate::transform::{MirPass, MirSource}; /// The maximum number of bytes that we'll allocate space for a return value. const MAX_ALLOC_LIMIT: u64 = 1024; +/// Macro for machine-specific `InterpError` without allocation. +/// (These will never be shown to the user, but they help diagnose ICEs.) +macro_rules! throw_machine_stop_str { + ($($tt:tt)*) => {{ + // We make a new local type for it. The type itself does not carry any information, + // but its vtable (for the `MachineStopType` trait) does. + struct Zst; + // Debug-printing this type shows the desired string. + impl std::fmt::Debug for Zst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, $($tt)*) + } + } + impl rustc::mir::interpret::MachineStopType for Zst {} + throw_machine_stop!(Zst) + }}; +} + pub struct ConstProp; impl<'tcx> MirPass<'tcx> for ConstProp { @@ -192,10 +210,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _ret: Option<(PlaceTy<'tcx>, BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { - #[derive(Debug)] - struct ConstPropIntrinsic; - impl MachineStopType for ConstPropIntrinsic {} - throw_machine_stop!(ConstPropIntrinsic) + throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") } fn assert_panic( @@ -216,11 +231,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _left: ImmTy<'tcx>, _right: ImmTy<'tcx>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - #[derive(Debug)] - struct ConstPropPtrOp; - impl MachineStopType for ConstPropPtrOp {} // We can't do this because aliasing of memory can differ between const eval and llvm - throw_machine_stop!(ConstPropPtrOp) + throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } #[inline(always)] @@ -243,10 +255,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _ecx: &mut InterpCx<'mir, 'tcx, Self>, _dest: PlaceTy<'tcx>, ) -> InterpResult<'tcx> { - #[derive(Debug)] - struct ConstPropBox; - impl MachineStopType for ConstPropBox {} - throw_machine_stop!(ConstPropBox) + throw_machine_stop_str!("can't const prop heap allocations") } fn access_local( @@ -257,10 +266,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { let l = &frame.locals[local]; if l.value == LocalValue::Uninitialized { - #[derive(Debug)] - struct ConstPropUninitLocal; - impl MachineStopType for ConstPropUninitLocal {} - throw_machine_stop!(ConstPropUninitLocal) + throw_machine_stop_str!("tried to access an uninitialized local") } l.access() @@ -270,13 +276,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _memory_extra: &(), allocation: &Allocation, ) -> InterpResult<'tcx> { - #[derive(Debug)] - struct ConstPropGlobalMem; - impl MachineStopType for ConstPropGlobalMem {} // if the static allocation is mutable or if it has relocations (it may be legal to mutate // the memory behind that in the future), then we can't const prop it if allocation.mutability == Mutability::Mut || allocation.relocations().len() > 0 { - throw_machine_stop!(ConstPropGlobalMem) + throw_machine_stop_str!("can't eval mutable statics in ConstProp") } Ok(()) -- cgit 1.4.1-3-g733a5 From e619b85776feca7ae484c42dff1e37e0844aa06c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 11:03:39 +0100 Subject: make sure we are checking the size of the right thing --- src/librustc/mir/interpret/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 010b73db9ac..bd7d2c57509 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -578,7 +578,7 @@ impl InterpError<'_> { pub fn allocates(&self) -> bool { match self { // Zero-sized boxes do not allocate. - InterpError::MachineStop(b) => mem::size_of_val(&**b) > 0, + InterpError::MachineStop(b) => mem::size_of_val::(&**b) > 0, InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) -- cgit 1.4.1-3-g733a5 From 19e69359564c919023e294b485d952bc240260e2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 23 Mar 2020 12:40:14 +0100 Subject: Clean up E0452 explanation --- src/librustc_error_codes/error_codes/E0452.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/librustc_error_codes/error_codes/E0452.md b/src/librustc_error_codes/error_codes/E0452.md index be3d573e10d..429813a7cdd 100644 --- a/src/librustc_error_codes/error_codes/E0452.md +++ b/src/librustc_error_codes/error_codes/E0452.md @@ -1,4 +1,6 @@ -An invalid lint attribute has been given. Erroneous code example: +An invalid lint attribute has been given. + +Erroneous code example: ```compile_fail,E0452 #![allow(foo = "")] // error: malformed lint attribute -- cgit 1.4.1-3-g733a5 From 799b15ed96942aec81aecab4b2ae2f9243b632fa Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Mar 2020 15:30:35 +0100 Subject: Evaluate repeat expression lengths as late as possible --- src/librustc/mir/mod.rs | 32 ++++++--- src/librustc/mir/tcx.rs | 4 +- src/librustc/ty/sty.rs | 70 +++++++++++++++++++- src/librustc_codegen_ssa/mir/rvalue.rs | 3 + src/librustc_mir/borrow_check/type_check/mod.rs | 6 +- src/librustc_mir_build/hair/cx/expr.rs | 31 +-------- src/librustc_mir_build/hair/mod.rs | 2 +- src/librustc_typeck/astconv.rs | 77 +--------------------- src/librustc_typeck/check/expr.rs | 21 +----- src/librustc_typeck/check/mod.rs | 7 +- src/test/compile-fail/issue-52443.rs | 7 +- src/test/ui/closures/issue-52437.rs | 1 + src/test/ui/closures/issue-52437.stderr | 12 +++- src/test/ui/const-generics/issues/issue-61336-1.rs | 3 +- .../ui/const-generics/issues/issue-61336-1.stderr | 8 --- src/test/ui/const-generics/issues/issue-61336-2.rs | 7 +- .../ui/const-generics/issues/issue-61336-2.stderr | 22 ++++--- src/test/ui/const-generics/issues/issue-61336.rs | 3 +- .../ui/const-generics/issues/issue-61336.stderr | 20 +++--- src/test/ui/const-generics/issues/issue-62456.rs | 3 +- .../ui/const-generics/issues/issue-62456.stderr | 8 --- src/test/ui/const-generics/issues/issue-62504.rs | 2 +- .../ui/const-generics/issues/issue-62504.stderr | 10 ++- src/test/ui/const-generics/issues/issue-67739.rs | 3 +- .../ui/const-generics/issues/issue-67739.stderr | 8 --- .../ui/consts/const-eval/const-eval-overflow-3.rs | 1 + .../consts/const-eval/const-eval-overflow-3.stderr | 14 +++- .../ui/consts/const-eval/const-eval-overflow-3b.rs | 1 + .../const-eval/const-eval-overflow-3b.stderr | 11 +++- src/test/ui/consts/const-eval/issue-52442.rs | 4 +- src/test/ui/consts/const-eval/issue-52442.stderr | 20 +----- .../ui/consts/const-eval/match-test-ptr-null.rs | 2 +- .../consts/const-eval/match-test-ptr-null.stderr | 27 +++++++- src/test/ui/consts/issue-52432.rs | 1 - src/test/ui/consts/issue-52432.stderr | 12 +--- src/test/ui/consts/too_generic_eval_ice.rs | 1 + src/test/ui/consts/too_generic_eval_ice.stderr | 12 +++- src/test/ui/issues/issue-39559-2.rs | 1 + src/test/ui/issues/issue-39559-2.stderr | 16 ++++- src/test/ui/issues/issue-52060.rs | 1 + src/test/ui/issues/issue-52060.stderr | 13 +++- .../issue-69602-type-err-during-codegen-ice.rs | 1 - .../issue-69602-type-err-during-codegen-ice.stderr | 8 +-- src/test/ui/repeat_count.stderr | 12 ++-- .../issue-65035-static-with-parent-generics.rs | 1 + .../issue-65035-static-with-parent-generics.stderr | 14 +++- 46 files changed, 279 insertions(+), 264 deletions(-) delete mode 100644 src/test/ui/const-generics/issues/issue-67739.stderr (limited to 'src') diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9018cd2656f..d81b940cbe7 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2066,7 +2066,7 @@ pub enum Rvalue<'tcx> { Use(Operand<'tcx>), /// [x; 32] - Repeat(Operand<'tcx>, u64), + Repeat(Operand<'tcx>, &'tcx ty::Const<'tcx>), /// &x or &mut x Ref(Region<'tcx>, BorrowKind, Place<'tcx>), @@ -2194,7 +2194,11 @@ impl<'tcx> Debug for Rvalue<'tcx> { match *self { Use(ref place) => write!(fmt, "{:?}", place), - Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b), + Repeat(ref a, ref b) => { + write!(fmt, "[{:?}; ", a)?; + pretty_print_const(b, fmt, false)?; + write!(fmt, "]") + } Len(ref a) => write!(fmt, "Len({:?})", a), Cast(ref kind, ref place, ref ty) => { write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind) @@ -2562,18 +2566,26 @@ impl<'tcx> Debug for Constant<'tcx> { impl<'tcx> Display for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - use crate::ty::print::PrettyPrinter; write!(fmt, "const ")?; - ty::tls::with(|tcx| { - let literal = tcx.lift(&self.literal).unwrap(); - let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS); - cx.print_alloc_ids = true; - cx.pretty_print_const(literal, true)?; - Ok(()) - }) + pretty_print_const(self.literal, fmt, true) } } +fn pretty_print_const( + c: &ty::Const<'tcx>, + fmt: &mut Formatter<'_>, + print_types: bool, +) -> fmt::Result { + use crate::ty::print::PrettyPrinter; + ty::tls::with(|tcx| { + let literal = tcx.lift(&c).unwrap(); + let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS); + cx.print_alloc_ids = true; + cx.pretty_print_const(literal, print_types)?; + Ok(()) + }) +} + impl<'tcx> graph::DirectedGraph for Body<'tcx> { type Node = BasicBlock; } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 13996a74acb..feb66319267 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -149,7 +149,9 @@ impl<'tcx> Rvalue<'tcx> { { match *self { Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), - Rvalue::Repeat(ref operand, count) => tcx.mk_array(operand.ty(local_decls, tcx), count), + Rvalue::Repeat(ref operand, count) => { + tcx.mk_ty(ty::Array(operand.ty(local_decls, tcx), count)) + } Rvalue::Ref(reg, bk, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 00310ef9b31..5d1f6ae3877 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -8,7 +8,7 @@ use self::TyKind::*; use crate::infer::canonical::Canonical; use crate::middle::region; use crate::mir::interpret::ConstValue; -use crate::mir::interpret::Scalar; +use crate::mir::interpret::{LitToConstInput, Scalar}; use crate::mir::Promoted; use crate::ty::layout::VariantIdx; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; @@ -2401,7 +2401,75 @@ pub struct Const<'tcx> { #[cfg(target_arch = "x86_64")] static_assert_size!(Const<'_>, 48); +/// Returns the `DefId` of the constant parameter that the provided expression is a path to. +fn const_param_def_id(expr: &hir::Expr<'_>) -> Option { + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments + // currently have to be wrapped in curly brackets, so it's necessary to special-case. + let expr = match &expr.kind { + hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { + block.expr.as_ref().unwrap() + } + _ => expr, + }; + + match &expr.kind { + hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res { + hir::def::Res::Def(hir::def::DefKind::ConstParam, did) => Some(did), + _ => None, + }, + _ => None, + } +} + impl<'tcx> Const<'tcx> { + pub fn from_hir_anon_const( + tcx: TyCtxt<'tcx>, + ast_const: &hir::AnonConst, + ty: Ty<'tcx>, + ) -> &'tcx Self { + debug!("Const::from_hir_anon_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const); + + let def_id = tcx.hir().local_def_id(ast_const.hir_id); + + let expr = &tcx.hir().body(ast_const.body).value; + + let lit_input = match expr.kind { + hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), + hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind { + hir::ExprKind::Lit(ref lit) => { + Some(LitToConstInput { lit: &lit.node, ty, neg: true }) + } + _ => None, + }, + _ => None, + }; + + if let Some(lit_input) = lit_input { + // If an error occurred, ignore that it's a literal and leave reporting the error up to + // mir. + if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { + return c; + } else { + tcx.sess.delay_span_bug(expr.span, "ast_const_to_const: couldn't lit_to_const"); + } + } + + let kind = if let Some(def_id) = const_param_def_id(expr) { + // Find the name and index of the const parameter by indexing the generics of the + // parent item and construct a `ParamConst`. + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let item_id = tcx.hir().get_parent_node(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)]; + let name = tcx.hir().name(hir_id); + ty::ConstKind::Param(ty::ParamConst::new(index, name)) + } else { + ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id), None) + }; + tcx.mk_const(ty::Const { val: kind, ty }) + } + #[inline] pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { tcx.mk_const(Self { val: ConstKind::Value(val), ty }) diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 245df0846b5..880bce7fde4 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -106,6 +106,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + let count = + self.monomorphize(&count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); + bx.write_operand_repeatedly(cg_elem, count, dest) } diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 521861624cb..e1aacb1fa26 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1986,7 +1986,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Rvalue::Repeat(operand, len) => { - if *len > 1 { + // If the length cannot be evaluated we must assume that the length can be larger + // than 1. + // If the length is larger than 1, the repeat expression will need to copy the + // element, so we require the `Copy` trait. + if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { if let Operand::Move(_) = operand { // While this is located in `nll::typeck` this error is not an NLL error, it's // a required check to make sure that repeated elements implement `Copy`. diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index 02b596863ab..b9c9e9834ef 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -3,7 +3,7 @@ use crate::hair::cx::to_ref::ToRef; use crate::hair::cx::Cx; use crate::hair::util::UserAnnotatedTyHelpers; use crate::hair::*; -use rustc::mir::interpret::{ErrorHandled, Scalar}; +use rustc::mir::interpret::Scalar; use rustc::mir::BorrowKind; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; @@ -406,34 +406,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( // Now comes the rote stuff: hir::ExprKind::Repeat(ref v, ref count) => { - let def_id = cx.tcx.hir().local_def_id(count.hir_id); - let substs = InternalSubsts::identity_for_item(cx.tcx, def_id); - let span = cx.tcx.def_span(def_id); - let count = match cx.tcx.const_eval_resolve( - ty::ParamEnv::reveal_all(), - def_id, - substs, - None, - Some(span), - ) { - Ok(cv) => { - if let Some(count) = cv.try_to_bits_for_ty( - cx.tcx, - ty::ParamEnv::reveal_all(), - cx.tcx.types.usize, - ) { - count as u64 - } else { - bug!("repeat count constant value can't be converted to usize"); - } - } - Err(ErrorHandled::Reported) => 0, - Err(ErrorHandled::TooGeneric) => { - let span = cx.tcx.def_span(def_id); - cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters"); - 0 - } - }; + let count = ty::Const::from_hir_anon_const(cx.tcx, count, cx.tcx.types.usize); ExprKind::Repeat { value: v.to_ref(), count } } diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs index cb93ba7c925..77042240acf 100644 --- a/src/librustc_mir_build/hair/mod.rs +++ b/src/librustc_mir_build/hair/mod.rs @@ -229,7 +229,7 @@ crate enum ExprKind<'tcx> { }, Repeat { value: ExprRef<'tcx>, - count: u64, + count: &'tcx Const<'tcx>, }, Array { fields: Vec>, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 408e5c2d2f2..2d7bf81aedd 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -22,7 +22,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::print; -use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs}; +use rustc_hir::{Constness, GenericArg, GenericArgs}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS}; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -39,8 +39,6 @@ use std::collections::BTreeSet; use std::iter; use std::slice; -use rustc::mir::interpret::LitToConstInput; - #[derive(Debug)] pub struct PathSeg(pub DefId, pub usize); @@ -782,7 +780,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.ast_const_to_const(&ct.value, tcx.type_of(param.def_id)).into() + ty::Const::from_hir_anon_const(tcx, &ct.value, tcx.type_of(param.def_id)).into() } _ => unreachable!(), }, @@ -2766,7 +2764,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .unwrap_or(tcx.types.err) } hir::TyKind::Array(ref ty, ref length) => { - let length = self.ast_const_to_const(length, tcx.types.usize); + let length = ty::Const::from_hir_anon_const(tcx, length, tcx.types.usize); let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) } @@ -2798,75 +2796,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { result_ty } - /// Returns the `DefId` of the constant parameter that the provided expression is a path to. - pub fn const_param_def_id(&self, expr: &hir::Expr<'_>) -> Option { - // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments - // currently have to be wrapped in curly brackets, so it's necessary to special-case. - let expr = match &expr.kind { - ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { - block.expr.as_ref().unwrap() - } - _ => expr, - }; - - match &expr.kind { - ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res { - Res::Def(DefKind::ConstParam, did) => Some(did), - _ => None, - }, - _ => None, - } - } - - pub fn ast_const_to_const( - &self, - ast_const: &hir::AnonConst, - ty: Ty<'tcx>, - ) -> &'tcx ty::Const<'tcx> { - debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const); - - let tcx = self.tcx(); - let def_id = tcx.hir().local_def_id(ast_const.hir_id); - - let expr = &tcx.hir().body(ast_const.body).value; - - let lit_input = match expr.kind { - hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), - hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind { - hir::ExprKind::Lit(ref lit) => { - Some(LitToConstInput { lit: &lit.node, ty, neg: true }) - } - _ => None, - }, - _ => None, - }; - - if let Some(lit_input) = lit_input { - // If an error occurred, ignore that it's a literal and leave reporting the error up to - // mir. - if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { - return c; - } else { - tcx.sess.delay_span_bug(expr.span, "ast_const_to_const: couldn't lit_to_const"); - } - } - - let kind = if let Some(def_id) = self.const_param_def_id(expr) { - // Find the name and index of the const parameter by indexing the generics of the - // parent item and construct a `ParamConst`. - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let item_id = tcx.hir().get_parent_node(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)]; - let name = tcx.hir().name(hir_id); - ty::ConstKind::Param(ty::ParamConst::new(index, name)) - } else { - ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id), None) - }; - tcx.mk_const(ty::Const { val: kind, ty }) - } - pub fn impl_trait_ty_to_ty( &self, def_id: DefId, diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 7203980b238..e57e6cd80ca 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -18,7 +18,6 @@ use crate::type_error_struct; use crate::util::common::ErrorReported; use rustc::middle::lang_items; -use rustc::mir::interpret::ErrorHandled; use rustc::ty; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::Ty; @@ -1009,12 +1008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let tcx = self.tcx; let count_def_id = tcx.hir().local_def_id(count.hir_id); - let count = if self.const_param_def_id(count).is_some() { - Ok(self.to_const(count, tcx.type_of(count_def_id))) - } else { - tcx.const_eval_poly(count_def_id) - .map(|val| ty::Const::from_value(tcx, val, tcx.type_of(count_def_id))) - }; + let count = self.to_const(count, tcx.type_of(count_def_id)); let uty = match expected { ExpectHasType(uty) => match uty.kind { @@ -1042,17 +1036,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if element_ty.references_error() { return tcx.types.err; } - match count { - Ok(count) => tcx.mk_ty(ty::Array(t, count)), - Err(ErrorHandled::TooGeneric) => { - self.tcx.sess.span_err( - tcx.def_span(count_def_id), - "array lengths can't depend on generic parameters", - ); - tcx.types.err - } - Err(ErrorHandled::Reported) => tcx.types.err, - } + + tcx.mk_ty(ty::Array(t, count)) } fn check_expr_tuple( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 32f0f578d05..292ad1e94a7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3279,13 +3279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - /// Returns the `DefId` of the constant parameter that the provided expression is a path to. - pub fn const_param_def_id(&self, hir_c: &hir::AnonConst) -> Option { - AstConv::const_param_def_id(self, &self.tcx.hir().body(hir_c.body).value) - } - pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - AstConv::ast_const_to_const(self, ast_c, ty) + ty::Const::from_hir_anon_const(self.tcx, ast_c, ty) } // If the type given by the user has free regions, save it for later, since diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs index 597fbbf00d5..3a022230b39 100644 --- a/src/test/compile-fail/issue-52443.rs +++ b/src/test/compile-fail/issue-52443.rs @@ -7,10 +7,5 @@ fn main() { //~^ ERROR `while` is not allowed in a `const` //~| WARN denote infinite loops with [(); { for _ in 0usize.. {}; 0}]; - //~^ ERROR calls in constants are limited to constant functions - //~| ERROR calls in constants are limited to constant functions - //~| ERROR `for` is not allowed in a `const` - //~| ERROR references in constants may only refer to immutable values - //~| ERROR evaluation of constant value failed - //~| ERROR constant contains unimplemented expression type + //~^ ERROR `for` is not allowed in a `const` } diff --git a/src/test/ui/closures/issue-52437.rs b/src/test/ui/closures/issue-52437.rs index 1e649a556e0..634638e1335 100644 --- a/src/test/ui/closures/issue-52437.rs +++ b/src/test/ui/closures/issue-52437.rs @@ -3,4 +3,5 @@ fn main() { //~^ ERROR: invalid label name `'static` //~| ERROR: `loop` is not allowed in a `const` //~| ERROR: type annotations needed + //~| ERROR mismatched types } diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr index b9225e55fe5..acb59c7b02d 100644 --- a/src/test/ui/closures/issue-52437.stderr +++ b/src/test/ui/closures/issue-52437.stderr @@ -19,7 +19,15 @@ error[E0282]: type annotations needed LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] | ^ consider giving this closure parameter a type -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/issue-52437.rs:2:5 + | +LL | fn main() { + | - expected `()` because of default return type +LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[(); _]` + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0282, E0658. +Some errors have detailed explanations: E0282, E0308, E0658. For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/issues/issue-61336-1.rs b/src/test/ui/const-generics/issues/issue-61336-1.rs index 5b5e431bf2f..165d3e1c2e6 100644 --- a/src/test/ui/const-generics/issues/issue-61336-1.rs +++ b/src/test/ui/const-generics/issues/issue-61336-1.rs @@ -1,9 +1,10 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +// build-pass + fn f(x: T) -> [T; N] { [x; N] - //~^ ERROR array lengths can't depend on generic parameters } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-61336-1.stderr b/src/test/ui/const-generics/issues/issue-61336-1.stderr index 949fa896d87..d48d8ff6894 100644 --- a/src/test/ui/const-generics/issues/issue-61336-1.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-1.stderr @@ -6,11 +6,3 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default -error: array lengths can't depend on generic parameters - --> $DIR/issue-61336-1.rs:5:9 - | -LL | [x; N] - | ^ - -error: aborting due to previous error - diff --git a/src/test/ui/const-generics/issues/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs index 7bb36f41b8f..c5bf6b6ce94 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.rs +++ b/src/test/ui/const-generics/issues/issue-61336-2.rs @@ -2,13 +2,12 @@ //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash fn f(x: T) -> [T; N] { - [x; {N}] - //~^ ERROR array lengths can't depend on generic parameters + [x; { N }] } fn g(x: T) -> [T; N] { - [x; {N}] - //~^ ERROR array lengths can't depend on generic parameters + [x; { N }] + //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr index 63f86c81b1e..9ced427b93c 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.stderr @@ -6,17 +6,19 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default -error: array lengths can't depend on generic parameters - --> $DIR/issue-61336-2.rs:5:9 +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/issue-61336-2.rs:9:5 | -LL | [x; {N}] - | ^^^ - -error: array lengths can't depend on generic parameters - --> $DIR/issue-61336-2.rs:10:9 +LL | [x; { N }] + | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | +help: consider restricting this type parameter with `T: std::marker::Copy` + --> $DIR/issue-61336-2.rs:8:6 | -LL | [x; {N}] - | ^^^ +LL | fn g(x: T) -> [T; N] { + | ^ + = note: the `Copy` trait is required because the repeated element will be copied -error: aborting due to 2 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs index edc012cbb3d..7e84e62d8be 100644 --- a/src/test/ui/const-generics/issues/issue-61336.rs +++ b/src/test/ui/const-generics/issues/issue-61336.rs @@ -3,12 +3,11 @@ fn f(x: T) -> [T; N] { [x; N] - //~^ ERROR array lengths can't depend on generic parameters } fn g(x: T) -> [T; N] { [x; N] - //~^ ERROR array lengths can't depend on generic parameters + //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr index f96e8e02d4e..ace7955fbdd 100644 --- a/src/test/ui/const-generics/issues/issue-61336.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.stderr @@ -6,17 +6,19 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default -error: array lengths can't depend on generic parameters - --> $DIR/issue-61336.rs:5:9 +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/issue-61336.rs:9:5 | LL | [x; N] - | ^ - -error: array lengths can't depend on generic parameters - --> $DIR/issue-61336.rs:10:9 + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | -LL | [x; N] - | ^ +help: consider restricting this type parameter with `T: std::marker::Copy` + --> $DIR/issue-61336.rs:8:6 + | +LL | fn g(x: T) -> [T; N] { + | ^ + = note: the `Copy` trait is required because the repeated element will be copied -error: aborting due to 2 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs index c5e6fe9104b..14b1190df0f 100644 --- a/src/test/ui/const-generics/issues/issue-62456.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -1,9 +1,10 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +// build-pass + fn foo() { let _ = [0u64; N + 1]; - //~^ ERROR array lengths can't depend on generic parameters } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr index 9cdccf8407c..47dd3c01fa9 100644 --- a/src/test/ui/const-generics/issues/issue-62456.stderr +++ b/src/test/ui/const-generics/issues/issue-62456.stderr @@ -6,11 +6,3 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default -error: array lengths can't depend on generic parameters - --> $DIR/issue-62456.rs:5:20 - | -LL | let _ = [0u64; N + 1]; - | ^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 74ed3d354fc..cd3cfaac3b9 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -16,7 +16,7 @@ struct ArrayHolder([u32; X]); impl ArrayHolder<{ X }> { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) - //~^ ERROR: array lengths can't depend on generic parameters + //~^ ERROR: mismatched types } } diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.stderr index c2a752ec171..4482389bbdd 100644 --- a/src/test/ui/const-generics/issues/issue-62504.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.stderr @@ -1,8 +1,12 @@ -error: array lengths can't depend on generic parameters - --> $DIR/issue-62504.rs:18:25 +error[E0308]: mismatched types + --> $DIR/issue-62504.rs:18:21 | LL | ArrayHolder([0; Self::SIZE]) - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE` + | + = note: expected array `[u32; _]` + found array `[u32; _]` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index 79c5ac9dd18..3d657b0947b 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -1,5 +1,7 @@ // Regression test for #67739 +// check-pass + #![allow(incomplete_features)] #![feature(const_generics)] @@ -10,7 +12,6 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::()]; - //~^ ERROR: array lengths can't depend on generic parameters 0 } } diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.stderr deleted file mode 100644 index a31b556c086..00000000000 --- a/src/test/ui/const-generics/issues/issue-67739.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: array lengths can't depend on generic parameters - --> $DIR/issue-67739.rs:12:15 - | -LL | [0u8; mem::size_of::()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs index 6fd8e9cbc80..3ae55ebdbaf 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs @@ -19,6 +19,7 @@ const A_I8_I : [u32; (i8::MAX as usize) + 1] = [0; (i8::MAX + 1) as usize]; //~^ ERROR evaluation of constant value failed +//~| ERROR mismatched types fn main() { foo(&A_I8_I[..]); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr index 2c5b4607aa4..94b7c12fc1a 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -4,6 +4,16 @@ error[E0080]: evaluation of constant value failed LL | = [0; (i8::MAX + 1) as usize]; | ^^^^^^^^^^^^^ attempt to add with overflow -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/const-eval-overflow-3.rs:20:7 + | +LL | = [0; (i8::MAX + 1) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `128usize`, found `(i8::MAX + 1) as usize` + | + = note: expected array `[u32; 128]` + found array `[u32; _]` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0080`. +Some errors have detailed explanations: E0080, E0308. +For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs index db6f17a671a..e7b88e00feb 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs @@ -18,6 +18,7 @@ const A_I8_I = [0; (i8::MAX + 1u8) as usize]; //~^ ERROR mismatched types //~| ERROR cannot add `u8` to `i8` +//~| ERROR mismatched types fn main() { foo(&A_I8_I[..]); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index 3da34fe9af7..aebe4feef8d 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -12,7 +12,16 @@ LL | = [0; (i8::MAX + 1u8) as usize]; | = help: the trait `std::ops::Add` is not implemented for `i8` -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/const-eval-overflow-3b.rs:18:7 + | +LL | = [0; (i8::MAX + 1u8) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `128usize`, found `(i8::MAX + 1u8) as usize` + | + = note: expected array `[u32; 128]` + found array `[u32; _]` + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/const-eval/issue-52442.rs b/src/test/ui/consts/const-eval/issue-52442.rs index d820c705161..df4cc8e3026 100644 --- a/src/test/ui/consts/const-eval/issue-52442.rs +++ b/src/test/ui/consts/const-eval/issue-52442.rs @@ -1,6 +1,4 @@ fn main() { [(); { &loop { break } as *const _ as usize } ]; - //~^ ERROR casting pointers to integers in constants is unstable - //~| ERROR `loop` is not allowed in a `const` - //~| ERROR evaluation of constant value failed + //~^ ERROR `loop` is not allowed in a `const` } diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr index eda2dbf0b6b..0ea974f1f66 100644 --- a/src/test/ui/consts/const-eval/issue-52442.stderr +++ b/src/test/ui/consts/const-eval/issue-52442.stderr @@ -7,22 +7,6 @@ LL | [(); { &loop { break } as *const _ as usize } ]; = note: see issue #52000 for more information = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/issue-52442.rs:2:13 - | -LL | [(); { &loop { break } as *const _ as usize } ]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #51910 for more information - = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable - -error[E0080]: evaluation of constant value failed - --> $DIR/issue-52442.rs:2:13 - | -LL | [(); { &loop { break } as *const _ as usize } ]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants - -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0080, E0658. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.rs b/src/test/ui/consts/const-eval/match-test-ptr-null.rs index 80494d16629..5cfe36f57e6 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.rs +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.rs @@ -2,7 +2,7 @@ fn main() { // Make sure match uses the usual pointer comparison code path -- i.e., it should complain // that pointer comparison is disallowed, not that parts of a pointer are accessed as raw // bytes. - let _: [u8; 0] = [4; { + let _: [u8; 0] = [4; { //~ ERROR mismatched types match &1 as *const i32 as usize { //~^ ERROR casting pointers to integers in constants //~| ERROR `match` is not allowed in a `const` diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr index b47f6d5f845..7c4da5e7d86 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr @@ -28,7 +28,30 @@ error[E0080]: evaluation of constant value failed LL | match &1 as *const i32 as usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/match-test-ptr-null.rs:5:22 + | +LL | let _: [u8; 0] = [4; { + | ____________-------___^ + | | | + | | expected due to this +LL | | match &1 as *const i32 as usize { +LL | | +LL | | +... | +LL | | } +LL | | }]; + | |______^ expected `0usize`, found `{ + match &1 as *const i32 as usize { + 0 => 42, + n => n, + } + }` + | + = note: expected array `[u8; 0]` + found array `[u8; _]` + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0080, E0658. +Some errors have detailed explanations: E0080, E0308, E0658. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/issue-52432.rs b/src/test/ui/consts/issue-52432.rs index 2d4c939f47d..ded79458e63 100644 --- a/src/test/ui/consts/issue-52432.rs +++ b/src/test/ui/consts/issue-52432.rs @@ -6,5 +6,4 @@ fn main() { //~| ERROR: type annotations needed [(); &(static || {}) as *const _ as usize]; //~^ ERROR: closures cannot be static - //~| ERROR: evaluation of constant value failed } diff --git a/src/test/ui/consts/issue-52432.stderr b/src/test/ui/consts/issue-52432.stderr index e9539d24118..d25c11138f4 100644 --- a/src/test/ui/consts/issue-52432.stderr +++ b/src/test/ui/consts/issue-52432.stderr @@ -16,13 +16,7 @@ error[E0282]: type annotations needed LL | [(); &(static |x| {}) as *const _ as usize]; | ^ consider giving this closure parameter a type -error[E0080]: evaluation of constant value failed - --> $DIR/issue-52432.rs:7:10 - | -LL | [(); &(static || {}) as *const _ as usize]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0080, E0282, E0697. -For more information about an error, try `rustc --explain E0080`. +Some errors have detailed explanations: E0282, E0697. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/consts/too_generic_eval_ice.rs b/src/test/ui/consts/too_generic_eval_ice.rs index 7a299169bc4..7e4d4dbe446 100644 --- a/src/test/ui/consts/too_generic_eval_ice.rs +++ b/src/test/ui/consts/too_generic_eval_ice.rs @@ -7,6 +7,7 @@ impl Foo { [5; Self::HOST_SIZE] == [6; 0] //~ ERROR no associated item named `HOST_SIZE` //~^ the size for values of type `A` cannot be known //~| the size for values of type `B` cannot be known + //~| binary operation `==` cannot be applied to type `[{integer}; _]` } } diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index 8836de0023c..ffa28225b79 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -41,7 +41,15 @@ LL | [5; Self::HOST_SIZE] == [6; 0] = help: the trait `std::marker::Sized` is not implemented for `B` = note: to learn more, visit -error: aborting due to 3 previous errors +error[E0369]: binary operation `==` cannot be applied to type `[{integer}; _]` + --> $DIR/too_generic_eval_ice.rs:7:30 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | -------------------- ^^ ------ [{integer}; 0] + | | + | [{integer}; _] + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0599. +Some errors have detailed explanations: E0277, E0369, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-39559-2.rs b/src/test/ui/issues/issue-39559-2.rs index 3a52e4d6216..ec0275b2d6c 100644 --- a/src/test/ui/issues/issue-39559-2.rs +++ b/src/test/ui/issues/issue-39559-2.rs @@ -17,4 +17,5 @@ fn main() { = [0; Dim3::dim()]; //~^ ERROR E0015 //~| ERROR E0080 + //~| ERROR mismatched types } diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr index 586debbbe53..7cbf63c2da0 100644 --- a/src/test/ui/issues/issue-39559-2.stderr +++ b/src/test/ui/issues/issue-39559-2.stderr @@ -22,7 +22,19 @@ error[E0080]: evaluation of constant value failed LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ calling non-const function `::dim` -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/issue-39559-2.rs:17:11 + | +LL | let array: [usize; Dim3::dim()] + | -------------------- expected due to this +... +LL | = [0; Dim3::dim()]; + | ^^^^^^^^^^^^^^^^ expected `Dim3::dim()`, found `Dim3::dim()` + | + = note: expected array `[usize; _]` + found array `[usize; _]` + +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0015, E0080. +Some errors have detailed explanations: E0015, E0080, E0308. For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-52060.rs b/src/test/ui/issues/issue-52060.rs index fed08902c8b..2688049fcc9 100644 --- a/src/test/ui/issues/issue-52060.rs +++ b/src/test/ui/issues/issue-52060.rs @@ -4,5 +4,6 @@ static A: &'static [u32] = &[1]; static B: [u32; 1] = [0; A.len()]; //~^ ERROR [E0013] //~| ERROR evaluation of constant value failed +//~| ERROR mismatched types fn main() {} diff --git a/src/test/ui/issues/issue-52060.stderr b/src/test/ui/issues/issue-52060.stderr index 502825e9766..e076e183937 100644 --- a/src/test/ui/issues/issue-52060.stderr +++ b/src/test/ui/issues/issue-52060.stderr @@ -12,7 +12,16 @@ error[E0080]: evaluation of constant value failed LL | static B: [u32; 1] = [0; A.len()]; | ^ constant accesses static -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/issue-52060.rs:4:22 + | +LL | static B: [u32; 1] = [0; A.len()]; + | ^^^^^^^^^^^^ expected `1usize`, found `A.len()` + | + = note: expected array `[u32; 1]` + found array `[u32; _]` + +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0013, E0080. +Some errors have detailed explanations: E0013, E0080, E0308. For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs index d060f26fb2a..2c5257ce063 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs @@ -19,5 +19,4 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA` fn main() { let _ = [0; B::VALUE]; - //~^ ERROR array lengths can't depend on generic parameters } diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr index c6b2b4d27a2..8ae0f8b804c 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr @@ -13,13 +13,7 @@ LL | type MyA: TraitA; LL | impl TraitB for B { | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation -error: array lengths can't depend on generic parameters - --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 - | -LL | let _ = [0; B::VALUE]; - | ^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0046, E0437. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr index efad00b272c..4a2d1d9f921 100644 --- a/src/test/ui/repeat_count.stderr +++ b/src/test/ui/repeat_count.stderr @@ -28,6 +28,12 @@ error[E0308]: mismatched types LL | let e = [0; "foo"]; | ^^^^^ expected `usize`, found `&str` +error[E0308]: mismatched types + --> $DIR/repeat_count.rs:28:17 + | +LL | let g = [0; G { g: () }]; + | ^^^^^^^^^^^ expected `usize`, found struct `main::G` + error[E0308]: mismatched types --> $DIR/repeat_count.rs:19:17 | @@ -50,12 +56,6 @@ help: you can convert an `isize` to `usize` and panic if the converted value wou LL | let f = [0_usize; (-1_isize).try_into().unwrap()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/repeat_count.rs:28:17 - | -LL | let g = [0; G { g: () }]; - | ^^^^^^^^^^^ expected `usize`, found struct `main::G` - error: aborting due to 8 previous errors Some errors have detailed explanations: E0308, E0435. diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs index 63d3431ec9b..708d72a2df7 100644 --- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs +++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs @@ -24,6 +24,7 @@ fn i() { static a: [u8; N] = [0; N]; //~^ ERROR can't use generic parameters from outer function //~^^ ERROR can't use generic parameters from outer function + //~| ERROR mismatched types } fn main() {} diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr index 82e2aa2db8e..97c60c72298 100644 --- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr +++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr @@ -48,6 +48,16 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/issue-65035-static-with-parent-generics.rs:24:25 + | +LL | static a: [u8; N] = [0; N]; + | ^^^^^^ expected `N`, found `N` + | + = note: expected array `[u8; _]` + found array `[u8; _]` + +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0401`. +Some errors have detailed explanations: E0308, E0401. +For more information about an error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From fa5a15c7d507f8d2d27770602101b9d0b5cc71bc Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Mar 2020 15:53:00 +0100 Subject: Document most methods on `ty::Const` --- src/librustc/ty/sty.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src') diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5d1f6ae3877..7200ebef940 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2422,6 +2422,8 @@ fn const_param_def_id(expr: &hir::Expr<'_>) -> Option { } impl<'tcx> Const<'tcx> { + /// Literals and const generic parameters are eagerly converted to a constant, everything else + /// becomes `Unevaluated`. pub fn from_hir_anon_const( tcx: TyCtxt<'tcx>, ast_const: &hir::AnonConst, @@ -2471,16 +2473,19 @@ impl<'tcx> Const<'tcx> { } #[inline] + /// Interns the given value as a constant. pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { tcx.mk_const(Self { val: ConstKind::Value(val), ty }) } #[inline] + /// Interns the given scalar as a constant. pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self { Self::from_value(tcx, ConstValue::Scalar(val), ty) } #[inline] + /// Creates a constant with the given integer value and interns it. pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self { let size = tcx .layout_of(ty) @@ -2490,21 +2495,27 @@ impl<'tcx> Const<'tcx> { } #[inline] + /// Creates an interned zst constant. pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { Self::from_scalar(tcx, Scalar::zst(), ty) } #[inline] + /// Creates an interned bool constant. pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> &'tcx Self { Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) } #[inline] + /// Creates an interned usize constant. pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self { Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) } #[inline] + /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of + /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it + /// contains const generic parameters or pointers). pub fn try_eval_bits( &self, tcx: TyCtxt<'tcx>, @@ -2518,6 +2529,8 @@ impl<'tcx> Const<'tcx> { } #[inline] + /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the + /// unevaluated constant. pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> { let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| { let param_env_and_substs = param_env.with_reveal_all().and(substs); @@ -2574,12 +2587,14 @@ impl<'tcx> Const<'tcx> { } #[inline] + /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { self.try_eval_bits(tcx, param_env, ty) .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self)) } #[inline] + /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`. pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 { self.eval_bits(tcx, param_env, tcx.types.usize) as u64 } -- cgit 1.4.1-3-g733a5 From 3f89c38bc0231f08e0eee6fa9942e7c71b5544f3 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Mar 2020 20:12:54 +0100 Subject: Inline `const_param_def_id` at its only use site --- src/librustc/ty/sty.rs | 62 +++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7200ebef940..9e0f4668d95 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2401,26 +2401,6 @@ pub struct Const<'tcx> { #[cfg(target_arch = "x86_64")] static_assert_size!(Const<'_>, 48); -/// Returns the `DefId` of the constant parameter that the provided expression is a path to. -fn const_param_def_id(expr: &hir::Expr<'_>) -> Option { - // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments - // currently have to be wrapped in curly brackets, so it's necessary to special-case. - let expr = match &expr.kind { - hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { - block.expr.as_ref().unwrap() - } - _ => expr, - }; - - match &expr.kind { - hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res { - hir::def::Res::Def(hir::def::DefKind::ConstParam, did) => Some(did), - _ => None, - }, - _ => None, - } -} - impl<'tcx> Const<'tcx> { /// Literals and const generic parameters are eagerly converted to a constant, everything else /// becomes `Unevaluated`. @@ -2456,20 +2436,36 @@ impl<'tcx> Const<'tcx> { } } - let kind = if let Some(def_id) = const_param_def_id(expr) { - // Find the name and index of the const parameter by indexing the generics of the - // parent item and construct a `ParamConst`. - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let item_id = tcx.hir().get_parent_node(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)]; - let name = tcx.hir().name(hir_id); - ty::ConstKind::Param(ty::ParamConst::new(index, name)) - } else { - ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id), None) + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments + // currently have to be wrapped in curly brackets, so it's necessary to special-case. + let expr = match &expr.kind { + hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { + block.expr.as_ref().unwrap() + } + _ => expr, }; - tcx.mk_const(ty::Const { val: kind, ty }) + + use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; + let val = match expr.kind { + ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { + // Find the name and index of the const parameter by indexing the generics of + // the parent item and construct a `ParamConst`. + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let item_id = tcx.hir().get_parent_node(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)]; + let name = tcx.hir().name(hir_id); + ty::ConstKind::Param(ty::ParamConst::new(index, name)) + } + _ => ty::ConstKind::Unevaluated( + def_id, + InternalSubsts::identity_for_item(tcx, def_id), + None, + ), + }; + + tcx.mk_const(ty::Const { val, ty }) } #[inline] -- cgit 1.4.1-3-g733a5 From 770be24ccd9c47c05aceff91ce5a081798d97c67 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 17 Mar 2020 18:54:20 +0100 Subject: Use `DefId`s to identify anon consts when converting from HIR to ty::Const --- src/librustc/ty/sty.rs | 14 ++++++-------- src/librustc_mir_build/hair/cx/expr.rs | 1 + src/librustc_typeck/astconv.rs | 4 +++- src/librustc_typeck/check/mod.rs | 3 ++- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 9e0f4668d95..e5c88c1c9ba 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2404,16 +2404,14 @@ static_assert_size!(Const<'_>, 48); impl<'tcx> Const<'tcx> { /// Literals and const generic parameters are eagerly converted to a constant, everything else /// becomes `Unevaluated`. - pub fn from_hir_anon_const( - tcx: TyCtxt<'tcx>, - ast_const: &hir::AnonConst, - ty: Ty<'tcx>, - ) -> &'tcx Self { - debug!("Const::from_hir_anon_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const); + pub fn from_hir_anon_const(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Ty<'tcx>) -> &'tcx Self { + debug!("Const::from_hir_anon_const(id={:?})", def_id); + + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let def_id = tcx.hir().local_def_id(ast_const.hir_id); + let body_id = tcx.hir().body_owned_by(hir_id); - let expr = &tcx.hir().body(ast_const.body).value; + let expr = &tcx.hir().body(body_id).value; let lit_input = match expr.kind { hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index b9c9e9834ef..73c442e4a91 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -406,6 +406,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( // Now comes the rote stuff: hir::ExprKind::Repeat(ref v, ref count) => { + let count = cx.tcx.hir().local_def_id(count.hir_id); let count = ty::Const::from_hir_anon_const(cx.tcx, count, cx.tcx.types.usize); ExprKind::Repeat { value: v.to_ref(), count } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 2d7bf81aedd..ee713482268 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -780,7 +780,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - ty::Const::from_hir_anon_const(tcx, &ct.value, tcx.type_of(param.def_id)).into() + let ct = tcx.hir().local_def_id(ct.value.hir_id); + ty::Const::from_hir_anon_const(tcx, ct, tcx.type_of(param.def_id)).into() } _ => unreachable!(), }, @@ -2764,6 +2765,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .unwrap_or(tcx.types.err) } hir::TyKind::Array(ref ty, ref length) => { + let length = tcx.hir().local_def_id(length.hir_id); let length = ty::Const::from_hir_anon_const(tcx, length, tcx.types.usize); let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 292ad1e94a7..f790bcfbb09 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3280,7 +3280,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - ty::Const::from_hir_anon_const(self.tcx, ast_c, ty) + let c = self.tcx.hir().local_def_id(ast_c.hir_id); + ty::Const::from_hir_anon_const(self.tcx, c, ty) } // If the type given by the user has free regions, save it for later, since -- cgit 1.4.1-3-g733a5 From c3b98813c42ae0a0da402f1a933ad7c24b1c1c43 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 11 Mar 2020 22:24:20 +0000 Subject: Remove `ReClosureBound` --- src/librustc/ich/impls_ty.rs | 3 -- src/librustc/mir/query.rs | 49 +++++++++++----------- src/librustc/ty/print/pretty.rs | 8 +--- src/librustc/ty/structural_impls.rs | 2 - src/librustc/ty/sty.rs | 10 ----- .../infer/canonical/canonicalizer.rs | 4 -- src/librustc_infer/infer/combine.rs | 4 -- src/librustc_infer/infer/error_reporting/mod.rs | 5 --- src/librustc_infer/infer/freshen.rs | 4 -- .../infer/lexical_region_resolve/mod.rs | 7 +--- src/librustc_infer/infer/region_constraints/mod.rs | 2 +- .../borrow_check/diagnostics/region_name.rs | 3 +- src/librustc_mir/borrow_check/region_infer/mod.rs | 41 ++++-------------- src/librustc_trait_selection/opaque_types.rs | 6 +-- src/librustc_typeck/outlives/utils.rs | 1 - src/librustc_typeck/variance/constraints.rs | 1 - src/librustdoc/clean/mod.rs | 1 - .../projection-one-region-closure.stderr | 2 +- ...rojection-one-region-trait-bound-closure.stderr | 2 +- ...rojection-two-region-trait-bound-closure.stderr | 24 +++++------ 20 files changed, 50 insertions(+), 129 deletions(-) (limited to 'src') diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 844250f51a0..433076bb834 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -92,9 +92,6 @@ impl<'a> HashStable> for ty::RegionKind { ty::ReFree(ref free_region) => { free_region.hash_stable(hcx, hasher); } - ty::ReClosureBound(vid) => { - vid.hash_stable(hcx, hasher); - } ty::ReVar(..) | ty::RePlaceholder(..) => { bug!("StableHasher: unexpected region {:?}", *self) } diff --git a/src/librustc/mir/query.rs b/src/librustc/mir/query.rs index 824cdfe55bf..8c81f5227d2 100644 --- a/src/librustc/mir/query.rs +++ b/src/librustc/mir/query.rs @@ -88,34 +88,35 @@ pub struct ConstQualifs { /// requirements are then verified and proved by the closure's /// creating function. This struct encodes those requirements. /// -/// The requirements are listed as being between various -/// `RegionVid`. The 0th region refers to `'static`; subsequent region -/// vids refer to the free regions that appear in the closure (or -/// generator's) type, in order of appearance. (This numbering is -/// actually defined by the `UniversalRegions` struct in the NLL -/// region checker. See for example -/// `UniversalRegions::closure_mapping`.) Note that we treat the free -/// regions in the closure's type "as if" they were erased, so their -/// precise identity is not important, only their position. +/// The requirements are listed as being between various `RegionVid`. The 0th +/// region refers to `'static`; subsequent region vids refer to the free +/// regions that appear in the closure (or generator's) type, in order of +/// appearance. (This numbering is actually defined by the `UniversalRegions` +/// struct in the NLL region checker. See for example +/// `UniversalRegions::closure_mapping`.) Note the free regions in the +/// closure's signature and captures are erased. /// /// Example: If type check produces a closure with the closure substs: /// /// ```text /// ClosureSubsts = [ -/// i8, // the "closure kind" -/// for<'x> fn(&'a &'x u32) -> &'x u32, // the "closure signature" -/// &'a String, // some upvar +/// 'a, // From the parent. +/// 'b, +/// i8, // the "closure kind" +/// for<'x> fn(&' &'x u32) -> &'x u32, // the "closure signature" +/// &' String, // some upvar /// ] /// ``` /// -/// here, there is one unique free region (`'a`) but it appears -/// twice. We would "renumber" each occurrence to a unique vid, as follows: +/// We would "renumber" each free region to a unique vid, as follows: /// /// ```text /// ClosureSubsts = [ -/// i8, // the "closure kind" -/// for<'x> fn(&'1 &'x u32) -> &'x u32, // the "closure signature" -/// &'2 String, // some upvar +/// '1, // From the parent. +/// '2, +/// i8, // the "closure kind" +/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature" +/// &'4 String, // some upvar /// ] /// ``` /// @@ -124,14 +125,12 @@ pub struct ConstQualifs { /// can be extracted from its type and constrained to have the given /// outlives relationship. /// -/// In some cases, we have to record outlives requirements between -/// types and regions as well. In that case, if those types include -/// any regions, those regions are recorded as `ReClosureBound` -/// instances assigned one of these same indices. Those regions will -/// be substituted away by the creator. We use `ReClosureBound` in -/// that case because the regions must be allocated in the global -/// `TyCtxt`, and hence we cannot use `ReVar` (which is what we use -/// internally within the rest of the NLL code). +/// In some cases, we have to record outlives requirements between types and +/// regions as well. In that case, if those types include any regions, those +/// regions are recorded using their external names (`ReStatic`, +/// `ReEarlyBound`, `ReFree`). We use these because in a query response we +/// cannot use `ReVar` (which is what we use internally within the rest of the +/// NLL code). #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct ClosureRegionRequirements<'tcx> { /// The number of external regions defined on the closure. In our diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index cb01d821c18..301254d4f0d 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1547,7 +1547,7 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { ty::ReVar(_) | ty::ReScope(_) | ty::ReErased => false, - ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true, + ty::ReStatic | ty::ReEmpty(_) => true, } } @@ -1659,12 +1659,6 @@ impl FmtPrinter<'_, '_, F> { p!(write("'", ui)); return Ok(self); } - - // The user should never encounter these in unsubstituted form. - ty::ReClosureBound(vid) => { - p!(write("{:?}", vid)); - return Ok(self); - } } p!(write("'_")); diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index e2fa0313911..81be5b11143 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -81,8 +81,6 @@ impl fmt::Debug for ty::RegionKind { match *self { ty::ReEarlyBound(ref data) => write!(f, "ReEarlyBound({}, {})", data.index, data.name), - ty::ReClosureBound(ref vid) => write!(f, "ReClosureBound({:?})", vid), - ty::ReLateBound(binder_id, ref bound_region) => { write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region) } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index e265a2f8257..7f0ee1a8619 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1442,12 +1442,6 @@ pub enum RegionKind { /// Erased region, used by trait selection, in MIR and during codegen. ReErased, - - /// These are regions bound in the "defining type" for a - /// closure. They are used ONLY as part of the - /// `ClosureRegionRequirements` that are produced by MIR borrowck. - /// See `ClosureRegionRequirements` for more details. - ReClosureBound(RegionVid), } impl<'tcx> rustc_serialize::UseSpecializedDecodable for Region<'tcx> {} @@ -1689,7 +1683,6 @@ impl RegionKind { RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(), RegionKind::ReEmpty(_) => false, RegionKind::ReErased => false, - RegionKind::ReClosureBound(..) => false, } } @@ -1770,9 +1763,6 @@ impl RegionKind { ty::ReEmpty(_) | ty::ReStatic => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } - ty::ReClosureBound(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - } ty::ReLateBound(..) => { flags = flags | TypeFlags::HAS_RE_LATE_BOUND; } diff --git a/src/librustc_infer/infer/canonical/canonicalizer.rs b/src/librustc_infer/infer/canonical/canonicalizer.rs index 964e378f7ab..ad23ecc1e36 100644 --- a/src/librustc_infer/infer/canonical/canonicalizer.rs +++ b/src/librustc_infer/infer/canonical/canonicalizer.rs @@ -336,10 +336,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { | ty::ReEmpty(_) | ty::RePlaceholder(..) | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r), - - ty::ReClosureBound(..) => { - bug!("closure bound region encountered during canonicalization"); - } } } diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 9d06e26d9bb..0f5d4d30a23 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -581,10 +581,6 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { return Ok(r); } - ty::ReClosureBound(..) => { - span_bug!(self.span, "encountered unexpected ReClosureBound: {:?}", r,); - } - ty::RePlaceholder(..) | ty::ReVar(..) | ty::ReEmpty(_) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index a544381f33d..239b67a1da3 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -152,11 +152,6 @@ pub(super) fn note_and_explain_region( ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { (format!("lifetime {:?}", region), None) } - - // We shouldn't encounter an error message with ReClosureBound. - ty::ReClosureBound(..) => { - bug!("encountered unexpected ReClosureBound: {:?}", region,); - } }; emit_msg_span(err, prefix, description, span, suffix); diff --git a/src/librustc_infer/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs index a454feea36b..fa28cf5b454 100644 --- a/src/librustc_infer/infer/freshen.rs +++ b/src/librustc_infer/infer/freshen.rs @@ -135,10 +135,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { // replace all free regions with 'erased self.tcx().lifetimes.re_erased } - - ty::ReClosureBound(..) => { - bug!("encountered unexpected region: {:?}", r,); - } } } diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs index b7278ecd5e4..dfad3d8e26f 100644 --- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs @@ -464,12 +464,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// term "concrete regions"). fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { let r = match (a, b) { - (&ty::ReClosureBound(..), _) - | (_, &ty::ReClosureBound(..)) - | (&ReLateBound(..), _) - | (_, &ReLateBound(..)) - | (&ReErased, _) - | (_, &ReErased) => { + (&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => { bug!("cannot relate region: LUB({:?}, {:?})", a, b); } diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 868b9504379..e9ad7313ea0 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -798,7 +798,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { | ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT, ty::ReEmpty(ui) => ui, ty::RePlaceholder(placeholder) => placeholder.universe, - ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid), + ty::ReVar(vid) => self.var_universe(vid), ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region), } } diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs index 7103fc596c9..2d0ccd4a988 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs @@ -292,8 +292,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReEmpty(_) - | ty::ReErased - | ty::ReClosureBound(..) => None, + | ty::ReErased => None, } } diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index fe96b3e34a2..c8b0e59ebb1 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -940,8 +940,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// inference variables with some region from the closure /// signature -- this is not always possible, so this is a /// fallible process. Presuming we do find a suitable region, we - /// will represent it with a `ReClosureBound`, which is a - /// `RegionKind` variant that can be allocated in the gcx. + /// will use it's *external name*, which will be a `RegionKind` + /// variant that can be used in query responses such as + /// `ReEarlyBound`. fn try_promote_type_test_subject( &self, infcx: &InferCtxt<'_, 'tcx>, @@ -991,14 +992,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { // find an equivalent. let upper_bound = self.non_local_universal_upper_bound(region_vid); if self.region_contains(region_vid, upper_bound) { - tcx.mk_region(ty::ReClosureBound(upper_bound)) + self.definitions[upper_bound].external_name.unwrap_or(r) } else { - // In the case of a failure, use a `ReVar` - // result. This will cause the `lift` later on to - // fail. + // In the case of a failure, use a `ReVar` result. This will + // cause the `has_local_value` later on to return `None`. r } }); + debug!("try_promote_type_test_subject: folded ty = {:?}", ty); // `has_local_value` will only be true if we failed to promote some region. @@ -2029,15 +2030,6 @@ pub trait ClosureRegionRequirementsExt<'tcx> { closure_def_id: DefId, closure_substs: SubstsRef<'tcx>, ) -> Vec>; - - fn subst_closure_mapping( - &self, - tcx: TyCtxt<'tcx>, - closure_mapping: &IndexVec>, - value: &T, - ) -> T - where - T: TypeFoldable<'tcx>; } impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx> { @@ -2094,7 +2086,6 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx } ClosureOutlivesSubject::Ty(ty) => { - let ty = self.subst_closure_mapping(tcx, closure_mapping, &ty); debug!( "apply_requirements: ty={:?} \ outlived_region={:?} \ @@ -2107,22 +2098,4 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx }) .collect() } - - fn subst_closure_mapping( - &self, - tcx: TyCtxt<'tcx>, - closure_mapping: &IndexVec>, - value: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - tcx.fold_regions(value, &mut false, |r, _depth| { - if let ty::ReClosureBound(vid) = r { - closure_mapping[*vid] - } else { - bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r) - } - }) - } } diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 6cf1302783c..9367616e71a 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -823,11 +823,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { // The regions that we expect from borrow checking. ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} - ty::ReEmpty(_) - | ty::RePlaceholder(_) - | ty::ReVar(_) - | ty::ReScope(_) - | ty::ReClosureBound(_) => { + ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) | ty::ReScope(_) => { // All of the regions in the type should either have been // erased by writeback, or mapped back to named regions by // borrow checking. diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index 0cc322f8c2d..e1bd78e5113 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -170,7 +170,6 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool { // These regions don't appear in types from type declarations: RegionKind::ReErased - | RegionKind::ReClosureBound(..) | RegionKind::ReScope(..) | RegionKind::ReVar(..) | RegionKind::RePlaceholder(..) diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 54f84272ae8..11612066d44 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -449,7 +449,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::ReFree(..) - | ty::ReClosureBound(..) | ty::ReScope(..) | ty::ReVar(..) | ty::RePlaceholder(..) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c4ad4554a00..c16cf9ac10c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -450,7 +450,6 @@ impl Clean> for ty::RegionKind { | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReEmpty(_) - | ty::ReClosureBound(_) | ty::ReErased => { debug!("cannot clean region {:?}", self); None diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index 118a849f984..2bdb5384800 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -108,7 +108,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 - = note: where >::AssocType: '_#3r + = note: where >::AssocType: '_#3r note: no external requirements --> $DIR/projection-one-region-closure.rs:62:1 diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 59d8aa484bd..1ed4c519d2b 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -90,7 +90,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 - = note: where >::AssocType: '_#3r + = note: where >::AssocType: '_#3r note: no external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:52:1 diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index ff402f89ae8..b1ee9fac5f9 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -10,7 +10,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] = note: late-bound region is '_#4r = note: number of external vids: 5 - = note: where >::AssocType: '_#3r + = note: where >::AssocType: '_#3r note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:34:1 @@ -26,13 +26,13 @@ LL | | } | = note: defining type: no_relationships_late::<'_#1r, '_#2r, T> -error[E0309]: the associated type `>::AssocType` may not live long enough +error[E0309]: the associated type `>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:38:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `>::AssocType: 'a`... + = help: consider adding an explicit lifetime bound `>::AssocType: 'a`... note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 @@ -45,7 +45,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 - = note: where >::AssocType: '_#4r + = note: where >::AssocType: '_#4r note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:43:1 @@ -61,13 +61,13 @@ LL | | } | = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T> -error[E0309]: the associated type `>::AssocType` may not live long enough +error[E0309]: the associated type `>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `>::AssocType: 'a`... + = help: consider adding an explicit lifetime bound `>::AssocType: 'a`... note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:61:29 @@ -80,7 +80,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 - = note: where >::AssocType: '_#4r + = note: where >::AssocType: '_#4r note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:53:1 @@ -107,7 +107,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 - = note: where >::AssocType: '_#4r + = note: where >::AssocType: '_#4r note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:65:1 @@ -134,7 +134,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 - = note: where >::AssocType: '_#4r + = note: where >::AssocType: '_#4r note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:74:1 @@ -162,7 +162,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] = note: late-bound region is '_#3r = note: number of external vids: 4 - = note: where >::AssocType: '_#2r + = note: where >::AssocType: '_#2r note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:83:1 @@ -202,7 +202,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 - = note: where >::AssocType: '_#3r + = note: where >::AssocType: '_#3r note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:92:1 @@ -229,7 +229,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: number of external vids: 3 - = note: where >::AssocType: '_#2r + = note: where >::AssocType: '_#2r note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:101:1 -- cgit 1.4.1-3-g733a5 From f080f944f134700c48801a3b826330c9bd3aa5cc Mon Sep 17 00:00:00 2001 From: CDirkx Date: Mon, 23 Mar 2020 19:16:12 +0100 Subject: Add const generics test for all range types. In addition to the regression test of `RangeInclusive` for #70155, now all range types are checked for usability within const generics: - `RangeFrom` - `RangeFull` - `RangeToInclusive` - `RangeTo` - `Range` The test are moved from `test\ui\const-generics\issues\issue-70155` to `test\ui\const-generics\std\range` in anticipation of future similar tests for std types. --- src/test/ui/const-generics/issues/issue-70155.rs | 12 ------------ .../const-generics/std/range/const-generics-range-from.rs | 11 +++++++++++ .../const-generics/std/range/const-generics-range-full.rs | 11 +++++++++++ .../std/range/const-generics-range-inclusive.rs | 13 +++++++++++++ .../std/range/const-generics-range-to-inclusive.rs | 11 +++++++++++ .../ui/const-generics/std/range/const-generics-range-to.rs | 11 +++++++++++ .../ui/const-generics/std/range/const-generics-range.rs | 11 +++++++++++ 7 files changed, 68 insertions(+), 12 deletions(-) delete mode 100644 src/test/ui/const-generics/issues/issue-70155.rs create mode 100644 src/test/ui/const-generics/std/range/const-generics-range-from.rs create mode 100644 src/test/ui/const-generics/std/range/const-generics-range-full.rs create mode 100644 src/test/ui/const-generics/std/range/const-generics-range-inclusive.rs create mode 100644 src/test/ui/const-generics/std/range/const-generics-range-to-inclusive.rs create mode 100644 src/test/ui/const-generics/std/range/const-generics-range-to.rs create mode 100644 src/test/ui/const-generics/std/range/const-generics-range.rs (limited to 'src') diff --git a/src/test/ui/const-generics/issues/issue-70155.rs b/src/test/ui/const-generics/issues/issue-70155.rs deleted file mode 100644 index be71b347590..00000000000 --- a/src/test/ui/const-generics/issues/issue-70155.rs +++ /dev/null @@ -1,12 +0,0 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] - -// Regression test for #70155: -// `RangeInclusive` should be usable with const generics - -struct S>; - -const C : S<{ 0 ..= 999 }> = S; - -pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-from.rs b/src/test/ui/const-generics/std/range/const-generics-range-from.rs new file mode 100644 index 00000000000..487a51ddf25 --- /dev/null +++ b/src/test/ui/const-generics/std/range/const-generics-range-from.rs @@ -0,0 +1,11 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +// `RangeFrom` should be usable within const generics: + +struct S>; + +const C : S<{ 0 .. }> = S; + +pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-full.rs b/src/test/ui/const-generics/std/range/const-generics-range-full.rs new file mode 100644 index 00000000000..2af2dd8343b --- /dev/null +++ b/src/test/ui/const-generics/std/range/const-generics-range-full.rs @@ -0,0 +1,11 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +// `RangeFull` should be usable within const generics: + +struct S; + +const C : S<{ .. }> = S; + +pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-inclusive.rs b/src/test/ui/const-generics/std/range/const-generics-range-inclusive.rs new file mode 100644 index 00000000000..c9f7420f6ac --- /dev/null +++ b/src/test/ui/const-generics/std/range/const-generics-range-inclusive.rs @@ -0,0 +1,13 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +// Regression test for #70155 + +// `RangeInclusive` should be usable within const generics: + +struct S>; + +const C : S<{ 0 ..= 999 }> = S; + +pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-to-inclusive.rs b/src/test/ui/const-generics/std/range/const-generics-range-to-inclusive.rs new file mode 100644 index 00000000000..dbef24f853c --- /dev/null +++ b/src/test/ui/const-generics/std/range/const-generics-range-to-inclusive.rs @@ -0,0 +1,11 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +// `RangeToInclusive` should be usable within const generics: + +struct S>; + +const C : S<{ ..= 999 }> = S; + +pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-to.rs b/src/test/ui/const-generics/std/range/const-generics-range-to.rs new file mode 100644 index 00000000000..ed479316a82 --- /dev/null +++ b/src/test/ui/const-generics/std/range/const-generics-range-to.rs @@ -0,0 +1,11 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +// `RangeTo` should be usable within const generics: + +struct S>; + +const C : S<{ .. 1000 }> = S; + +pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range.rs b/src/test/ui/const-generics/std/range/const-generics-range.rs new file mode 100644 index 00000000000..ea4b72780c9 --- /dev/null +++ b/src/test/ui/const-generics/std/range/const-generics-range.rs @@ -0,0 +1,11 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +// `Range` should be usable within const generics: + +struct S>; + +const C : S<{ 0 .. 1000 }> = S; + +pub fn main() {} -- cgit 1.4.1-3-g733a5 From 9bcd9fe6743aabcf6d96b3fafcd86d1e36114eed Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 23 Mar 2020 19:19:07 +0100 Subject: Address review comments --- src/librustc/ty/sty.rs | 14 ++++++++------ src/librustc_mir_build/hair/cx/expr.rs | 4 ++-- src/librustc_typeck/astconv.rs | 8 ++++---- src/librustc_typeck/check/expr.rs | 3 +-- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/mod.rs | 8 ++++---- 6 files changed, 20 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index e5c88c1c9ba..ed441797874 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -20,7 +20,7 @@ use polonius_engine::Atom; use rustc_ast::ast::{self, Ident}; use rustc_data_structures::captures::Captures; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::vec::Idx; use rustc_macros::HashStable; use rustc_span::symbol::{kw, Symbol}; @@ -2404,15 +2404,17 @@ static_assert_size!(Const<'_>, 48); impl<'tcx> Const<'tcx> { /// Literals and const generic parameters are eagerly converted to a constant, everything else /// becomes `Unevaluated`. - pub fn from_hir_anon_const(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Ty<'tcx>) -> &'tcx Self { - debug!("Const::from_hir_anon_const(id={:?})", def_id); + pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self { + debug!("Const::from_anon_const(id={:?})", def_id); - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let body_id = tcx.hir().body_owned_by(hir_id); let expr = &tcx.hir().body(body_id).value; + let ty = tcx.type_of(def_id.to_def_id()); + let lit_input = match expr.kind { hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind { @@ -2457,8 +2459,8 @@ impl<'tcx> Const<'tcx> { ty::ConstKind::Param(ty::ParamConst::new(index, name)) } _ => ty::ConstKind::Unevaluated( - def_id, - InternalSubsts::identity_for_item(tcx, def_id), + def_id.to_def_id(), + InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), None, ), }; diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index 73c442e4a91..a45c3089064 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -406,8 +406,8 @@ fn make_mirror_unadjusted<'a, 'tcx>( // Now comes the rote stuff: hir::ExprKind::Repeat(ref v, ref count) => { - let count = cx.tcx.hir().local_def_id(count.hir_id); - let count = ty::Const::from_hir_anon_const(cx.tcx, count, cx.tcx.types.usize); + let count_def_id = cx.tcx.hir().local_def_id(count.hir_id).expect_local(); + let count = ty::Const::from_anon_const(cx.tcx, count_def_id); ExprKind::Repeat { value: v.to_ref(), count } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ee713482268..1aa92021393 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -780,8 +780,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - let ct = tcx.hir().local_def_id(ct.value.hir_id); - ty::Const::from_hir_anon_const(tcx, ct, tcx.type_of(param.def_id)).into() + let ct_def_id = tcx.hir().local_def_id(ct.value.hir_id).expect_local(); + ty::Const::from_anon_const(tcx, ct_def_id).into() } _ => unreachable!(), }, @@ -2765,8 +2765,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .unwrap_or(tcx.types.err) } hir::TyKind::Array(ref ty, ref length) => { - let length = tcx.hir().local_def_id(length.hir_id); - let length = ty::Const::from_hir_anon_const(tcx, length, tcx.types.usize); + let length_def_id = tcx.hir().local_def_id(length.hir_id).expect_local(); + let length = ty::Const::from_anon_const(tcx, length_def_id); let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index e57e6cd80ca..77a8e92c379 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1007,8 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let count_def_id = tcx.hir().local_def_id(count.hir_id); - let count = self.to_const(count, tcx.type_of(count_def_id)); + let count = self.to_const(count); let uty = match expected { ExpectHasType(uty) => match uty.kind { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 48c72567b5c..d340d6ff5c2 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -331,7 +331,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => self.to_ty(ty).into(), (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into() + self.to_const(&ct.value).into() } _ => unreachable!(), }, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f790bcfbb09..6f0f69a7943 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3279,9 +3279,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - let c = self.tcx.hir().local_def_id(ast_c.hir_id); - ty::Const::from_hir_anon_const(self.tcx, c, ty) + pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { + let c = self.tcx.hir().local_def_id(ast_c.hir_id).expect_local(); + ty::Const::from_anon_const(self.tcx, c) } // If the type given by the user has free regions, save it for later, since @@ -5510,7 +5510,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.to_ty(ty).into() } (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into() + self.to_const(&ct.value).into() } _ => unreachable!(), }, -- cgit 1.4.1-3-g733a5 From 9fdde0a000c7132fc0b79e2f44b52042dc8227dd Mon Sep 17 00:00:00 2001 From: CDirkx Date: Mon, 23 Mar 2020 19:27:13 +0100 Subject: Merge tests. Merge tests to a single test file. --- .../ui/const-generics/std/const-generics-range.rs | 30 ++++++++++++++++++++++ .../std/range/const-generics-range-from.rs | 11 -------- .../std/range/const-generics-range-full.rs | 11 -------- .../std/range/const-generics-range-inclusive.rs | 13 ---------- .../std/range/const-generics-range-to-inclusive.rs | 11 -------- .../std/range/const-generics-range-to.rs | 11 -------- .../std/range/const-generics-range.rs | 11 -------- 7 files changed, 30 insertions(+), 68 deletions(-) create mode 100644 src/test/ui/const-generics/std/const-generics-range.rs delete mode 100644 src/test/ui/const-generics/std/range/const-generics-range-from.rs delete mode 100644 src/test/ui/const-generics/std/range/const-generics-range-full.rs delete mode 100644 src/test/ui/const-generics/std/range/const-generics-range-inclusive.rs delete mode 100644 src/test/ui/const-generics/std/range/const-generics-range-to-inclusive.rs delete mode 100644 src/test/ui/const-generics/std/range/const-generics-range-to.rs delete mode 100644 src/test/ui/const-generics/std/range/const-generics-range.rs (limited to 'src') diff --git a/src/test/ui/const-generics/std/const-generics-range.rs b/src/test/ui/const-generics/std/const-generics-range.rs new file mode 100644 index 00000000000..6d56fe0d7b8 --- /dev/null +++ b/src/test/ui/const-generics/std/const-generics-range.rs @@ -0,0 +1,30 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +// `Range` should be usable within const generics: +struct _Range>; +const RANGE : _Range<{ 0 .. 1000 }> = _Range; + +// `RangeFrom` should be usable within const generics: +struct _RangeFrom>; +const RANGE_FROM : _RangeFrom<{ 0 .. }> = _RangeFrom; + +// `RangeFull` should be usable within const generics: +struct _RangeFull; +const RANGE_FULL : _RangeFull<{ .. }> = _RangeFull; + +// Regression test for #70155 +// `RangeInclusive` should be usable within const generics: +struct _RangeInclusive>; +const RANGE_INCLUSIVE : _RangeInclusive<{ 0 ..= 999 }> = _RangeInclusive; + +// `RangeTo` should be usable within const generics: +struct _RangeTo>; +const RANGE_TO : _RangeTo<{ .. 1000 }> = _RangeTo; + +// `RangeToInclusive` should be usable within const generics: +struct _RangeToInclusive>; +const RANGE_TO_INCLUSIVE : _RangeToInclusive<{ ..= 999 }> = _RangeToInclusive; + +pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-from.rs b/src/test/ui/const-generics/std/range/const-generics-range-from.rs deleted file mode 100644 index 487a51ddf25..00000000000 --- a/src/test/ui/const-generics/std/range/const-generics-range-from.rs +++ /dev/null @@ -1,11 +0,0 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] - -// `RangeFrom` should be usable within const generics: - -struct S>; - -const C : S<{ 0 .. }> = S; - -pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-full.rs b/src/test/ui/const-generics/std/range/const-generics-range-full.rs deleted file mode 100644 index 2af2dd8343b..00000000000 --- a/src/test/ui/const-generics/std/range/const-generics-range-full.rs +++ /dev/null @@ -1,11 +0,0 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] - -// `RangeFull` should be usable within const generics: - -struct S; - -const C : S<{ .. }> = S; - -pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-inclusive.rs b/src/test/ui/const-generics/std/range/const-generics-range-inclusive.rs deleted file mode 100644 index c9f7420f6ac..00000000000 --- a/src/test/ui/const-generics/std/range/const-generics-range-inclusive.rs +++ /dev/null @@ -1,13 +0,0 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] - -// Regression test for #70155 - -// `RangeInclusive` should be usable within const generics: - -struct S>; - -const C : S<{ 0 ..= 999 }> = S; - -pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-to-inclusive.rs b/src/test/ui/const-generics/std/range/const-generics-range-to-inclusive.rs deleted file mode 100644 index dbef24f853c..00000000000 --- a/src/test/ui/const-generics/std/range/const-generics-range-to-inclusive.rs +++ /dev/null @@ -1,11 +0,0 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] - -// `RangeToInclusive` should be usable within const generics: - -struct S>; - -const C : S<{ ..= 999 }> = S; - -pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range-to.rs b/src/test/ui/const-generics/std/range/const-generics-range-to.rs deleted file mode 100644 index ed479316a82..00000000000 --- a/src/test/ui/const-generics/std/range/const-generics-range-to.rs +++ /dev/null @@ -1,11 +0,0 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] - -// `RangeTo` should be usable within const generics: - -struct S>; - -const C : S<{ .. 1000 }> = S; - -pub fn main() {} diff --git a/src/test/ui/const-generics/std/range/const-generics-range.rs b/src/test/ui/const-generics/std/range/const-generics-range.rs deleted file mode 100644 index ea4b72780c9..00000000000 --- a/src/test/ui/const-generics/std/range/const-generics-range.rs +++ /dev/null @@ -1,11 +0,0 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] - -// `Range` should be usable within const generics: - -struct S>; - -const C : S<{ 0 .. 1000 }> = S; - -pub fn main() {} -- cgit 1.4.1-3-g733a5 From 124ab20d4bbbe28d50b641836e3a87f1d796767d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 23 Mar 2020 19:35:19 +0100 Subject: Limit `from_anon_const` to `AnonConst`s. --- src/librustc/ty/sty.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index ed441797874..e49a29f687c 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2409,7 +2409,10 @@ impl<'tcx> Const<'tcx> { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let body_id = tcx.hir().body_owned_by(hir_id); + let body_id = match tcx.hir().get(hir_id) { + hir::Node::AnonConst(ac) => ac.body, + _ => span_bug!(tcx.def_span(def_id.to_def_id()), "from_anon_const can only process anonymous constants"), + }; let expr = &tcx.hir().body(body_id).value; -- cgit 1.4.1-3-g733a5 From e75158d4861e8cd0b0f8a11f360714c56577ba1e Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 22 Mar 2020 18:50:30 -0700 Subject: Account for bad placeholder types in where clauses --- src/librustc_typeck/astconv.rs | 34 +++---- src/librustc_typeck/check/mod.rs | 9 +- src/librustc_typeck/collect.rs | 22 +++-- src/test/ui/did_you_mean/bad-assoc-ty.rs | 32 ++++++ src/test/ui/did_you_mean/bad-assoc-ty.stderr | 110 ++++++++++++++++++++- src/test/ui/typeck/typeck_type_placeholder_item.rs | 5 - .../ui/typeck/typeck_type_placeholder_item.stderr | 66 ++++--------- 7 files changed, 192 insertions(+), 86 deletions(-) (limited to 'src') diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3ee6d5df735..378a68315b2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -20,7 +20,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::Visitor; +use rustc_hir::intravisit::{walk_generics, Visitor}; use rustc_hir::print; use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS}; @@ -838,18 +838,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }, ); - if !inferred_params.is_empty() { - // We always collect the spans for placeholder types when evaluating `fn`s, but we - // only want to emit an error complaining about them if infer types (`_`) are not - // allowed. `allow_ty_infer` gates this behavior. - crate::collect::placeholder_type_error( - tcx, - inferred_params[0], - &[], - inferred_params, - false, - ); - } self.complain_about_missing_type_params( missing_type_params, @@ -2739,7 +2727,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } hir::TyKind::BareFn(ref bf) => { require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - tcx.mk_fn_ptr(self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl, &[], None)) + tcx.mk_fn_ptr(self.ty_of_fn( + bf.unsafety, + bf.abi, + &bf.decl, + &hir::Generics::empty(), + None, + )) } hir::TyKind::TraitObject(ref bounds, ref lifetime) => { self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) @@ -2922,7 +2916,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { unsafety: hir::Unsafety, abi: abi::Abi, decl: &hir::FnDecl<'_>, - generic_params: &[hir::GenericParam<'_>], + generics: &hir::Generics<'_>, ident_span: Option, ) -> ty::PolyFnSig<'tcx> { debug!("ty_of_fn"); @@ -2934,6 +2928,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for ty in decl.inputs { visitor.visit_ty(ty); } + walk_generics(&mut visitor, generics); + let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None)); let output_ty = match decl.output { hir::FnRetTy::Return(ref output) => { @@ -2955,7 +2951,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { crate::collect::placeholder_type_error( tcx, ident_span.map(|sp| sp.shrink_to_hi()).unwrap_or(DUMMY_SP), - generic_params, + &generics.params[..], visitor.0, ident_span.is_some(), ); @@ -2981,8 +2977,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.sess, decl.output.span(), E0581, - "return type references {} \ - which is not constrained by the fn input types", + "return type references {} which is not constrained by the fn input types", lifetime_name ); if let ty::BrAnon(_) = *br { @@ -2993,8 +2988,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // though we can easily give a hint that ought to be // relevant. err.note( - "lifetimes appearing in an associated type \ - are not considered constrained", + "lifetimes appearing in an associated type are not considered constrained", ); } err.emit(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e4bd42f61c3..ce0be508357 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1003,7 +1003,14 @@ fn typeck_tables_of_with_fallback<'tcx>( let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) { let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - AstConv::ty_of_fn(&fcx, header.unsafety, header.abi, decl, &[], None) + AstConv::ty_of_fn( + &fcx, + header.unsafety, + header.abi, + decl, + &hir::Generics::empty(), + None, + ) } else { tcx.fn_sig(def_id) }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a79c0653077..2de43a6b1ef 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1502,7 +1502,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { sig.header.unsafety, sig.header.abi, &sig.decl, - &generics.params[..], + &generics, Some(ident.span), ), } @@ -1513,14 +1513,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { ident, generics, .. - }) => AstConv::ty_of_fn( - &icx, - header.unsafety, - header.abi, - decl, - &generics.params[..], - Some(ident.span), - ), + }) => { + AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl, &generics, Some(ident.span)) + } ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(ref fn_decl, _, _), .. }) => { let abi = tcx.hir().get_foreign_abi(hir_id); @@ -2142,7 +2137,14 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( } else { hir::Unsafety::Unsafe }; - let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl, &[], None); + let fty = AstConv::ty_of_fn( + &ItemCtxt::new(tcx, def_id), + unsafety, + abi, + decl, + &hir::Generics::empty(), + None, + ); // Feature gate SIMD types in FFI, since I am not sure that the // ABIs are handled at all correctly. -huonw diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs index 00845a17b11..e66b432ede2 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.rs +++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs @@ -49,4 +49,36 @@ trait K {} fn foo>(x: X) {} //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +fn bar(_: F) where F: Fn() -> _ {} +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + +fn baz _>(_: F) {} +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + +struct L(F) where F: Fn() -> _; +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures +struct M where F: Fn() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + a: F, +} +enum N where F: Fn() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + Foo(F), +} + +union O where F: Fn() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR unions with non-`Copy` fields are unstable + foo: F, +} + +trait P where F: Fn() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures +} + +trait Q { + fn foo(_: F) where F: Fn() -> _ {} + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +} + fn main() {} diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index 6d5f3d9f143..875c02bae4a 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -57,6 +57,19 @@ LL | type J = ty!(u8); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0658]: unions with non-`Copy` fields are unstable + --> $DIR/bad-assoc-ty.rs:69:1 + | +LL | / union O where F: Fn() -> _ { +LL | | +LL | | +LL | | foo: F, +LL | | } + | |_^ + | + = note: see issue #55149 for more information + = help: add `#![feature(untagged_unions)]` to the crate attributes to enable + error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:1:10 | @@ -129,8 +142,101 @@ LL | fn foo>(x: X) {} | ^ ^ not allowed in type signatures | | | not allowed in type signatures + | +help: use type parameters instead + | +LL | fn foo>(x: X) {} + | ^^^ ^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:52:34 + | +LL | fn bar(_: F) where F: Fn() -> _ {} + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn bar(_: F) where F: Fn() -> T {} + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:55:19 + | +LL | fn baz _>(_: F) {} + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn baz T>(_: F) {} + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:58:33 + | +LL | struct L(F) where F: Fn() -> _; + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | struct L(F) where F: Fn() -> T; + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:60:30 + | +LL | struct M where F: Fn() -> _ { + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | struct M where F: Fn() -> T { + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:64:28 + | +LL | enum N where F: Fn() -> _ { + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | enum N where F: Fn() -> T { + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:69:29 + | +LL | union O where F: Fn() -> _ { + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | union O where F: Fn() -> T { + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:75:29 + | +LL | trait P where F: Fn() -> _ { + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | trait P where F: Fn() -> T { + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:80:38 + | +LL | fn foo(_: F) where F: Fn() -> _ {} + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn foo(_: F) where F: Fn() -> T {} + | ^^^ ^ -error: aborting due to 20 previous errors +error: aborting due to 29 previous errors -Some errors have detailed explanations: E0121, E0223. +Some errors have detailed explanations: E0121, E0223, E0658. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index 6cd2b8c75b6..5444fc62d82 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -158,12 +158,9 @@ trait BadTrait<_> {} //~^ ERROR expected identifier, found reserved identifier `_` impl BadTrait<_> for BadStruct<_> {} //~^ ERROR the type placeholder `_` is not allowed within types on item signatures -//~| ERROR the type placeholder `_` is not allowed within types on item signatures -//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn impl_trait() -> impl BadTrait<_> { //~^ ERROR the type placeholder `_` is not allowed within types on item signatures -//~| ERROR the type placeholder `_` is not allowed within types on item signatures unimplemented!() } @@ -178,14 +175,12 @@ struct BadStruct2<_, T>(_, T); type X = Box<_>; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures -//~| ERROR the type placeholder `_` is not allowed within types on item signatures struct Struct; trait Trait {} impl Trait for Struct {} type Y = impl Trait<_>; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures -//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn foo() -> Y { Struct } diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index dc86ab30dfe..955765e1175 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -11,25 +11,25 @@ LL | trait BadTrait<_> {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:170:19 + --> $DIR/typeck_type_placeholder_item.rs:167:19 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:170:22 + --> $DIR/typeck_type_placeholder_item.rs:167:22 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:175:19 + --> $DIR/typeck_type_placeholder_item.rs:172:19 | LL | struct BadStruct2<_, T>(_, T); | ^ expected identifier, found reserved identifier error: associated constant in `impl` without body - --> $DIR/typeck_type_placeholder_item.rs:208:5 + --> $DIR/typeck_type_placeholder_item.rs:203:5 | LL | const C: _; | ^^^^^^^^^^- @@ -37,7 +37,7 @@ LL | const C: _; | help: provide a definition for the constant: `= ;` error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters - --> $DIR/typeck_type_placeholder_item.rs:170:22 + --> $DIR/typeck_type_placeholder_item.rs:167:22 | LL | struct BadStruct1<_, _>(_); | - ^ already used @@ -351,18 +351,6 @@ help: use type parameters instead LL | struct BadStruct(T); | ^ ^ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:159:32 - | -LL | impl BadTrait<_> for BadStruct<_> {} - | ^ not allowed in type signatures - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:159:15 - | -LL | impl BadTrait<_> for BadStruct<_> {} - | ^ not allowed in type signatures - error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:159:15 | @@ -377,13 +365,13 @@ LL | impl BadTrait for BadStruct {} | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:164:34 + --> $DIR/typeck_type_placeholder_item.rs:162:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:170:25 + --> $DIR/typeck_type_placeholder_item.rs:167:25 | LL | struct BadStruct1<_, _>(_); | ^ not allowed in type signatures @@ -394,7 +382,7 @@ LL | struct BadStruct1(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:175:25 + --> $DIR/typeck_type_placeholder_item.rs:172:25 | LL | struct BadStruct2<_, T>(_, T); | ^ not allowed in type signatures @@ -405,13 +393,7 @@ LL | struct BadStruct2(K, T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:179:14 - | -LL | type X = Box<_>; - | ^ not allowed in type signatures - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:179:14 + --> $DIR/typeck_type_placeholder_item.rs:176:14 | LL | type X = Box<_>; | ^ not allowed in type signatures @@ -531,37 +513,25 @@ LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:164:34 - | -LL | fn impl_trait() -> impl BadTrait<_> { - | ^ not allowed in type signatures - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:186:21 - | -LL | type Y = impl Trait<_>; - | ^ not allowed in type signatures - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:186:21 + --> $DIR/typeck_type_placeholder_item.rs:182:21 | LL | type Y = impl Trait<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:195:14 + --> $DIR/typeck_type_placeholder_item.rs:190:14 | LL | type B = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:197:14 + --> $DIR/typeck_type_placeholder_item.rs:192:14 | LL | const C: _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:199:14 + --> $DIR/typeck_type_placeholder_item.rs:194:14 | LL | const D: _ = 42; | ^ @@ -606,25 +576,25 @@ LL | fn clone(&self) -> _ { FnTest9 } | help: replace with the correct return type: `main::FnTest9` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:204:14 + --> $DIR/typeck_type_placeholder_item.rs:199:14 | LL | type A = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:206:14 + --> $DIR/typeck_type_placeholder_item.rs:201:14 | LL | type B = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:208:14 + --> $DIR/typeck_type_placeholder_item.rs:203:14 | LL | const C: _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:211:14 + --> $DIR/typeck_type_placeholder_item.rs:206:14 | LL | const D: _ = 42; | ^ @@ -632,7 +602,7 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace `_` with the correct type: `i32` -error: aborting due to 71 previous errors +error: aborting due to 66 previous errors Some errors have detailed explanations: E0121, E0282, E0403. For more information about an error, try `rustc --explain E0121`. -- cgit 1.4.1-3-g733a5 From 5aa15bfa1c54d3139559e7296ff2b74ebedcc07e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 23 Mar 2020 22:24:31 +0100 Subject: Remove leftover mentions of `from_anon_const` --- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc/ty/sty.rs | 2 +- src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index dfe5adb1bbf..4ca9ad46daa 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -151,7 +151,7 @@ pub struct LitToConstInput<'tcx> { pub enum LitToConstError { /// The literal's inferred type did not match the expected `ty` in the input. /// This is used for graceful error handling (`delay_span_bug`) in - /// type checking (`AstConv::ast_const_to_const`). + /// type checking (`Const::from_anon_const`). TypeError, UnparseableFloat, Reported, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index e49a29f687c..73fe15d9a17 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2435,7 +2435,7 @@ impl<'tcx> Const<'tcx> { if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { return c; } else { - tcx.sess.delay_span_bug(expr.span, "ast_const_to_const: couldn't lit_to_const"); + tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const"); } } diff --git a/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs b/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs index 98be8c345a9..f0d5fea8e02 100644 --- a/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs +++ b/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs @@ -3,7 +3,7 @@ // we call the query `lit_to_const(input);`. // However, the literal `input.lit` would not be of the type expected by `input.ty`. // As a result, we immediately called `bug!(...)` instead of bubbling up the problem -// so that it could be handled by the caller of `lit_to_const` (`ast_const_to_const`). +// so that it could be handled by the caller of `lit_to_const` (`from_anon_const`). fn main() {} -- cgit 1.4.1-3-g733a5 From 4f513b5fd7945937cba8bbfab84ae33e14642b85 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 23 Mar 2020 22:39:59 +0100 Subject: Split out some impls from rustc::mir into a separate submodule --- src/librustc/mir/mod.rs | 323 +------------------------------------- src/librustc/mir/type_foldable.rs | 322 +++++++++++++++++++++++++++++++++++++ 2 files changed, 323 insertions(+), 322 deletions(-) create mode 100644 src/librustc/mir/type_foldable.rs (limited to 'src') diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d81b940cbe7..63019c57b2f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -45,6 +45,7 @@ pub mod mono; mod query; pub mod tcx; pub mod traversal; +mod type_foldable; pub mod visit; /// Types for locals @@ -2683,325 +2684,3 @@ impl Location { } } } - -/* - * `TypeFoldable` implementations for MIR types -*/ - -CloneTypeFoldableAndLiftImpls! { - BlockTailInfo, - MirPhase, - SourceInfo, - FakeReadCause, - RetagKind, - SourceScope, - SourceScopeData, - SourceScopeLocalData, - UserTypeAnnotationIndex, -} - -impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - use crate::mir::TerminatorKind::*; - - let kind = match self.kind { - Goto { target } => Goto { target }, - SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { - discr: discr.fold_with(folder), - switch_ty: switch_ty.fold_with(folder), - values: values.clone(), - targets: targets.clone(), - }, - Drop { ref location, target, unwind } => { - Drop { location: location.fold_with(folder), target, unwind } - } - DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { - location: location.fold_with(folder), - value: value.fold_with(folder), - target, - unwind, - }, - Yield { ref value, resume, ref resume_arg, drop } => Yield { - value: value.fold_with(folder), - resume, - resume_arg: resume_arg.fold_with(folder), - drop, - }, - Call { ref func, ref args, ref destination, cleanup, from_hir_call } => { - let dest = - destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); - - Call { - func: func.fold_with(folder), - args: args.fold_with(folder), - destination: dest, - cleanup, - from_hir_call, - } - } - Assert { ref cond, expected, ref msg, target, cleanup } => { - use AssertKind::*; - let msg = match msg { - BoundsCheck { ref len, ref index } => { - BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) } - } - Overflow(_) - | OverflowNeg - | DivisionByZero - | RemainderByZero - | ResumedAfterReturn(_) - | ResumedAfterPanic(_) => msg.clone(), - }; - Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup } - } - GeneratorDrop => GeneratorDrop, - Resume => Resume, - Abort => Abort, - Return => Return, - Unreachable => Unreachable, - FalseEdges { real_target, imaginary_target } => { - FalseEdges { real_target, imaginary_target } - } - FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, - }; - Terminator { source_info: self.source_info, kind } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - use crate::mir::TerminatorKind::*; - - match self.kind { - SwitchInt { ref discr, switch_ty, .. } => { - discr.visit_with(visitor) || switch_ty.visit_with(visitor) - } - Drop { ref location, .. } => location.visit_with(visitor), - DropAndReplace { ref location, ref value, .. } => { - location.visit_with(visitor) || value.visit_with(visitor) - } - Yield { ref value, .. } => value.visit_with(visitor), - Call { ref func, ref args, ref destination, .. } => { - let dest = if let Some((ref loc, _)) = *destination { - loc.visit_with(visitor) - } else { - false - }; - dest || func.visit_with(visitor) || args.visit_with(visitor) - } - Assert { ref cond, ref msg, .. } => { - if cond.visit_with(visitor) { - use AssertKind::*; - match msg { - BoundsCheck { ref len, ref index } => { - len.visit_with(visitor) || index.visit_with(visitor) - } - Overflow(_) - | OverflowNeg - | DivisionByZero - | RemainderByZero - | ResumedAfterReturn(_) - | ResumedAfterPanic(_) => false, - } - } else { - false - } - } - Goto { .. } - | Resume - | Abort - | Return - | GeneratorDrop - | Unreachable - | FalseEdges { .. } - | FalseUnwind { .. } => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { - fn super_fold_with>(&self, _: &mut F) -> Self { - *self - } - - fn super_visit_with>(&self, _: &mut V) -> bool { - false - } -} - -impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.local.visit_with(visitor) || self.projection.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_place_elems(&v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - use crate::mir::Rvalue::*; - match *self { - Use(ref op) => Use(op.fold_with(folder)), - Repeat(ref op, len) => Repeat(op.fold_with(folder), len), - Ref(region, bk, ref place) => { - Ref(region.fold_with(folder), bk, place.fold_with(folder)) - } - AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)), - Len(ref place) => Len(place.fold_with(folder)), - Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), - BinaryOp(op, ref rhs, ref lhs) => { - BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) - } - CheckedBinaryOp(op, ref rhs, ref lhs) => { - CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) - } - UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), - Discriminant(ref place) => Discriminant(place.fold_with(folder)), - NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), - Aggregate(ref kind, ref fields) => { - let kind = box match **kind { - AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), - AggregateKind::Tuple => AggregateKind::Tuple, - AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( - def, - v, - substs.fold_with(folder), - user_ty.fold_with(folder), - n, - ), - AggregateKind::Closure(id, substs) => { - AggregateKind::Closure(id, substs.fold_with(folder)) - } - AggregateKind::Generator(id, substs, movablity) => { - AggregateKind::Generator(id, substs.fold_with(folder), movablity) - } - }; - Aggregate(kind, fields.fold_with(folder)) - } - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - use crate::mir::Rvalue::*; - match *self { - Use(ref op) => op.visit_with(visitor), - Repeat(ref op, _) => op.visit_with(visitor), - Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), - AddressOf(_, ref place) => place.visit_with(visitor), - Len(ref place) => place.visit_with(visitor), - Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), - BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => { - rhs.visit_with(visitor) || lhs.visit_with(visitor) - } - UnaryOp(_, ref val) => val.visit_with(visitor), - Discriminant(ref place) => place.visit_with(visitor), - NullaryOp(_, ty) => ty.visit_with(visitor), - Aggregate(ref kind, ref fields) => { - (match **kind { - AggregateKind::Array(ty) => ty.visit_with(visitor), - AggregateKind::Tuple => false, - AggregateKind::Adt(_, _, substs, user_ty, _) => { - substs.visit_with(visitor) || user_ty.visit_with(visitor) - } - AggregateKind::Closure(_, substs) => substs.visit_with(visitor), - AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), - }) || fields.visit_with(visitor) - } - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)), - Operand::Move(ref place) => Operand::Move(place.fold_with(folder)), - Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), - Operand::Constant(ref c) => c.visit_with(visitor), - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - use crate::mir::ProjectionElem::*; - - match *self { - Deref => Deref, - Field(f, ty) => Field(f, ty.fold_with(folder)), - Index(v) => Index(v.fold_with(folder)), - Downcast(symbol, variantidx) => Downcast(symbol, variantidx), - ConstantIndex { offset, min_length, from_end } => { - ConstantIndex { offset, min_length, from_end } - } - Subslice { from, to, from_end } => Subslice { from, to, from_end }, - } - } - - fn super_visit_with>(&self, visitor: &mut Vs) -> bool { - use crate::mir::ProjectionElem::*; - - match self { - Field(_, ty) => ty.visit_with(visitor), - Index(v) => v.visit_with(visitor), - _ => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for Field { - fn super_fold_with>(&self, _: &mut F) -> Self { - *self - } - fn super_visit_with>(&self, _: &mut V) -> bool { - false - } -} - -impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { - fn super_fold_with>(&self, _: &mut F) -> Self { - *self - } - fn super_visit_with>(&self, _: &mut V) -> bool { - false - } -} - -impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix { - fn super_fold_with>(&self, _: &mut F) -> Self { - self.clone() - } - fn super_visit_with>(&self, _: &mut V) -> bool { - false - } -} - -impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - Constant { - span: self.span, - user_ty: self.user_ty.fold_with(folder), - literal: self.literal.fold_with(folder), - } - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.literal.visit_with(visitor) - } -} diff --git a/src/librustc/mir/type_foldable.rs b/src/librustc/mir/type_foldable.rs new file mode 100644 index 00000000000..9520f081b6b --- /dev/null +++ b/src/librustc/mir/type_foldable.rs @@ -0,0 +1,322 @@ +//! `TypeFoldable` implementations for MIR types + +use super::*; +use crate::ty; + +CloneTypeFoldableAndLiftImpls! { + BlockTailInfo, + MirPhase, + SourceInfo, + FakeReadCause, + RetagKind, + SourceScope, + SourceScopeData, + SourceScopeLocalData, + UserTypeAnnotationIndex, +} + +impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + use crate::mir::TerminatorKind::*; + + let kind = match self.kind { + Goto { target } => Goto { target }, + SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { + discr: discr.fold_with(folder), + switch_ty: switch_ty.fold_with(folder), + values: values.clone(), + targets: targets.clone(), + }, + Drop { ref location, target, unwind } => { + Drop { location: location.fold_with(folder), target, unwind } + } + DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { + location: location.fold_with(folder), + value: value.fold_with(folder), + target, + unwind, + }, + Yield { ref value, resume, ref resume_arg, drop } => Yield { + value: value.fold_with(folder), + resume, + resume_arg: resume_arg.fold_with(folder), + drop, + }, + Call { ref func, ref args, ref destination, cleanup, from_hir_call } => { + let dest = + destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); + + Call { + func: func.fold_with(folder), + args: args.fold_with(folder), + destination: dest, + cleanup, + from_hir_call, + } + } + Assert { ref cond, expected, ref msg, target, cleanup } => { + use AssertKind::*; + let msg = match msg { + BoundsCheck { ref len, ref index } => { + BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) } + } + Overflow(_) + | OverflowNeg + | DivisionByZero + | RemainderByZero + | ResumedAfterReturn(_) + | ResumedAfterPanic(_) => msg.clone(), + }; + Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup } + } + GeneratorDrop => GeneratorDrop, + Resume => Resume, + Abort => Abort, + Return => Return, + Unreachable => Unreachable, + FalseEdges { real_target, imaginary_target } => { + FalseEdges { real_target, imaginary_target } + } + FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, + }; + Terminator { source_info: self.source_info, kind } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use crate::mir::TerminatorKind::*; + + match self.kind { + SwitchInt { ref discr, switch_ty, .. } => { + discr.visit_with(visitor) || switch_ty.visit_with(visitor) + } + Drop { ref location, .. } => location.visit_with(visitor), + DropAndReplace { ref location, ref value, .. } => { + location.visit_with(visitor) || value.visit_with(visitor) + } + Yield { ref value, .. } => value.visit_with(visitor), + Call { ref func, ref args, ref destination, .. } => { + let dest = if let Some((ref loc, _)) = *destination { + loc.visit_with(visitor) + } else { + false + }; + dest || func.visit_with(visitor) || args.visit_with(visitor) + } + Assert { ref cond, ref msg, .. } => { + if cond.visit_with(visitor) { + use AssertKind::*; + match msg { + BoundsCheck { ref len, ref index } => { + len.visit_with(visitor) || index.visit_with(visitor) + } + Overflow(_) + | OverflowNeg + | DivisionByZero + | RemainderByZero + | ResumedAfterReturn(_) + | ResumedAfterPanic(_) => false, + } + } else { + false + } + } + Goto { .. } + | Resume + | Abort + | Return + | GeneratorDrop + | Unreachable + | FalseEdges { .. } + | FalseUnwind { .. } => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { + fn super_fold_with>(&self, _: &mut F) -> Self { + *self + } + + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + +impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.local.visit_with(visitor) || self.projection.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + folder.tcx().intern_place_elems(&v) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + +impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + use crate::mir::Rvalue::*; + match *self { + Use(ref op) => Use(op.fold_with(folder)), + Repeat(ref op, len) => Repeat(op.fold_with(folder), len), + Ref(region, bk, ref place) => { + Ref(region.fold_with(folder), bk, place.fold_with(folder)) + } + AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)), + Len(ref place) => Len(place.fold_with(folder)), + Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), + BinaryOp(op, ref rhs, ref lhs) => { + BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) + } + CheckedBinaryOp(op, ref rhs, ref lhs) => { + CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) + } + UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), + Discriminant(ref place) => Discriminant(place.fold_with(folder)), + NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), + Aggregate(ref kind, ref fields) => { + let kind = box match **kind { + AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), + AggregateKind::Tuple => AggregateKind::Tuple, + AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( + def, + v, + substs.fold_with(folder), + user_ty.fold_with(folder), + n, + ), + AggregateKind::Closure(id, substs) => { + AggregateKind::Closure(id, substs.fold_with(folder)) + } + AggregateKind::Generator(id, substs, movablity) => { + AggregateKind::Generator(id, substs.fold_with(folder), movablity) + } + }; + Aggregate(kind, fields.fold_with(folder)) + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use crate::mir::Rvalue::*; + match *self { + Use(ref op) => op.visit_with(visitor), + Repeat(ref op, _) => op.visit_with(visitor), + Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), + AddressOf(_, ref place) => place.visit_with(visitor), + Len(ref place) => place.visit_with(visitor), + Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), + BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => { + rhs.visit_with(visitor) || lhs.visit_with(visitor) + } + UnaryOp(_, ref val) => val.visit_with(visitor), + Discriminant(ref place) => place.visit_with(visitor), + NullaryOp(_, ty) => ty.visit_with(visitor), + Aggregate(ref kind, ref fields) => { + (match **kind { + AggregateKind::Array(ty) => ty.visit_with(visitor), + AggregateKind::Tuple => false, + AggregateKind::Adt(_, _, substs, user_ty, _) => { + substs.visit_with(visitor) || user_ty.visit_with(visitor) + } + AggregateKind::Closure(_, substs) => substs.visit_with(visitor), + AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), + }) || fields.visit_with(visitor) + } + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match *self { + Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)), + Operand::Move(ref place) => Operand::Move(place.fold_with(folder)), + Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), + Operand::Constant(ref c) => c.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + use crate::mir::ProjectionElem::*; + + match *self { + Deref => Deref, + Field(f, ty) => Field(f, ty.fold_with(folder)), + Index(v) => Index(v.fold_with(folder)), + Downcast(symbol, variantidx) => Downcast(symbol, variantidx), + ConstantIndex { offset, min_length, from_end } => { + ConstantIndex { offset, min_length, from_end } + } + Subslice { from, to, from_end } => Subslice { from, to, from_end }, + } + } + + fn super_visit_with>(&self, visitor: &mut Vs) -> bool { + use crate::mir::ProjectionElem::*; + + match self { + Field(_, ty) => ty.visit_with(visitor), + Index(v) => v.visit_with(visitor), + _ => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Field { + fn super_fold_with>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + +impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { + fn super_fold_with>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + +impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix { + fn super_fold_with>(&self, _: &mut F) -> Self { + self.clone() + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + +impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + Constant { + span: self.span, + user_ty: self.user_ty.fold_with(folder), + literal: self.literal.fold_with(folder), + } + } + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.literal.visit_with(visitor) + } +} -- cgit 1.4.1-3-g733a5 From a7e2641b9aba10d6eabf6978d3b5506d99ae633c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 31 Dec 2019 10:51:58 +0100 Subject: Move dep_graph to new crate librustc_query_system. --- src/librustc/dep_graph/README.md | 4 - src/librustc/dep_graph/debug.rs | 58 - src/librustc/dep_graph/graph.rs | 1196 --------------------- src/librustc/dep_graph/mod.rs | 17 - src/librustc/dep_graph/prev.rs | 55 - src/librustc/dep_graph/query.rs | 74 -- src/librustc/dep_graph/safe.rs | 57 - src/librustc/dep_graph/serialized.rs | 34 - src/librustc_query_system/dep_graph/README.md | 4 + src/librustc_query_system/dep_graph/debug.rs | 58 + src/librustc_query_system/dep_graph/dep_node.rs | 520 +++++++++ src/librustc_query_system/dep_graph/graph.rs | 1196 +++++++++++++++++++++ src/librustc_query_system/dep_graph/mod.rs | 17 + src/librustc_query_system/dep_graph/prev.rs | 55 + src/librustc_query_system/dep_graph/query.rs | 74 ++ src/librustc_query_system/dep_graph/safe.rs | 57 + src/librustc_query_system/dep_graph/serialized.rs | 34 + 17 files changed, 2015 insertions(+), 1495 deletions(-) delete mode 100644 src/librustc/dep_graph/README.md delete mode 100644 src/librustc/dep_graph/debug.rs delete mode 100644 src/librustc/dep_graph/graph.rs delete mode 100644 src/librustc/dep_graph/mod.rs delete mode 100644 src/librustc/dep_graph/prev.rs delete mode 100644 src/librustc/dep_graph/query.rs delete mode 100644 src/librustc/dep_graph/safe.rs delete mode 100644 src/librustc/dep_graph/serialized.rs create mode 100644 src/librustc_query_system/dep_graph/README.md create mode 100644 src/librustc_query_system/dep_graph/debug.rs create mode 100644 src/librustc_query_system/dep_graph/dep_node.rs create mode 100644 src/librustc_query_system/dep_graph/graph.rs create mode 100644 src/librustc_query_system/dep_graph/mod.rs create mode 100644 src/librustc_query_system/dep_graph/prev.rs create mode 100644 src/librustc_query_system/dep_graph/query.rs create mode 100644 src/librustc_query_system/dep_graph/safe.rs create mode 100644 src/librustc_query_system/dep_graph/serialized.rs (limited to 'src') diff --git a/src/librustc/dep_graph/README.md b/src/librustc/dep_graph/README.md deleted file mode 100644 index b9d91cd35a8..00000000000 --- a/src/librustc/dep_graph/README.md +++ /dev/null @@ -1,4 +0,0 @@ -To learn more about how dependency tracking works in rustc, see the [rustc -guide]. - -[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/query.html diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs deleted file mode 100644 index d44c54593a6..00000000000 --- a/src/librustc/dep_graph/debug.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Code for debugging the dep-graph. - -use super::dep_node::DepNode; -use std::error::Error; - -/// A dep-node filter goes from a user-defined string to a query over -/// nodes. Right now the format is like this: -/// -/// x & y & z -/// -/// where the format-string of the dep-node must contain `x`, `y`, and -/// `z`. -#[derive(Debug)] -pub struct DepNodeFilter { - text: String, -} - -impl DepNodeFilter { - pub fn new(text: &str) -> Self { - DepNodeFilter { text: text.trim().to_string() } - } - - /// Returns `true` if all nodes always pass the filter. - pub fn accepts_all(&self) -> bool { - self.text.is_empty() - } - - /// Tests whether `node` meets the filter, returning true if so. - pub fn test(&self, node: &DepNode) -> bool { - let debug_str = format!("{:?}", node); - self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f)) - } -} - -/// A filter like `F -> G` where `F` and `G` are valid dep-node -/// filters. This can be used to test the source/target independently. -pub struct EdgeFilter { - pub source: DepNodeFilter, - pub target: DepNodeFilter, -} - -impl EdgeFilter { - pub fn new(test: &str) -> Result> { - let parts: Vec<_> = test.split("->").collect(); - if parts.len() != 2 { - Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into()) - } else { - Ok(EdgeFilter { - source: DepNodeFilter::new(parts[0]), - target: DepNodeFilter::new(parts[1]), - }) - } - } - - pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { - self.source.test(source) && self.target.test(target) - } -} diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs deleted file mode 100644 index 36edf0f0fc2..00000000000 --- a/src/librustc/dep_graph/graph.rs +++ /dev/null @@ -1,1196 +0,0 @@ -use crate::ty::{self, TyCtxt}; -use parking_lot::{Condvar, Mutex}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::profiling::QueryInvocationId; -use rustc_data_structures::sharded::{self, Sharded}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; -use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; -use rustc_index::vec::{Idx, IndexVec}; -use smallvec::SmallVec; -use std::collections::hash_map::Entry; -use std::env; -use std::hash::Hash; -use std::mem; -use std::sync::atomic::Ordering::Relaxed; - -use crate::ich::{Fingerprint, StableHashingContext, StableHashingContextProvider}; - -use super::debug::EdgeFilter; -use super::dep_node::{DepKind, DepNode, WorkProductId}; -use super::prev::PreviousDepGraph; -use super::query::DepGraphQuery; -use super::safe::DepGraphSafe; -use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; - -#[derive(Clone)] -pub struct DepGraph { - data: Option>, - - /// This field is used for assigning DepNodeIndices when running in - /// non-incremental mode. Even in non-incremental mode we make sure that - /// each task has a `DepNodeIndex` that uniquely identifies it. This unique - /// ID is used for self-profiling. - virtual_dep_node_index: Lrc, -} - -rustc_index::newtype_index! { - pub struct DepNodeIndex { .. } -} - -impl DepNodeIndex { - pub const INVALID: DepNodeIndex = DepNodeIndex::MAX; -} - -impl std::convert::From for QueryInvocationId { - #[inline] - fn from(dep_node_index: DepNodeIndex) -> Self { - QueryInvocationId(dep_node_index.as_u32()) - } -} - -#[derive(PartialEq)] -pub enum DepNodeColor { - Red, - Green(DepNodeIndex), -} - -impl DepNodeColor { - pub fn is_green(self) -> bool { - match self { - DepNodeColor::Red => false, - DepNodeColor::Green(_) => true, - } - } -} - -struct DepGraphData { - /// The new encoding of the dependency graph, optimized for red/green - /// tracking. The `current` field is the dependency graph of only the - /// current compilation session: We don't merge the previous dep-graph into - /// current one anymore. - current: CurrentDepGraph, - - /// The dep-graph from the previous compilation session. It contains all - /// nodes and edges as well as all fingerprints of nodes that have them. - previous: PreviousDepGraph, - - colors: DepNodeColorMap, - - /// A set of loaded diagnostics that is in the progress of being emitted. - emitting_diagnostics: Mutex>, - - /// Used to wait for diagnostics to be emitted. - emitting_diagnostics_cond_var: Condvar, - - /// When we load, there may be `.o` files, cached MIR, or other such - /// things available to us. If we find that they are not dirty, we - /// load the path to the file storing those work-products here into - /// this map. We can later look for and extract that data. - previous_work_products: FxHashMap, - - dep_node_debug: Lock>, -} - -pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option -where - R: for<'a> HashStable>, -{ - let mut stable_hasher = StableHasher::new(); - result.hash_stable(hcx, &mut stable_hasher); - - Some(stable_hasher.finish()) -} - -impl DepGraph { - pub fn new( - prev_graph: PreviousDepGraph, - prev_work_products: FxHashMap, - ) -> DepGraph { - let prev_graph_node_count = prev_graph.node_count(); - - DepGraph { - data: Some(Lrc::new(DepGraphData { - previous_work_products: prev_work_products, - dep_node_debug: Default::default(), - current: CurrentDepGraph::new(prev_graph_node_count), - emitting_diagnostics: Default::default(), - emitting_diagnostics_cond_var: Condvar::new(), - previous: prev_graph, - colors: DepNodeColorMap::new(prev_graph_node_count), - })), - virtual_dep_node_index: Lrc::new(AtomicU32::new(0)), - } - } - - pub fn new_disabled() -> DepGraph { - DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } - } - - /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise. - #[inline] - pub fn is_fully_enabled(&self) -> bool { - self.data.is_some() - } - - pub fn query(&self) -> DepGraphQuery { - let data = self.data.as_ref().unwrap().current.data.lock(); - let nodes: Vec<_> = data.iter().map(|n| n.node).collect(); - let mut edges = Vec::new(); - for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) { - for &edge_target in edge_targets.iter() { - let to = data[edge_target].node; - edges.push((from, to)); - } - } - - DepGraphQuery::new(&nodes[..], &edges[..]) - } - - pub fn assert_ignored(&self) { - if let Some(..) = self.data { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); - }) - } - } - - pub fn with_ignore(&self, op: OP) -> R - where - OP: FnOnce() -> R, - { - ty::tls::with_context(|icx| { - let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }) - } - - /// Starts a new dep-graph task. Dep-graph tasks are specified - /// using a free function (`task`) and **not** a closure -- this - /// is intentional because we want to exercise tight control over - /// what state they have access to. In particular, we want to - /// prevent implicit 'leaks' of tracked state into the task (which - /// could then be read without generating correct edges in the - /// dep-graph -- see the [rustc dev guide] for more details on - /// the dep-graph). To this end, the task function gets exactly two - /// pieces of state: the context `cx` and an argument `arg`. Both - /// of these bits of state must be of some type that implements - /// `DepGraphSafe` and hence does not leak. - /// - /// The choice of two arguments is not fundamental. One argument - /// would work just as well, since multiple values can be - /// collected using tuples. However, using two arguments works out - /// to be quite convenient, since it is common to need a context - /// (`cx`) and some argument (e.g., a `DefId` identifying what - /// item to process). - /// - /// For cases where you need some other number of arguments: - /// - /// - If you only need one argument, just use `()` for the `arg` - /// parameter. - /// - If you need 3+ arguments, use a tuple for the - /// `arg` parameter. - /// - /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html - pub fn with_task<'a, C, A, R>( - &self, - key: DepNode, - cx: C, - arg: A, - task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, - ) -> (R, DepNodeIndex) - where - C: DepGraphSafe + StableHashingContextProvider<'a>, - { - self.with_task_impl( - key, - cx, - arg, - false, - task, - |_key| { - Some(TaskDeps { - #[cfg(debug_assertions)] - node: Some(_key), - reads: SmallVec::new(), - read_set: Default::default(), - }) - }, - |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), - hash_result, - ) - } - - fn with_task_impl<'a, C, A, R>( - &self, - key: DepNode, - cx: C, - arg: A, - no_tcx: bool, - task: fn(C, A) -> R, - create_task: fn(DepNode) -> Option, - finish_task_and_alloc_depnode: fn( - &CurrentDepGraph, - DepNode, - Fingerprint, - Option, - ) -> DepNodeIndex, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, - ) -> (R, DepNodeIndex) - where - C: DepGraphSafe + StableHashingContextProvider<'a>, - { - if let Some(ref data) = self.data { - let task_deps = create_task(key).map(Lock::new); - - // In incremental mode, hash the result of the task. We don't - // do anything with the hash yet, but we are computing it - // anyway so that - // - we make sure that the infrastructure works and - // - we can get an idea of the runtime cost. - let mut hcx = cx.get_stable_hashing_context(); - - let result = if no_tcx { - task(cx, arg) - } else { - ty::tls::with_context(|icx| { - let icx = - ty::tls::ImplicitCtxt { task_deps: task_deps.as_ref(), ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| task(cx, arg)) - }) - }; - - let current_fingerprint = hash_result(&mut hcx, &result); - - let dep_node_index = finish_task_and_alloc_depnode( - &data.current, - key, - current_fingerprint.unwrap_or(Fingerprint::ZERO), - task_deps.map(|lock| lock.into_inner()), - ); - - let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks; - - // Determine the color of the new DepNode. - if let Some(prev_index) = data.previous.node_to_index_opt(&key) { - let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - - let color = if let Some(current_fingerprint) = current_fingerprint { - if current_fingerprint == prev_fingerprint { - if print_status { - eprintln!("[task::green] {:?}", key); - } - DepNodeColor::Green(dep_node_index) - } else { - if print_status { - eprintln!("[task::red] {:?}", key); - } - DepNodeColor::Red - } - } else { - if print_status { - eprintln!("[task::unknown] {:?}", key); - } - // Mark the node as Red if we can't hash the result - DepNodeColor::Red - }; - - debug_assert!( - data.colors.get(prev_index).is_none(), - "DepGraph::with_task() - Duplicate DepNodeColor \ - insertion for {:?}", - key - ); - - data.colors.insert(prev_index, color); - } else { - if print_status { - eprintln!("[task::new] {:?}", key); - } - } - - (result, dep_node_index) - } else { - (task(cx, arg), self.next_virtual_depnode_index()) - } - } - - /// Executes something within an "anonymous" task, that is, a task the - /// `DepNode` of which is determined by the list of inputs it read from. - pub fn with_anon_task(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex) - where - OP: FnOnce() -> R, - { - if let Some(ref data) = self.data { - let (result, task_deps) = ty::tls::with_context(|icx| { - let task_deps = Lock::new(TaskDeps::default()); - - let r = { - let icx = ty::tls::ImplicitCtxt { task_deps: Some(&task_deps), ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }; - - (r, task_deps.into_inner()) - }); - let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps); - (result, dep_node_index) - } else { - (op(), self.next_virtual_depnode_index()) - } - } - - /// Executes something within an "eval-always" task which is a task - /// that runs whenever anything changes. - pub fn with_eval_always_task<'a, C, A, R>( - &self, - key: DepNode, - cx: C, - arg: A, - task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, - ) -> (R, DepNodeIndex) - where - C: DepGraphSafe + StableHashingContextProvider<'a>, - { - self.with_task_impl( - key, - cx, - arg, - false, - task, - |_| None, - |data, key, fingerprint, _| data.alloc_node(key, smallvec![], fingerprint), - hash_result, - ) - } - - #[inline] - pub fn read(&self, v: DepNode) { - if let Some(ref data) = self.data { - let map = data.current.node_to_node_index.get_shard_by_value(&v).lock(); - if let Some(dep_node_index) = map.get(&v).copied() { - std::mem::drop(map); - data.read_index(dep_node_index); - } else { - bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind) - } - } - } - - #[inline] - pub fn read_index(&self, dep_node_index: DepNodeIndex) { - if let Some(ref data) = self.data { - data.read_index(dep_node_index); - } - } - - #[inline] - pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { - self.data - .as_ref() - .unwrap() - .current - .node_to_node_index - .get_shard_by_value(dep_node) - .lock() - .get(dep_node) - .cloned() - .unwrap() - } - - #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { - if let Some(ref data) = self.data { - data.current - .node_to_node_index - .get_shard_by_value(&dep_node) - .lock() - .contains_key(dep_node) - } else { - false - } - } - - #[inline] - pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { - let data = self.data.as_ref().expect("dep graph enabled").current.data.lock(); - data[dep_node_index].fingerprint - } - - pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { - self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) - } - - #[inline] - pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { - self.data.as_ref().unwrap().previous.node_to_index(dep_node) - } - - /// Checks whether a previous work product exists for `v` and, if - /// so, return the path that leads to it. Used to skip doing work. - pub fn previous_work_product(&self, v: &WorkProductId) -> Option { - self.data.as_ref().and_then(|data| data.previous_work_products.get(v).cloned()) - } - - /// Access the map of work-products created during the cached run. Only - /// used during saving of the dep-graph. - pub fn previous_work_products(&self) -> &FxHashMap { - &self.data.as_ref().unwrap().previous_work_products - } - - #[inline(always)] - pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) - where - F: FnOnce() -> String, - { - let dep_node_debug = &self.data.as_ref().unwrap().dep_node_debug; - - if dep_node_debug.borrow().contains_key(&dep_node) { - return; - } - let debug_str = debug_str_gen(); - dep_node_debug.borrow_mut().insert(dep_node, debug_str); - } - - pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { - self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() - } - - pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> { - if cfg!(debug_assertions) { - let current_dep_graph = &self.data.as_ref().unwrap().current; - - Some(( - current_dep_graph.total_read_count.load(Relaxed), - current_dep_graph.total_duplicate_read_count.load(Relaxed), - )) - } else { - None - } - } - - pub fn serialize(&self) -> SerializedDepGraph { - let data = self.data.as_ref().unwrap().current.data.lock(); - - let fingerprints: IndexVec = - data.iter().map(|d| d.fingerprint).collect(); - let nodes: IndexVec = data.iter().map(|d| d.node).collect(); - - let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum(); - - let mut edge_list_indices = IndexVec::with_capacity(nodes.len()); - let mut edge_list_data = Vec::with_capacity(total_edge_count); - - for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) { - let start = edge_list_data.len() as u32; - // This should really just be a memcpy :/ - edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index()))); - let end = edge_list_data.len() as u32; - - debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len()); - edge_list_indices.push((start, end)); - } - - debug_assert!(edge_list_data.len() <= u32::MAX as usize); - debug_assert_eq!(edge_list_data.len(), total_edge_count); - - SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data } - } - - pub fn node_color(&self, dep_node: &DepNode) -> Option { - if let Some(ref data) = self.data { - if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { - return data.colors.get(prev_index); - } else { - // This is a node that did not exist in the previous compilation - // session, so we consider it to be red. - return Some(DepNodeColor::Red); - } - } - - None - } - - /// Try to read a node index for the node dep_node. - /// A node will have an index, when it's already been marked green, or when we can mark it - /// green. This function will mark the current task as a reader of the specified node, when - /// a node index can be found for that node. - pub fn try_mark_green_and_read( - &self, - tcx: TyCtxt<'_>, - dep_node: &DepNode, - ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { - self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| { - debug_assert!(self.is_green(&dep_node)); - self.read_index(dep_node_index); - (prev_index, dep_node_index) - }) - } - - pub fn try_mark_green( - &self, - tcx: TyCtxt<'_>, - dep_node: &DepNode, - ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { - debug_assert!(!dep_node.kind.is_eval_always()); - - // Return None if the dep graph is disabled - let data = self.data.as_ref()?; - - // Return None if the dep node didn't exist in the previous session - let prev_index = data.previous.node_to_index_opt(dep_node)?; - - match data.colors.get(prev_index) { - Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)), - Some(DepNodeColor::Red) => None, - None => { - // This DepNode and the corresponding query invocation existed - // in the previous compilation session too, so we can try to - // mark it as green by recursively marking all of its - // dependencies green. - self.try_mark_previous_green(tcx, data, prev_index, &dep_node) - .map(|dep_node_index| (prev_index, dep_node_index)) - } - } - } - - /// Try to mark a dep-node which existed in the previous compilation session as green. - fn try_mark_previous_green<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - data: &DepGraphData, - prev_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, - ) -> Option { - debug!("try_mark_previous_green({:?}) - BEGIN", dep_node); - - #[cfg(not(parallel_compiler))] - { - debug_assert!( - !data - .current - .node_to_node_index - .get_shard_by_value(dep_node) - .lock() - .contains_key(dep_node) - ); - debug_assert!(data.colors.get(prev_dep_node_index).is_none()); - } - - // We never try to mark eval_always nodes as green - debug_assert!(!dep_node.kind.is_eval_always()); - - debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node); - - let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); - - let mut current_deps = SmallVec::new(); - - for &dep_dep_node_index in prev_deps { - let dep_dep_node_color = data.colors.get(dep_dep_node_index); - - match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { - // This dependency has been marked as green before, we are - // still fine and can continue with checking the other - // dependencies. - debug!( - "try_mark_previous_green({:?}) --- found dependency {:?} to \ - be immediately green", - dep_node, - data.previous.index_to_node(dep_dep_node_index) - ); - current_deps.push(node_index); - } - Some(DepNodeColor::Red) => { - // We found a dependency the value of which has changed - // compared to the previous compilation session. We cannot - // mark the DepNode as green and also don't need to bother - // with checking any of the other dependencies. - debug!( - "try_mark_previous_green({:?}) - END - dependency {:?} was \ - immediately red", - dep_node, - data.previous.index_to_node(dep_dep_node_index) - ); - return None; - } - None => { - let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); - - // We don't know the state of this dependency. If it isn't - // an eval_always node, let's try to mark it green recursively. - if !dep_dep_node.kind.is_eval_always() { - debug!( - "try_mark_previous_green({:?}) --- state of dependency {:?} \ - is unknown, trying to mark it green", - dep_node, dep_dep_node - ); - - let node_index = self.try_mark_previous_green( - tcx, - data, - dep_dep_node_index, - dep_dep_node, - ); - if let Some(node_index) = node_index { - debug!( - "try_mark_previous_green({:?}) --- managed to MARK \ - dependency {:?} as green", - dep_node, dep_dep_node - ); - current_deps.push(node_index); - continue; - } - } else { - // FIXME: This match is just a workaround for incremental bugs and should - // be removed. https://github.com/rust-lang/rust/issues/62649 is one such - // bug that must be fixed before removing this. - match dep_dep_node.kind { - DepKind::hir_owner - | DepKind::hir_owner_nodes - | DepKind::CrateMetadata => { - if let Some(def_id) = dep_dep_node.extract_def_id(tcx) { - if def_id_corresponds_to_hir_dep_node(tcx, def_id) { - if dep_dep_node.kind == DepKind::CrateMetadata { - // The `DefPath` has corresponding node, - // and that node should have been marked - // either red or green in `data.colors`. - bug!( - "DepNode {:?} should have been \ - pre-marked as red or green but wasn't.", - dep_dep_node - ); - } - } else { - // This `DefPath` does not have a - // corresponding `DepNode` (e.g. a - // struct field), and the ` DefPath` - // collided with the `DefPath` of a - // proper item that existed in the - // previous compilation session. - // - // Since the given `DefPath` does not - // denote the item that previously - // existed, we just fail to mark green. - return None; - } - } else { - // If the node does not exist anymore, we - // just fail to mark green. - return None; - } - } - _ => { - // For other kinds of nodes it's OK to be - // forced. - } - } - } - - // We failed to mark it green, so we try to force the query. - debug!( - "try_mark_previous_green({:?}) --- trying to force \ - dependency {:?}", - dep_node, dep_dep_node - ); - if crate::ty::query::force_from_dep_node(tcx, dep_dep_node) { - let dep_dep_node_color = data.colors.get(dep_dep_node_index); - - match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { - debug!( - "try_mark_previous_green({:?}) --- managed to \ - FORCE dependency {:?} to green", - dep_node, dep_dep_node - ); - current_deps.push(node_index); - } - Some(DepNodeColor::Red) => { - debug!( - "try_mark_previous_green({:?}) - END - \ - dependency {:?} was red after forcing", - dep_node, dep_dep_node - ); - return None; - } - None => { - if !tcx.sess.has_errors_or_delayed_span_bugs() { - bug!( - "try_mark_previous_green() - Forcing the DepNode \ - should have set its color" - ) - } else { - // If the query we just forced has resulted in - // some kind of compilation error, we cannot rely on - // the dep-node color having been properly updated. - // This means that the query system has reached an - // invalid state. We let the compiler continue (by - // returning `None`) so it can emit error messages - // and wind down, but rely on the fact that this - // invalid state will not be persisted to the - // incremental compilation cache because of - // compilation errors being present. - debug!( - "try_mark_previous_green({:?}) - END - \ - dependency {:?} resulted in compilation error", - dep_node, dep_dep_node - ); - return None; - } - } - } - } else { - // The DepNode could not be forced. - debug!( - "try_mark_previous_green({:?}) - END - dependency {:?} \ - could not be forced", - dep_node, dep_dep_node - ); - return None; - } - } - } - } - - // If we got here without hitting a `return` that means that all - // dependencies of this DepNode could be marked as green. Therefore we - // can also mark this DepNode as green. - - // There may be multiple threads trying to mark the same dep node green concurrently - - let dep_node_index = { - // Copy the fingerprint from the previous graph, - // so we don't have to recompute it - let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index); - - // We allocating an entry for the node in the current dependency graph and - // adding all the appropriate edges imported from the previous graph - data.current.intern_node(*dep_node, current_deps, fingerprint) - }; - - // ... emitting any stored diagnostic ... - - // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere - // Maybe store a list on disk and encode this fact in the DepNodeState - let diagnostics = tcx.queries.on_disk_cache.load_diagnostics(tcx, prev_dep_node_index); - - #[cfg(not(parallel_compiler))] - debug_assert!( - data.colors.get(prev_dep_node_index).is_none(), - "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \ - insertion for {:?}", - dep_node - ); - - if unlikely!(!diagnostics.is_empty()) { - self.emit_diagnostics(tcx, data, dep_node_index, prev_dep_node_index, diagnostics); - } - - // ... and finally storing a "Green" entry in the color map. - // Multiple threads can all write the same color here - data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); - - debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node); - Some(dep_node_index) - } - - /// Atomically emits some loaded diagnostics. - /// This may be called concurrently on multiple threads for the same dep node. - #[cold] - #[inline(never)] - fn emit_diagnostics<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - data: &DepGraphData, - dep_node_index: DepNodeIndex, - prev_dep_node_index: SerializedDepNodeIndex, - diagnostics: Vec, - ) { - let mut emitting = data.emitting_diagnostics.lock(); - - if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) { - // The node is already green so diagnostics must have been emitted already - return; - } - - if emitting.insert(dep_node_index) { - // We were the first to insert the node in the set so this thread - // must emit the diagnostics and signal other potentially waiting - // threads after. - mem::drop(emitting); - - // Promote the previous diagnostics to the current session. - tcx.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics.clone().into()); - - let handle = tcx.sess.diagnostic(); - - for diagnostic in diagnostics { - handle.emit_diagnostic(&diagnostic); - } - - // Mark the node as green now that diagnostics are emitted - data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); - - // Remove the node from the set - data.emitting_diagnostics.lock().remove(&dep_node_index); - - // Wake up waiters - data.emitting_diagnostics_cond_var.notify_all(); - } else { - // We must wait for the other thread to finish emitting the diagnostic - - loop { - data.emitting_diagnostics_cond_var.wait(&mut emitting); - if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) - { - break; - } - } - } - } - - // Returns true if the given node has been marked as green during the - // current compilation session. Used in various assertions - pub fn is_green(&self, dep_node: &DepNode) -> bool { - self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) - } - - // This method loads all on-disk cacheable query results into memory, so - // they can be written out to the new cache file again. Most query results - // will already be in memory but in the case where we marked something as - // green but then did not need the value, that value will never have been - // loaded from disk. - // - // This method will only load queries that will end up in the disk cache. - // Other queries will not be executed. - pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) { - let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); - - let data = self.data.as_ref().unwrap(); - for prev_index in data.colors.values.indices() { - match data.colors.get(prev_index) { - Some(DepNodeColor::Green(_)) => { - let dep_node = data.previous.index_to_node(prev_index); - dep_node.try_load_from_on_disk_cache(tcx); - } - None | Some(DepNodeColor::Red) => { - // We can skip red nodes because a node can only be marked - // as red if the query result was recomputed and thus is - // already in memory. - } - } - } - } - - fn next_virtual_depnode_index(&self) -> DepNodeIndex { - let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); - DepNodeIndex::from_u32(index) - } -} - -fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - def_id.index == hir_id.owner.local_def_index -} - -/// A "work product" is an intermediate result that we save into the -/// incremental directory for later re-use. The primary example are -/// the object files that we save for each partition at code -/// generation time. -/// -/// Each work product is associated with a dep-node, representing the -/// process that produced the work-product. If that dep-node is found -/// to be dirty when we load up, then we will delete the work-product -/// at load time. If the work-product is found to be clean, then we -/// will keep a record in the `previous_work_products` list. -/// -/// In addition, work products have an associated hash. This hash is -/// an extra hash that can be used to decide if the work-product from -/// a previous compilation can be re-used (in addition to the dirty -/// edges check). -/// -/// As the primary example, consider the object files we generate for -/// each partition. In the first run, we create partitions based on -/// the symbols that need to be compiled. For each partition P, we -/// hash the symbols in P and create a `WorkProduct` record associated -/// with `DepNode::CodegenUnit(P)`; the hash is the set of symbols -/// in P. -/// -/// The next time we compile, if the `DepNode::CodegenUnit(P)` is -/// judged to be clean (which means none of the things we read to -/// generate the partition were found to be dirty), it will be loaded -/// into previous work products. We will then regenerate the set of -/// symbols in the partition P and hash them (note that new symbols -/// may be added -- for example, new monomorphizations -- even if -/// nothing in P changed!). We will compare that hash against the -/// previous hash. If it matches up, we can reuse the object file. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct WorkProduct { - pub cgu_name: String, - /// Saved files associated with this CGU. - pub saved_files: Vec<(WorkProductFileKind, String)>, -} - -#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable, PartialEq)] -pub enum WorkProductFileKind { - Object, - Bytecode, - BytecodeCompressed, -} - -#[derive(Clone)] -struct DepNodeData { - node: DepNode, - edges: EdgesVec, - fingerprint: Fingerprint, -} - -/// `CurrentDepGraph` stores the dependency graph for the current session. -/// It will be populated as we run queries or tasks. -/// -/// The nodes in it are identified by an index (`DepNodeIndex`). -/// The data for each node is stored in its `DepNodeData`, found in the `data` field. -/// -/// We never remove nodes from the graph: they are only added. -/// -/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are -/// locked separately. Operations that take a `DepNodeIndex` typically just access -/// the data field. -/// -/// The only operation that must manipulate both locks is adding new nodes, in which case -/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted, -/// acquire the lock on `data.` -pub(super) struct CurrentDepGraph { - data: Lock>, - node_to_node_index: Sharded>, - - /// Used to trap when a specific edge is added to the graph. - /// This is used for debug purposes and is only active with `debug_assertions`. - #[allow(dead_code)] - forbidden_edge: Option, - - /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of - /// their edges. This has the beneficial side-effect that multiple anonymous - /// nodes can be coalesced into one without changing the semantics of the - /// dependency graph. However, the merging of nodes can lead to a subtle - /// problem during red-green marking: The color of an anonymous node from - /// the current session might "shadow" the color of the node with the same - /// ID from the previous session. In order to side-step this problem, we make - /// sure that anonymous `NodeId`s allocated in different sessions don't overlap. - /// This is implemented by mixing a session-key into the ID fingerprint of - /// each anon node. The session-key is just a random number generated when - /// the `DepGraph` is created. - anon_id_seed: Fingerprint, - - /// These are simple counters that are for profiling and - /// debugging and only active with `debug_assertions`. - total_read_count: AtomicU64, - total_duplicate_read_count: AtomicU64, -} - -impl CurrentDepGraph { - fn new(prev_graph_node_count: usize) -> CurrentDepGraph { - use std::time::{SystemTime, UNIX_EPOCH}; - - let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; - let mut stable_hasher = StableHasher::new(); - nanos.hash(&mut stable_hasher); - - let forbidden_edge = if cfg!(debug_assertions) { - match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { - Ok(s) => match EdgeFilter::new(&s) { - Ok(f) => Some(f), - Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), - }, - Err(_) => None, - } - } else { - None - }; - - // Pre-allocate the dep node structures. We over-allocate a little so - // that we hopefully don't have to re-allocate during this compilation - // session. The over-allocation is 2% plus a small constant to account - // for the fact that in very small crates 2% might not be enough. - let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200; - - CurrentDepGraph { - data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)), - node_to_node_index: Sharded::new(|| { - FxHashMap::with_capacity_and_hasher( - new_node_count_estimate / sharded::SHARDS, - Default::default(), - ) - }), - anon_id_seed: stable_hasher.finish(), - forbidden_edge, - total_read_count: AtomicU64::new(0), - total_duplicate_read_count: AtomicU64::new(0), - } - } - - fn complete_task( - &self, - node: DepNode, - task_deps: TaskDeps, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - self.alloc_node(node, task_deps.reads, fingerprint) - } - - fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex { - debug_assert!(!kind.is_eval_always()); - - let mut hasher = StableHasher::new(); - - // The dep node indices are hashed here instead of hashing the dep nodes of the - // dependencies. These indices may refer to different nodes per session, but this isn't - // a problem here because we that ensure the final dep node hash is per session only by - // combining it with the per session random number `anon_id_seed`. This hash only need - // to map the dependencies to a single value on a per session basis. - task_deps.reads.hash(&mut hasher); - - let target_dep_node = DepNode { - kind, - - // Fingerprint::combine() is faster than sending Fingerprint - // through the StableHasher (at least as long as StableHasher - // is so slow). - hash: self.anon_id_seed.combine(hasher.finish()), - }; - - self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO) - } - - fn alloc_node( - &self, - dep_node: DepNode, - edges: EdgesVec, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - debug_assert!( - !self.node_to_node_index.get_shard_by_value(&dep_node).lock().contains_key(&dep_node) - ); - self.intern_node(dep_node, edges, fingerprint) - } - - fn intern_node( - &self, - dep_node: DepNode, - edges: EdgesVec, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let mut data = self.data.lock(); - let dep_node_index = DepNodeIndex::new(data.len()); - data.push(DepNodeData { node: dep_node, edges, fingerprint }); - entry.insert(dep_node_index); - dep_node_index - } - } - } -} - -impl DepGraphData { - #[inline(never)] - fn read_index(&self, source: DepNodeIndex) { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - if let Some(task_deps) = icx.task_deps { - let mut task_deps = task_deps.lock(); - let task_deps = &mut *task_deps; - if cfg!(debug_assertions) { - self.current.total_read_count.fetch_add(1, Relaxed); - } - - // As long as we only have a low number of reads we can avoid doing a hash - // insert and potentially allocating/reallocating the hashmap - let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { - task_deps.reads.iter().all(|other| *other != source) - } else { - task_deps.read_set.insert(source) - }; - if new_read { - task_deps.reads.push(source); - if task_deps.reads.len() == TASK_DEPS_READS_CAP { - // Fill `read_set` with what we have so far so we can use the hashset next - // time - task_deps.read_set.extend(task_deps.reads.iter().copied()); - } - - #[cfg(debug_assertions)] - { - if let Some(target) = task_deps.node { - let data = self.current.data.lock(); - if let Some(ref forbidden_edge) = self.current.forbidden_edge { - let source = data[source].node; - if forbidden_edge.test(&source, &target) { - bug!("forbidden edge {:?} -> {:?} created", source, target) - } - } - } - } - } else if cfg!(debug_assertions) { - self.current.total_duplicate_read_count.fetch_add(1, Relaxed); - } - } - }) - } -} - -/// The capacity of the `reads` field `SmallVec` -const TASK_DEPS_READS_CAP: usize = 8; -type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; -#[derive(Default)] -pub struct TaskDeps { - #[cfg(debug_assertions)] - node: Option, - reads: EdgesVec, - read_set: FxHashSet, -} - -// A data structure that stores Option values as a contiguous -// array, using one u32 per entry. -struct DepNodeColorMap { - values: IndexVec, -} - -const COMPRESSED_NONE: u32 = 0; -const COMPRESSED_RED: u32 = 1; -const COMPRESSED_FIRST_GREEN: u32 = 2; - -impl DepNodeColorMap { - fn new(size: usize) -> DepNodeColorMap { - DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() } - } - - fn get(&self, index: SerializedDepNodeIndex) -> Option { - match self.values[index].load(Ordering::Acquire) { - COMPRESSED_NONE => None, - COMPRESSED_RED => Some(DepNodeColor::Red), - value => { - Some(DepNodeColor::Green(DepNodeIndex::from_u32(value - COMPRESSED_FIRST_GREEN))) - } - } - } - - fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) { - self.values[index].store( - match color { - DepNodeColor::Red => COMPRESSED_RED, - DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN, - }, - Ordering::Release, - ) - } -} diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs deleted file mode 100644 index 1fbd90743f4..00000000000 --- a/src/librustc/dep_graph/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub mod debug; -mod dep_node; -mod graph; -mod prev; -mod query; -mod safe; -mod serialized; - -pub(crate) use self::dep_node::DepNodeParams; -pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, WorkProductId}; -pub use self::graph::WorkProductFileKind; -pub use self::graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; -pub use self::prev::PreviousDepGraph; -pub use self::query::DepGraphQuery; -pub use self::safe::AssertDepGraphSafe; -pub use self::safe::DepGraphSafe; -pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs deleted file mode 100644 index fbc8f7bc997..00000000000 --- a/src/librustc/dep_graph/prev.rs +++ /dev/null @@ -1,55 +0,0 @@ -use super::dep_node::DepNode; -use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; -use crate::ich::Fingerprint; -use rustc_data_structures::fx::FxHashMap; - -#[derive(Debug, RustcEncodable, RustcDecodable, Default)] -pub struct PreviousDepGraph { - data: SerializedDepGraph, - index: FxHashMap, -} - -impl PreviousDepGraph { - pub fn new(data: SerializedDepGraph) -> PreviousDepGraph { - let index: FxHashMap<_, _> = - data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); - PreviousDepGraph { data, index } - } - - #[inline] - pub fn edge_targets_from( - &self, - dep_node_index: SerializedDepNodeIndex, - ) -> &[SerializedDepNodeIndex] { - self.data.edge_targets_from(dep_node_index) - } - - #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { - self.data.nodes[dep_node_index] - } - - #[inline] - pub fn node_to_index(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { - self.index[dep_node] - } - - #[inline] - pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { - self.index.get(dep_node).cloned() - } - - #[inline] - pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { - self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index]) - } - - #[inline] - pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint { - self.data.fingerprints[dep_node_index] - } - - pub fn node_count(&self) -> usize { - self.index.len() - } -} diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs deleted file mode 100644 index c71c11ed0eb..00000000000 --- a/src/librustc/dep_graph/query.rs +++ /dev/null @@ -1,74 +0,0 @@ -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::implementation::{ - Direction, Graph, NodeIndex, INCOMING, OUTGOING, -}; - -use super::DepNode; - -pub struct DepGraphQuery { - pub graph: Graph, - pub indices: FxHashMap, -} - -impl DepGraphQuery { - pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { - let mut graph = Graph::with_capacity(nodes.len(), edges.len()); - let mut indices = FxHashMap::default(); - for node in nodes { - indices.insert(node.clone(), graph.add_node(node.clone())); - } - - for &(ref source, ref target) in edges { - let source = indices[source]; - let target = indices[target]; - graph.add_edge(source, target, ()); - } - - DepGraphQuery { graph, indices } - } - - pub fn contains_node(&self, node: &DepNode) -> bool { - self.indices.contains_key(&node) - } - - pub fn nodes(&self) -> Vec<&DepNode> { - self.graph.all_nodes().iter().map(|n| &n.data).collect() - } - - pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { - self.graph - .all_edges() - .iter() - .map(|edge| (edge.source(), edge.target())) - .map(|(s, t)| (self.graph.node_data(s), self.graph.node_data(t))) - .collect() - } - - fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { - if let Some(&index) = self.indices.get(node) { - self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect() - } else { - vec![] - } - } - - /// All nodes reachable from `node`. In other words, things that - /// will have to be recomputed if `node` changes. - pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { - self.reachable_nodes(node, OUTGOING) - } - - /// All nodes that can reach `node`. - pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { - self.reachable_nodes(node, INCOMING) - } - - /// Just the outgoing edges from `node`. - pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { - if let Some(&index) = self.indices.get(&node) { - self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect() - } else { - vec![] - } - } -} diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs deleted file mode 100644 index 74e32867cde..00000000000 --- a/src/librustc/dep_graph/safe.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! The `DepGraphSafe` trait - -use crate::ty::TyCtxt; - -use rustc_ast::ast::NodeId; -use rustc_hir::def_id::DefId; -use rustc_hir::BodyId; - -/// The `DepGraphSafe` trait is used to specify what kinds of values -/// are safe to "leak" into a task. The idea is that this should be -/// only be implemented for things like the tcx as well as various id -/// types, which will create reads in the dep-graph whenever the trait -/// loads anything that might depend on the input program. -pub trait DepGraphSafe {} - -/// A `BodyId` on its own doesn't give access to any particular state. -/// You must fetch the state from the various maps or generate -/// on-demand queries, all of which create reads. -impl DepGraphSafe for BodyId {} - -/// A `NodeId` on its own doesn't give access to any particular state. -/// You must fetch the state from the various maps or generate -/// on-demand queries, all of which create reads. -impl DepGraphSafe for NodeId {} - -/// A `DefId` on its own doesn't give access to any particular state. -/// You must fetch the state from the various maps or generate -/// on-demand queries, all of which create reads. -impl DepGraphSafe for DefId {} - -/// The type context itself can be used to access all kinds of tracked -/// state, but those accesses should always generate read events. -impl<'tcx> DepGraphSafe for TyCtxt<'tcx> {} - -/// Tuples make it easy to build up state. -impl DepGraphSafe for (A, B) -where - A: DepGraphSafe, - B: DepGraphSafe, -{ -} - -/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe. -impl<'a, A> DepGraphSafe for &'a A where A: DepGraphSafe {} - -/// Mut ref to dep-graph-safe stuff should still be dep-graph-safe. -impl<'a, A> DepGraphSafe for &'a mut A where A: DepGraphSafe {} - -/// No data here! :) -impl DepGraphSafe for () {} - -/// A convenient override that lets you pass arbitrary state into a -/// task. Every use should be accompanied by a comment explaining why -/// it makes sense (or how it could be refactored away in the future). -pub struct AssertDepGraphSafe(pub T); - -impl DepGraphSafe for AssertDepGraphSafe {} diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs deleted file mode 100644 index 45ef52dbf39..00000000000 --- a/src/librustc/dep_graph/serialized.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! The data that we will serialize and deserialize. - -use crate::dep_graph::DepNode; -use crate::ich::Fingerprint; -use rustc_index::vec::IndexVec; - -rustc_index::newtype_index! { - pub struct SerializedDepNodeIndex { .. } -} - -/// Data for use when recompiling the **current crate**. -#[derive(Debug, RustcEncodable, RustcDecodable, Default)] -pub struct SerializedDepGraph { - /// The set of all DepNodes in the graph - pub nodes: IndexVec, - /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to - /// the DepNode at the same index in the nodes vector. - pub fingerprints: IndexVec, - /// For each DepNode, stores the list of edges originating from that - /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, - /// which holds the actual DepNodeIndices of the target nodes. - pub edge_list_indices: IndexVec, - /// A flattened list of all edge targets in the graph. Edge sources are - /// implicit in edge_list_indices. - pub edge_list_data: Vec, -} - -impl SerializedDepGraph { - #[inline] - pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] { - let targets = self.edge_list_indices[source]; - &self.edge_list_data[targets.0 as usize..targets.1 as usize] - } -} diff --git a/src/librustc_query_system/dep_graph/README.md b/src/librustc_query_system/dep_graph/README.md new file mode 100644 index 00000000000..b9d91cd35a8 --- /dev/null +++ b/src/librustc_query_system/dep_graph/README.md @@ -0,0 +1,4 @@ +To learn more about how dependency tracking works in rustc, see the [rustc +guide]. + +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/query.html diff --git a/src/librustc_query_system/dep_graph/debug.rs b/src/librustc_query_system/dep_graph/debug.rs new file mode 100644 index 00000000000..d44c54593a6 --- /dev/null +++ b/src/librustc_query_system/dep_graph/debug.rs @@ -0,0 +1,58 @@ +//! Code for debugging the dep-graph. + +use super::dep_node::DepNode; +use std::error::Error; + +/// A dep-node filter goes from a user-defined string to a query over +/// nodes. Right now the format is like this: +/// +/// x & y & z +/// +/// where the format-string of the dep-node must contain `x`, `y`, and +/// `z`. +#[derive(Debug)] +pub struct DepNodeFilter { + text: String, +} + +impl DepNodeFilter { + pub fn new(text: &str) -> Self { + DepNodeFilter { text: text.trim().to_string() } + } + + /// Returns `true` if all nodes always pass the filter. + pub fn accepts_all(&self) -> bool { + self.text.is_empty() + } + + /// Tests whether `node` meets the filter, returning true if so. + pub fn test(&self, node: &DepNode) -> bool { + let debug_str = format!("{:?}", node); + self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f)) + } +} + +/// A filter like `F -> G` where `F` and `G` are valid dep-node +/// filters. This can be used to test the source/target independently. +pub struct EdgeFilter { + pub source: DepNodeFilter, + pub target: DepNodeFilter, +} + +impl EdgeFilter { + pub fn new(test: &str) -> Result> { + let parts: Vec<_> = test.split("->").collect(); + if parts.len() != 2 { + Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into()) + } else { + Ok(EdgeFilter { + source: DepNodeFilter::new(parts[0]), + target: DepNodeFilter::new(parts[1]), + }) + } + } + + pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { + self.source.test(source) && self.target.test(target) + } +} diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs new file mode 100644 index 00000000000..e3df9d5d04b --- /dev/null +++ b/src/librustc_query_system/dep_graph/dep_node.rs @@ -0,0 +1,520 @@ +//! This module defines the `DepNode` type which the compiler uses to represent +//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which +//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc) +//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which +//! depends on the node's `DepKind`. Together, the kind and the fingerprint +//! fully identify a dependency node, even across multiple compilation sessions. +//! In other words, the value of the fingerprint does not depend on anything +//! that is specific to a given compilation session, like an unpredictable +//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a +//! pointer. The concept behind this could be compared to how git commit hashes +//! uniquely identify a given commit and has a few advantages: +//! +//! * A `DepNode` can simply be serialized to disk and loaded in another session +//! without the need to do any "rebasing (like we have to do for Spans and +//! NodeIds) or "retracing" like we had to do for `DefId` in earlier +//! implementations of the dependency graph. +//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to +//! implement `Copy`, `Sync`, `Send`, `Freeze`, etc. +//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into +//! memory without any post-processing (e.g., "abomination-style" pointer +//! reconstruction). +//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that +//! refer to things that do not exist anymore. In previous implementations +//! `DepNode` contained a `DefId`. A `DepNode` referring to something that +//! had been removed between the previous and the current compilation session +//! could not be instantiated because the current compilation session +//! contained no `DefId` for thing that had been removed. +//! +//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro +//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The +//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at +//! runtime in order to construct a valid `DepNode` fingerprint. +//! +//! Because the macro sees what parameters a given `DepKind` requires, it can +//! "infer" some properties for each kind of `DepNode`: +//! +//! * Whether a `DepNode` of a given kind has any parameters at all. Some +//! `DepNode`s could represent global concepts with only one value. +//! * Whether it is possible, in principle, to reconstruct a query key from a +//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter, +//! in which case it is possible to map the node's fingerprint back to the +//! `DefId` it was computed from. In other cases, too much information gets +//! lost during fingerprint computation. +//! +//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only +//! valid `DepNode` instances can be constructed. For example, the API does not +//! allow for constructing parameterless `DepNode`s with anything other +//! than a zeroed out fingerprint. More generally speaking, it relieves the +//! user of the `DepNode` API of having to know how to compute the expected +//! fingerprint for a given set of node parameters. + +use crate::hir::map::DefPathHash; +use crate::ich::{Fingerprint, StableHashingContext}; +use crate::mir; +use crate::mir::interpret::{GlobalId, LitToConstInput}; +use crate::traits; +use crate::traits::query::{ + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, +}; +use crate::ty::subst::SubstsRef; +use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc_hir::HirId; +use rustc_span::symbol::Symbol; +use std::fmt; +use std::hash::Hash; + +// erase!() just makes tokens go away. It's used to specify which macro argument +// is repeated (i.e., which sub-expression of the macro we are in) but don't need +// to actually use any of the arguments. +macro_rules! erase { + ($x:tt) => {{}}; +} + +macro_rules! is_anon_attr { + (anon) => { + true + }; + ($attr:ident) => { + false + }; +} + +macro_rules! is_eval_always_attr { + (eval_always) => { + true + }; + ($attr:ident) => { + false + }; +} + +macro_rules! contains_anon_attr { + ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false}); +} + +macro_rules! contains_eval_always_attr { + ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); +} + +macro_rules! define_dep_nodes { + (<$tcx:tt> + $( + [$($attrs:tt)*] + $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* + ,)* + ) => ( + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, + RustcEncodable, RustcDecodable)] + #[allow(non_camel_case_types)] + pub enum DepKind { + $($variant),* + } + + impl DepKind { + #[allow(unreachable_code)] + pub fn can_reconstruct_query_key<$tcx>(&self) -> bool { + match *self { + $( + DepKind :: $variant => { + if contains_anon_attr!($($attrs)*) { + return false; + } + + // tuple args + $({ + return <$tuple_arg_ty as DepNodeParams> + ::CAN_RECONSTRUCT_QUERY_KEY; + })* + + true + } + )* + } + } + + pub fn is_anon(&self) -> bool { + match *self { + $( + DepKind :: $variant => { contains_anon_attr!($($attrs)*) } + )* + } + } + + pub fn is_eval_always(&self) -> bool { + match *self { + $( + DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) } + )* + } + } + + #[allow(unreachable_code)] + pub fn has_params(&self) -> bool { + match *self { + $( + DepKind :: $variant => { + // tuple args + $({ + erase!($tuple_arg_ty); + return true; + })* + + false + } + )* + } + } + } + + pub struct DepConstructor; + + #[allow(non_camel_case_types)] + impl DepConstructor { + $( + #[inline(always)] + #[allow(unreachable_code, non_snake_case)] + pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode { + // tuple args + $({ + erase!($tuple_arg_ty); + let hash = DepNodeParams::to_fingerprint(&arg, _tcx); + let dep_node = DepNode { + kind: DepKind::$variant, + hash + }; + + #[cfg(debug_assertions)] + { + if !dep_node.kind.can_reconstruct_query_key() && + (_tcx.sess.opts.debugging_opts.incremental_info || + _tcx.sess.opts.debugging_opts.query_dep_graph) + { + _tcx.dep_graph.register_dep_node_debug_str(dep_node, || { + arg.to_debug_str(_tcx) + }); + } + } + + return dep_node; + })* + + DepNode { + kind: DepKind::$variant, + hash: Fingerprint::ZERO, + } + } + )* + } + + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, + RustcEncodable, RustcDecodable)] + pub struct DepNode { + pub kind: DepKind, + pub hash: Fingerprint, + } + + impl DepNode { + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + pub fn from_def_path_hash(def_path_hash: DefPathHash, + kind: DepKind) + -> DepNode { + debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); + DepNode { + kind, + hash: def_path_hash.0, + } + } + + /// Creates a new, parameterless DepNode. This method will assert + /// that the DepNode corresponding to the given DepKind actually + /// does not require any parameters. + pub fn new_no_params(kind: DepKind) -> DepNode { + debug_assert!(!kind.has_params()); + DepNode { + kind, + hash: Fingerprint::ZERO, + } + } + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { + if self.kind.can_reconstruct_query_key() { + let def_path_hash = DefPathHash(self.hash); + tcx.def_path_hash_to_def_id.as_ref()? + .get(&def_path_hash).cloned() + } else { + None + } + } + + /// Used in testing + pub fn from_label_string(label: &str, + def_path_hash: DefPathHash) + -> Result { + let kind = match label { + $( + stringify!($variant) => DepKind::$variant, + )* + _ => return Err(()), + }; + + if !kind.can_reconstruct_query_key() { + return Err(()); + } + + if kind.has_params() { + Ok(DepNode::from_def_path_hash(def_path_hash, kind)) + } else { + Ok(DepNode::new_no_params(kind)) + } + } + + /// Used in testing + pub fn has_label_string(label: &str) -> bool { + match label { + $( + stringify!($variant) => true, + )* + _ => false, + } + } + } + + /// Contains variant => str representations for constructing + /// DepNode groups for tests. + #[allow(dead_code, non_upper_case_globals)] + pub mod label_strs { + $( + pub const $variant: &str = stringify!($variant); + )* + } + ); +} + +impl fmt::Debug for DepNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind)?; + + if !self.kind.has_params() && !self.kind.is_anon() { + return Ok(()); + } + + write!(f, "(")?; + + crate::ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = self.extract_def_id(tcx) { + write!(f, "{}", tcx.def_path_debug_str(def_id))?; + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { + write!(f, "{}", s)?; + } else { + write!(f, "{}", self.hash)?; + } + } else { + write!(f, "{}", self.hash)?; + } + Ok(()) + })?; + + write!(f, ")") + } +} + +rustc_dep_node_append!([define_dep_nodes!][ <'tcx> + // We use this for most things when incr. comp. is turned off. + [] Null, + + // Represents metadata from an extern crate. + [eval_always] CrateMetadata(CrateNum), + + [anon] TraitSelect, + + [] CompileCodegenUnit(Symbol), +]); + +pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized { + const CAN_RECONSTRUCT_QUERY_KEY: bool; + + /// This method turns the parameters of a DepNodeConstructor into an opaque + /// Fingerprint to be used in DepNode. + /// Not all DepNodeParams support being turned into a Fingerprint (they + /// don't need to if the corresponding DepNode is anonymous). + fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { + panic!("Not implemented. Accidentally called on anonymous node?") + } + + fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + format!("{:?}", self) + } + + /// This method tries to recover the query key from the given `DepNode`, + /// something which is needed when forcing `DepNode`s during red-green + /// evaluation. The query system will only call this method if + /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`. + /// It is always valid to return `None` here, in which case incremental + /// compilation will treat the query as having changed instead of forcing it. + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; +} + +impl<'tcx, T> DepNodeParams<'tcx> for T +where + T: HashStable> + fmt::Debug, +{ + default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + + default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { + let mut hcx = tcx.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + + self.hash_stable(&mut hcx, &mut hasher); + + hasher.finish() + } + + default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + format!("{:?}", *self) + } + + default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option { + None + } +} + +impl<'tcx> DepNodeParams<'tcx> for DefId { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + tcx.def_path_hash(*self).0 + } + + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + tcx.def_path_str(*self) + } + + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { + dep_node.extract_def_id(tcx) + } +} + +impl<'tcx> DepNodeParams<'tcx> for DefIndex { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + tcx.hir().definitions().def_path_hash(*self).0 + } + + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + tcx.def_path_str(DefId::local(*self)) + } + + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { + dep_node.extract_def_id(tcx).map(|id| id.index) + } +} + +impl<'tcx> DepNodeParams<'tcx> for CrateNum { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; + tcx.def_path_hash(def_id).0 + } + + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + tcx.crate_name(*self).to_string() + } + + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { + dep_node.extract_def_id(tcx).map(|id| id.krate) + } +} + +impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { + const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + + // We actually would not need to specialize the implementation of this + // method but it's faster to combine the hashes than to instantiate a full + // hashing context and stable-hashing state. + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + let (def_id_0, def_id_1) = *self; + + let def_path_hash_0 = tcx.def_path_hash(def_id_0); + let def_path_hash_1 = tcx.def_path_hash(def_id_1); + + def_path_hash_0.0.combine(def_path_hash_1.0) + } + + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + let (def_id_0, def_id_1) = *self; + + format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1)) + } +} + +impl<'tcx> DepNodeParams<'tcx> for HirId { + const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + + // We actually would not need to specialize the implementation of this + // method but it's faster to combine the hashes than to instantiate a full + // hashing context and stable-hashing state. + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + let HirId { owner, local_id } = *self; + + let def_path_hash = tcx.def_path_hash(DefId::local(owner)); + let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into()); + + def_path_hash.0.combine(local_id) + } +} + +/// A "work product" corresponds to a `.o` (or other) file that we +/// save in between runs. These IDs do not have a `DefId` but rather +/// some independent path or string that persists between runs without +/// the need to be mapped or unmapped. (This ensures we can serialize +/// them even in the absence of a tcx.) +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + RustcEncodable, + RustcDecodable, + HashStable +)] +pub struct WorkProductId { + hash: Fingerprint, +} + +impl WorkProductId { + pub fn from_cgu_name(cgu_name: &str) -> WorkProductId { + let mut hasher = StableHasher::new(); + cgu_name.len().hash(&mut hasher); + cgu_name.hash(&mut hasher); + WorkProductId { hash: hasher.finish() } + } + + pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId { + WorkProductId { hash: fingerprint } + } +} diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs new file mode 100644 index 00000000000..36edf0f0fc2 --- /dev/null +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -0,0 +1,1196 @@ +use crate::ty::{self, TyCtxt}; +use parking_lot::{Condvar, Mutex}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::profiling::QueryInvocationId; +use rustc_data_structures::sharded::{self, Sharded}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_errors::Diagnostic; +use rustc_hir::def_id::DefId; +use rustc_index::vec::{Idx, IndexVec}; +use smallvec::SmallVec; +use std::collections::hash_map::Entry; +use std::env; +use std::hash::Hash; +use std::mem; +use std::sync::atomic::Ordering::Relaxed; + +use crate::ich::{Fingerprint, StableHashingContext, StableHashingContextProvider}; + +use super::debug::EdgeFilter; +use super::dep_node::{DepKind, DepNode, WorkProductId}; +use super::prev::PreviousDepGraph; +use super::query::DepGraphQuery; +use super::safe::DepGraphSafe; +use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; + +#[derive(Clone)] +pub struct DepGraph { + data: Option>, + + /// This field is used for assigning DepNodeIndices when running in + /// non-incremental mode. Even in non-incremental mode we make sure that + /// each task has a `DepNodeIndex` that uniquely identifies it. This unique + /// ID is used for self-profiling. + virtual_dep_node_index: Lrc, +} + +rustc_index::newtype_index! { + pub struct DepNodeIndex { .. } +} + +impl DepNodeIndex { + pub const INVALID: DepNodeIndex = DepNodeIndex::MAX; +} + +impl std::convert::From for QueryInvocationId { + #[inline] + fn from(dep_node_index: DepNodeIndex) -> Self { + QueryInvocationId(dep_node_index.as_u32()) + } +} + +#[derive(PartialEq)] +pub enum DepNodeColor { + Red, + Green(DepNodeIndex), +} + +impl DepNodeColor { + pub fn is_green(self) -> bool { + match self { + DepNodeColor::Red => false, + DepNodeColor::Green(_) => true, + } + } +} + +struct DepGraphData { + /// The new encoding of the dependency graph, optimized for red/green + /// tracking. The `current` field is the dependency graph of only the + /// current compilation session: We don't merge the previous dep-graph into + /// current one anymore. + current: CurrentDepGraph, + + /// The dep-graph from the previous compilation session. It contains all + /// nodes and edges as well as all fingerprints of nodes that have them. + previous: PreviousDepGraph, + + colors: DepNodeColorMap, + + /// A set of loaded diagnostics that is in the progress of being emitted. + emitting_diagnostics: Mutex>, + + /// Used to wait for diagnostics to be emitted. + emitting_diagnostics_cond_var: Condvar, + + /// When we load, there may be `.o` files, cached MIR, or other such + /// things available to us. If we find that they are not dirty, we + /// load the path to the file storing those work-products here into + /// this map. We can later look for and extract that data. + previous_work_products: FxHashMap, + + dep_node_debug: Lock>, +} + +pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option +where + R: for<'a> HashStable>, +{ + let mut stable_hasher = StableHasher::new(); + result.hash_stable(hcx, &mut stable_hasher); + + Some(stable_hasher.finish()) +} + +impl DepGraph { + pub fn new( + prev_graph: PreviousDepGraph, + prev_work_products: FxHashMap, + ) -> DepGraph { + let prev_graph_node_count = prev_graph.node_count(); + + DepGraph { + data: Some(Lrc::new(DepGraphData { + previous_work_products: prev_work_products, + dep_node_debug: Default::default(), + current: CurrentDepGraph::new(prev_graph_node_count), + emitting_diagnostics: Default::default(), + emitting_diagnostics_cond_var: Condvar::new(), + previous: prev_graph, + colors: DepNodeColorMap::new(prev_graph_node_count), + })), + virtual_dep_node_index: Lrc::new(AtomicU32::new(0)), + } + } + + pub fn new_disabled() -> DepGraph { + DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } + } + + /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise. + #[inline] + pub fn is_fully_enabled(&self) -> bool { + self.data.is_some() + } + + pub fn query(&self) -> DepGraphQuery { + let data = self.data.as_ref().unwrap().current.data.lock(); + let nodes: Vec<_> = data.iter().map(|n| n.node).collect(); + let mut edges = Vec::new(); + for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) { + for &edge_target in edge_targets.iter() { + let to = data[edge_target].node; + edges.push((from, to)); + } + } + + DepGraphQuery::new(&nodes[..], &edges[..]) + } + + pub fn assert_ignored(&self) { + if let Some(..) = self.data { + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); + }) + } + } + + pub fn with_ignore(&self, op: OP) -> R + where + OP: FnOnce() -> R, + { + ty::tls::with_context(|icx| { + let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; + + ty::tls::enter_context(&icx, |_| op()) + }) + } + + /// Starts a new dep-graph task. Dep-graph tasks are specified + /// using a free function (`task`) and **not** a closure -- this + /// is intentional because we want to exercise tight control over + /// what state they have access to. In particular, we want to + /// prevent implicit 'leaks' of tracked state into the task (which + /// could then be read without generating correct edges in the + /// dep-graph -- see the [rustc dev guide] for more details on + /// the dep-graph). To this end, the task function gets exactly two + /// pieces of state: the context `cx` and an argument `arg`. Both + /// of these bits of state must be of some type that implements + /// `DepGraphSafe` and hence does not leak. + /// + /// The choice of two arguments is not fundamental. One argument + /// would work just as well, since multiple values can be + /// collected using tuples. However, using two arguments works out + /// to be quite convenient, since it is common to need a context + /// (`cx`) and some argument (e.g., a `DefId` identifying what + /// item to process). + /// + /// For cases where you need some other number of arguments: + /// + /// - If you only need one argument, just use `()` for the `arg` + /// parameter. + /// - If you need 3+ arguments, use a tuple for the + /// `arg` parameter. + /// + /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html + pub fn with_task<'a, C, A, R>( + &self, + key: DepNode, + cx: C, + arg: A, + task: fn(C, A) -> R, + hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + ) -> (R, DepNodeIndex) + where + C: DepGraphSafe + StableHashingContextProvider<'a>, + { + self.with_task_impl( + key, + cx, + arg, + false, + task, + |_key| { + Some(TaskDeps { + #[cfg(debug_assertions)] + node: Some(_key), + reads: SmallVec::new(), + read_set: Default::default(), + }) + }, + |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), + hash_result, + ) + } + + fn with_task_impl<'a, C, A, R>( + &self, + key: DepNode, + cx: C, + arg: A, + no_tcx: bool, + task: fn(C, A) -> R, + create_task: fn(DepNode) -> Option, + finish_task_and_alloc_depnode: fn( + &CurrentDepGraph, + DepNode, + Fingerprint, + Option, + ) -> DepNodeIndex, + hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + ) -> (R, DepNodeIndex) + where + C: DepGraphSafe + StableHashingContextProvider<'a>, + { + if let Some(ref data) = self.data { + let task_deps = create_task(key).map(Lock::new); + + // In incremental mode, hash the result of the task. We don't + // do anything with the hash yet, but we are computing it + // anyway so that + // - we make sure that the infrastructure works and + // - we can get an idea of the runtime cost. + let mut hcx = cx.get_stable_hashing_context(); + + let result = if no_tcx { + task(cx, arg) + } else { + ty::tls::with_context(|icx| { + let icx = + ty::tls::ImplicitCtxt { task_deps: task_deps.as_ref(), ..icx.clone() }; + + ty::tls::enter_context(&icx, |_| task(cx, arg)) + }) + }; + + let current_fingerprint = hash_result(&mut hcx, &result); + + let dep_node_index = finish_task_and_alloc_depnode( + &data.current, + key, + current_fingerprint.unwrap_or(Fingerprint::ZERO), + task_deps.map(|lock| lock.into_inner()), + ); + + let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks; + + // Determine the color of the new DepNode. + if let Some(prev_index) = data.previous.node_to_index_opt(&key) { + let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); + + let color = if let Some(current_fingerprint) = current_fingerprint { + if current_fingerprint == prev_fingerprint { + if print_status { + eprintln!("[task::green] {:?}", key); + } + DepNodeColor::Green(dep_node_index) + } else { + if print_status { + eprintln!("[task::red] {:?}", key); + } + DepNodeColor::Red + } + } else { + if print_status { + eprintln!("[task::unknown] {:?}", key); + } + // Mark the node as Red if we can't hash the result + DepNodeColor::Red + }; + + debug_assert!( + data.colors.get(prev_index).is_none(), + "DepGraph::with_task() - Duplicate DepNodeColor \ + insertion for {:?}", + key + ); + + data.colors.insert(prev_index, color); + } else { + if print_status { + eprintln!("[task::new] {:?}", key); + } + } + + (result, dep_node_index) + } else { + (task(cx, arg), self.next_virtual_depnode_index()) + } + } + + /// Executes something within an "anonymous" task, that is, a task the + /// `DepNode` of which is determined by the list of inputs it read from. + pub fn with_anon_task(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex) + where + OP: FnOnce() -> R, + { + if let Some(ref data) = self.data { + let (result, task_deps) = ty::tls::with_context(|icx| { + let task_deps = Lock::new(TaskDeps::default()); + + let r = { + let icx = ty::tls::ImplicitCtxt { task_deps: Some(&task_deps), ..icx.clone() }; + + ty::tls::enter_context(&icx, |_| op()) + }; + + (r, task_deps.into_inner()) + }); + let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps); + (result, dep_node_index) + } else { + (op(), self.next_virtual_depnode_index()) + } + } + + /// Executes something within an "eval-always" task which is a task + /// that runs whenever anything changes. + pub fn with_eval_always_task<'a, C, A, R>( + &self, + key: DepNode, + cx: C, + arg: A, + task: fn(C, A) -> R, + hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + ) -> (R, DepNodeIndex) + where + C: DepGraphSafe + StableHashingContextProvider<'a>, + { + self.with_task_impl( + key, + cx, + arg, + false, + task, + |_| None, + |data, key, fingerprint, _| data.alloc_node(key, smallvec![], fingerprint), + hash_result, + ) + } + + #[inline] + pub fn read(&self, v: DepNode) { + if let Some(ref data) = self.data { + let map = data.current.node_to_node_index.get_shard_by_value(&v).lock(); + if let Some(dep_node_index) = map.get(&v).copied() { + std::mem::drop(map); + data.read_index(dep_node_index); + } else { + bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind) + } + } + } + + #[inline] + pub fn read_index(&self, dep_node_index: DepNodeIndex) { + if let Some(ref data) = self.data { + data.read_index(dep_node_index); + } + } + + #[inline] + pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { + self.data + .as_ref() + .unwrap() + .current + .node_to_node_index + .get_shard_by_value(dep_node) + .lock() + .get(dep_node) + .cloned() + .unwrap() + } + + #[inline] + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + if let Some(ref data) = self.data { + data.current + .node_to_node_index + .get_shard_by_value(&dep_node) + .lock() + .contains_key(dep_node) + } else { + false + } + } + + #[inline] + pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { + let data = self.data.as_ref().expect("dep graph enabled").current.data.lock(); + data[dep_node_index].fingerprint + } + + pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { + self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) + } + + #[inline] + pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { + self.data.as_ref().unwrap().previous.node_to_index(dep_node) + } + + /// Checks whether a previous work product exists for `v` and, if + /// so, return the path that leads to it. Used to skip doing work. + pub fn previous_work_product(&self, v: &WorkProductId) -> Option { + self.data.as_ref().and_then(|data| data.previous_work_products.get(v).cloned()) + } + + /// Access the map of work-products created during the cached run. Only + /// used during saving of the dep-graph. + pub fn previous_work_products(&self) -> &FxHashMap { + &self.data.as_ref().unwrap().previous_work_products + } + + #[inline(always)] + pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) + where + F: FnOnce() -> String, + { + let dep_node_debug = &self.data.as_ref().unwrap().dep_node_debug; + + if dep_node_debug.borrow().contains_key(&dep_node) { + return; + } + let debug_str = debug_str_gen(); + dep_node_debug.borrow_mut().insert(dep_node, debug_str); + } + + pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { + self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() + } + + pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> { + if cfg!(debug_assertions) { + let current_dep_graph = &self.data.as_ref().unwrap().current; + + Some(( + current_dep_graph.total_read_count.load(Relaxed), + current_dep_graph.total_duplicate_read_count.load(Relaxed), + )) + } else { + None + } + } + + pub fn serialize(&self) -> SerializedDepGraph { + let data = self.data.as_ref().unwrap().current.data.lock(); + + let fingerprints: IndexVec = + data.iter().map(|d| d.fingerprint).collect(); + let nodes: IndexVec = data.iter().map(|d| d.node).collect(); + + let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum(); + + let mut edge_list_indices = IndexVec::with_capacity(nodes.len()); + let mut edge_list_data = Vec::with_capacity(total_edge_count); + + for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) { + let start = edge_list_data.len() as u32; + // This should really just be a memcpy :/ + edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index()))); + let end = edge_list_data.len() as u32; + + debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len()); + edge_list_indices.push((start, end)); + } + + debug_assert!(edge_list_data.len() <= u32::MAX as usize); + debug_assert_eq!(edge_list_data.len(), total_edge_count); + + SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data } + } + + pub fn node_color(&self, dep_node: &DepNode) -> Option { + if let Some(ref data) = self.data { + if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { + return data.colors.get(prev_index); + } else { + // This is a node that did not exist in the previous compilation + // session, so we consider it to be red. + return Some(DepNodeColor::Red); + } + } + + None + } + + /// Try to read a node index for the node dep_node. + /// A node will have an index, when it's already been marked green, or when we can mark it + /// green. This function will mark the current task as a reader of the specified node, when + /// a node index can be found for that node. + pub fn try_mark_green_and_read( + &self, + tcx: TyCtxt<'_>, + dep_node: &DepNode, + ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { + self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| { + debug_assert!(self.is_green(&dep_node)); + self.read_index(dep_node_index); + (prev_index, dep_node_index) + }) + } + + pub fn try_mark_green( + &self, + tcx: TyCtxt<'_>, + dep_node: &DepNode, + ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { + debug_assert!(!dep_node.kind.is_eval_always()); + + // Return None if the dep graph is disabled + let data = self.data.as_ref()?; + + // Return None if the dep node didn't exist in the previous session + let prev_index = data.previous.node_to_index_opt(dep_node)?; + + match data.colors.get(prev_index) { + Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)), + Some(DepNodeColor::Red) => None, + None => { + // This DepNode and the corresponding query invocation existed + // in the previous compilation session too, so we can try to + // mark it as green by recursively marking all of its + // dependencies green. + self.try_mark_previous_green(tcx, data, prev_index, &dep_node) + .map(|dep_node_index| (prev_index, dep_node_index)) + } + } + } + + /// Try to mark a dep-node which existed in the previous compilation session as green. + fn try_mark_previous_green<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + data: &DepGraphData, + prev_dep_node_index: SerializedDepNodeIndex, + dep_node: &DepNode, + ) -> Option { + debug!("try_mark_previous_green({:?}) - BEGIN", dep_node); + + #[cfg(not(parallel_compiler))] + { + debug_assert!( + !data + .current + .node_to_node_index + .get_shard_by_value(dep_node) + .lock() + .contains_key(dep_node) + ); + debug_assert!(data.colors.get(prev_dep_node_index).is_none()); + } + + // We never try to mark eval_always nodes as green + debug_assert!(!dep_node.kind.is_eval_always()); + + debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node); + + let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); + + let mut current_deps = SmallVec::new(); + + for &dep_dep_node_index in prev_deps { + let dep_dep_node_color = data.colors.get(dep_dep_node_index); + + match dep_dep_node_color { + Some(DepNodeColor::Green(node_index)) => { + // This dependency has been marked as green before, we are + // still fine and can continue with checking the other + // dependencies. + debug!( + "try_mark_previous_green({:?}) --- found dependency {:?} to \ + be immediately green", + dep_node, + data.previous.index_to_node(dep_dep_node_index) + ); + current_deps.push(node_index); + } + Some(DepNodeColor::Red) => { + // We found a dependency the value of which has changed + // compared to the previous compilation session. We cannot + // mark the DepNode as green and also don't need to bother + // with checking any of the other dependencies. + debug!( + "try_mark_previous_green({:?}) - END - dependency {:?} was \ + immediately red", + dep_node, + data.previous.index_to_node(dep_dep_node_index) + ); + return None; + } + None => { + let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); + + // We don't know the state of this dependency. If it isn't + // an eval_always node, let's try to mark it green recursively. + if !dep_dep_node.kind.is_eval_always() { + debug!( + "try_mark_previous_green({:?}) --- state of dependency {:?} \ + is unknown, trying to mark it green", + dep_node, dep_dep_node + ); + + let node_index = self.try_mark_previous_green( + tcx, + data, + dep_dep_node_index, + dep_dep_node, + ); + if let Some(node_index) = node_index { + debug!( + "try_mark_previous_green({:?}) --- managed to MARK \ + dependency {:?} as green", + dep_node, dep_dep_node + ); + current_deps.push(node_index); + continue; + } + } else { + // FIXME: This match is just a workaround for incremental bugs and should + // be removed. https://github.com/rust-lang/rust/issues/62649 is one such + // bug that must be fixed before removing this. + match dep_dep_node.kind { + DepKind::hir_owner + | DepKind::hir_owner_nodes + | DepKind::CrateMetadata => { + if let Some(def_id) = dep_dep_node.extract_def_id(tcx) { + if def_id_corresponds_to_hir_dep_node(tcx, def_id) { + if dep_dep_node.kind == DepKind::CrateMetadata { + // The `DefPath` has corresponding node, + // and that node should have been marked + // either red or green in `data.colors`. + bug!( + "DepNode {:?} should have been \ + pre-marked as red or green but wasn't.", + dep_dep_node + ); + } + } else { + // This `DefPath` does not have a + // corresponding `DepNode` (e.g. a + // struct field), and the ` DefPath` + // collided with the `DefPath` of a + // proper item that existed in the + // previous compilation session. + // + // Since the given `DefPath` does not + // denote the item that previously + // existed, we just fail to mark green. + return None; + } + } else { + // If the node does not exist anymore, we + // just fail to mark green. + return None; + } + } + _ => { + // For other kinds of nodes it's OK to be + // forced. + } + } + } + + // We failed to mark it green, so we try to force the query. + debug!( + "try_mark_previous_green({:?}) --- trying to force \ + dependency {:?}", + dep_node, dep_dep_node + ); + if crate::ty::query::force_from_dep_node(tcx, dep_dep_node) { + let dep_dep_node_color = data.colors.get(dep_dep_node_index); + + match dep_dep_node_color { + Some(DepNodeColor::Green(node_index)) => { + debug!( + "try_mark_previous_green({:?}) --- managed to \ + FORCE dependency {:?} to green", + dep_node, dep_dep_node + ); + current_deps.push(node_index); + } + Some(DepNodeColor::Red) => { + debug!( + "try_mark_previous_green({:?}) - END - \ + dependency {:?} was red after forcing", + dep_node, dep_dep_node + ); + return None; + } + None => { + if !tcx.sess.has_errors_or_delayed_span_bugs() { + bug!( + "try_mark_previous_green() - Forcing the DepNode \ + should have set its color" + ) + } else { + // If the query we just forced has resulted in + // some kind of compilation error, we cannot rely on + // the dep-node color having been properly updated. + // This means that the query system has reached an + // invalid state. We let the compiler continue (by + // returning `None`) so it can emit error messages + // and wind down, but rely on the fact that this + // invalid state will not be persisted to the + // incremental compilation cache because of + // compilation errors being present. + debug!( + "try_mark_previous_green({:?}) - END - \ + dependency {:?} resulted in compilation error", + dep_node, dep_dep_node + ); + return None; + } + } + } + } else { + // The DepNode could not be forced. + debug!( + "try_mark_previous_green({:?}) - END - dependency {:?} \ + could not be forced", + dep_node, dep_dep_node + ); + return None; + } + } + } + } + + // If we got here without hitting a `return` that means that all + // dependencies of this DepNode could be marked as green. Therefore we + // can also mark this DepNode as green. + + // There may be multiple threads trying to mark the same dep node green concurrently + + let dep_node_index = { + // Copy the fingerprint from the previous graph, + // so we don't have to recompute it + let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index); + + // We allocating an entry for the node in the current dependency graph and + // adding all the appropriate edges imported from the previous graph + data.current.intern_node(*dep_node, current_deps, fingerprint) + }; + + // ... emitting any stored diagnostic ... + + // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere + // Maybe store a list on disk and encode this fact in the DepNodeState + let diagnostics = tcx.queries.on_disk_cache.load_diagnostics(tcx, prev_dep_node_index); + + #[cfg(not(parallel_compiler))] + debug_assert!( + data.colors.get(prev_dep_node_index).is_none(), + "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \ + insertion for {:?}", + dep_node + ); + + if unlikely!(!diagnostics.is_empty()) { + self.emit_diagnostics(tcx, data, dep_node_index, prev_dep_node_index, diagnostics); + } + + // ... and finally storing a "Green" entry in the color map. + // Multiple threads can all write the same color here + data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); + + debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node); + Some(dep_node_index) + } + + /// Atomically emits some loaded diagnostics. + /// This may be called concurrently on multiple threads for the same dep node. + #[cold] + #[inline(never)] + fn emit_diagnostics<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + data: &DepGraphData, + dep_node_index: DepNodeIndex, + prev_dep_node_index: SerializedDepNodeIndex, + diagnostics: Vec, + ) { + let mut emitting = data.emitting_diagnostics.lock(); + + if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) { + // The node is already green so diagnostics must have been emitted already + return; + } + + if emitting.insert(dep_node_index) { + // We were the first to insert the node in the set so this thread + // must emit the diagnostics and signal other potentially waiting + // threads after. + mem::drop(emitting); + + // Promote the previous diagnostics to the current session. + tcx.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics.clone().into()); + + let handle = tcx.sess.diagnostic(); + + for diagnostic in diagnostics { + handle.emit_diagnostic(&diagnostic); + } + + // Mark the node as green now that diagnostics are emitted + data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); + + // Remove the node from the set + data.emitting_diagnostics.lock().remove(&dep_node_index); + + // Wake up waiters + data.emitting_diagnostics_cond_var.notify_all(); + } else { + // We must wait for the other thread to finish emitting the diagnostic + + loop { + data.emitting_diagnostics_cond_var.wait(&mut emitting); + if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) + { + break; + } + } + } + } + + // Returns true if the given node has been marked as green during the + // current compilation session. Used in various assertions + pub fn is_green(&self, dep_node: &DepNode) -> bool { + self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) + } + + // This method loads all on-disk cacheable query results into memory, so + // they can be written out to the new cache file again. Most query results + // will already be in memory but in the case where we marked something as + // green but then did not need the value, that value will never have been + // loaded from disk. + // + // This method will only load queries that will end up in the disk cache. + // Other queries will not be executed. + pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) { + let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); + + let data = self.data.as_ref().unwrap(); + for prev_index in data.colors.values.indices() { + match data.colors.get(prev_index) { + Some(DepNodeColor::Green(_)) => { + let dep_node = data.previous.index_to_node(prev_index); + dep_node.try_load_from_on_disk_cache(tcx); + } + None | Some(DepNodeColor::Red) => { + // We can skip red nodes because a node can only be marked + // as red if the query result was recomputed and thus is + // already in memory. + } + } + } + } + + fn next_virtual_depnode_index(&self) -> DepNodeIndex { + let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); + DepNodeIndex::from_u32(index) + } +} + +fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + def_id.index == hir_id.owner.local_def_index +} + +/// A "work product" is an intermediate result that we save into the +/// incremental directory for later re-use. The primary example are +/// the object files that we save for each partition at code +/// generation time. +/// +/// Each work product is associated with a dep-node, representing the +/// process that produced the work-product. If that dep-node is found +/// to be dirty when we load up, then we will delete the work-product +/// at load time. If the work-product is found to be clean, then we +/// will keep a record in the `previous_work_products` list. +/// +/// In addition, work products have an associated hash. This hash is +/// an extra hash that can be used to decide if the work-product from +/// a previous compilation can be re-used (in addition to the dirty +/// edges check). +/// +/// As the primary example, consider the object files we generate for +/// each partition. In the first run, we create partitions based on +/// the symbols that need to be compiled. For each partition P, we +/// hash the symbols in P and create a `WorkProduct` record associated +/// with `DepNode::CodegenUnit(P)`; the hash is the set of symbols +/// in P. +/// +/// The next time we compile, if the `DepNode::CodegenUnit(P)` is +/// judged to be clean (which means none of the things we read to +/// generate the partition were found to be dirty), it will be loaded +/// into previous work products. We will then regenerate the set of +/// symbols in the partition P and hash them (note that new symbols +/// may be added -- for example, new monomorphizations -- even if +/// nothing in P changed!). We will compare that hash against the +/// previous hash. If it matches up, we can reuse the object file. +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct WorkProduct { + pub cgu_name: String, + /// Saved files associated with this CGU. + pub saved_files: Vec<(WorkProductFileKind, String)>, +} + +#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable, PartialEq)] +pub enum WorkProductFileKind { + Object, + Bytecode, + BytecodeCompressed, +} + +#[derive(Clone)] +struct DepNodeData { + node: DepNode, + edges: EdgesVec, + fingerprint: Fingerprint, +} + +/// `CurrentDepGraph` stores the dependency graph for the current session. +/// It will be populated as we run queries or tasks. +/// +/// The nodes in it are identified by an index (`DepNodeIndex`). +/// The data for each node is stored in its `DepNodeData`, found in the `data` field. +/// +/// We never remove nodes from the graph: they are only added. +/// +/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are +/// locked separately. Operations that take a `DepNodeIndex` typically just access +/// the data field. +/// +/// The only operation that must manipulate both locks is adding new nodes, in which case +/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted, +/// acquire the lock on `data.` +pub(super) struct CurrentDepGraph { + data: Lock>, + node_to_node_index: Sharded>, + + /// Used to trap when a specific edge is added to the graph. + /// This is used for debug purposes and is only active with `debug_assertions`. + #[allow(dead_code)] + forbidden_edge: Option, + + /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of + /// their edges. This has the beneficial side-effect that multiple anonymous + /// nodes can be coalesced into one without changing the semantics of the + /// dependency graph. However, the merging of nodes can lead to a subtle + /// problem during red-green marking: The color of an anonymous node from + /// the current session might "shadow" the color of the node with the same + /// ID from the previous session. In order to side-step this problem, we make + /// sure that anonymous `NodeId`s allocated in different sessions don't overlap. + /// This is implemented by mixing a session-key into the ID fingerprint of + /// each anon node. The session-key is just a random number generated when + /// the `DepGraph` is created. + anon_id_seed: Fingerprint, + + /// These are simple counters that are for profiling and + /// debugging and only active with `debug_assertions`. + total_read_count: AtomicU64, + total_duplicate_read_count: AtomicU64, +} + +impl CurrentDepGraph { + fn new(prev_graph_node_count: usize) -> CurrentDepGraph { + use std::time::{SystemTime, UNIX_EPOCH}; + + let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; + let mut stable_hasher = StableHasher::new(); + nanos.hash(&mut stable_hasher); + + let forbidden_edge = if cfg!(debug_assertions) { + match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { + Ok(s) => match EdgeFilter::new(&s) { + Ok(f) => Some(f), + Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), + }, + Err(_) => None, + } + } else { + None + }; + + // Pre-allocate the dep node structures. We over-allocate a little so + // that we hopefully don't have to re-allocate during this compilation + // session. The over-allocation is 2% plus a small constant to account + // for the fact that in very small crates 2% might not be enough. + let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200; + + CurrentDepGraph { + data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)), + node_to_node_index: Sharded::new(|| { + FxHashMap::with_capacity_and_hasher( + new_node_count_estimate / sharded::SHARDS, + Default::default(), + ) + }), + anon_id_seed: stable_hasher.finish(), + forbidden_edge, + total_read_count: AtomicU64::new(0), + total_duplicate_read_count: AtomicU64::new(0), + } + } + + fn complete_task( + &self, + node: DepNode, + task_deps: TaskDeps, + fingerprint: Fingerprint, + ) -> DepNodeIndex { + self.alloc_node(node, task_deps.reads, fingerprint) + } + + fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex { + debug_assert!(!kind.is_eval_always()); + + let mut hasher = StableHasher::new(); + + // The dep node indices are hashed here instead of hashing the dep nodes of the + // dependencies. These indices may refer to different nodes per session, but this isn't + // a problem here because we that ensure the final dep node hash is per session only by + // combining it with the per session random number `anon_id_seed`. This hash only need + // to map the dependencies to a single value on a per session basis. + task_deps.reads.hash(&mut hasher); + + let target_dep_node = DepNode { + kind, + + // Fingerprint::combine() is faster than sending Fingerprint + // through the StableHasher (at least as long as StableHasher + // is so slow). + hash: self.anon_id_seed.combine(hasher.finish()), + }; + + self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO) + } + + fn alloc_node( + &self, + dep_node: DepNode, + edges: EdgesVec, + fingerprint: Fingerprint, + ) -> DepNodeIndex { + debug_assert!( + !self.node_to_node_index.get_shard_by_value(&dep_node).lock().contains_key(&dep_node) + ); + self.intern_node(dep_node, edges, fingerprint) + } + + fn intern_node( + &self, + dep_node: DepNode, + edges: EdgesVec, + fingerprint: Fingerprint, + ) -> DepNodeIndex { + match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let mut data = self.data.lock(); + let dep_node_index = DepNodeIndex::new(data.len()); + data.push(DepNodeData { node: dep_node, edges, fingerprint }); + entry.insert(dep_node_index); + dep_node_index + } + } + } +} + +impl DepGraphData { + #[inline(never)] + fn read_index(&self, source: DepNodeIndex) { + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + if let Some(task_deps) = icx.task_deps { + let mut task_deps = task_deps.lock(); + let task_deps = &mut *task_deps; + if cfg!(debug_assertions) { + self.current.total_read_count.fetch_add(1, Relaxed); + } + + // As long as we only have a low number of reads we can avoid doing a hash + // insert and potentially allocating/reallocating the hashmap + let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { + task_deps.reads.iter().all(|other| *other != source) + } else { + task_deps.read_set.insert(source) + }; + if new_read { + task_deps.reads.push(source); + if task_deps.reads.len() == TASK_DEPS_READS_CAP { + // Fill `read_set` with what we have so far so we can use the hashset next + // time + task_deps.read_set.extend(task_deps.reads.iter().copied()); + } + + #[cfg(debug_assertions)] + { + if let Some(target) = task_deps.node { + let data = self.current.data.lock(); + if let Some(ref forbidden_edge) = self.current.forbidden_edge { + let source = data[source].node; + if forbidden_edge.test(&source, &target) { + bug!("forbidden edge {:?} -> {:?} created", source, target) + } + } + } + } + } else if cfg!(debug_assertions) { + self.current.total_duplicate_read_count.fetch_add(1, Relaxed); + } + } + }) + } +} + +/// The capacity of the `reads` field `SmallVec` +const TASK_DEPS_READS_CAP: usize = 8; +type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; +#[derive(Default)] +pub struct TaskDeps { + #[cfg(debug_assertions)] + node: Option, + reads: EdgesVec, + read_set: FxHashSet, +} + +// A data structure that stores Option values as a contiguous +// array, using one u32 per entry. +struct DepNodeColorMap { + values: IndexVec, +} + +const COMPRESSED_NONE: u32 = 0; +const COMPRESSED_RED: u32 = 1; +const COMPRESSED_FIRST_GREEN: u32 = 2; + +impl DepNodeColorMap { + fn new(size: usize) -> DepNodeColorMap { + DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() } + } + + fn get(&self, index: SerializedDepNodeIndex) -> Option { + match self.values[index].load(Ordering::Acquire) { + COMPRESSED_NONE => None, + COMPRESSED_RED => Some(DepNodeColor::Red), + value => { + Some(DepNodeColor::Green(DepNodeIndex::from_u32(value - COMPRESSED_FIRST_GREEN))) + } + } + } + + fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) { + self.values[index].store( + match color { + DepNodeColor::Red => COMPRESSED_RED, + DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN, + }, + Ordering::Release, + ) + } +} diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs new file mode 100644 index 00000000000..1fbd90743f4 --- /dev/null +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -0,0 +1,17 @@ +pub mod debug; +mod dep_node; +mod graph; +mod prev; +mod query; +mod safe; +mod serialized; + +pub(crate) use self::dep_node::DepNodeParams; +pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, WorkProductId}; +pub use self::graph::WorkProductFileKind; +pub use self::graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; +pub use self::prev::PreviousDepGraph; +pub use self::query::DepGraphQuery; +pub use self::safe::AssertDepGraphSafe; +pub use self::safe::DepGraphSafe; +pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; diff --git a/src/librustc_query_system/dep_graph/prev.rs b/src/librustc_query_system/dep_graph/prev.rs new file mode 100644 index 00000000000..fbc8f7bc997 --- /dev/null +++ b/src/librustc_query_system/dep_graph/prev.rs @@ -0,0 +1,55 @@ +use super::dep_node::DepNode; +use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; +use crate::ich::Fingerprint; +use rustc_data_structures::fx::FxHashMap; + +#[derive(Debug, RustcEncodable, RustcDecodable, Default)] +pub struct PreviousDepGraph { + data: SerializedDepGraph, + index: FxHashMap, +} + +impl PreviousDepGraph { + pub fn new(data: SerializedDepGraph) -> PreviousDepGraph { + let index: FxHashMap<_, _> = + data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); + PreviousDepGraph { data, index } + } + + #[inline] + pub fn edge_targets_from( + &self, + dep_node_index: SerializedDepNodeIndex, + ) -> &[SerializedDepNodeIndex] { + self.data.edge_targets_from(dep_node_index) + } + + #[inline] + pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { + self.data.nodes[dep_node_index] + } + + #[inline] + pub fn node_to_index(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { + self.index[dep_node] + } + + #[inline] + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { + self.index.get(dep_node).cloned() + } + + #[inline] + pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { + self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index]) + } + + #[inline] + pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint { + self.data.fingerprints[dep_node_index] + } + + pub fn node_count(&self) -> usize { + self.index.len() + } +} diff --git a/src/librustc_query_system/dep_graph/query.rs b/src/librustc_query_system/dep_graph/query.rs new file mode 100644 index 00000000000..c71c11ed0eb --- /dev/null +++ b/src/librustc_query_system/dep_graph/query.rs @@ -0,0 +1,74 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::graph::implementation::{ + Direction, Graph, NodeIndex, INCOMING, OUTGOING, +}; + +use super::DepNode; + +pub struct DepGraphQuery { + pub graph: Graph, + pub indices: FxHashMap, +} + +impl DepGraphQuery { + pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { + let mut graph = Graph::with_capacity(nodes.len(), edges.len()); + let mut indices = FxHashMap::default(); + for node in nodes { + indices.insert(node.clone(), graph.add_node(node.clone())); + } + + for &(ref source, ref target) in edges { + let source = indices[source]; + let target = indices[target]; + graph.add_edge(source, target, ()); + } + + DepGraphQuery { graph, indices } + } + + pub fn contains_node(&self, node: &DepNode) -> bool { + self.indices.contains_key(&node) + } + + pub fn nodes(&self) -> Vec<&DepNode> { + self.graph.all_nodes().iter().map(|n| &n.data).collect() + } + + pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { + self.graph + .all_edges() + .iter() + .map(|edge| (edge.source(), edge.target())) + .map(|(s, t)| (self.graph.node_data(s), self.graph.node_data(t))) + .collect() + } + + fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { + if let Some(&index) = self.indices.get(node) { + self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect() + } else { + vec![] + } + } + + /// All nodes reachable from `node`. In other words, things that + /// will have to be recomputed if `node` changes. + pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { + self.reachable_nodes(node, OUTGOING) + } + + /// All nodes that can reach `node`. + pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { + self.reachable_nodes(node, INCOMING) + } + + /// Just the outgoing edges from `node`. + pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { + if let Some(&index) = self.indices.get(&node) { + self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect() + } else { + vec![] + } + } +} diff --git a/src/librustc_query_system/dep_graph/safe.rs b/src/librustc_query_system/dep_graph/safe.rs new file mode 100644 index 00000000000..74e32867cde --- /dev/null +++ b/src/librustc_query_system/dep_graph/safe.rs @@ -0,0 +1,57 @@ +//! The `DepGraphSafe` trait + +use crate::ty::TyCtxt; + +use rustc_ast::ast::NodeId; +use rustc_hir::def_id::DefId; +use rustc_hir::BodyId; + +/// The `DepGraphSafe` trait is used to specify what kinds of values +/// are safe to "leak" into a task. The idea is that this should be +/// only be implemented for things like the tcx as well as various id +/// types, which will create reads in the dep-graph whenever the trait +/// loads anything that might depend on the input program. +pub trait DepGraphSafe {} + +/// A `BodyId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for BodyId {} + +/// A `NodeId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for NodeId {} + +/// A `DefId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for DefId {} + +/// The type context itself can be used to access all kinds of tracked +/// state, but those accesses should always generate read events. +impl<'tcx> DepGraphSafe for TyCtxt<'tcx> {} + +/// Tuples make it easy to build up state. +impl DepGraphSafe for (A, B) +where + A: DepGraphSafe, + B: DepGraphSafe, +{ +} + +/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe. +impl<'a, A> DepGraphSafe for &'a A where A: DepGraphSafe {} + +/// Mut ref to dep-graph-safe stuff should still be dep-graph-safe. +impl<'a, A> DepGraphSafe for &'a mut A where A: DepGraphSafe {} + +/// No data here! :) +impl DepGraphSafe for () {} + +/// A convenient override that lets you pass arbitrary state into a +/// task. Every use should be accompanied by a comment explaining why +/// it makes sense (or how it could be refactored away in the future). +pub struct AssertDepGraphSafe(pub T); + +impl DepGraphSafe for AssertDepGraphSafe {} diff --git a/src/librustc_query_system/dep_graph/serialized.rs b/src/librustc_query_system/dep_graph/serialized.rs new file mode 100644 index 00000000000..45ef52dbf39 --- /dev/null +++ b/src/librustc_query_system/dep_graph/serialized.rs @@ -0,0 +1,34 @@ +//! The data that we will serialize and deserialize. + +use crate::dep_graph::DepNode; +use crate::ich::Fingerprint; +use rustc_index::vec::IndexVec; + +rustc_index::newtype_index! { + pub struct SerializedDepNodeIndex { .. } +} + +/// Data for use when recompiling the **current crate**. +#[derive(Debug, RustcEncodable, RustcDecodable, Default)] +pub struct SerializedDepGraph { + /// The set of all DepNodes in the graph + pub nodes: IndexVec, + /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to + /// the DepNode at the same index in the nodes vector. + pub fingerprints: IndexVec, + /// For each DepNode, stores the list of edges originating from that + /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, + /// which holds the actual DepNodeIndices of the target nodes. + pub edge_list_indices: IndexVec, + /// A flattened list of all edge targets in the graph. Edge sources are + /// implicit in edge_list_indices. + pub edge_list_data: Vec, +} + +impl SerializedDepGraph { + #[inline] + pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] { + let targets = self.edge_list_indices[source]; + &self.edge_list_data[targets.0 as usize..targets.1 as usize] + } +} -- cgit 1.4.1-3-g733a5 From 6624dc4045505e942ce219dcc374061cef50e3f1 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 18 Mar 2020 10:25:22 +0100 Subject: Make librustc_query_system compile. --- Cargo.lock | 17 + src/librustc/Cargo.toml | 1 + src/librustc_query_system/Cargo.toml | 22 ++ src/librustc_query_system/dep_graph/debug.rs | 6 +- src/librustc_query_system/dep_graph/dep_node.rs | 427 ++-------------------- src/librustc_query_system/dep_graph/graph.rs | 272 ++++++-------- src/librustc_query_system/dep_graph/mod.rs | 100 ++++- src/librustc_query_system/dep_graph/prev.rs | 30 +- src/librustc_query_system/dep_graph/query.rs | 26 +- src/librustc_query_system/dep_graph/safe.rs | 6 - src/librustc_query_system/dep_graph/serialized.rs | 23 +- src/librustc_query_system/lib.rs | 32 ++ 12 files changed, 358 insertions(+), 604 deletions(-) create mode 100644 src/librustc_query_system/Cargo.toml create mode 100644 src/librustc_query_system/lib.rs (limited to 'src') diff --git a/Cargo.lock b/Cargo.lock index c65c3a45ec2..22a06151353 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3116,6 +3116,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_macros", + "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", @@ -4021,6 +4022,22 @@ dependencies = [ "rustc_typeck", ] +[[package]] +name = "rustc_query_system" +version = "0.0.0" +dependencies = [ + "log", + "parking_lot 0.9.0", + "rustc_ast", + "rustc_data_structures", + "rustc_errors", + "rustc_hir", + "rustc_index", + "rustc_macros", + "serialize", + "smallvec 1.0.0", +] + [[package]] name = "rustc_resolve" version = "0.0.0" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 481d691b8e9..47b94a2f1a4 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -25,6 +25,7 @@ rustc_hir = { path = "../librustc_hir" } rustc_target = { path = "../librustc_target" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_query_system = { path = "../librustc_query_system" } rustc_errors = { path = "../librustc_errors" } rustc_index = { path = "../librustc_index" } rustc_serialize = { path = "../libserialize", package = "serialize" } diff --git a/src/librustc_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml new file mode 100644 index 00000000000..a01bb5e5ea3 --- /dev/null +++ b/src/librustc_query_system/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_query_system" +version = "0.0.0" +edition = "2018" + +[lib] +name = "rustc_query_system" +path = "lib.rs" +doctest = false + +[dependencies] +log = { version = "0.4", features = ["release_max_level_info", "std"] } +rustc_ast = { path = "../librustc_ast" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_errors = { path = "../librustc_errors" } +rustc_hir = { path = "../librustc_hir" } +rustc_index = { path = "../librustc_index" } +rustc_macros = { path = "../librustc_macros" } +rustc_serialize = { path = "../libserialize", package = "serialize" } +parking_lot = "0.9" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_query_system/dep_graph/debug.rs b/src/librustc_query_system/dep_graph/debug.rs index d44c54593a6..718a2f1039a 100644 --- a/src/librustc_query_system/dep_graph/debug.rs +++ b/src/librustc_query_system/dep_graph/debug.rs @@ -1,6 +1,6 @@ //! Code for debugging the dep-graph. -use super::dep_node::DepNode; +use super::{DepKind, DepNode}; use std::error::Error; /// A dep-node filter goes from a user-defined string to a query over @@ -26,7 +26,7 @@ impl DepNodeFilter { } /// Tests whether `node` meets the filter, returning true if so. - pub fn test(&self, node: &DepNode) -> bool { + pub fn test(&self, node: &DepNode) -> bool { let debug_str = format!("{:?}", node); self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f)) } @@ -52,7 +52,7 @@ impl EdgeFilter { } } - pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { + pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { self.source.test(source) && self.target.test(target) } } diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs index e3df9d5d04b..9dcba30300f 100644 --- a/src/librustc_query_system/dep_graph/dep_node.rs +++ b/src/librustc_query_system/dep_graph/dep_node.rs @@ -26,10 +26,10 @@ //! could not be instantiated because the current compilation session //! contained no `DefId` for thing that had been removed. //! -//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro -//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The -//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at -//! runtime in order to construct a valid `DepNode` fingerprint. +//! `DepNode` definition happens in `librustc` with the `define_dep_nodes!()` macro. +//! This macro defines the `DepKind` enum and a corresponding `DepConstructor` enum. The +//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at runtime in order +//! to construct a valid `DepNode` fingerprint. //! //! Because the macro sees what parameters a given `DepKind` requires, it can //! "infer" some properties for each kind of `DepNode`: @@ -41,326 +41,50 @@ //! in which case it is possible to map the node's fingerprint back to the //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. -//! -//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only -//! valid `DepNode` instances can be constructed. For example, the API does not -//! allow for constructing parameterless `DepNode`s with anything other -//! than a zeroed out fingerprint. More generally speaking, it relieves the -//! user of the `DepNode` API of having to know how to compute the expected -//! fingerprint for a given set of node parameters. -use crate::hir::map::DefPathHash; -use crate::ich::{Fingerprint, StableHashingContext}; -use crate::mir; -use crate::mir::interpret::{GlobalId, LitToConstInput}; -use crate::traits; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, -}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use super::{DepContext, DepKind}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; -use rustc_hir::HirId; -use rustc_span::symbol::Symbol; +use rustc_macros::HashStable_Generic; + use std::fmt; use std::hash::Hash; -// erase!() just makes tokens go away. It's used to specify which macro argument -// is repeated (i.e., which sub-expression of the macro we are in) but don't need -// to actually use any of the arguments. -macro_rules! erase { - ($x:tt) => {{}}; -} - -macro_rules! is_anon_attr { - (anon) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! is_eval_always_attr { - (eval_always) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! contains_anon_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false}); -} - -macro_rules! contains_eval_always_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +pub struct DepNode { + pub kind: K, + pub hash: Fingerprint, } -macro_rules! define_dep_nodes { - (<$tcx:tt> - $( - [$($attrs:tt)*] - $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* - ,)* - ) => ( - #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, - RustcEncodable, RustcDecodable)] - #[allow(non_camel_case_types)] - pub enum DepKind { - $($variant),* - } - - impl DepKind { - #[allow(unreachable_code)] - pub fn can_reconstruct_query_key<$tcx>(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - if contains_anon_attr!($($attrs)*) { - return false; - } - - // tuple args - $({ - return <$tuple_arg_ty as DepNodeParams> - ::CAN_RECONSTRUCT_QUERY_KEY; - })* - - true - } - )* - } - } - - pub fn is_anon(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_anon_attr!($($attrs)*) } - )* - } - } - - pub fn is_eval_always(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) } - )* - } - } - - #[allow(unreachable_code)] - pub fn has_params(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - // tuple args - $({ - erase!($tuple_arg_ty); - return true; - })* - - false - } - )* - } - } - } - - pub struct DepConstructor; - - #[allow(non_camel_case_types)] - impl DepConstructor { - $( - #[inline(always)] - #[allow(unreachable_code, non_snake_case)] - pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode { - // tuple args - $({ - erase!($tuple_arg_ty); - let hash = DepNodeParams::to_fingerprint(&arg, _tcx); - let dep_node = DepNode { - kind: DepKind::$variant, - hash - }; - - #[cfg(debug_assertions)] - { - if !dep_node.kind.can_reconstruct_query_key() && - (_tcx.sess.opts.debugging_opts.incremental_info || - _tcx.sess.opts.debugging_opts.query_dep_graph) - { - _tcx.dep_graph.register_dep_node_debug_str(dep_node, || { - arg.to_debug_str(_tcx) - }); - } - } - - return dep_node; - })* - - DepNode { - kind: DepKind::$variant, - hash: Fingerprint::ZERO, - } - } - )* - } - - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, - RustcEncodable, RustcDecodable)] - pub struct DepNode { - pub kind: DepKind, - pub hash: Fingerprint, - } - - impl DepNode { - /// Construct a DepNode from the given DepKind and DefPathHash. This - /// method will assert that the given DepKind actually requires a - /// single DefId/DefPathHash parameter. - pub fn from_def_path_hash(def_path_hash: DefPathHash, - kind: DepKind) - -> DepNode { - debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); - DepNode { - kind, - hash: def_path_hash.0, - } - } - - /// Creates a new, parameterless DepNode. This method will assert - /// that the DepNode corresponding to the given DepKind actually - /// does not require any parameters. - pub fn new_no_params(kind: DepKind) -> DepNode { - debug_assert!(!kind.has_params()); - DepNode { - kind, - hash: Fingerprint::ZERO, - } - } - - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { - if self.kind.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(self.hash); - tcx.def_path_hash_to_def_id.as_ref()? - .get(&def_path_hash).cloned() - } else { - None - } - } - - /// Used in testing - pub fn from_label_string(label: &str, - def_path_hash: DefPathHash) - -> Result { - let kind = match label { - $( - stringify!($variant) => DepKind::$variant, - )* - _ => return Err(()), - }; - - if !kind.can_reconstruct_query_key() { - return Err(()); - } - - if kind.has_params() { - Ok(DepNode::from_def_path_hash(def_path_hash, kind)) - } else { - Ok(DepNode::new_no_params(kind)) - } - } - - /// Used in testing - pub fn has_label_string(label: &str) -> bool { - match label { - $( - stringify!($variant) => true, - )* - _ => false, - } - } - } - - /// Contains variant => str representations for constructing - /// DepNode groups for tests. - #[allow(dead_code, non_upper_case_globals)] - pub mod label_strs { - $( - pub const $variant: &str = stringify!($variant); - )* - } - ); +impl DepNode { + /// Creates a new, parameterless DepNode. This method will assert + /// that the DepNode corresponding to the given DepKind actually + /// does not require any parameters. + pub fn new_no_params(kind: K) -> DepNode { + debug_assert!(!kind.has_params()); + DepNode { kind, hash: Fingerprint::ZERO } + } } -impl fmt::Debug for DepNode { +impl fmt::Debug for DepNode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.kind)?; - - if !self.kind.has_params() && !self.kind.is_anon() { - return Ok(()); - } - - write!(f, "(")?; - - crate::ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(def_id) = self.extract_def_id(tcx) { - write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { - write!(f, "{}", s)?; - } else { - write!(f, "{}", self.hash)?; - } - } else { - write!(f, "{}", self.hash)?; - } - Ok(()) - })?; - - write!(f, ")") + K::debug_node(self, f) } } -rustc_dep_node_append!([define_dep_nodes!][ <'tcx> - // We use this for most things when incr. comp. is turned off. - [] Null, - - // Represents metadata from an extern crate. - [eval_always] CrateMetadata(CrateNum), - - [anon] TraitSelect, - - [] CompileCodegenUnit(Symbol), -]); - -pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized { +pub trait DepNodeParams: fmt::Debug + Sized { const CAN_RECONSTRUCT_QUERY_KEY: bool; /// This method turns the parameters of a DepNodeConstructor into an opaque /// Fingerprint to be used in DepNode. /// Not all DepNodeParams support being turned into a Fingerprint (they /// don't need to if the corresponding DepNode is anonymous). - fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { + fn to_fingerprint(&self, _: Ctxt) -> Fingerprint { panic!("Not implemented. Accidentally called on anonymous node?") } - fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + fn to_debug_str(&self, _: Ctxt) -> String { format!("{:?}", self) } @@ -370,16 +94,16 @@ pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized { /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`. /// It is always valid to return `None` here, in which case incremental /// compilation will treat the query as having changed instead of forcing it. - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; + fn recover(tcx: Ctxt, dep_node: &DepNode) -> Option; } -impl<'tcx, T> DepNodeParams<'tcx> for T +impl DepNodeParams for T where - T: HashStable> + fmt::Debug, + T: HashStable + fmt::Debug, { default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { + default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint { let mut hcx = tcx.create_stable_hashing_context(); let mut hasher = StableHasher::new(); @@ -388,102 +112,15 @@ where hasher.finish() } - default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + default fn to_debug_str(&self, _: Ctxt) -> String { format!("{:?}", *self) } - default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option { + default fn recover(_: Ctxt, _: &DepNode) -> Option { None } } -impl<'tcx> DepNodeParams<'tcx> for DefId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - tcx.def_path_hash(*self).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.def_path_str(*self) - } - - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx) - } -} - -impl<'tcx> DepNodeParams<'tcx> for DefIndex { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - tcx.hir().definitions().def_path_hash(*self).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.def_path_str(DefId::local(*self)) - } - - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.index) - } -} - -impl<'tcx> DepNodeParams<'tcx> for CrateNum { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; - tcx.def_path_hash(def_id).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.crate_name(*self).to_string() - } - - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.krate) - } -} - -impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { - const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - // We actually would not need to specialize the implementation of this - // method but it's faster to combine the hashes than to instantiate a full - // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let (def_id_0, def_id_1) = *self; - - let def_path_hash_0 = tcx.def_path_hash(def_id_0); - let def_path_hash_1 = tcx.def_path_hash(def_id_1); - - def_path_hash_0.0.combine(def_path_hash_1.0) - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - let (def_id_0, def_id_1) = *self; - - format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1)) - } -} - -impl<'tcx> DepNodeParams<'tcx> for HirId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - // We actually would not need to specialize the implementation of this - // method but it's faster to combine the hashes than to instantiate a full - // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let HirId { owner, local_id } = *self; - - let def_path_hash = tcx.def_path_hash(DefId::local(owner)); - let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into()); - - def_path_hash.0.combine(local_id) - } -} - /// A "work product" corresponds to a `.o` (or other) file that we /// save in between runs. These IDs do not have a `DefId` but rather /// some independent path or string that persists between runs without @@ -500,7 +137,7 @@ impl<'tcx> DepNodeParams<'tcx> for HirId { Hash, RustcEncodable, RustcDecodable, - HashStable + HashStable_Generic )] pub struct WorkProductId { hash: Fingerprint, diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index 36edf0f0fc2..5e004c5428a 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -1,32 +1,33 @@ -use crate::ty::{self, TyCtxt}; -use parking_lot::{Condvar, Mutex}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::QueryInvocationId; use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_data_structures::unlikely; use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; -use smallvec::SmallVec; + +use parking_lot::{Condvar, Mutex}; +use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use std::env; use std::hash::Hash; use std::mem; +use std::panic as bug; use std::sync::atomic::Ordering::Relaxed; -use crate::ich::{Fingerprint, StableHashingContext, StableHashingContextProvider}; - use super::debug::EdgeFilter; -use super::dep_node::{DepKind, DepNode, WorkProductId}; use super::prev::PreviousDepGraph; use super::query::DepGraphQuery; use super::safe::DepGraphSafe; use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; +use super::{DepContext, DepKind, DepNode, WorkProductId}; +use crate::{HashStableContext, HashStableContextProvider}; #[derive(Clone)] -pub struct DepGraph { - data: Option>, +pub struct DepGraph { + data: Option>>, /// This field is used for assigning DepNodeIndices when running in /// non-incremental mode. Even in non-incremental mode we make sure that @@ -65,16 +66,16 @@ impl DepNodeColor { } } -struct DepGraphData { +struct DepGraphData { /// The new encoding of the dependency graph, optimized for red/green /// tracking. The `current` field is the dependency graph of only the /// current compilation session: We don't merge the previous dep-graph into /// current one anymore. - current: CurrentDepGraph, + current: CurrentDepGraph, /// The dep-graph from the previous compilation session. It contains all /// nodes and edges as well as all fingerprints of nodes that have them. - previous: PreviousDepGraph, + previous: PreviousDepGraph, colors: DepNodeColorMap, @@ -90,12 +91,12 @@ struct DepGraphData { /// this map. We can later look for and extract that data. previous_work_products: FxHashMap, - dep_node_debug: Lock>, + dep_node_debug: Lock, String>>, } -pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option +pub fn hash_result(hcx: &mut HashCtxt, result: &R) -> Option where - R: for<'a> HashStable>, + R: HashStable, { let mut stable_hasher = StableHasher::new(); result.hash_stable(hcx, &mut stable_hasher); @@ -103,11 +104,11 @@ where Some(stable_hasher.finish()) } -impl DepGraph { +impl DepGraph { pub fn new( - prev_graph: PreviousDepGraph, + prev_graph: PreviousDepGraph, prev_work_products: FxHashMap, - ) -> DepGraph { + ) -> DepGraph { let prev_graph_node_count = prev_graph.node_count(); DepGraph { @@ -124,7 +125,7 @@ impl DepGraph { } } - pub fn new_disabled() -> DepGraph { + pub fn new_disabled() -> DepGraph { DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } } @@ -134,7 +135,7 @@ impl DepGraph { self.data.is_some() } - pub fn query(&self) -> DepGraphQuery { + pub fn query(&self) -> DepGraphQuery { let data = self.data.as_ref().unwrap().current.data.lock(); let nodes: Vec<_> = data.iter().map(|n| n.node).collect(); let mut edges = Vec::new(); @@ -150,10 +151,7 @@ impl DepGraph { pub fn assert_ignored(&self) { if let Some(..) = self.data { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); - }) + K::assert_ignored(); } } @@ -161,11 +159,7 @@ impl DepGraph { where OP: FnOnce() -> R, { - ty::tls::with_context(|icx| { - let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }) + K::with_ignore_deps(op) } /// Starts a new dep-graph task. Dep-graph tasks are specified @@ -195,16 +189,17 @@ impl DepGraph { /// `arg` parameter. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html - pub fn with_task<'a, C, A, R>( + pub fn with_task( &self, - key: DepNode, + key: DepNode, cx: C, arg: A, task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: impl FnOnce(&mut H, &R) -> Option, ) -> (R, DepNodeIndex) where - C: DepGraphSafe + StableHashingContextProvider<'a>, + C: DepGraphSafe + HashStableContextProvider, + H: HashStableContext, { self.with_task_impl( key, @@ -218,6 +213,7 @@ impl DepGraph { node: Some(_key), reads: SmallVec::new(), read_set: Default::default(), + phantom_data: std::marker::PhantomData, }) }, |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), @@ -225,24 +221,25 @@ impl DepGraph { ) } - fn with_task_impl<'a, C, A, R>( + fn with_task_impl( &self, - key: DepNode, + key: DepNode, cx: C, arg: A, no_tcx: bool, task: fn(C, A) -> R, - create_task: fn(DepNode) -> Option, + create_task: fn(DepNode) -> Option>, finish_task_and_alloc_depnode: fn( - &CurrentDepGraph, - DepNode, + &CurrentDepGraph, + DepNode, Fingerprint, - Option, + Option>, ) -> DepNodeIndex, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: impl FnOnce(&mut H, &R) -> Option, ) -> (R, DepNodeIndex) where - C: DepGraphSafe + StableHashingContextProvider<'a>, + C: DepGraphSafe + HashStableContextProvider, + H: HashStableContext, { if let Some(ref data) = self.data { let task_deps = create_task(key).map(Lock::new); @@ -257,12 +254,7 @@ impl DepGraph { let result = if no_tcx { task(cx, arg) } else { - ty::tls::with_context(|icx| { - let icx = - ty::tls::ImplicitCtxt { task_deps: task_deps.as_ref(), ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| task(cx, arg)) - }) + K::with_deps(task_deps.as_ref(), || task(cx, arg)) }; let current_fingerprint = hash_result(&mut hcx, &result); @@ -274,7 +266,7 @@ impl DepGraph { task_deps.map(|lock| lock.into_inner()), ); - let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks; + let print_status = cfg!(debug_assertions) && hcx.debug_dep_tasks(); // Determine the color of the new DepNode. if let Some(prev_index) = data.previous.node_to_index_opt(&key) { @@ -322,22 +314,16 @@ impl DepGraph { /// Executes something within an "anonymous" task, that is, a task the /// `DepNode` of which is determined by the list of inputs it read from. - pub fn with_anon_task(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex) + pub fn with_anon_task(&self, dep_kind: K, op: OP) -> (R, DepNodeIndex) where OP: FnOnce() -> R, { if let Some(ref data) = self.data { - let (result, task_deps) = ty::tls::with_context(|icx| { - let task_deps = Lock::new(TaskDeps::default()); - - let r = { - let icx = ty::tls::ImplicitCtxt { task_deps: Some(&task_deps), ..icx.clone() }; + let task_deps = Lock::new(TaskDeps::default()); - ty::tls::enter_context(&icx, |_| op()) - }; + let result = K::with_deps(Some(&task_deps), op); + let task_deps = task_deps.into_inner(); - (r, task_deps.into_inner()) - }); let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps); (result, dep_node_index) } else { @@ -347,16 +333,17 @@ impl DepGraph { /// Executes something within an "eval-always" task which is a task /// that runs whenever anything changes. - pub fn with_eval_always_task<'a, C, A, R>( + pub fn with_eval_always_task( &self, - key: DepNode, + key: DepNode, cx: C, arg: A, task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: impl FnOnce(&mut H, &R) -> Option, ) -> (R, DepNodeIndex) where - C: DepGraphSafe + StableHashingContextProvider<'a>, + C: DepGraphSafe + HashStableContextProvider, + H: HashStableContext, { self.with_task_impl( key, @@ -371,7 +358,7 @@ impl DepGraph { } #[inline] - pub fn read(&self, v: DepNode) { + pub fn read(&self, v: DepNode) { if let Some(ref data) = self.data { let map = data.current.node_to_node_index.get_shard_by_value(&v).lock(); if let Some(dep_node_index) = map.get(&v).copied() { @@ -391,7 +378,7 @@ impl DepGraph { } #[inline] - pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { + pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { self.data .as_ref() .unwrap() @@ -405,7 +392,7 @@ impl DepGraph { } #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { if let Some(ref data) = self.data { data.current .node_to_node_index @@ -423,12 +410,12 @@ impl DepGraph { data[dep_node_index].fingerprint } - pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { + pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) } #[inline] - pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { + pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { self.data.as_ref().unwrap().previous.node_to_index(dep_node) } @@ -445,7 +432,7 @@ impl DepGraph { } #[inline(always)] - pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) + pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) where F: FnOnce() -> String, { @@ -458,7 +445,7 @@ impl DepGraph { dep_node_debug.borrow_mut().insert(dep_node, debug_str); } - pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { + pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() } @@ -475,7 +462,7 @@ impl DepGraph { } } - pub fn serialize(&self) -> SerializedDepGraph { + pub fn serialize(&self) -> SerializedDepGraph { let data = self.data.as_ref().unwrap().current.data.lock(); let fingerprints: IndexVec = @@ -503,7 +490,7 @@ impl DepGraph { SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data } } - pub fn node_color(&self, dep_node: &DepNode) -> Option { + pub fn node_color(&self, dep_node: &DepNode) -> Option { if let Some(ref data) = self.data { if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { return data.colors.get(prev_index); @@ -521,10 +508,10 @@ impl DepGraph { /// A node will have an index, when it's already been marked green, or when we can mark it /// green. This function will mark the current task as a reader of the specified node, when /// a node index can be found for that node. - pub fn try_mark_green_and_read( + pub fn try_mark_green_and_read>( &self, - tcx: TyCtxt<'_>, - dep_node: &DepNode, + tcx: Ctxt, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| { debug_assert!(self.is_green(&dep_node)); @@ -533,10 +520,10 @@ impl DepGraph { }) } - pub fn try_mark_green( + pub fn try_mark_green>( &self, - tcx: TyCtxt<'_>, - dep_node: &DepNode, + tcx: Ctxt, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { debug_assert!(!dep_node.kind.is_eval_always()); @@ -561,12 +548,12 @@ impl DepGraph { } /// Try to mark a dep-node which existed in the previous compilation session as green. - fn try_mark_previous_green<'tcx>( + fn try_mark_previous_green>( &self, - tcx: TyCtxt<'tcx>, - data: &DepGraphData, + tcx: Ctxt, + data: &DepGraphData, prev_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, + dep_node: &DepNode, ) -> Option { debug!("try_mark_previous_green({:?}) - BEGIN", dep_node); @@ -649,49 +636,7 @@ impl DepGraph { continue; } } else { - // FIXME: This match is just a workaround for incremental bugs and should - // be removed. https://github.com/rust-lang/rust/issues/62649 is one such - // bug that must be fixed before removing this. - match dep_dep_node.kind { - DepKind::hir_owner - | DepKind::hir_owner_nodes - | DepKind::CrateMetadata => { - if let Some(def_id) = dep_dep_node.extract_def_id(tcx) { - if def_id_corresponds_to_hir_dep_node(tcx, def_id) { - if dep_dep_node.kind == DepKind::CrateMetadata { - // The `DefPath` has corresponding node, - // and that node should have been marked - // either red or green in `data.colors`. - bug!( - "DepNode {:?} should have been \ - pre-marked as red or green but wasn't.", - dep_dep_node - ); - } - } else { - // This `DefPath` does not have a - // corresponding `DepNode` (e.g. a - // struct field), and the ` DefPath` - // collided with the `DefPath` of a - // proper item that existed in the - // previous compilation session. - // - // Since the given `DefPath` does not - // denote the item that previously - // existed, we just fail to mark green. - return None; - } - } else { - // If the node does not exist anymore, we - // just fail to mark green. - return None; - } - } - _ => { - // For other kinds of nodes it's OK to be - // forced. - } - } + tcx.ensure_node_can_be_forced(dep_dep_node)?; } // We failed to mark it green, so we try to force the query. @@ -700,7 +645,7 @@ impl DepGraph { dependency {:?}", dep_node, dep_dep_node ); - if crate::ty::query::force_from_dep_node(tcx, dep_dep_node) { + if tcx.force_from_dep_node(dep_dep_node) { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { @@ -721,7 +666,7 @@ impl DepGraph { return None; } None => { - if !tcx.sess.has_errors_or_delayed_span_bugs() { + if !tcx.has_errors_or_delayed_span_bugs() { bug!( "try_mark_previous_green() - Forcing the DepNode \ should have set its color" @@ -779,7 +724,7 @@ impl DepGraph { // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere // Maybe store a list on disk and encode this fact in the DepNodeState - let diagnostics = tcx.queries.on_disk_cache.load_diagnostics(tcx, prev_dep_node_index); + let diagnostics = tcx.load_diagnostics(prev_dep_node_index); #[cfg(not(parallel_compiler))] debug_assert!( @@ -805,10 +750,10 @@ impl DepGraph { /// This may be called concurrently on multiple threads for the same dep node. #[cold] #[inline(never)] - fn emit_diagnostics<'tcx>( + fn emit_diagnostics>( &self, - tcx: TyCtxt<'tcx>, - data: &DepGraphData, + tcx: Ctxt, + data: &DepGraphData, dep_node_index: DepNodeIndex, prev_dep_node_index: SerializedDepNodeIndex, diagnostics: Vec, @@ -827,9 +772,9 @@ impl DepGraph { mem::drop(emitting); // Promote the previous diagnostics to the current session. - tcx.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics.clone().into()); + tcx.store_diagnostics(dep_node_index, diagnostics.clone().into()); - let handle = tcx.sess.diagnostic(); + let handle = tcx.diagnostic(); for diagnostic in diagnostics { handle.emit_diagnostic(&diagnostic); @@ -858,7 +803,7 @@ impl DepGraph { // Returns true if the given node has been marked as green during the // current compilation session. Used in various assertions - pub fn is_green(&self, dep_node: &DepNode) -> bool { + pub fn is_green(&self, dep_node: &DepNode) -> bool { self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) } @@ -870,15 +815,15 @@ impl DepGraph { // // This method will only load queries that will end up in the disk cache. // Other queries will not be executed. - pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) { - let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); + pub fn exec_cache_promotions>(&self, tcx: Ctxt) { + let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion"); let data = self.data.as_ref().unwrap(); for prev_index in data.colors.values.indices() { match data.colors.get(prev_index) { Some(DepNodeColor::Green(_)) => { let dep_node = data.previous.index_to_node(prev_index); - dep_node.try_load_from_on_disk_cache(tcx); + tcx.try_load_from_on_disk_cache(&dep_node); } None | Some(DepNodeColor::Red) => { // We can skip red nodes because a node can only be marked @@ -895,11 +840,6 @@ impl DepGraph { } } -fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - def_id.index == hir_id.owner.local_def_index -} - /// A "work product" is an intermediate result that we save into the /// incremental directory for later re-use. The primary example are /// the object files that we save for each partition at code @@ -946,8 +886,8 @@ pub enum WorkProductFileKind { } #[derive(Clone)] -struct DepNodeData { - node: DepNode, +struct DepNodeData { + node: DepNode, edges: EdgesVec, fingerprint: Fingerprint, } @@ -967,9 +907,9 @@ struct DepNodeData { /// The only operation that must manipulate both locks is adding new nodes, in which case /// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted, /// acquire the lock on `data.` -pub(super) struct CurrentDepGraph { - data: Lock>, - node_to_node_index: Sharded>, +pub(super) struct CurrentDepGraph { + data: Lock>>, + node_to_node_index: Sharded, DepNodeIndex>>, /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. @@ -995,8 +935,8 @@ pub(super) struct CurrentDepGraph { total_duplicate_read_count: AtomicU64, } -impl CurrentDepGraph { - fn new(prev_graph_node_count: usize) -> CurrentDepGraph { +impl CurrentDepGraph { + fn new(prev_graph_node_count: usize) -> CurrentDepGraph { use std::time::{SystemTime, UNIX_EPOCH}; let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); @@ -1039,14 +979,14 @@ impl CurrentDepGraph { fn complete_task( &self, - node: DepNode, - task_deps: TaskDeps, + node: DepNode, + task_deps: TaskDeps, fingerprint: Fingerprint, ) -> DepNodeIndex { self.alloc_node(node, task_deps.reads, fingerprint) } - fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex { + fn complete_anon_task(&self, kind: K, task_deps: TaskDeps) -> DepNodeIndex { debug_assert!(!kind.is_eval_always()); let mut hasher = StableHasher::new(); @@ -1072,7 +1012,7 @@ impl CurrentDepGraph { fn alloc_node( &self, - dep_node: DepNode, + dep_node: DepNode, edges: EdgesVec, fingerprint: Fingerprint, ) -> DepNodeIndex { @@ -1084,7 +1024,7 @@ impl CurrentDepGraph { fn intern_node( &self, - dep_node: DepNode, + dep_node: DepNode, edges: EdgesVec, fingerprint: Fingerprint, ) -> DepNodeIndex { @@ -1101,12 +1041,11 @@ impl CurrentDepGraph { } } -impl DepGraphData { +impl DepGraphData { #[inline(never)] fn read_index(&self, source: DepNodeIndex) { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - if let Some(task_deps) = icx.task_deps { + K::read_deps(|task_deps| { + if let Some(task_deps) = task_deps { let mut task_deps = task_deps.lock(); let task_deps = &mut *task_deps; if cfg!(debug_assertions) { @@ -1151,12 +1090,25 @@ impl DepGraphData { /// The capacity of the `reads` field `SmallVec` const TASK_DEPS_READS_CAP: usize = 8; type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; -#[derive(Default)] -pub struct TaskDeps { + +pub struct TaskDeps { #[cfg(debug_assertions)] - node: Option, + node: Option>, reads: EdgesVec, read_set: FxHashSet, + phantom_data: std::marker::PhantomData>, +} + +impl Default for TaskDeps { + fn default() -> Self { + Self { + #[cfg(debug_assertions)] + node: None, + reads: EdgesVec::new(), + read_set: FxHashSet::default(), + phantom_data: std::marker::PhantomData, + } + } } // A data structure that stores Option values as a contiguous diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index 1fbd90743f4..77bc8f61293 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -6,12 +6,94 @@ mod query; mod safe; mod serialized; -pub(crate) use self::dep_node::DepNodeParams; -pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, WorkProductId}; -pub use self::graph::WorkProductFileKind; -pub use self::graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; -pub use self::prev::PreviousDepGraph; -pub use self::query::DepGraphQuery; -pub use self::safe::AssertDepGraphSafe; -pub use self::safe::DepGraphSafe; -pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; +pub use dep_node::{DepNode, DepNodeParams, WorkProductId}; +pub use graph::WorkProductFileKind; +pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; +pub use prev::PreviousDepGraph; +pub use query::DepGraphQuery; +pub use safe::AssertDepGraphSafe; +pub use safe::DepGraphSafe; +pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; + +use rustc_data_structures::profiling::SelfProfilerRef; +use rustc_data_structures::sync::Lock; +use rustc_data_structures::thin_vec::ThinVec; +use rustc_errors::Diagnostic; +use rustc_hir::def_id::DefId; + +use std::fmt; +use std::hash::Hash; + +pub trait DepContext: Copy { + type DepKind: self::DepKind; + type StableHashingContext: crate::HashStableContext; + + /// Create a hashing context for hashing new results. + fn create_stable_hashing_context(&self) -> Self::StableHashingContext; + + /// Force the execution of a query given the associated `DepNode`. + fn force_from_dep_node(&self, node: &DepNode) -> bool; + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, node: &DepNode) -> Option; + + /// Check the legality of forcing this node. + fn ensure_node_can_be_forced(&self, dep_dep_node: &DepNode) -> Option<()>; + + /// Return whether the current session is tainted by errors. + fn has_errors_or_delayed_span_bugs(&self) -> bool; + + /// Return the diagnostic handler. + fn diagnostic(&self) -> &rustc_errors::Handler; + + /// Load data from the on-disk cache. + fn try_load_from_on_disk_cache(&self, dep_node: &DepNode); + + /// Load diagnostics associated to the node in the previous session. + fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec; + + /// Register diagnostics for the given node, for use in next session. + fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec); + + /// Access the profiler. + fn profiler(&self) -> &SelfProfilerRef; +} + +/// Describe the different families of dependency nodes. +pub trait DepKind: Copy + fmt::Debug + Eq + Ord + Hash { + /// Return whether this kind always require evaluation. + fn is_eval_always(&self) -> bool; + + /// Return whether this kind requires additional parameters to be executed. + fn has_params(&self) -> bool; + + /// Implementation of `std::fmt::Debug` for `DepNode`. + fn debug_node(node: &DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result; + + /// Assert the current implicit context does not track any dependency. + fn assert_ignored(); + + /// Execute the operation ignoring the dependencies. + fn with_ignore_deps(op: OP) -> R + where + OP: FnOnce() -> R; + + /// Execute the operation with provided dependencies. + fn with_deps(deps: Option<&Lock>>, op: OP) -> R + where + OP: FnOnce() -> R; + + /// Access dependencies from current implicit context. + fn read_deps(op: OP) -> () + where + OP: for<'a> FnOnce(Option<&'a Lock>>) -> (); +} diff --git a/src/librustc_query_system/dep_graph/prev.rs b/src/librustc_query_system/dep_graph/prev.rs index fbc8f7bc997..5cba64cac4b 100644 --- a/src/librustc_query_system/dep_graph/prev.rs +++ b/src/librustc_query_system/dep_graph/prev.rs @@ -1,16 +1,22 @@ -use super::dep_node::DepNode; use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; -use crate::ich::Fingerprint; +use super::{DepKind, DepNode}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -#[derive(Debug, RustcEncodable, RustcDecodable, Default)] -pub struct PreviousDepGraph { - data: SerializedDepGraph, - index: FxHashMap, +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct PreviousDepGraph { + data: SerializedDepGraph, + index: FxHashMap, SerializedDepNodeIndex>, } -impl PreviousDepGraph { - pub fn new(data: SerializedDepGraph) -> PreviousDepGraph { +impl Default for PreviousDepGraph { + fn default() -> Self { + PreviousDepGraph { data: Default::default(), index: Default::default() } + } +} + +impl PreviousDepGraph { + pub fn new(data: SerializedDepGraph) -> PreviousDepGraph { let index: FxHashMap<_, _> = data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); PreviousDepGraph { data, index } @@ -25,22 +31,22 @@ impl PreviousDepGraph { } #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { + pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { self.data.nodes[dep_node_index] } #[inline] - pub fn node_to_index(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { + pub fn node_to_index(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { self.index[dep_node] } #[inline] - pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { self.index.get(dep_node).cloned() } #[inline] - pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { + pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index]) } diff --git a/src/librustc_query_system/dep_graph/query.rs b/src/librustc_query_system/dep_graph/query.rs index c71c11ed0eb..4a4283b2a0c 100644 --- a/src/librustc_query_system/dep_graph/query.rs +++ b/src/librustc_query_system/dep_graph/query.rs @@ -3,15 +3,15 @@ use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; -use super::DepNode; +use super::{DepKind, DepNode}; -pub struct DepGraphQuery { - pub graph: Graph, - pub indices: FxHashMap, +pub struct DepGraphQuery { + pub graph: Graph, ()>, + pub indices: FxHashMap, NodeIndex>, } -impl DepGraphQuery { - pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { +impl DepGraphQuery { + pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { let mut graph = Graph::with_capacity(nodes.len(), edges.len()); let mut indices = FxHashMap::default(); for node in nodes { @@ -27,15 +27,15 @@ impl DepGraphQuery { DepGraphQuery { graph, indices } } - pub fn contains_node(&self, node: &DepNode) -> bool { + pub fn contains_node(&self, node: &DepNode) -> bool { self.indices.contains_key(&node) } - pub fn nodes(&self) -> Vec<&DepNode> { + pub fn nodes(&self) -> Vec<&DepNode> { self.graph.all_nodes().iter().map(|n| &n.data).collect() } - pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { + pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { self.graph .all_edges() .iter() @@ -44,7 +44,7 @@ impl DepGraphQuery { .collect() } - fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { + fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(node) { self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect() } else { @@ -54,17 +54,17 @@ impl DepGraphQuery { /// All nodes reachable from `node`. In other words, things that /// will have to be recomputed if `node` changes. - pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, OUTGOING) } /// All nodes that can reach `node`. - pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, INCOMING) } /// Just the outgoing edges from `node`. - pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(&node) { self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect() } else { diff --git a/src/librustc_query_system/dep_graph/safe.rs b/src/librustc_query_system/dep_graph/safe.rs index 74e32867cde..7bba348f884 100644 --- a/src/librustc_query_system/dep_graph/safe.rs +++ b/src/librustc_query_system/dep_graph/safe.rs @@ -1,7 +1,5 @@ //! The `DepGraphSafe` trait -use crate::ty::TyCtxt; - use rustc_ast::ast::NodeId; use rustc_hir::def_id::DefId; use rustc_hir::BodyId; @@ -28,10 +26,6 @@ impl DepGraphSafe for NodeId {} /// on-demand queries, all of which create reads. impl DepGraphSafe for DefId {} -/// The type context itself can be used to access all kinds of tracked -/// state, but those accesses should always generate read events. -impl<'tcx> DepGraphSafe for TyCtxt<'tcx> {} - /// Tuples make it easy to build up state. impl DepGraphSafe for (A, B) where diff --git a/src/librustc_query_system/dep_graph/serialized.rs b/src/librustc_query_system/dep_graph/serialized.rs index 45ef52dbf39..4a89da23ea6 100644 --- a/src/librustc_query_system/dep_graph/serialized.rs +++ b/src/librustc_query_system/dep_graph/serialized.rs @@ -1,7 +1,7 @@ //! The data that we will serialize and deserialize. -use crate::dep_graph::DepNode; -use crate::ich::Fingerprint; +use super::{DepKind, DepNode}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_index::vec::IndexVec; rustc_index::newtype_index! { @@ -9,10 +9,10 @@ rustc_index::newtype_index! { } /// Data for use when recompiling the **current crate**. -#[derive(Debug, RustcEncodable, RustcDecodable, Default)] -pub struct SerializedDepGraph { +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct SerializedDepGraph { /// The set of all DepNodes in the graph - pub nodes: IndexVec, + pub nodes: IndexVec>, /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to /// the DepNode at the same index in the nodes vector. pub fingerprints: IndexVec, @@ -25,7 +25,18 @@ pub struct SerializedDepGraph { pub edge_list_data: Vec, } -impl SerializedDepGraph { +impl Default for SerializedDepGraph { + fn default() -> Self { + SerializedDepGraph { + nodes: Default::default(), + fingerprints: Default::default(), + edge_list_indices: Default::default(), + edge_list_data: Default::default(), + } + } +} + +impl SerializedDepGraph { #[inline] pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] { let targets = self.edge_list_indices[source]; diff --git a/src/librustc_query_system/lib.rs b/src/librustc_query_system/lib.rs new file mode 100644 index 00000000000..ef4886828c4 --- /dev/null +++ b/src/librustc_query_system/lib.rs @@ -0,0 +1,32 @@ +#![feature(const_fn)] +#![feature(const_if_match)] +#![feature(const_panic)] +#![feature(core_intrinsics)] +#![feature(specialization)] +#![feature(stmt_expr_attributes)] + +#[macro_use] +extern crate log; + +pub mod dep_graph; + +pub trait HashStableContext { + fn debug_dep_tasks(&self) -> bool; +} + +/// Something that can provide a stable hashing context. +pub trait HashStableContextProvider { + fn get_stable_hashing_context(&self) -> Ctxt; +} + +impl> HashStableContextProvider for &T { + fn get_stable_hashing_context(&self) -> Ctxt { + (**self).get_stable_hashing_context() + } +} + +impl> HashStableContextProvider for &mut T { + fn get_stable_hashing_context(&self) -> Ctxt { + (**self).get_stable_hashing_context() + } +} -- cgit 1.4.1-3-g733a5 From db7bd5f828faa85880fc3cbac0c7b679e2225321 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 18 Mar 2020 10:32:58 +0100 Subject: Fallout in other crates. --- src/librustc/dep_graph/dep_node.rs | 187 ++++--------------- src/librustc/dep_graph/mod.rs | 233 ++++++++++++++++++++++++ src/librustc/dep_graph/safe.rs | 9 + src/librustc/ty/query/mod.rs | 13 -- src/librustc_incremental/assert_dep_graph.rs | 2 +- src/librustc_incremental/persist/dirty_clean.rs | 4 +- src/librustc_macros/src/query.rs | 8 +- src/librustc_metadata/rmeta/decoder.rs | 2 +- src/librustc_query_system/dep_graph/dep_node.rs | 15 +- 9 files changed, 287 insertions(+), 186 deletions(-) create mode 100644 src/librustc/dep_graph/mod.rs create mode 100644 src/librustc/dep_graph/safe.rs (limited to 'src') diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 7cde57e1f13..ee44c07d3a9 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -50,7 +50,7 @@ //! fingerprint for a given set of node parameters. use crate::hir::map::DefPathHash; -use crate::ich::{Fingerprint, StableHashingContext}; +use crate::ich::Fingerprint; use crate::mir; use crate::mir::interpret::{GlobalId, LitToConstInput}; use crate::traits; @@ -62,13 +62,13 @@ use crate::traits::query::{ use crate::ty::subst::SubstsRef; use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::HirId; use rustc_span::symbol::Symbol; -use std::fmt; use std::hash::Hash; +pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; + // erase!() just makes tokens go away. It's used to specify which macro argument // is repeated (i.e., which sub-expression of the macro we are in) but don't need // to actually use any of the arguments. @@ -128,7 +128,7 @@ macro_rules! define_dep_nodes { // tuple args $({ - return <$tuple_arg_ty as DepNodeParams> + return <$tuple_arg_ty as DepNodeParams>> ::CAN_RECONSTRUCT_QUERY_KEY; })* @@ -212,20 +212,27 @@ macro_rules! define_dep_nodes { )* } - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, - RustcEncodable, RustcDecodable)] - pub struct DepNode { - pub kind: DepKind, - pub hash: Fingerprint, + pub type DepNode = rustc_query_system::dep_graph::DepNode; + + pub trait DepNodeExt: Sized { + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; + + /// Used in testing + fn from_label_string(label: &str, def_path_hash: DefPathHash) + -> Result; + + /// Used in testing + fn has_label_string(label: &str) -> bool; } - impl DepNode { + impl DepNodeExt for DepNode { /// Construct a DepNode from the given DepKind and DefPathHash. This /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. - pub fn from_def_path_hash(def_path_hash: DefPathHash, - kind: DepKind) - -> DepNode { + fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); DepNode { kind, @@ -233,17 +240,6 @@ macro_rules! define_dep_nodes { } } - /// Creates a new, parameterless DepNode. This method will assert - /// that the DepNode corresponding to the given DepKind actually - /// does not require any parameters. - pub fn new_no_params(kind: DepKind) -> DepNode { - debug_assert!(!kind.has_params()); - DepNode { - kind, - hash: Fingerprint::ZERO, - } - } - /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: /// @@ -254,20 +250,8 @@ macro_rules! define_dep_nodes { /// DepNode. Condition (2) might not be fulfilled if a DepNode /// refers to something from the previous compilation session that /// has been removed. - pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { - if self.kind.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(self.hash); - tcx.def_path_hash_to_def_id.as_ref()? - .get(&def_path_hash).cloned() - } else { - None - } - } - /// Used in testing - pub fn from_label_string(label: &str, - def_path_hash: DefPathHash) - -> Result { + fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result { let kind = match label { $( stringify!($variant) => DepKind::$variant, @@ -287,7 +271,7 @@ macro_rules! define_dep_nodes { } /// Used in testing - pub fn has_label_string(label: &str) -> bool { + fn has_label_string(label: &str) -> bool { match label { $( stringify!($variant) => true, @@ -308,35 +292,6 @@ macro_rules! define_dep_nodes { ); } -impl fmt::Debug for DepNode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.kind)?; - - if !self.kind.has_params() && !self.kind.is_anon() { - return Ok(()); - } - - write!(f, "(")?; - - crate::ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(def_id) = self.extract_def_id(tcx) { - write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { - write!(f, "{}", s)?; - } else { - write!(f, "{}", self.hash)?; - } - } else { - write!(f, "{}", self.hash)?; - } - Ok(()) - })?; - - write!(f, ")") - } -} - rustc_dep_node_append!([define_dep_nodes!][ <'tcx> // We use this for most things when incr. comp. is turned off. [] Null, @@ -349,58 +304,10 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [] CompileCodegenUnit(Symbol), ]); -pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized { - const CAN_RECONSTRUCT_QUERY_KEY: bool; - - /// This method turns the parameters of a DepNodeConstructor into an opaque - /// Fingerprint to be used in DepNode. - /// Not all DepNodeParams support being turned into a Fingerprint (they - /// don't need to if the corresponding DepNode is anonymous). - fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { - panic!("Not implemented. Accidentally called on anonymous node?") - } - - fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { - format!("{:?}", self) - } - - /// This method tries to recover the query key from the given `DepNode`, - /// something which is needed when forcing `DepNode`s during red-green - /// evaluation. The query system will only call this method if - /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`. - /// It is always valid to return `None` here, in which case incremental - /// compilation will treat the query as having changed instead of forcing it. - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; -} - -impl<'tcx, T> DepNodeParams<'tcx> for T -where - T: HashStable> + fmt::Debug, -{ - default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { - let mut hcx = tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - - self.hash_stable(&mut hcx, &mut hasher); - - hasher.finish() - } - - default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { - format!("{:?}", *self) - } - - default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option { - None - } -} - -impl<'tcx> DepNodeParams<'tcx> for DefId { +impl<'tcx> DepNodeParams> for DefId { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { tcx.def_path_hash(*self).0 } @@ -409,14 +316,14 @@ impl<'tcx> DepNodeParams<'tcx> for DefId { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx) + tcx.extract_def_id(dep_node) } } -impl<'tcx> DepNodeParams<'tcx> for LocalDefId { +impl<'tcx> DepNodeParams> for LocalDefId { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { self.to_def_id().to_fingerprint(tcx) } @@ -425,14 +332,14 @@ impl<'tcx> DepNodeParams<'tcx> for LocalDefId { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.expect_local()) + tcx.extract_def_id(dep_node).map(|id| id.expect_local()) } } -impl<'tcx> DepNodeParams<'tcx> for CrateNum { +impl<'tcx> DepNodeParams> for CrateNum { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; tcx.def_path_hash(def_id).0 } @@ -442,17 +349,17 @@ impl<'tcx> DepNodeParams<'tcx> for CrateNum { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.krate) + tcx.extract_def_id(dep_node).map(|id| id.krate) } } -impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { +impl<'tcx> DepNodeParams> for (DefId, DefId) { const CAN_RECONSTRUCT_QUERY_KEY: bool = false; // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let (def_id_0, def_id_1) = *self; let def_path_hash_0 = tcx.def_path_hash(def_id_0); @@ -468,13 +375,13 @@ impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { } } -impl<'tcx> DepNodeParams<'tcx> for HirId { +impl<'tcx> DepNodeParams> for HirId { const CAN_RECONSTRUCT_QUERY_KEY: bool = false; // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let HirId { owner, local_id } = *self; let def_path_hash = tcx.def_path_hash(owner.to_def_id()); @@ -483,27 +390,3 @@ impl<'tcx> DepNodeParams<'tcx> for HirId { def_path_hash.0.combine(local_id) } } - -/// A "work product" corresponds to a `.o` (or other) file that we -/// save in between runs. These IDs do not have a `DefId` but rather -/// some independent path or string that persists between runs without -/// the need to be mapped or unmapped. (This ensures we can serialize -/// them even in the absence of a tcx.) -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable)] -pub struct WorkProductId { - hash: Fingerprint, -} - -impl WorkProductId { - pub fn from_cgu_name(cgu_name: &str) -> WorkProductId { - let mut hasher = StableHasher::new(); - cgu_name.len().hash(&mut hasher); - cgu_name.hash(&mut hasher); - WorkProductId { hash: hasher.finish() } - } - - pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId { - WorkProductId { hash: fingerprint } - } -} diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs new file mode 100644 index 00000000000..79295b2f827 --- /dev/null +++ b/src/librustc/dep_graph/mod.rs @@ -0,0 +1,233 @@ +use crate::hir::map::definitions::DefPathHash; +use crate::ich::StableHashingContext; +use crate::ty::{self, TyCtxt}; +use rustc_data_structures::profiling::SelfProfilerRef; +use rustc_data_structures::sync::Lock; +use rustc_data_structures::thin_vec::ThinVec; +use rustc_errors::Diagnostic; +use rustc_hir::def_id::DefId; + +mod dep_node; +mod safe; + +pub(crate) use rustc_query_system::dep_graph::DepNodeParams; +pub use rustc_query_system::dep_graph::{ + debug, hash_result, DepContext, DepNodeColor, DepNodeIndex, SerializedDepNodeIndex, + WorkProduct, WorkProductFileKind, WorkProductId, +}; + +pub use dep_node::{label_strs, DepConstructor, DepKind, DepNode, DepNodeExt}; +pub use safe::AssertDepGraphSafe; +pub use safe::DepGraphSafe; + +pub type DepGraph = rustc_query_system::dep_graph::DepGraph; +pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; +pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery; +pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph; +pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph; + +impl rustc_query_system::dep_graph::DepKind for DepKind { + fn is_eval_always(&self) -> bool { + DepKind::is_eval_always(self) + } + + fn has_params(&self) -> bool { + DepKind::has_params(self) + } + + fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", node.kind)?; + + if !node.kind.has_params() && !node.kind.is_anon() { + return Ok(()); + } + + write!(f, "(")?; + + ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = tcx.extract_def_id(node) { + write!(f, "{}", tcx.def_path_debug_str(def_id))?; + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) { + write!(f, "{}", s)?; + } else { + write!(f, "{}", node.hash)?; + } + } else { + write!(f, "{}", node.hash)?; + } + Ok(()) + })?; + + write!(f, ")") + } + + fn assert_ignored() { + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); + }) + } + + fn with_ignore_deps(op: OP) -> R + where + OP: FnOnce() -> R, + { + ty::tls::with_context(|icx| { + let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; + + ty::tls::enter_context(&icx, |_| op()) + }) + } + + fn with_deps(task_deps: Option<&Lock>, op: OP) -> R + where + OP: FnOnce() -> R, + { + ty::tls::with_context(|icx| { + let icx = ty::tls::ImplicitCtxt { task_deps, ..icx.clone() }; + + ty::tls::enter_context(&icx, |_| op()) + }) + } + + fn read_deps(op: OP) -> () + where + OP: for<'a> FnOnce(Option<&'a Lock>) -> (), + { + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + op(icx.task_deps) + }) + } +} + +impl<'tcx> DepContext for TyCtxt<'tcx> { + type DepKind = DepKind; + type StableHashingContext = StableHashingContext<'tcx>; + + fn create_stable_hashing_context(&self) -> Self::StableHashingContext { + TyCtxt::create_stable_hashing_context(*self) + } + + fn force_from_dep_node(&self, node: &DepNode) -> bool { + ty::query::force_from_dep_node(*self, node) + } + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, node: &DepNode) -> Option { + if node.kind.can_reconstruct_query_key() { + let def_path_hash = DefPathHash(node.hash); + self.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() + } else { + None + } + } + + fn ensure_node_can_be_forced(&self, dep_dep_node: &DepNode) -> Option<()> { + // FIXME: This match is just a workaround for incremental bugs and should + // be removed. https://github.com/rust-lang/rust/issues/62649 is one such + // bug that must be fixed before removing this. + match dep_dep_node.kind { + DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => { + if let Some(def_id) = self.extract_def_id(dep_dep_node) { + if def_id_corresponds_to_hir_dep_node(*self, def_id) { + if dep_dep_node.kind == DepKind::CrateMetadata { + // The `DefPath` has corresponding node, + // and that node should have been marked + // either red or green in `data.colors`. + bug!( + "DepNode {:?} should have been \ + pre-marked as red or green but wasn't.", + dep_dep_node + ); + } + } else { + // This `DefPath` does not have a + // corresponding `DepNode` (e.g. a + // struct field), and the ` DefPath` + // collided with the `DefPath` of a + // proper item that existed in the + // previous compilation session. + // + // Since the given `DefPath` does not + // denote the item that previously + // existed, we just fail to mark green. + return None; + } + } else { + // If the node does not exist anymore, we + // just fail to mark green. + return None; + } + } + _ => { + // For other kinds of nodes it's OK to be + // forced. + } + } + Some(()) + } + + fn has_errors_or_delayed_span_bugs(&self) -> bool { + self.sess.has_errors_or_delayed_span_bugs() + } + + fn diagnostic(&self) -> &rustc_errors::Handler { + self.sess.diagnostic() + } + + // Interactions with on_disk_cache + fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { + use crate::mir::interpret::GlobalId; + use crate::ty::query::queries; + use crate::ty::query::QueryDescription; + rustc_dep_node_try_load_from_on_disk_cache!(dep_node, *self) + } + + fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { + self.queries.on_disk_cache.load_diagnostics(*self, prev_dep_node_index) + } + + fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec) { + self.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics) + } + + fn profiler(&self) -> &SelfProfilerRef { + &self.prof + } +} + +fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + def_id.index == hir_id.owner.local_def_index +} + +impl rustc_query_system::HashStableContext for StableHashingContext<'_> { + fn debug_dep_tasks(&self) -> bool { + self.sess().opts.debugging_opts.dep_tasks + } +} + +impl rustc_query_system::HashStableContextProvider> for TyCtxt<'tcx> { + fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> { + self.create_stable_hashing_context() + } +} + +impl rustc_query_system::HashStableContextProvider> + for StableHashingContext<'a> +{ + fn get_stable_hashing_context(&self) -> Self { + self.clone() + } +} diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs new file mode 100644 index 00000000000..47a1c09672f --- /dev/null +++ b/src/librustc/dep_graph/safe.rs @@ -0,0 +1,9 @@ +//! The `DepGraphSafe` trait + +use crate::ty::TyCtxt; + +pub use rustc_query_system::dep_graph::{AssertDepGraphSafe, DepGraphSafe}; + +/// The type context itself can be used to access all kinds of tracked +/// state, but those accesses should always generate read events. +impl<'tcx> DepGraphSafe for TyCtxt<'tcx> {} diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 32ba13b1dbe..4cfd1f8f3c4 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -191,16 +191,3 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool false } - -impl DepNode { - /// Check whether the query invocation corresponding to the given - /// DepNode is eligible for on-disk-caching. If so, this is method - /// will execute the query corresponding to the given DepNode. - /// Also, as a sanity check, it expects that the corresponding query - /// invocation has been marked as green already. - pub fn try_load_from_on_disk_cache<'tcx>(&self, tcx: TyCtxt<'tcx>) { - use crate::dep_graph::DepKind; - - rustc_dep_node_try_load_from_on_disk_cache!(self, tcx) - } -} diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index a7dccaf974b..305e0fcc383 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -35,7 +35,7 @@ use graphviz as dot; use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; -use rustc::dep_graph::{DepGraphQuery, DepKind, DepNode}; +use rustc::dep_graph::{DepGraphQuery, DepKind, DepNode, DepNodeExt}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; use rustc_ast::ast; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index a7a272654f7..4fe23a9f7ae 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -13,7 +13,7 @@ //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. -use rustc::dep_graph::{label_strs, DepNode}; +use rustc::dep_graph::{label_strs, DepContext, DepNode, DepNodeExt}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; use rustc_ast::ast::{self, Attribute, NestedMetaItem}; @@ -382,7 +382,7 @@ impl DirtyCleanVisitor<'tcx> { } fn dep_node_str(&self, dep_node: &DepNode) -> String { - if let Some(def_id) = dep_node.extract_def_id(self.tcx) { + if let Some(def_id) = self.tcx.extract_def_id(dep_node) { format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id)) } else { format!("{:?}({:?})", dep_node.kind, dep_node.hash) diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index 56b7be2f7e2..44745434663 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -430,13 +430,13 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { try_load_from_on_disk_cache_stream.extend(quote! { DepKind::#name => { - if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY { + if <#arg as DepNodeParams>>::CAN_RECONSTRUCT_QUERY_KEY { debug_assert!($tcx.dep_graph .node_color($dep_node) .map(|c| c.is_green()) .unwrap_or(false)); - let key = <#arg as DepNodeParams>::recover($tcx, $dep_node).unwrap(); + let key = <#arg as DepNodeParams>>::recover($tcx, $dep_node).unwrap(); if queries::#name::cache_on_disk($tcx, key, None) { let _ = $tcx.#name(key); } @@ -487,8 +487,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { // Add a match arm to force the query given the dep node dep_node_force_stream.extend(quote! { DepKind::#name => { - if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY { - if let Some(key) = <#arg as DepNodeParams>::recover($tcx, $dep_node) { + if <#arg as DepNodeParams>>::CAN_RECONSTRUCT_QUERY_KEY { + if let Some(key) = <#arg as DepNodeParams>>::recover($tcx, $dep_node) { $tcx.force_query::>( key, DUMMY_SP, diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index e7e05097a54..4e086bcbb2d 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -4,7 +4,7 @@ use crate::creader::CrateMetadataRef; use crate::rmeta::table::{FixedSizeEncoding, Table}; use crate::rmeta::*; -use rustc::dep_graph::{self, DepNode, DepNodeIndex}; +use rustc::dep_graph::{self, DepNode, DepNodeExt, DepNodeIndex}; use rustc::hir::exports::Export; use rustc::middle::cstore::{CrateSource, ExternCrate}; use rustc::middle::cstore::{ForeignModule, LinkagePreference, NativeLibrary}; diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs index 9dcba30300f..c6fff2f0164 100644 --- a/src/librustc_query_system/dep_graph/dep_node.rs +++ b/src/librustc_query_system/dep_graph/dep_node.rs @@ -126,19 +126,8 @@ where /// some independent path or string that persists between runs without /// the need to be mapped or unmapped. (This ensures we can serialize /// them even in the absence of a tcx.) -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable_Generic -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(HashStable_Generic)] pub struct WorkProductId { hash: Fingerprint, } -- cgit 1.4.1-3-g733a5 From 2326ae39b262169fa853c510aa1bc795a166dc26 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Mar 2020 00:21:57 +0100 Subject: Merge ensure_node_can_be_forced into force_from_dep_node. --- src/librustc/dep_graph/mod.rs | 14 ++++++-------- src/librustc_query_system/dep_graph/graph.rs | 4 +--- src/librustc_query_system/dep_graph/mod.rs | 7 ++----- 3 files changed, 9 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 79295b2f827..d739223f6cb 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -110,10 +110,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { TyCtxt::create_stable_hashing_context(*self) } - fn force_from_dep_node(&self, node: &DepNode) -> bool { - ty::query::force_from_dep_node(*self, node) - } - /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: /// @@ -133,7 +129,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } } - fn ensure_node_can_be_forced(&self, dep_dep_node: &DepNode) -> Option<()> { + fn try_force_previous_green(&self, dep_dep_node: &DepNode) -> bool { // FIXME: This match is just a workaround for incremental bugs and should // be removed. https://github.com/rust-lang/rust/issues/62649 is one such // bug that must be fixed before removing this. @@ -162,12 +158,12 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // Since the given `DefPath` does not // denote the item that previously // existed, we just fail to mark green. - return None; + return false; } } else { // If the node does not exist anymore, we // just fail to mark green. - return None; + return false; } } _ => { @@ -175,7 +171,9 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // forced. } } - Some(()) + + debug!("try_force_previous_green({:?}) --- trying to force", dep_dep_node); + ty::query::force_from_dep_node(*self, dep_dep_node) } fn has_errors_or_delayed_span_bugs(&self) -> bool { diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index 5e004c5428a..36edf255a77 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -635,8 +635,6 @@ impl DepGraph { current_deps.push(node_index); continue; } - } else { - tcx.ensure_node_can_be_forced(dep_dep_node)?; } // We failed to mark it green, so we try to force the query. @@ -645,7 +643,7 @@ impl DepGraph { dependency {:?}", dep_node, dep_dep_node ); - if tcx.force_from_dep_node(dep_dep_node) { + if tcx.try_force_previous_green(dep_dep_node) { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index 77bc8f61293..c9983013d38 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -31,8 +31,8 @@ pub trait DepContext: Copy { /// Create a hashing context for hashing new results. fn create_stable_hashing_context(&self) -> Self::StableHashingContext; - /// Force the execution of a query given the associated `DepNode`. - fn force_from_dep_node(&self, node: &DepNode) -> bool; + /// Try to force a dep node to execute and see if it's green. + fn try_force_previous_green(&self, node: &DepNode) -> bool; /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: @@ -46,9 +46,6 @@ pub trait DepContext: Copy { /// has been removed. fn extract_def_id(&self, node: &DepNode) -> Option; - /// Check the legality of forcing this node. - fn ensure_node_can_be_forced(&self, dep_dep_node: &DepNode) -> Option<()>; - /// Return whether the current session is tainted by errors. fn has_errors_or_delayed_span_bugs(&self) -> bool; -- cgit 1.4.1-3-g733a5 From 3a8bb20230c4bb8f40aeca1d6ca3dea048b9e2e3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Mar 2020 00:27:09 +0100 Subject: Remove assert_ignored and with_ignore_deps. --- src/librustc/dep_graph/mod.rs | 18 ------------------ src/librustc_query_system/dep_graph/graph.rs | 6 ++++-- src/librustc_query_system/dep_graph/mod.rs | 8 -------- 3 files changed, 4 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index d739223f6cb..5ccc0d281db 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -62,24 +62,6 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { write!(f, ")") } - fn assert_ignored() { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); - }) - } - - fn with_ignore_deps(op: OP) -> R - where - OP: FnOnce() -> R, - { - ty::tls::with_context(|icx| { - let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }) - } - fn with_deps(task_deps: Option<&Lock>, op: OP) -> R where OP: FnOnce() -> R, diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index 36edf255a77..c012dc687d7 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -151,7 +151,9 @@ impl DepGraph { pub fn assert_ignored(&self) { if let Some(..) = self.data { - K::assert_ignored(); + K::read_deps(|task_deps| { + assert!(task_deps.is_none(), "expected no task dependency tracking"); + }) } } @@ -159,7 +161,7 @@ impl DepGraph { where OP: FnOnce() -> R, { - K::with_ignore_deps(op) + K::with_deps(None, op) } /// Starts a new dep-graph task. Dep-graph tasks are specified diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index c9983013d38..e6a927c11dd 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -76,14 +76,6 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Ord + Hash { /// Implementation of `std::fmt::Debug` for `DepNode`. fn debug_node(node: &DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result; - /// Assert the current implicit context does not track any dependency. - fn assert_ignored(); - - /// Execute the operation ignoring the dependencies. - fn with_ignore_deps(op: OP) -> R - where - OP: FnOnce() -> R; - /// Execute the operation with provided dependencies. fn with_deps(deps: Option<&Lock>>, op: OP) -> R where -- cgit 1.4.1-3-g733a5 From d08cc0ba67d9989548ae163083b7e3a3dec6b9a2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Mar 2020 09:28:37 +0100 Subject: Put extract_def_id back on DepNode. --- src/librustc/dep_graph/dep_node.rs | 27 ++++++++++++++++++++++--- src/librustc/dep_graph/mod.rs | 24 ++-------------------- src/librustc_incremental/persist/dirty_clean.rs | 4 ++-- src/librustc_query_system/dep_graph/mod.rs | 13 ------------ 4 files changed, 28 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index ee44c07d3a9..fdcc1a0db05 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -220,6 +220,18 @@ macro_rules! define_dep_nodes { /// single DefId/DefPathHash parameter. fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option; + /// Used in testing fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result; @@ -250,6 +262,15 @@ macro_rules! define_dep_nodes { /// DepNode. Condition (2) might not be fulfilled if a DepNode /// refers to something from the previous compilation session that /// has been removed. + fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option { + if self.kind.can_reconstruct_query_key() { + let def_path_hash = DefPathHash(self.hash); + tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() + } else { + None + } + } + /// Used in testing fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result { let kind = match label { @@ -316,7 +337,7 @@ impl<'tcx> DepNodeParams> for DefId { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - tcx.extract_def_id(dep_node) + dep_node.extract_def_id(tcx) } } @@ -332,7 +353,7 @@ impl<'tcx> DepNodeParams> for LocalDefId { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - tcx.extract_def_id(dep_node).map(|id| id.expect_local()) + dep_node.extract_def_id(tcx).map(|id| id.expect_local()) } } @@ -349,7 +370,7 @@ impl<'tcx> DepNodeParams> for CrateNum { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - tcx.extract_def_id(dep_node).map(|id| id.krate) + dep_node.extract_def_id(tcx).map(|id| id.krate) } } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 5ccc0d281db..47cc5f58559 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -1,4 +1,3 @@ -use crate::hir::map::definitions::DefPathHash; use crate::ich::StableHashingContext; use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; @@ -46,7 +45,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { - if let Some(def_id) = tcx.extract_def_id(node) { + if let Some(def_id) = node.extract_def_id(tcx) { write!(f, "{}", tcx.def_path_debug_str(def_id))?; } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) { write!(f, "{}", s)?; @@ -92,32 +91,13 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { TyCtxt::create_stable_hashing_context(*self) } - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - fn extract_def_id(&self, node: &DepNode) -> Option { - if node.kind.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(node.hash); - self.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() - } else { - None - } - } - fn try_force_previous_green(&self, dep_dep_node: &DepNode) -> bool { // FIXME: This match is just a workaround for incremental bugs and should // be removed. https://github.com/rust-lang/rust/issues/62649 is one such // bug that must be fixed before removing this. match dep_dep_node.kind { DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => { - if let Some(def_id) = self.extract_def_id(dep_dep_node) { + if let Some(def_id) = dep_dep_node.extract_def_id(*self) { if def_id_corresponds_to_hir_dep_node(*self, def_id) { if dep_dep_node.kind == DepKind::CrateMetadata { // The `DefPath` has corresponding node, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 4fe23a9f7ae..9ddd238afff 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -13,7 +13,7 @@ //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. -use rustc::dep_graph::{label_strs, DepContext, DepNode, DepNodeExt}; +use rustc::dep_graph::{label_strs, DepNode, DepNodeExt}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; use rustc_ast::ast::{self, Attribute, NestedMetaItem}; @@ -382,7 +382,7 @@ impl DirtyCleanVisitor<'tcx> { } fn dep_node_str(&self, dep_node: &DepNode) -> String { - if let Some(def_id) = self.tcx.extract_def_id(dep_node) { + if let Some(def_id) = dep_node.extract_def_id(self.tcx) { format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id)) } else { format!("{:?}({:?})", dep_node.kind, dep_node.hash) diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index e6a927c11dd..a54b8497fde 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -19,7 +19,6 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; use std::fmt; use std::hash::Hash; @@ -34,18 +33,6 @@ pub trait DepContext: Copy { /// Try to force a dep node to execute and see if it's green. fn try_force_previous_green(&self, node: &DepNode) -> bool; - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - fn extract_def_id(&self, node: &DepNode) -> Option; - /// Return whether the current session is tainted by errors. fn has_errors_or_delayed_span_bugs(&self) -> bool; -- cgit 1.4.1-3-g733a5 From e0f7b897bad6e5ff4a011cccc0326bdc886e9e73 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 22 Mar 2020 20:47:30 +0100 Subject: Address review. --- src/librustc/dep_graph/mod.rs | 20 +++++++++----------- src/librustc/ty/query/mod.rs | 6 ++++++ src/librustc_query_system/dep_graph/graph.rs | 18 +++++++++--------- src/librustc_query_system/dep_graph/mod.rs | 2 +- 4 files changed, 25 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 47cc5f58559..4ed2d32c23b 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -91,22 +91,22 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { TyCtxt::create_stable_hashing_context(*self) } - fn try_force_previous_green(&self, dep_dep_node: &DepNode) -> bool { + fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool { // FIXME: This match is just a workaround for incremental bugs and should // be removed. https://github.com/rust-lang/rust/issues/62649 is one such // bug that must be fixed before removing this. - match dep_dep_node.kind { + match dep_node.kind { DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => { - if let Some(def_id) = dep_dep_node.extract_def_id(*self) { + if let Some(def_id) = dep_node.extract_def_id(*self) { if def_id_corresponds_to_hir_dep_node(*self, def_id) { - if dep_dep_node.kind == DepKind::CrateMetadata { + if dep_node.kind == DepKind::CrateMetadata { // The `DefPath` has corresponding node, // and that node should have been marked // either red or green in `data.colors`. bug!( "DepNode {:?} should have been \ pre-marked as red or green but wasn't.", - dep_dep_node + dep_node ); } } else { @@ -134,8 +134,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } } - debug!("try_force_previous_green({:?}) --- trying to force", dep_dep_node); - ty::query::force_from_dep_node(*self, dep_dep_node) + debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); + ty::query::force_from_dep_node(*self, dep_node) } fn has_errors_or_delayed_span_bugs(&self) -> bool { @@ -148,10 +148,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // Interactions with on_disk_cache fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { - use crate::mir::interpret::GlobalId; - use crate::ty::query::queries; - use crate::ty::query::QueryDescription; - rustc_dep_node_try_load_from_on_disk_cache!(dep_node, *self) + use crate::ty::query::try_load_from_on_disk_cache; + try_load_from_on_disk_cache(*self, dep_node) } fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 4cfd1f8f3c4..a59824f684d 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -191,3 +191,9 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool false } + +pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) { + use crate::dep_graph::DepKind; + + rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx) +} diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index c012dc687d7..7352551559c 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -13,8 +13,8 @@ use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use std::env; use std::hash::Hash; +use std::marker::PhantomData; use std::mem; -use std::panic as bug; use std::sync::atomic::Ordering::Relaxed; use super::debug::EdgeFilter; @@ -215,7 +215,7 @@ impl DepGraph { node: Some(_key), reads: SmallVec::new(), read_set: Default::default(), - phantom_data: std::marker::PhantomData, + phantom_data: PhantomData, }) }, |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), @@ -367,7 +367,7 @@ impl DepGraph { std::mem::drop(map); data.read_index(dep_node_index); } else { - bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind) + panic!("DepKind {:?} should be pre-allocated but isn't.", v.kind) } } } @@ -645,7 +645,7 @@ impl DepGraph { dependency {:?}", dep_node, dep_dep_node ); - if tcx.try_force_previous_green(dep_dep_node) { + if tcx.try_force_from_dep_node(dep_dep_node) { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { @@ -667,7 +667,7 @@ impl DepGraph { } None => { if !tcx.has_errors_or_delayed_span_bugs() { - bug!( + panic!( "try_mark_previous_green() - Forcing the DepNode \ should have set its color" ) @@ -948,7 +948,7 @@ impl CurrentDepGraph { match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { Ok(s) => match EdgeFilter::new(&s) { Ok(f) => Some(f), - Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), + Err(err) => panic!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), }, Err(_) => None, } @@ -1074,7 +1074,7 @@ impl DepGraphData { if let Some(ref forbidden_edge) = self.current.forbidden_edge { let source = data[source].node; if forbidden_edge.test(&source, &target) { - bug!("forbidden edge {:?} -> {:?} created", source, target) + panic!("forbidden edge {:?} -> {:?} created", source, target) } } } @@ -1096,7 +1096,7 @@ pub struct TaskDeps { node: Option>, reads: EdgesVec, read_set: FxHashSet, - phantom_data: std::marker::PhantomData>, + phantom_data: PhantomData>, } impl Default for TaskDeps { @@ -1106,7 +1106,7 @@ impl Default for TaskDeps { node: None, reads: EdgesVec::new(), read_set: FxHashSet::default(), - phantom_data: std::marker::PhantomData, + phantom_data: PhantomData, } } } diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index a54b8497fde..825b341cd14 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -31,7 +31,7 @@ pub trait DepContext: Copy { fn create_stable_hashing_context(&self) -> Self::StableHashingContext; /// Try to force a dep node to execute and see if it's green. - fn try_force_previous_green(&self, node: &DepNode) -> bool; + fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool; /// Return whether the current session is tainted by errors. fn has_errors_or_delayed_span_bugs(&self) -> bool; -- cgit 1.4.1-3-g733a5 From 9f4c8889e51cf60641b42b7e43bfdf048dbd692d Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 23 Mar 2020 00:16:00 +0100 Subject: Fully qualify the path to DepKind. This is needed since `middle::cstore` defines another type named `DepKind`, and we should not rely on shadowing to get the right one. --- src/librustc/ty/query/mod.rs | 12 ++++-------- src/librustc_macros/src/query.rs | 6 +++--- 2 files changed, 7 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index a59824f684d..b45b3b3f539 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -150,8 +150,6 @@ rustc_query_append! { [define_queries!][<'tcx>] } /// add it to the "We don't have enough information to reconstruct..." group in /// the match below. pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool { - use crate::dep_graph::DepKind; - // We must avoid ever having to call `force_from_dep_node()` for a // `DepNode::codegen_unit`: // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we @@ -166,7 +164,7 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool // hit the cache instead of having to go through `force_from_dep_node`. // This assertion makes sure, we actually keep applying the solution above. debug_assert!( - dep_node.kind != DepKind::codegen_unit, + dep_node.kind != crate::dep_graph::DepKind::codegen_unit, "calling force_from_dep_node() on DepKind::codegen_unit" ); @@ -177,14 +175,14 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool rustc_dep_node_force!([dep_node, tcx] // These are inputs that are expected to be pre-allocated and that // should therefore always be red or green already. - DepKind::CrateMetadata | + crate::dep_graph::DepKind::CrateMetadata | // These are anonymous nodes. - DepKind::TraitSelect | + crate::dep_graph::DepKind::TraitSelect | // We don't have enough information to reconstruct the query key of // these. - DepKind::CompileCodegenUnit => { + crate::dep_graph::DepKind::CompileCodegenUnit => { bug!("force_from_dep_node: encountered {:?}", dep_node) } ); @@ -193,7 +191,5 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool } pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) { - use crate::dep_graph::DepKind; - rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx) } diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index 44745434663..e7005f2f5ba 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -429,7 +429,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { }); try_load_from_on_disk_cache_stream.extend(quote! { - DepKind::#name => { + ::rustc::dep_graph::DepKind::#name => { if <#arg as DepNodeParams>>::CAN_RECONSTRUCT_QUERY_KEY { debug_assert!($tcx.dep_graph .node_color($dep_node) @@ -486,7 +486,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { // Add a match arm to force the query given the dep node dep_node_force_stream.extend(quote! { - DepKind::#name => { + ::rustc::dep_graph::DepKind::#name => { if <#arg as DepNodeParams>>::CAN_RECONSTRUCT_QUERY_KEY { if let Some(key) = <#arg as DepNodeParams>>::recover($tcx, $dep_node) { $tcx.force_query::>( @@ -509,7 +509,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { } dep_node_force_stream.extend(quote! { - DepKind::Null => { + ::rustc::dep_graph::DepKind::Null => { bug!("Cannot force dep node: {:?}", $dep_node) } }); -- cgit 1.4.1-3-g733a5 From 0f918cba3ff48216a140db4fd06e2ea13abc78c9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 23 Mar 2020 07:28:53 +0100 Subject: Move import. --- src/librustc/dep_graph/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 4ed2d32c23b..3c39597584d 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -1,4 +1,5 @@ use crate::ich::StableHashingContext; +use crate::ty::query::try_load_from_on_disk_cache; use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; @@ -148,7 +149,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // Interactions with on_disk_cache fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { - use crate::ty::query::try_load_from_on_disk_cache; try_load_from_on_disk_cache(*self, dep_node) } -- cgit 1.4.1-3-g733a5 From 9b1893f310d185478a0980a7367d5fbc9affcbcc Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Mar 2020 00:16:05 +0100 Subject: Run rustfmt --- src/librustc/ty/sty.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 73fe15d9a17..cfd99cbbb9f 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2411,7 +2411,10 @@ impl<'tcx> Const<'tcx> { let body_id = match tcx.hir().get(hir_id) { hir::Node::AnonConst(ac) => ac.body, - _ => span_bug!(tcx.def_span(def_id.to_def_id()), "from_anon_const can only process anonymous constants"), + _ => span_bug!( + tcx.def_span(def_id.to_def_id()), + "from_anon_const can only process anonymous constants" + ), }; let expr = &tcx.hir().body(body_id).value; -- cgit 1.4.1-3-g733a5