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