Auto merge of #70343 - Centril:rollup-94egfvs, r=Centril

Rollup of 11 pull requests

Successful merges:

 - #67761 (Move the dep_graph construction to a dedicated crate.)
 - #69740 (Replace some desc logic in librustc_lint with article_and_desc)
 - #69981 (Evaluate repeat expression lengths as late as possible)
 - #70087 (Remove const eval loop detector)
 - #70242 (Improve E0308 error message wording)
 - #70264 (Fix invalid suggestion on `&mut` iterators yielding `&` references)
 - #70267 (get rid of ConstPropUnsupported; use ZST marker structs instead)
 - #70277 (Remove `ReClosureBound`)
 - #70283 (Add regression test for #70155.)
 - #70294 (Account for bad placeholder types in where clauses)
 - #70309 (Clean up E0452 explanation)

Failed merges:

r? @ghost
This commit is contained in:
bors
2020-03-24 00:53:25 +00:00
127 changed files with 1969 additions and 1937 deletions
+17
View File
@@ -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"
+1 -1
View File
@@ -164,7 +164,7 @@ pub fn is<T: Any>(&self) -> bool {
// Get `TypeId` of the type this function is instantiated with.
let t = TypeId::of::<T>();
// 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.
+1
View File
@@ -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" }
+47 -143
View File
@@ -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::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 @@ pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
// tuple args
$({
return <$tuple_arg_ty as DepNodeParams>
return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>>
::CAN_RECONSTRUCT_QUERY_KEY;
})*
@@ -212,20 +212,39 @@ pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode {
)*
}
#[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<DepKind>;
impl 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.
pub fn from_def_path_hash(def_path_hash: DefPathHash,
kind: DepKind)
-> DepNode {
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<DefId>;
/// Used in testing
fn from_label_string(label: &str, def_path_hash: DefPathHash)
-> Result<Self, ()>;
/// Used in testing
fn has_label_string(label: &str) -> bool;
}
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.
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 +252,6 @@ pub fn from_def_path_hash(def_path_hash: DefPathHash,
}
}
/// 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 +262,17 @@ pub fn new_no_params(kind: DepKind) -> DepNode {
/// 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<DefId> {
fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
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()
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<DepNode, ()> {
fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
let kind = match label {
$(
stringify!($variant) => DepKind::$variant,
@@ -287,7 +292,7 @@ pub fn from_label_string(label: &str,
}
/// 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 +313,6 @@ pub mod label_strs {
);
}
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 +325,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
[] 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<Self>;
}
impl<'tcx, T> DepNodeParams<'tcx> for T
where
T: HashStable<StableHashingContext<'tcx>> + 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<Self> {
None
}
}
impl<'tcx> DepNodeParams<'tcx> for DefId {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> 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
}
@@ -413,10 +341,10 @@ fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
}
}
impl<'tcx> DepNodeParams<'tcx> for LocalDefId {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> 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)
}
@@ -429,10 +357,10 @@ fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
}
}
impl<'tcx> DepNodeParams<'tcx> for CrateNum {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> 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
}
@@ -446,13 +374,13 @@ fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
}
}
impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) {
impl<'tcx> DepNodeParams<TyCtxt<'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 {
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 +396,13 @@ fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
}
}
impl<'tcx> DepNodeParams<'tcx> for HirId {
impl<'tcx> DepNodeParams<TyCtxt<'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 {
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 +411,3 @@ fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
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 }
}
}
+190 -16
View File
@@ -1,17 +1,191 @@
pub mod debug;
mod dep_node;
mod graph;
mod prev;
mod query;
mod safe;
mod serialized;
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;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::DefId;
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};
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<DepKind>;
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph<DepKind>;
pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
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) = 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)?;
} else {
write!(f, "{}", node.hash)?;
}
} else {
write!(f, "{}", node.hash)?;
}
Ok(())
})?;
write!(f, ")")
}
fn with_deps<OP, R>(task_deps: Option<&Lock<TaskDeps>>, 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: OP) -> ()
where
OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps>>) -> (),
{
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 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_node.kind {
DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => {
if let Some(def_id) = dep_node.extract_def_id(*self) {
if def_id_corresponds_to_hir_dep_node(*self, def_id) {
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_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 false;
}
} else {
// If the node does not exist anymore, we
// just fail to mark green.
return false;
}
}
_ => {
// For other kinds of nodes it's OK to be
// forced.
}
}
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 {
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) {
try_load_from_on_disk_cache(*self, dep_node)
}
fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> {
self.queries.on_disk_cache.load_diagnostics(*self, prev_dep_node_index)
}
fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>) {
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<StableHashingContext<'tcx>> for TyCtxt<'tcx> {
fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
self.create_stable_hashing_context()
}
}
impl rustc_query_system::HashStableContextProvider<StableHashingContext<'a>>
for StableHashingContext<'a>
{
fn get_stable_hashing_context(&self) -> Self {
self.clone()
}
}
+1 -49
View File
@@ -2,56 +2,8 @@
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 {}
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> {}
/// Tuples make it easy to build up state.
impl<A, B> 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<T>(pub T);
impl<T> DepGraphSafe for AssertDepGraphSafe<T> {}
-3
View File
@@ -92,9 +92,6 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
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)
}
+36 -18
View File
@@ -14,7 +14,7 @@
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, fmt, mem};
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
pub enum ErrorHandled {
@@ -449,9 +449,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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.
@@ -470,9 +467,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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)
}
@@ -494,8 +488,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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.
StepLimitReached,
}
impl fmt::Debug for ResourceExhaustionInfo {
@@ -505,15 +501,36 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
StackFrameLimitReached => {
write!(f, "reached the configured maximum number of stack frames")
}
InfiniteLoop => write!(
f,
"duplicate interpreter state observed here, const evaluation will never \
terminate"
),
StepLimitReached => {
write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
}
}
}
}
/// A trait to work around not having trait object upcasting.
pub trait AsAny: Any {
fn as_any(&self) -> &dyn Any;
}
impl<T: Any> 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: AsAny + fmt::Debug + Send {}
impl MachineStopType for String {}
impl dyn MachineStopType {
#[inline(always)]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.as_any().downcast_ref()
}
}
pub enum InterpError<'tcx> {
/// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo),
@@ -527,7 +544,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<dyn Any + Send>),
MachineStop(Box<dyn MachineStopType>),
}
pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
@@ -547,7 +564,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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),
}
}
}
@@ -558,8 +575,9 @@ impl InterpError<'_> {
/// waste of resources.
pub fn allocates(&self) -> bool {
match self {
InterpError::MachineStop(_)
| InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
// Zero-sized boxes do not allocate.
InterpError::MachineStop(b) => mem::size_of_val::<dyn MachineStopType>(&**b) > 0,
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
_ => false,
+3 -3
View File
@@ -97,8 +97,8 @@ macro_rules! throw_machine_stop {
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};
@@ -156,7 +156,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,
+23 -332
View File
@@ -45,6 +45,7 @@
mod query;
pub mod tcx;
pub mod traversal;
mod type_foldable;
pub mod visit;
/// Types for locals
@@ -2046,7 +2047,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>),
@@ -2174,7 +2175,11 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
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)
@@ -2542,18 +2547,26 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
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;
}
@@ -2651,325 +2664,3 @@ pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) ->
}
}
}
/*
* `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<F: TypeFolder<'tcx>>(&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<V: TypeVisitor<'tcx>>(&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<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.local.visit_with(visitor) || self.projection.visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
folder.tcx().intern_place_elems(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
}
impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&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<V: TypeVisitor<'tcx>>(&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<F: TypeFolder<'tcx>>(&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<V: TypeVisitor<'tcx>>(&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<F: TypeFolder<'tcx>>(&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<Vs: TypeVisitor<'tcx>>(&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<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
self.clone()
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.literal.visit_with(visitor)
}
}
+24 -25
View File
@@ -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(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
/// &'<erased> 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
+3 -1
View File
@@ -149,7 +149,9 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'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() })
+322
View File
@@ -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<F: TypeFolder<'tcx>>(&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<V: TypeVisitor<'tcx>>(&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<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.local.visit_with(visitor) || self.projection.visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
folder.tcx().intern_place_elems(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
}
impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&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<V: TypeVisitor<'tcx>>(&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<F: TypeFolder<'tcx>>(&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<V: TypeVisitor<'tcx>>(&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<F: TypeFolder<'tcx>>(&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<Vs: TypeVisitor<'tcx>>(&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<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
self.clone()
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.literal.visit_with(visitor)
}
}
+1 -7
View File
@@ -1574,7 +1574,7 @@ fn region_should_not_be_omitted(&self, region: ty::Region<'_>) -> bool {
ty::ReVar(_) | ty::ReScope(_) | ty::ReErased => false,
ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true,
ty::ReStatic | ty::ReEmpty(_) => true,
}
}
@@ -1686,12 +1686,6 @@ pub fn pretty_print_region(mut self, region: ty::Region<'_>) -> Result<Self, fmt
p!(write("'<empty:{:?}>", ui));
return Ok(self);
}
// The user should never encounter these in unsubstituted form.
ty::ReClosureBound(vid) => {
p!(write("{:?}", vid));
return Ok(self);
}
}
p!(write("'_"));
+6 -17
View File
@@ -150,8 +150,6 @@
/// 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)
}
);
@@ -192,15 +190,6 @@ 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)
}
pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx)
}
-2
View File
@@ -81,8 +81,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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)
}
+87 -12
View File
@@ -8,7 +8,7 @@
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, InternalSubsts, Subst, SubstsRef};
@@ -20,7 +20,7 @@
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};
@@ -1352,12 +1352,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> {}
@@ -1567,7 +1561,6 @@ pub fn has_name(&self) -> bool {
RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
RegionKind::ReEmpty(_) => false,
RegionKind::ReErased => false,
RegionKind::ReClosureBound(..) => false,
}
}
@@ -1648,9 +1641,6 @@ pub fn type_flags(&self) -> TypeFlags {
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;
}
@@ -2275,17 +2265,92 @@ pub struct Const<'tcx> {
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_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
debug!("Const::from_anon_const(id={:?})", def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(def_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;
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 {
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, "Const::from_anon_const: couldn't lit_to_const");
}
}
// 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,
};
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.to_def_id(),
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
None,
),
};
tcx.mk_const(ty::Const { val, ty })
}
#[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)
@@ -2295,21 +2360,27 @@ pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'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>,
@@ -2323,6 +2394,8 @@ pub fn try_eval_bits(
}
#[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);
@@ -2379,12 +2452,14 @@ pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Op
}
#[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
}
+3
View File
@@ -106,6 +106,9 @@ pub fn codegen_rvalue(
}
}
let count =
self.monomorphize(&count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
bx.write_operand_repeatedly(cg_elem, count, dest)
}
@@ -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.
@@ -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
+1 -1
View File
@@ -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;
@@ -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, DepNode, DepNodeExt};
use rustc::hir::map::Map;
use rustc::ty::TyCtxt;
use rustc_ast::ast::{self, Attribute, NestedMetaItem};
@@ -336,10 +336,6 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'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");
}
}
}
-4
View File
@@ -581,10 +581,6 @@ fn regions(
return Ok(r);
}
ty::ReClosureBound(..) => {
span_bug!(self.span, "encountered unexpected ReClosureBound: {:?}", r,);
}
ty::RePlaceholder(..)
| ty::ReVar(..)
| ty::ReEmpty(_)
@@ -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);
-4
View File
@@ -135,10 +135,6 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
// replace all free regions with 'erased
self.tcx().lifetimes.re_erased
}
ty::ReClosureBound(..) => {
bug!("encountered unexpected region: {:?}", r,);
}
}
}
@@ -493,12 +493,7 @@ fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
/// 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);
}
@@ -798,7 +798,7 @@ pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
| 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),
}
}
+37 -33
View File
@@ -349,6 +349,7 @@ fn check_missing_docs_attrs(
id: Option<hir::HirId>,
attrs: &[ast::Attribute],
sp: Span,
article: &'static str,
desc: &'static str,
) {
// If we're building a test harness, then warning about
@@ -374,7 +375,7 @@ fn check_missing_docs_attrs(
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 @@ fn exit_lint_attrs(&mut self, _: &LateContext<'_, '_>, _attrs: &[ast::Attribute]
}
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, "the", "crate");
for macro_def in krate.exported_macros {
let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
@@ -413,12 +414,7 @@ fn check_crate(&mut self, cx: &LateContext<'_, '_>, krate: &hir::Crate<'_>) {
}
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 +424,39 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
}
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, article, desc);
}
fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::TraitItem<'_>) {
@@ -462,17 +464,15 @@ fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::Trait
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,
article,
desc,
);
}
@@ -483,29 +483,33 @@ fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, impl_item: &hir::ImplIte
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,
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");
}
}
+7 -7
View File
@@ -429,14 +429,14 @@ 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 {
::rustc::dep_graph::DepKind::#name => {
if <#arg as DepNodeParams<TyCtxt<'_>>>::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<TyCtxt<'_>>>::recover($tcx, $dep_node).unwrap();
if queries::#name::cache_on_disk($tcx, key, None) {
let _ = $tcx.#name(key);
}
@@ -486,9 +486,9 @@ 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) {
::rustc::dep_graph::DepKind::#name => {
if <#arg as DepNodeParams<TyCtxt<'_>>>::CAN_RECONSTRUCT_QUERY_KEY {
if let Some(key) = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node) {
$tcx.force_query::<crate::ty::query::queries::#name<'_>>(
key,
DUMMY_SP,
@@ -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)
}
});
+1 -1
View File
@@ -4,7 +4,7 @@
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};
@@ -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 @@ pub(crate) fn report_mutability_error(
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 @@ pub(crate) fn report_mutability_error(
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 @@ pub(crate) fn report_mutability_error(
))) => {
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 @@ pub(crate) fn report_mutability_error(
_ => 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<Span>,
opt_ty_info: Option<Span>,
) -> (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() }))
@@ -292,8 +292,7 @@ fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
| ty::ReVar(..)
| ty::RePlaceholder(..)
| ty::ReEmpty(_)
| ty::ReErased
| ty::ReClosureBound(..) => None,
| ty::ReErased => None,
}
}
@@ -940,8 +940,9 @@ fn try_promote_type_test(
/// 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 @@ fn try_promote_type_test_subject(
// 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 @@ fn apply_requirements(
closure_def_id: DefId,
closure_substs: SubstsRef<'tcx>,
) -> Vec<QueryOutlivesConstraint<'tcx>>;
fn subst_closure_mapping<T>(
&self,
tcx: TyCtxt<'tcx>,
closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
value: &T,
) -> T
where
T: TypeFoldable<'tcx>;
}
impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx> {
@@ -2094,7 +2086,6 @@ fn apply_requirements(
}
ClosureOutlivesSubject::Ty(ty) => {
let ty = self.subst_closure_mapping(tcx, closure_mapping, &ty);
debug!(
"apply_requirements: ty={:?} \
outlived_region={:?} \
@@ -2107,22 +2098,4 @@ fn apply_requirements(
})
.collect()
}
fn subst_closure_mapping<T>(
&self,
tcx: TyCtxt<'tcx>,
closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
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)
}
})
}
}
@@ -1986,7 +1986,11 @@ fn check_rvalue(
}
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`.
+20 -47
View File
@@ -3,7 +3,6 @@
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::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 @@ fn hook_panic_fn(
}
}
/// 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 @@ fn get_mut_or<E>(&mut self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Resu
}
}
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 @@ fn may_leak(self) -> bool {
}
}
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 = !;
@@ -345,26 +327,17 @@ fn box_alloc(
}
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!(StepLimitReached)
}
let span = ecx.frame().span;
ecx.machine.loop_detector.observe_and_analyze(*ecx.tcx, span, &ecx.memory, &ecx.stack[..])
Ok(())
}
#[inline(always)]
-19
View File
@@ -112,25 +112,6 @@ fn data_layout(&self) -> &TargetDataLayout {
}
}
// 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<AllocId, (MemoryKind<M::MemoryKinds>, 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 {
-1
View File
@@ -9,7 +9,6 @@
mod operand;
mod operator;
mod place;
pub(crate) mod snapshot; // for const_eval
mod step;
mod terminator;
mod traits;
-420
View File
@@ -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<u64>,
/// 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<InterpSnapshot<'mir, 'tcx>>,
}
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::<u64>();
// 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<T>
where
Ctx: SnapshotContext<'a>,
T: Snapshot<'a, Ctx>,
{
type Item = Option<<T as Snapshot<'a, Ctx>>::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<AllocationSnapshot<'a>>);
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<Place<(), AllocIdSnapshot<'a>>>,
locals: IndexVec<mir::Local, LocalValue<(), AllocIdSnapshot<'a>>>,
block: Option<mir::BasicBlock>,
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<Frame<'mir, 'tcx>>,
}
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<FrameSnapshot<'b, 'tcx>> {
// 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<H: Hasher>(&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::<u64>().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()
}
}
+24 -9
View File
@@ -39,6 +39,24 @@
/// 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,7 +210,7 @@ fn call_intrinsic(
_ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
_unwind: Option<BasicBlock>,
) -> InterpResult<'tcx> {
throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp"))
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
}
fn assert_panic(
@@ -204,7 +222,7 @@ fn assert_panic(
}
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(
@@ -214,10 +232,7 @@ fn binary_ptr_op(
_right: ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
// 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_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
}
#[inline(always)]
@@ -238,7 +253,7 @@ fn box_alloc(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_dest: PlaceTy<'tcx>,
) -> InterpResult<'tcx> {
throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword"))
throw_machine_stop_str!("can't const prop heap allocations")
}
fn access_local(
@@ -249,7 +264,7 @@ fn access_local(
let l = &frame.locals[local];
if l.value == LocalValue::Uninitialized {
throw_unsup!(ConstPropUnsupported("tried to access an uninitialized local"));
throw_machine_stop_str!("tried to access an uninitialized local")
}
l.access()
@@ -262,7 +277,7 @@ fn before_access_static(
// 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_str!("can't eval mutable statics in ConstProp")
}
Ok(())
+3 -29
View File
@@ -3,7 +3,7 @@
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,8 @@ 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_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 }
}
+1 -1
View File
@@ -229,7 +229,7 @@
},
Repeat {
value: ExprRef<'tcx>,
count: u64,
count: &'tcx Const<'tcx>,
},
Array {
fields: Vec<ExprRef<'tcx>>,
+22
View File
@@ -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"] }
@@ -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 @@ pub fn accepts_all(&self) -> bool {
}
/// Tests whether `node` meets the filter, returning true if so.
pub fn test(&self, node: &DepNode) -> bool {
pub fn test<K: DepKind>(&self, node: &DepNode<K>) -> bool {
let debug_str = format!("{:?}", node);
self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f))
}
@@ -52,7 +52,7 @@ pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> {
}
}
pub fn test(&self, source: &DepNode, target: &DepNode) -> bool {
pub fn test<K: DepKind>(&self, source: &DepNode<K>, target: &DepNode<K>) -> bool {
self.source.test(source) && self.target.test(target)
}
}
@@ -0,0 +1,146 @@
//! 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 `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`:
//!
//! * 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.
use super::{DepContext, DepKind};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::HashStable_Generic;
use std::fmt;
use std::hash::Hash;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct DepNode<K> {
pub kind: K,
pub hash: Fingerprint,
}
impl<K: DepKind> DepNode<K> {
/// 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<K> {
debug_assert!(!kind.has_params());
DepNode { kind, hash: Fingerprint::ZERO }
}
}
impl<K: DepKind> fmt::Debug for DepNode<K> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
K::debug_node(self, f)
}
}
pub trait DepNodeParams<Ctxt: DepContext>: 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, _: Ctxt) -> Fingerprint {
panic!("Not implemented. Accidentally called on anonymous node?")
}
fn to_debug_str(&self, _: Ctxt) -> 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: Ctxt, dep_node: &DepNode<Ctxt::DepKind>) -> Option<Self>;
}
impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
where
T: HashStable<Ctxt::StableHashingContext> + fmt::Debug,
{
default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
default fn to_fingerprint(&self, tcx: Ctxt) -> 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, _: Ctxt) -> String {
format!("{:?}", *self)
}
default fn recover(_: Ctxt, _: &DepNode<Ctxt::DepKind>) -> Option<Self> {
None
}
}
/// 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_Generic)]
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 }
}
}
@@ -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::marker::PhantomData;
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};
use super::{DepContext, DepKind, DepNode, WorkProductId};
use crate::{HashStableContext, HashStableContextProvider};
#[derive(Clone)]
pub struct DepGraph {
data: Option<Lrc<DepGraphData>>,
pub struct DepGraph<K: DepKind> {
data: Option<Lrc<DepGraphData<K>>>,
/// 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 @@ pub fn is_green(self) -> bool {
}
}
struct DepGraphData {
struct DepGraphData<K: DepKind> {
/// 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<K>,
/// 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<K>,
colors: DepNodeColorMap,
@@ -90,12 +91,12 @@ struct DepGraphData {
/// this map. We can later look for and extract that data.
previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
dep_node_debug: Lock<FxHashMap<DepNode, String>>,
dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
}
pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint>
pub fn hash_result<HashCtxt, R>(hcx: &mut HashCtxt, result: &R) -> Option<Fingerprint>
where
R: for<'a> HashStable<StableHashingContext<'a>>,
R: HashStable<HashCtxt>,
{
let mut stable_hasher = StableHasher::new();
result.hash_stable(hcx, &mut stable_hasher);
@@ -103,11 +104,11 @@ pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<
Some(stable_hasher.finish())
}
impl DepGraph {
impl<K: DepKind> DepGraph<K> {
pub fn new(
prev_graph: PreviousDepGraph,
prev_graph: PreviousDepGraph<K>,
prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
) -> DepGraph {
) -> DepGraph<K> {
let prev_graph_node_count = prev_graph.node_count();
DepGraph {
@@ -124,7 +125,7 @@ pub fn new(
}
}
pub fn new_disabled() -> DepGraph {
pub fn new_disabled() -> DepGraph<K> {
DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
}
@@ -134,7 +135,7 @@ pub fn is_fully_enabled(&self) -> bool {
self.data.is_some()
}
pub fn query(&self) -> DepGraphQuery {
pub fn query(&self) -> DepGraphQuery<K> {
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,9 +151,8 @@ pub fn query(&self) -> DepGraphQuery {
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::read_deps(|task_deps| {
assert!(task_deps.is_none(), "expected no task dependency tracking");
})
}
}
@@ -161,11 +161,7 @@ pub fn with_ignore<OP, R>(&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())
})
K::with_deps(None, op)
}
/// Starts a new dep-graph task. Dep-graph tasks are specified
@@ -195,16 +191,17 @@ pub fn with_ignore<OP, R>(&self, op: OP) -> R
/// `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<H, C, A, R>(
&self,
key: DepNode,
key: DepNode<K>,
cx: C,
arg: A,
task: fn(C, A) -> R,
hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
hash_result: impl FnOnce(&mut H, &R) -> Option<Fingerprint>,
) -> (R, DepNodeIndex)
where
C: DepGraphSafe + StableHashingContextProvider<'a>,
C: DepGraphSafe + HashStableContextProvider<H>,
H: HashStableContext,
{
self.with_task_impl(
key,
@@ -218,6 +215,7 @@ pub fn with_task<'a, C, A, R>(
node: Some(_key),
reads: SmallVec::new(),
read_set: Default::default(),
phantom_data: PhantomData,
})
},
|data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint),
@@ -225,24 +223,25 @@ pub fn with_task<'a, C, A, R>(
)
}
fn with_task_impl<'a, C, A, R>(
fn with_task_impl<H, C, A, R>(
&self,
key: DepNode,
key: DepNode<K>,
cx: C,
arg: A,
no_tcx: bool,
task: fn(C, A) -> R,
create_task: fn(DepNode) -> Option<TaskDeps>,
create_task: fn(DepNode<K>) -> Option<TaskDeps<K>>,
finish_task_and_alloc_depnode: fn(
&CurrentDepGraph,
DepNode,
&CurrentDepGraph<K>,
DepNode<K>,
Fingerprint,
Option<TaskDeps>,
Option<TaskDeps<K>>,
) -> DepNodeIndex,
hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
hash_result: impl FnOnce(&mut H, &R) -> Option<Fingerprint>,
) -> (R, DepNodeIndex)
where
C: DepGraphSafe + StableHashingContextProvider<'a>,
C: DepGraphSafe + HashStableContextProvider<H>,
H: HashStableContext,
{
if let Some(ref data) = self.data {
let task_deps = create_task(key).map(Lock::new);
@@ -257,12 +256,7 @@ fn with_task_impl<'a, C, A, R>(
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 +268,7 @@ fn with_task_impl<'a, C, A, R>(
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 +316,16 @@ fn with_task_impl<'a, C, A, R>(
/// 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<OP, R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex)
pub fn with_anon_task<OP, R>(&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 task_deps = Lock::new(TaskDeps::default());
let r = {
let icx = ty::tls::ImplicitCtxt { task_deps: Some(&task_deps), ..icx.clone() };
let result = K::with_deps(Some(&task_deps), op);
let task_deps = task_deps.into_inner();
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 {
@@ -347,16 +335,17 @@ pub fn with_anon_task<OP, R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeInd
/// 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<H, C, A, R>(
&self,
key: DepNode,
key: DepNode<K>,
cx: C,
arg: A,
task: fn(C, A) -> R,
hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
hash_result: impl FnOnce(&mut H, &R) -> Option<Fingerprint>,
) -> (R, DepNodeIndex)
where
C: DepGraphSafe + StableHashingContextProvider<'a>,
C: DepGraphSafe + HashStableContextProvider<H>,
H: HashStableContext,
{
self.with_task_impl(
key,
@@ -371,14 +360,14 @@ pub fn with_eval_always_task<'a, C, A, R>(
}
#[inline]
pub fn read(&self, v: DepNode) {
pub fn read(&self, v: DepNode<K>) {
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)
panic!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
}
}
}
@@ -391,7 +380,7 @@ pub fn read_index(&self, dep_node_index: DepNodeIndex) {
}
#[inline]
pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex {
pub fn dep_node_index_of(&self, dep_node: &DepNode<K>) -> DepNodeIndex {
self.data
.as_ref()
.unwrap()
@@ -405,7 +394,7 @@ pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex {
}
#[inline]
pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
if let Some(ref data) = self.data {
data.current
.node_to_node_index
@@ -423,12 +412,12 @@ pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint {
data[dep_node_index].fingerprint
}
pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
pub fn prev_fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
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<K>) -> SerializedDepNodeIndex {
self.data.as_ref().unwrap().previous.node_to_index(dep_node)
}
@@ -445,7 +434,7 @@ pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> {
}
#[inline(always)]
pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode, debug_str_gen: F)
pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F)
where
F: FnOnce() -> String,
{
@@ -458,7 +447,7 @@ pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode, debug_str_gen: F
dep_node_debug.borrow_mut().insert(dep_node, debug_str);
}
pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option<String> {
pub fn dep_node_debug_str(&self, dep_node: DepNode<K>) -> Option<String> {
self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned()
}
@@ -475,7 +464,7 @@ pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> {
}
}
pub fn serialize(&self) -> SerializedDepGraph {
pub fn serialize(&self) -> SerializedDepGraph<K> {
let data = self.data.as_ref().unwrap().current.data.lock();
let fingerprints: IndexVec<SerializedDepNodeIndex, _> =
@@ -503,7 +492,7 @@ pub fn serialize(&self) -> SerializedDepGraph {
SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data }
}
pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
pub fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> {
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 +510,10 @@ pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
/// 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<Ctxt: DepContext<DepKind = K>>(
&self,
tcx: TyCtxt<'_>,
dep_node: &DepNode,
tcx: Ctxt,
dep_node: &DepNode<K>,
) -> 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 +522,10 @@ pub fn try_mark_green_and_read(
})
}
pub fn try_mark_green(
pub fn try_mark_green<Ctxt: DepContext<DepKind = K>>(
&self,
tcx: TyCtxt<'_>,
dep_node: &DepNode,
tcx: Ctxt,
dep_node: &DepNode<K>,
) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
debug_assert!(!dep_node.kind.is_eval_always());
@@ -561,12 +550,12 @@ pub fn try_mark_green(
}
/// 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<Ctxt: DepContext<DepKind = K>>(
&self,
tcx: TyCtxt<'tcx>,
data: &DepGraphData,
tcx: Ctxt,
data: &DepGraphData<K>,
prev_dep_node_index: SerializedDepNodeIndex,
dep_node: &DepNode,
dep_node: &DepNode<K>,
) -> Option<DepNodeIndex> {
debug!("try_mark_previous_green({:?}) - BEGIN", dep_node);
@@ -648,50 +637,6 @@ fn try_mark_previous_green<'tcx>(
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.
@@ -700,7 +645,7 @@ fn try_mark_previous_green<'tcx>(
dependency {:?}",
dep_node, dep_dep_node
);
if crate::ty::query::force_from_dep_node(tcx, 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 {
@@ -721,8 +666,8 @@ fn try_mark_previous_green<'tcx>(
return None;
}
None => {
if !tcx.sess.has_errors_or_delayed_span_bugs() {
bug!(
if !tcx.has_errors_or_delayed_span_bugs() {
panic!(
"try_mark_previous_green() - Forcing the DepNode \
should have set its color"
)
@@ -779,7 +724,7 @@ fn try_mark_previous_green<'tcx>(
// 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 @@ fn try_mark_previous_green<'tcx>(
/// This may be called concurrently on multiple threads for the same dep node.
#[cold]
#[inline(never)]
fn emit_diagnostics<'tcx>(
fn emit_diagnostics<Ctxt: DepContext<DepKind = K>>(
&self,
tcx: TyCtxt<'tcx>,
data: &DepGraphData,
tcx: Ctxt,
data: &DepGraphData<K>,
dep_node_index: DepNodeIndex,
prev_dep_node_index: SerializedDepNodeIndex,
diagnostics: Vec<Diagnostic>,
@@ -827,9 +772,9 @@ fn emit_diagnostics<'tcx>(
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 @@ fn emit_diagnostics<'tcx>(
// 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<K>) -> bool {
self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false)
}
@@ -870,15 +815,15 @@ pub fn is_green(&self, dep_node: &DepNode) -> bool {
//
// 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<Ctxt: DepContext<DepKind = K>>(&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 @@ fn next_virtual_depnode_index(&self) -> DepNodeIndex {
}
}
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<K> {
node: DepNode<K>,
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<IndexVec<DepNodeIndex, DepNodeData>>,
node_to_node_index: Sharded<FxHashMap<DepNode, DepNodeIndex>>,
pub(super) struct CurrentDepGraph<K> {
data: Lock<IndexVec<DepNodeIndex, DepNodeData<K>>>,
node_to_node_index: Sharded<FxHashMap<DepNode<K>, 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<K: DepKind> CurrentDepGraph<K> {
fn new(prev_graph_node_count: usize) -> CurrentDepGraph<K> {
use std::time::{SystemTime, UNIX_EPOCH};
let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
@@ -1008,7 +948,7 @@ fn new(prev_graph_node_count: usize) -> 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,
}
@@ -1039,14 +979,14 @@ fn new(prev_graph_node_count: usize) -> CurrentDepGraph {
fn complete_task(
&self,
node: DepNode,
task_deps: TaskDeps,
node: DepNode<K>,
task_deps: TaskDeps<K>,
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<K>) -> DepNodeIndex {
debug_assert!(!kind.is_eval_always());
let mut hasher = StableHasher::new();
@@ -1072,7 +1012,7 @@ fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex
fn alloc_node(
&self,
dep_node: DepNode,
dep_node: DepNode<K>,
edges: EdgesVec,
fingerprint: Fingerprint,
) -> DepNodeIndex {
@@ -1084,7 +1024,7 @@ fn alloc_node(
fn intern_node(
&self,
dep_node: DepNode,
dep_node: DepNode<K>,
edges: EdgesVec,
fingerprint: Fingerprint,
) -> DepNodeIndex {
@@ -1101,12 +1041,11 @@ fn intern_node(
}
}
impl DepGraphData {
impl<K: DepKind> DepGraphData<K> {
#[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) {
@@ -1135,7 +1074,7 @@ fn read_index(&self, source: DepNodeIndex) {
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)
}
}
}
@@ -1151,12 +1090,25 @@ fn read_index(&self, source: DepNodeIndex) {
/// 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<K> {
#[cfg(debug_assertions)]
node: Option<DepNode>,
node: Option<DepNode<K>>,
reads: EdgesVec,
read_set: FxHashSet<DepNodeIndex>,
phantom_data: PhantomData<DepNode<K>>,
}
impl<K> Default for TaskDeps<K> {
fn default() -> Self {
Self {
#[cfg(debug_assertions)]
node: None,
reads: EdgesVec::new(),
read_set: FxHashSet::default(),
phantom_data: PhantomData,
}
}
}
// A data structure that stores Option<DepNodeColor> values as a contiguous
@@ -0,0 +1,75 @@
pub mod debug;
mod dep_node;
mod graph;
mod prev;
mod query;
mod safe;
mod serialized;
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 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;
/// Try to force a dep node to execute and see if it's green.
fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
/// 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<Self::DepKind>);
/// Load diagnostics associated to the node in the previous session.
fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic>;
/// Register diagnostics for the given node, for use in next session.
fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>);
/// 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<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
/// Execute the operation with provided dependencies.
fn with_deps<OP, R>(deps: Option<&Lock<TaskDeps<Self>>>, op: OP) -> R
where
OP: FnOnce() -> R;
/// Access dependencies from current implicit context.
fn read_deps<OP>(op: OP) -> ()
where
OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>) -> ();
}
@@ -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<DepNode, SerializedDepNodeIndex>,
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct PreviousDepGraph<K: DepKind> {
data: SerializedDepGraph<K>,
index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
}
impl PreviousDepGraph {
pub fn new(data: SerializedDepGraph) -> PreviousDepGraph {
impl<K: DepKind> Default for PreviousDepGraph<K> {
fn default() -> Self {
PreviousDepGraph { data: Default::default(), index: Default::default() }
}
}
impl<K: DepKind> PreviousDepGraph<K> {
pub fn new(data: SerializedDepGraph<K>) -> PreviousDepGraph<K> {
let index: FxHashMap<_, _> =
data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
PreviousDepGraph { data, index }
@@ -25,22 +31,22 @@ pub fn edge_targets_from(
}
#[inline]
pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode {
pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
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<K>) -> SerializedDepNodeIndex {
self.index[dep_node]
}
#[inline]
pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
self.index.get(dep_node).cloned()
}
#[inline]
pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index])
}
@@ -3,15 +3,15 @@
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
use super::DepNode;
use super::{DepKind, DepNode};
pub struct DepGraphQuery {
pub graph: Graph<DepNode, ()>,
pub indices: FxHashMap<DepNode, NodeIndex>,
pub struct DepGraphQuery<K> {
pub graph: Graph<DepNode<K>, ()>,
pub indices: FxHashMap<DepNode<K>, NodeIndex>,
}
impl DepGraphQuery {
pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery {
impl<K: DepKind> DepGraphQuery<K> {
pub fn new(nodes: &[DepNode<K>], edges: &[(DepNode<K>, DepNode<K>)]) -> DepGraphQuery<K> {
let mut graph = Graph::with_capacity(nodes.len(), edges.len());
let mut indices = FxHashMap::default();
for node in nodes {
@@ -27,15 +27,15 @@ pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery {
DepGraphQuery { graph, indices }
}
pub fn contains_node(&self, node: &DepNode) -> bool {
pub fn contains_node(&self, node: &DepNode<K>) -> bool {
self.indices.contains_key(&node)
}
pub fn nodes(&self) -> Vec<&DepNode> {
pub fn nodes(&self) -> Vec<&DepNode<K>> {
self.graph.all_nodes().iter().map(|n| &n.data).collect()
}
pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> {
pub fn edges(&self) -> Vec<(&DepNode<K>, &DepNode<K>)> {
self.graph
.all_edges()
.iter()
@@ -44,7 +44,7 @@ pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> {
.collect()
}
fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> {
fn reachable_nodes(&self, node: &DepNode<K>, direction: Direction) -> Vec<&DepNode<K>> {
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 @@ fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode>
/// 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<K>) -> Vec<&DepNode<K>> {
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<K>) -> Vec<&DepNode<K>> {
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<K>) -> Vec<&DepNode<K>> {
if let Some(&index) = self.indices.get(&node) {
self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect()
} else {
@@ -0,0 +1,51 @@
//! The `DepGraphSafe` trait
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 {}
/// Tuples make it easy to build up state.
impl<A, B> 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<T>(pub T);
impl<T> DepGraphSafe for AssertDepGraphSafe<T> {}
@@ -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 @@ pub struct SerializedDepNodeIndex { .. }
}
/// Data for use when recompiling the **current crate**.
#[derive(Debug, RustcEncodable, RustcDecodable, Default)]
pub struct SerializedDepGraph {
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedDepGraph<K: DepKind> {
/// The set of all DepNodes in the graph
pub nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
/// 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<SerializedDepNodeIndex, Fingerprint>,
@@ -25,7 +25,18 @@ pub struct SerializedDepGraph {
pub edge_list_data: Vec<SerializedDepNodeIndex>,
}
impl SerializedDepGraph {
impl<K: DepKind> Default for SerializedDepGraph<K> {
fn default() -> Self {
SerializedDepGraph {
nodes: Default::default(),
fingerprints: Default::default(),
edge_list_indices: Default::default(),
edge_list_data: Default::default(),
}
}
}
impl<K: DepKind> SerializedDepGraph<K> {
#[inline]
pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] {
let targets = self.edge_list_indices[source];
+32
View File
@@ -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<Ctxt> {
fn get_stable_hashing_context(&self) -> Ctxt;
}
impl<Ctxt, T: HashStableContextProvider<Ctxt>> HashStableContextProvider<Ctxt> for &T {
fn get_stable_hashing_context(&self) -> Ctxt {
(**self).get_stable_hashing_context()
}
}
impl<Ctxt, T: HashStableContextProvider<Ctxt>> HashStableContextProvider<Ctxt> for &mut T {
fn get_stable_hashing_context(&self) -> Ctxt {
(**self).get_stable_hashing_context()
}
}
+1 -5
View File
@@ -816,11 +816,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'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.
+19 -94
View File
@@ -20,9 +20,9 @@
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_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::iter;
use std::slice;
use rustc::mir::interpret::LitToConstInput;
#[derive(Debug)]
pub struct PathSeg(pub DefId, pub usize);
@@ -782,7 +780,8 @@ fn create_substs_for_ast_path<'a>(
}
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
self.ast_const_to_const(&ct.value, 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!(),
},
@@ -838,18 +837,6 @@ fn create_substs_for_ast_path<'a>(
}
},
);
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,
@@ -2747,7 +2734,13 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
}
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)
@@ -2775,7 +2768,8 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
.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_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)
}
@@ -2807,75 +2801,6 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
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<DefId> {
// 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,
@@ -2930,7 +2855,7 @@ pub fn ty_of_fn(
unsafety: hir::Unsafety,
abi: abi::Abi,
decl: &hir::FnDecl<'_>,
generic_params: &[hir::GenericParam<'_>],
generics: &hir::Generics<'_>,
ident_span: Option<Span>,
) -> ty::PolyFnSig<'tcx> {
debug!("ty_of_fn");
@@ -2942,6 +2867,8 @@ pub fn ty_of_fn(
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) => {
@@ -2963,7 +2890,7 @@ pub fn ty_of_fn(
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(),
);
@@ -2989,8 +2916,7 @@ pub fn ty_of_fn(
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 {
@@ -3001,8 +2927,7 @@ pub fn ty_of_fn(
// 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();
+3 -19
View File
@@ -18,7 +18,6 @@
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;
@@ -1008,13 +1007,7 @@ fn check_expr_repeat(
_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 = 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);
let uty = match expected {
ExpectHasType(uty) => match uty.kind {
@@ -1042,17 +1035,8 @@ fn check_expr_repeat(
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(
+1 -1
View File
@@ -331,7 +331,7 @@ fn instantiate_method_substs(
}
(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!(),
},
+12 -9
View File
@@ -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)
};
@@ -3279,13 +3286,9 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'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<DefId> {
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)
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
@@ -5512,7 +5515,7 @@ pub fn instantiate_value_path(
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!(),
},
+12 -10
View File
@@ -1486,7 +1486,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),
),
}
@@ -1497,14 +1497,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);
@@ -2127,7 +2122,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
-1
View File
@@ -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(..)
@@ -449,7 +449,6 @@ fn add_constraints_from_region(
}
ty::ReFree(..)
| ty::ReClosureBound(..)
| ty::ReScope(..)
| ty::ReVar(..)
| ty::RePlaceholder(..)
-1
View File
@@ -450,7 +450,6 @@ fn clean(&self, cx: &DocContext<'_>) -> Option<Lifetime> {
| ty::ReVar(..)
| ty::RePlaceholder(..)
| ty::ReEmpty(_)
| ty::ReClosureBound(_)
| ty::ReErased => {
debug!("cannot clean region {:?}", self);
None
+1 -6
View File
@@ -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`
}
@@ -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)]
@@ -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
}
}
@@ -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`.
+1
View File
@@ -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
}
+10 -2
View File
@@ -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 `[(); _]`
Some errors have detailed explanations: E0282, E0658.
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0282, E0308, E0658.
For more information about an error, try `rustc --explain E0282`.
@@ -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<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; N]
//~^ ERROR array lengths can't depend on generic parameters
}
fn main() {
@@ -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
@@ -2,13 +2,12 @@
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; {N}]
//~^ ERROR array lengths can't depend on generic parameters
[x; { N }]
}
fn g<T, const N: usize>(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() {
@@ -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`
|
LL | [x; {N}]
| ^^^
help: consider restricting this type parameter with `T: std::marker::Copy`
--> $DIR/issue-61336-2.rs:8:6
|
LL | fn g<T, const N: usize>(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`.
@@ -3,12 +3,11 @@
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; N]
//~^ ERROR array lengths can't depend on generic parameters
}
fn g<T, const N: usize>(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() {
@@ -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<T, const N: usize>(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`.
@@ -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<const N: usize>() {
let _ = [0u64; N + 1];
//~^ ERROR array lengths can't depend on generic parameters
}
fn main() {}
@@ -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
@@ -16,7 +16,7 @@ impl<const X: usize> HasSize for ArrayHolder<{ X }> {
impl<const X: usize> ArrayHolder<{ X }> {
pub const fn new() -> Self {
ArrayHolder([0; Self::SIZE])
//~^ ERROR: array lengths can't depend on generic parameters
//~^ ERROR: mismatched types
}
}
@@ -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`.
@@ -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::<Self::Associated>()];
//~^ ERROR: array lengths can't depend on generic parameters
0
}
}
@@ -1,8 +0,0 @@
error: array lengths can't depend on generic parameters
--> $DIR/issue-67739.rs:12:15
|
LL | [0u8; mem::size_of::<Self::Associated>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
@@ -0,0 +1,30 @@
// check-pass
#![allow(incomplete_features)]
#![feature(const_generics)]
// `Range` should be usable within const generics:
struct _Range<const R: std::ops::Range<usize>>;
const RANGE : _Range<{ 0 .. 1000 }> = _Range;
// `RangeFrom` should be usable within const generics:
struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
const RANGE_FROM : _RangeFrom<{ 0 .. }> = _RangeFrom;
// `RangeFull` should be usable within const generics:
struct _RangeFull<const R: std::ops::RangeFull>;
const RANGE_FULL : _RangeFull<{ .. }> = _RangeFull;
// Regression test for #70155
// `RangeInclusive` should be usable within const generics:
struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
const RANGE_INCLUSIVE : _RangeInclusive<{ 0 ..= 999 }> = _RangeInclusive;
// `RangeTo` should be usable within const generics:
struct _RangeTo<const R: std::ops::RangeTo<usize>>;
const RANGE_TO : _RangeTo<{ .. 1000 }> = _RangeTo;
// `RangeToInclusive` should be usable within const generics:
struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
const RANGE_TO_INCLUSIVE : _RangeToInclusive<{ ..= 999 }> = _RangeToInclusive;
pub fn main() {}
@@ -19,6 +19,7 @@
: [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[..]);
@@ -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; _]`
For more information about this error, try `rustc --explain E0080`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0308.
For more information about an error, try `rustc --explain E0080`.
@@ -18,6 +18,7 @@
= [0; (i8::MAX + 1u8) as usize];
//~^ ERROR mismatched types
//~| ERROR cannot add `u8` to `i8`
//~| ERROR mismatched types
fn main() {
foo(&A_I8_I[..]);
@@ -12,7 +12,16 @@ LL | = [0; (i8::MAX + 1u8) as usize];
|
= help: the trait `std::ops::Add<u8>` 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`.
@@ -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`
@@ -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 <https://github.com/rust-lang/rust/issues/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 step limit (see `#[const_eval_limit]`)
error: aborting due to 3 previous errors
+1 -3
View File
@@ -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`
}
@@ -7,22 +7,6 @@ LL | [(); { &loop { break } as *const _ as usize } ];
= note: see issue #52000 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/51910> for more information
= help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
error: aborting due to previous error
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
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`.
@@ -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 {
@@ -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 step limit (see `#[const_eval_limit]`)
error: aborting due to 2 previous errors
@@ -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`
@@ -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; _]`
Some errors have detailed explanations: E0080, E0658.
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0080, E0308, E0658.
For more information about an error, try `rustc --explain E0080`.
@@ -1,15 +1,21 @@
// check-pass
#![feature(const_eval_limit)]
#![const_eval_limit="1000"]
const CONSTANT: usize = limit();
#![feature(const_eval_limit)]
#![feature(const_loop, const_if_match)]
// 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"]
const X: usize = {
let mut x = 0;
while x != 1000 {
x += 1;
}
x
};
fn main() {
assert_eq!(CONSTANT, 1764);
}
const fn limit() -> usize {
let x = 42;
x * 42
assert_eq!(X, 1000);
}
@@ -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"]
const X: usize = {
let mut x = 0;
while x != 1000 {
//~^ ERROR any use of this value will cause an error
x += 1;
}
x
};
fn main() {
assert_eq!(CONSTANT, 1764);
}
const fn limit() -> usize { //~ WARNING Constant evaluating a complex constant, this might take some time
let x = 42;
x * 42
assert_eq!(X, 1000);
}
@@ -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 step limit (see `#[const_eval_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
-1
View File
@@ -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
}
+3 -9
View File
@@ -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 3 previous errors
error: aborting due to 4 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`.
@@ -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() {}
@@ -7,6 +7,7 @@ pub fn crash() -> bool {
[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}; _]`
}
}

Some files were not shown because too many files have changed in this diff Show More