mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-30 13:06:28 +03:00
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:
+17
@@ -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
@@ -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.
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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() })
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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("'_"));
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
mod operand;
|
||||
mod operator;
|
||||
mod place;
|
||||
pub(crate) mod snapshot; // for const_eval
|
||||
mod step;
|
||||
mod terminator;
|
||||
mod traits;
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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,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 }
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@
|
||||
},
|
||||
Repeat {
|
||||
value: ExprRef<'tcx>,
|
||||
count: u64,
|
||||
count: &'tcx Const<'tcx>,
|
||||
},
|
||||
Array {
|
||||
fields: Vec<ExprRef<'tcx>>,
|
||||
|
||||
@@ -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> {}
|
||||
+17
-6
@@ -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];
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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!(),
|
||||
},
|
||||
|
||||
@@ -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!(),
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(..)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user