Merge branch 'master' into drop
This commit is contained in:
commit
43cc32fbb2
3017 changed files with 7141 additions and 3254 deletions
13
RELEASES.md
13
RELEASES.md
|
|
@ -1,3 +1,16 @@
|
|||
Version 1.29.1 (2018-09-25)
|
||||
===========================
|
||||
|
||||
Security Notes
|
||||
--------------
|
||||
|
||||
- The standard library's `str::repeat` function contained an out of bounds write
|
||||
caused by an integer overflow. This has been fixed by deterministically
|
||||
panicking when an overflow happens.
|
||||
|
||||
Thank you to Scott McMurray for responsibily disclosing this vulnerability to
|
||||
us.
|
||||
|
||||
Version 1.29.0 (2018-09-13)
|
||||
==========================
|
||||
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ dependencies = [
|
|||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -2372,6 +2373,7 @@ dependencies = [
|
|||
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_codegen_utils 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_target 0.0.0",
|
||||
"rustc_typeck 0.0.0",
|
||||
|
|
|
|||
167
src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md
Normal file
167
src/doc/unstable-book/src/compiler-flags/emit-stack-sizes.md
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
# `emit-stack-sizes`
|
||||
|
||||
The tracking issue for this feature is: [#54192]
|
||||
|
||||
[#54192]: https://github.com/rust-lang/rust/issues/54192
|
||||
|
||||
------------------------
|
||||
|
||||
The rustc flag `-Z emit-stack-sizes` makes LLVM emit stack size metadata.
|
||||
|
||||
> **NOTE**: This LLVM feature only supports the ELF object format as of LLVM
|
||||
> 8.0. Using this flag with targets that use other object formats (e.g. macOS
|
||||
> and Windows) will result in it being ignored.
|
||||
|
||||
Consider this crate:
|
||||
|
||||
```
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::ptr;
|
||||
|
||||
pub fn foo() {
|
||||
// this function doesn't use the stack
|
||||
}
|
||||
|
||||
pub fn bar() {
|
||||
let xs = [0u32; 2];
|
||||
|
||||
// force LLVM to allocate `xs` on the stack
|
||||
unsafe { ptr::read_volatile(&xs.as_ptr()); }
|
||||
}
|
||||
```
|
||||
|
||||
Using the `-Z emit-stack-sizes` flag produces extra linker sections in the
|
||||
output *object file*.
|
||||
|
||||
``` console
|
||||
$ rustc -C opt-level=3 --emit=obj foo.rs
|
||||
|
||||
$ size -A foo.o
|
||||
foo.o :
|
||||
section size addr
|
||||
.text 0 0
|
||||
.text._ZN3foo3foo17he211d7b4a3a0c16eE 1 0
|
||||
.text._ZN3foo3bar17h1acb594305f70c2eE 22 0
|
||||
.note.GNU-stack 0 0
|
||||
.eh_frame 72 0
|
||||
Total 95
|
||||
|
||||
$ rustc -C opt-level=3 --emit=obj -Z emit-stack-sizes foo.rs
|
||||
|
||||
$ size -A foo.o
|
||||
foo.o :
|
||||
section size addr
|
||||
.text 0 0
|
||||
.text._ZN3foo3foo17he211d7b4a3a0c16eE 1 0
|
||||
.stack_sizes 9 0
|
||||
.text._ZN3foo3bar17h1acb594305f70c2eE 22 0
|
||||
.stack_sizes 9 0
|
||||
.note.GNU-stack 0 0
|
||||
.eh_frame 72 0
|
||||
Total 113
|
||||
```
|
||||
|
||||
As of LLVM 7.0 the data will be written into a section named `.stack_sizes` and
|
||||
the format is "an array of pairs of function symbol values (pointer size) and
|
||||
stack sizes (unsigned LEB128)".
|
||||
|
||||
``` console
|
||||
$ objdump -d foo.o
|
||||
|
||||
foo.o: file format elf64-x86-64
|
||||
|
||||
Disassembly of section .text._ZN3foo3foo17he211d7b4a3a0c16eE:
|
||||
|
||||
0000000000000000 <_ZN3foo3foo17he211d7b4a3a0c16eE>:
|
||||
0: c3 retq
|
||||
|
||||
Disassembly of section .text._ZN3foo3bar17h1acb594305f70c2eE:
|
||||
|
||||
0000000000000000 <_ZN3foo3bar17h1acb594305f70c2eE>:
|
||||
0: 48 83 ec 10 sub $0x10,%rsp
|
||||
4: 48 8d 44 24 08 lea 0x8(%rsp),%rax
|
||||
9: 48 89 04 24 mov %rax,(%rsp)
|
||||
d: 48 8b 04 24 mov (%rsp),%rax
|
||||
11: 48 83 c4 10 add $0x10,%rsp
|
||||
15: c3 retq
|
||||
|
||||
$ objdump -s -j .stack_sizes foo.o
|
||||
|
||||
foo.o: file format elf64-x86-64
|
||||
|
||||
Contents of section .stack_sizes:
|
||||
0000 00000000 00000000 00 .........
|
||||
Contents of section .stack_sizes:
|
||||
0000 00000000 00000000 10 .........
|
||||
```
|
||||
|
||||
It's important to note that linkers will discard this linker section by default.
|
||||
To preserve the section you can use a linker script like the one shown below.
|
||||
|
||||
``` text
|
||||
/* file: keep-stack-sizes.x */
|
||||
SECTIONS
|
||||
{
|
||||
/* `INFO` makes the section not allocatable so it won't be loaded into memory */
|
||||
.stack_sizes (INFO) :
|
||||
{
|
||||
KEEP(*(.stack_sizes));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The linker script must be passed to the linker using a rustc flag like `-C
|
||||
link-arg`.
|
||||
|
||||
```
|
||||
// file: src/main.rs
|
||||
use std::ptr;
|
||||
|
||||
#[inline(never)]
|
||||
fn main() {
|
||||
let xs = [0u32; 2];
|
||||
|
||||
// force LLVM to allocate `xs` on the stack
|
||||
unsafe { ptr::read_volatile(&xs.as_ptr()); }
|
||||
}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ RUSTFLAGS="-Z emit-stack-sizes" cargo build --release
|
||||
|
||||
$ size -A target/release/hello | grep stack_sizes || echo section was not found
|
||||
section was not found
|
||||
|
||||
$ RUSTFLAGS="-Z emit-stack-sizes" cargo rustc --release -- \
|
||||
-C link-arg=-Wl,-Tkeep-stack-sizes.x \
|
||||
-C link-arg=-N
|
||||
|
||||
$ size -A target/release/hello | grep stack_sizes
|
||||
.stack_sizes 90 176272
|
||||
|
||||
$ # non-allocatable section (flags don't contain the "A" (alloc) flag)
|
||||
$ readelf -S target/release/hello
|
||||
Section Headers:
|
||||
[Nr] Name Type Address Offset
|
||||
Size EntSize Flags Link Info Align
|
||||
(..)
|
||||
[1031] .stack_sizes PROGBITS 000000000002b090 0002b0f0
|
||||
000000000000005a 0000000000000000 L 5 0 1
|
||||
|
||||
$ objdump -s -j .stack_sizes target/release/hello
|
||||
|
||||
target/release/hello: file format elf64-x86-64
|
||||
|
||||
Contents of section .stack_sizes:
|
||||
2b090 c0040000 00000000 08f00400 00000000 ................
|
||||
2b0a0 00080005 00000000 00000810 05000000 ................
|
||||
2b0b0 00000000 20050000 00000000 10400500 .... ........@..
|
||||
2b0c0 00000000 00087005 00000000 00000080 ......p.........
|
||||
2b0d0 05000000 00000000 90050000 00000000 ................
|
||||
2b0e0 00a00500 00000000 0000 ..........
|
||||
```
|
||||
|
||||
> Author note: I'm not entirely sure why, in *this* case, `-N` is required in
|
||||
> addition to `-Tkeep-stack-sizes.x`. For example, it's not required when
|
||||
> producing statically linked files for the ARM Cortex-M architecture.
|
||||
|
|
@ -322,11 +322,8 @@ class RustStdBTreeSetPrinter(object):
|
|||
def children(self):
|
||||
(length, data_ptr) = \
|
||||
rustpp.extract_length_and_ptr_from_std_btreeset(self.__val)
|
||||
leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference())
|
||||
maybe_uninit_keys = leaf_node.get_child_at_index(3)
|
||||
manually_drop_keys = maybe_uninit_keys.get_child_at_index(1)
|
||||
keys = manually_drop_keys.get_child_at_index(0)
|
||||
gdb_ptr = keys.get_wrapped_value()
|
||||
val = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
|
||||
gdb_ptr = val.get_wrapped_value()
|
||||
for index in xrange(length):
|
||||
yield (str(index), gdb_ptr[index])
|
||||
|
||||
|
|
@ -348,14 +345,9 @@ class RustStdBTreeMapPrinter(object):
|
|||
def children(self):
|
||||
(length, data_ptr) = \
|
||||
rustpp.extract_length_and_ptr_from_std_btreemap(self.__val)
|
||||
leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference())
|
||||
maybe_uninit_keys = leaf_node.get_child_at_index(3)
|
||||
manually_drop_keys = maybe_uninit_keys.get_child_at_index(1)
|
||||
keys = manually_drop_keys.get_child_at_index(0)
|
||||
keys = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
|
||||
keys_ptr = keys.get_wrapped_value()
|
||||
maybe_uninit_vals = leaf_node.get_child_at_index(4)
|
||||
manually_drop_vals = maybe_uninit_vals.get_child_at_index(1)
|
||||
vals = manually_drop_vals.get_child_at_index(0)
|
||||
vals = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(4)
|
||||
vals_ptr = vals.get_wrapped_value()
|
||||
for index in xrange(length):
|
||||
yield (str(index), keys_ptr[index])
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
// This implies that even an empty internal node has at least one edge.
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{self, MaybeUninit};
|
||||
use core::mem;
|
||||
use core::ptr::{self, Unique, NonNull};
|
||||
use core::slice;
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ struct LeafNode<K, V> {
|
|||
/// This node's index into the parent node's `edges` array.
|
||||
/// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`.
|
||||
/// This is only guaranteed to be initialized when `parent` is nonnull.
|
||||
parent_idx: MaybeUninit<u16>,
|
||||
parent_idx: u16,
|
||||
|
||||
/// The number of keys and values this node stores.
|
||||
///
|
||||
|
|
@ -83,8 +83,8 @@ struct LeafNode<K, V> {
|
|||
|
||||
/// The arrays storing the actual data of the node. Only the first `len` elements of each
|
||||
/// array are initialized and valid.
|
||||
keys: MaybeUninit<[K; CAPACITY]>,
|
||||
vals: MaybeUninit<[V; CAPACITY]>,
|
||||
keys: [K; CAPACITY],
|
||||
vals: [V; CAPACITY],
|
||||
}
|
||||
|
||||
impl<K, V> LeafNode<K, V> {
|
||||
|
|
@ -94,10 +94,10 @@ impl<K, V> LeafNode<K, V> {
|
|||
LeafNode {
|
||||
// As a general policy, we leave fields uninitialized if they can be, as this should
|
||||
// be both slightly faster and easier to track in Valgrind.
|
||||
keys: MaybeUninit::uninitialized(),
|
||||
vals: MaybeUninit::uninitialized(),
|
||||
keys: mem::uninitialized(),
|
||||
vals: mem::uninitialized(),
|
||||
parent: ptr::null(),
|
||||
parent_idx: MaybeUninit::uninitialized(),
|
||||
parent_idx: mem::uninitialized(),
|
||||
len: 0
|
||||
}
|
||||
}
|
||||
|
|
@ -115,10 +115,10 @@ unsafe impl Sync for LeafNode<(), ()> {}
|
|||
// ever take a pointer past the first key.
|
||||
static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
|
||||
parent: ptr::null(),
|
||||
parent_idx: MaybeUninit::uninitialized(),
|
||||
parent_idx: 0,
|
||||
len: 0,
|
||||
keys: MaybeUninit::uninitialized(),
|
||||
vals: MaybeUninit::uninitialized(),
|
||||
keys: [(); CAPACITY],
|
||||
vals: [(); CAPACITY],
|
||||
};
|
||||
|
||||
/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
|
||||
|
|
@ -430,7 +430,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
|||
root: self.root,
|
||||
_marker: PhantomData
|
||||
},
|
||||
idx: unsafe { usize::from(*self.as_leaf().parent_idx.get_ref()) },
|
||||
idx: self.as_leaf().parent_idx as usize,
|
||||
_marker: PhantomData
|
||||
})
|
||||
} else {
|
||||
|
|
@ -567,7 +567,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
|
|||
// the node, which is allowed by LLVM.
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
self.as_leaf().keys.as_ptr() as *const K,
|
||||
self.as_leaf().keys.as_ptr(),
|
||||
self.len()
|
||||
)
|
||||
}
|
||||
|
|
@ -578,7 +578,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
|
|||
debug_assert!(!self.is_shared_root());
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
self.as_leaf().vals.as_ptr() as *const V,
|
||||
self.as_leaf().vals.as_ptr(),
|
||||
self.len()
|
||||
)
|
||||
}
|
||||
|
|
@ -605,7 +605,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
|||
} else {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
self.as_leaf_mut().keys.get_mut() as *mut [K] as *mut K,
|
||||
&mut self.as_leaf_mut().keys as *mut [K] as *mut K,
|
||||
self.len()
|
||||
)
|
||||
}
|
||||
|
|
@ -616,7 +616,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
|||
debug_assert!(!self.is_shared_root());
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
self.as_leaf_mut().vals.get_mut() as *mut [V] as *mut V,
|
||||
&mut self.as_leaf_mut().vals as *mut [V] as *mut V,
|
||||
self.len()
|
||||
)
|
||||
}
|
||||
|
|
@ -1013,7 +1013,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
|
|||
let ptr = self.node.as_internal_mut() as *mut _;
|
||||
let mut child = self.descend();
|
||||
child.as_leaf_mut().parent = ptr;
|
||||
child.as_leaf_mut().parent_idx.set(idx);
|
||||
child.as_leaf_mut().parent_idx = idx;
|
||||
}
|
||||
|
||||
/// Unsafely asserts to the compiler some static information about whether the underlying
|
||||
|
|
@ -1152,12 +1152,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV>
|
|||
|
||||
ptr::copy_nonoverlapping(
|
||||
self.node.keys().as_ptr().add(self.idx + 1),
|
||||
new_node.keys.as_mut_ptr() as *mut K,
|
||||
new_node.keys.as_mut_ptr(),
|
||||
new_len
|
||||
);
|
||||
ptr::copy_nonoverlapping(
|
||||
self.node.vals().as_ptr().add(self.idx + 1),
|
||||
new_node.vals.as_mut_ptr() as *mut V,
|
||||
new_node.vals.as_mut_ptr(),
|
||||
new_len
|
||||
);
|
||||
|
||||
|
|
@ -1210,12 +1210,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
|
|||
|
||||
ptr::copy_nonoverlapping(
|
||||
self.node.keys().as_ptr().add(self.idx + 1),
|
||||
new_node.data.keys.as_mut_ptr() as *mut K,
|
||||
new_node.data.keys.as_mut_ptr(),
|
||||
new_len
|
||||
);
|
||||
ptr::copy_nonoverlapping(
|
||||
self.node.vals().as_ptr().add(self.idx + 1),
|
||||
new_node.data.vals.as_mut_ptr() as *mut V,
|
||||
new_node.data.vals.as_mut_ptr(),
|
||||
new_len
|
||||
);
|
||||
ptr::copy_nonoverlapping(
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@
|
|||
#![feature(rustc_const_unstable)]
|
||||
#![feature(const_vec_new)]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(maybe_uninit)]
|
||||
|
||||
// Allow testing this library
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
|
||||
use mem::MaybeUninit;
|
||||
use mem;
|
||||
use num::flt2dec;
|
||||
|
||||
// Don't inline this so callers don't use the stack space this function
|
||||
|
|
@ -20,11 +20,11 @@ fn float_to_decimal_common_exact<T>(fmt: &mut Formatter, num: &T,
|
|||
where T: flt2dec::DecodableFloat
|
||||
{
|
||||
unsafe {
|
||||
let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64
|
||||
let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized();
|
||||
let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64
|
||||
let mut parts: [flt2dec::Part; 4] = mem::uninitialized();
|
||||
let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact,
|
||||
*num, sign, precision,
|
||||
false, buf.get_mut(), parts.get_mut());
|
||||
false, &mut buf, &mut parts);
|
||||
fmt.pad_formatted_parts(&formatted)
|
||||
}
|
||||
}
|
||||
|
|
@ -38,11 +38,10 @@ fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter, num: &T,
|
|||
{
|
||||
unsafe {
|
||||
// enough for f32 and f64
|
||||
let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized();
|
||||
let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized();
|
||||
let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized();
|
||||
let mut parts: [flt2dec::Part; 4] = mem::uninitialized();
|
||||
let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num,
|
||||
sign, precision, false, buf.get_mut(),
|
||||
parts.get_mut());
|
||||
sign, precision, false, &mut buf, &mut parts);
|
||||
fmt.pad_formatted_parts(&formatted)
|
||||
}
|
||||
}
|
||||
|
|
@ -76,11 +75,11 @@ fn float_to_exponential_common_exact<T>(fmt: &mut Formatter, num: &T,
|
|||
where T: flt2dec::DecodableFloat
|
||||
{
|
||||
unsafe {
|
||||
let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64
|
||||
let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized();
|
||||
let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64
|
||||
let mut parts: [flt2dec::Part; 6] = mem::uninitialized();
|
||||
let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact,
|
||||
*num, sign, precision,
|
||||
upper, buf.get_mut(), parts.get_mut());
|
||||
upper, &mut buf, &mut parts);
|
||||
fmt.pad_formatted_parts(&formatted)
|
||||
}
|
||||
}
|
||||
|
|
@ -95,11 +94,11 @@ fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter,
|
|||
{
|
||||
unsafe {
|
||||
// enough for f32 and f64
|
||||
let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized();
|
||||
let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized();
|
||||
let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized();
|
||||
let mut parts: [flt2dec::Part; 6] = mem::uninitialized();
|
||||
let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest,
|
||||
*num, sign, (0, 0), upper,
|
||||
buf.get_mut(), parts.get_mut());
|
||||
&mut buf, &mut parts);
|
||||
fmt.pad_formatted_parts(&formatted)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,8 +246,6 @@ macro_rules! test_v512 { ($item:item) => {}; }
|
|||
#[allow(unused_macros)]
|
||||
macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } }
|
||||
#[path = "../stdsimd/coresimd/mod.rs"]
|
||||
// replacing uses of mem::{uninitialized,zeroed} with MaybeUninit needs to be in the stdsimd repo
|
||||
#[allow(deprecated)]
|
||||
#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)]
|
||||
#[unstable(feature = "stdsimd", issue = "48556")]
|
||||
#[cfg(not(stage0))] // allow changes to how stdsimd works in stage0
|
||||
|
|
|
|||
|
|
@ -293,21 +293,21 @@ where
|
|||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<'a, P: fmt::Debug> fmt::Debug for Pin<P> {
|
||||
impl<P: fmt::Debug> fmt::Debug for Pin<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.pointer, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<'a, P: fmt::Display> fmt::Display for Pin<P> {
|
||||
impl<P: fmt::Display> fmt::Display for Pin<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.pointer, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<'a, P: fmt::Pointer> fmt::Pointer for Pin<P> {
|
||||
impl<P: fmt::Pointer> fmt::Pointer for Pin<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Pointer::fmt(&self.pointer, f)
|
||||
}
|
||||
|
|
@ -319,10 +319,10 @@ impl<'a, P: fmt::Pointer> fmt::Pointer for Pin<P> {
|
|||
// for other reasons, though, so we just need to take care not to allow such
|
||||
// impls to land in std.
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<'a, P, U> CoerceUnsized<Pin<U>> for Pin<P>
|
||||
impl<P, U> CoerceUnsized<Pin<U>> for Pin<P>
|
||||
where
|
||||
P: CoerceUnsized<U>,
|
||||
{}
|
||||
|
||||
#[unstable(feature = "pin", issue = "49150")]
|
||||
impl<'a, P> Unpin for Pin<P> {}
|
||||
impl<P> Unpin for Pin<P> {}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ use ops::CoerceUnsized;
|
|||
use fmt;
|
||||
use hash;
|
||||
use marker::{PhantomData, Unsize};
|
||||
use mem::{self, MaybeUninit};
|
||||
use mem;
|
||||
use nonzero::NonZero;
|
||||
|
||||
use cmp::Ordering::{self, Less, Equal, Greater};
|
||||
|
|
@ -294,12 +294,16 @@ pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
||||
// Give ourselves some scratch space to work with
|
||||
let mut tmp = MaybeUninit::<T>::uninitialized();
|
||||
let mut tmp: T = mem::uninitialized();
|
||||
|
||||
// Perform the swap
|
||||
copy_nonoverlapping(x, tmp.as_mut_ptr(), 1);
|
||||
copy_nonoverlapping(x, &mut tmp, 1);
|
||||
copy(y, x, 1); // `x` and `y` may overlap
|
||||
copy_nonoverlapping(tmp.get_ref(), y, 1);
|
||||
copy_nonoverlapping(&tmp, y, 1);
|
||||
|
||||
// y and t now point to the same thing, but we need to completely forget `tmp`
|
||||
// because it's no longer relevant.
|
||||
mem::forget(tmp);
|
||||
}
|
||||
|
||||
/// Swaps `count * size_of::<T>()` bytes between the two regions of memory
|
||||
|
|
@ -386,8 +390,8 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
|
|||
while i + block_size <= len {
|
||||
// Create some uninitialized memory as scratch space
|
||||
// Declaring `t` here avoids aligning the stack when this loop is unused
|
||||
let mut t = mem::MaybeUninit::<Block>::uninitialized();
|
||||
let t = t.as_mut_ptr() as *mut u8;
|
||||
let mut t: Block = mem::uninitialized();
|
||||
let t = &mut t as *mut _ as *mut u8;
|
||||
let x = x.add(i);
|
||||
let y = y.add(i);
|
||||
|
||||
|
|
@ -401,10 +405,10 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
|
|||
|
||||
if i < len {
|
||||
// Swap any remaining bytes
|
||||
let mut t = mem::MaybeUninit::<UnalignedBlock>::uninitialized();
|
||||
let mut t: UnalignedBlock = mem::uninitialized();
|
||||
let rem = len - i;
|
||||
|
||||
let t = t.as_mut_ptr() as *mut u8;
|
||||
let t = &mut t as *mut _ as *mut u8;
|
||||
let x = x.add(i);
|
||||
let y = y.add(i);
|
||||
|
||||
|
|
@ -569,9 +573,9 @@ pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
|
|||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn read<T>(src: *const T) -> T {
|
||||
let mut tmp = MaybeUninit::<T>::uninitialized();
|
||||
copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
|
||||
tmp.into_inner()
|
||||
let mut tmp: T = mem::uninitialized();
|
||||
copy_nonoverlapping(src, &mut tmp, 1);
|
||||
tmp
|
||||
}
|
||||
|
||||
/// Reads the value from `src` without moving it. This leaves the
|
||||
|
|
@ -636,11 +640,11 @@ pub unsafe fn read<T>(src: *const T) -> T {
|
|||
#[inline]
|
||||
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
|
||||
pub unsafe fn read_unaligned<T>(src: *const T) -> T {
|
||||
let mut tmp = MaybeUninit::<T>::uninitialized();
|
||||
let mut tmp: T = mem::uninitialized();
|
||||
copy_nonoverlapping(src as *const u8,
|
||||
tmp.as_mut_ptr() as *mut u8,
|
||||
&mut tmp as *mut T as *mut u8,
|
||||
mem::size_of::<T>());
|
||||
tmp.into_inner()
|
||||
tmp
|
||||
}
|
||||
|
||||
/// Overwrites a memory location with the given value without reading or
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use cmp;
|
||||
use mem::{self, MaybeUninit};
|
||||
use mem;
|
||||
use ptr;
|
||||
|
||||
/// Rotation is much faster if it has access to a little bit of memory. This
|
||||
|
|
@ -26,6 +26,12 @@ union RawArray<T> {
|
|||
}
|
||||
|
||||
impl<T> RawArray<T> {
|
||||
fn new() -> Self {
|
||||
unsafe { mem::uninitialized() }
|
||||
}
|
||||
fn ptr(&self) -> *mut T {
|
||||
unsafe { &self.typed as *const T as *mut T }
|
||||
}
|
||||
fn cap() -> usize {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
usize::max_value()
|
||||
|
|
@ -82,8 +88,8 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mid: *mut T, mut right: usize) {
|
|||
}
|
||||
}
|
||||
|
||||
let mut rawarray = MaybeUninit::<RawArray<T>>::uninitialized();
|
||||
let buf = &mut (*rawarray.as_mut_ptr()).typed as *mut [T; 2] as *mut T;
|
||||
let rawarray = RawArray::new();
|
||||
let buf = rawarray.ptr();
|
||||
|
||||
let dim = mid.sub(left).add(right);
|
||||
if left <= right {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
//! stable sorting implementation.
|
||||
|
||||
use cmp;
|
||||
use mem::{self, MaybeUninit};
|
||||
use mem;
|
||||
use ptr;
|
||||
|
||||
/// When dropped, copies from `src` into `dest`.
|
||||
|
|
@ -226,14 +226,14 @@ fn partition_in_blocks<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize
|
|||
let mut block_l = BLOCK;
|
||||
let mut start_l = ptr::null_mut();
|
||||
let mut end_l = ptr::null_mut();
|
||||
let mut offsets_l = MaybeUninit::<[u8; BLOCK]>::uninitialized();
|
||||
let mut offsets_l: [u8; BLOCK] = unsafe { mem::uninitialized() };
|
||||
|
||||
// The current block on the right side (from `r.sub(block_r)` to `r`).
|
||||
let mut r = unsafe { l.add(v.len()) };
|
||||
let mut block_r = BLOCK;
|
||||
let mut start_r = ptr::null_mut();
|
||||
let mut end_r = ptr::null_mut();
|
||||
let mut offsets_r = MaybeUninit::<[u8; BLOCK]>::uninitialized();
|
||||
let mut offsets_r: [u8; BLOCK] = unsafe { mem::uninitialized() };
|
||||
|
||||
// FIXME: When we get VLAs, try creating one array of length `min(v.len(), 2 * BLOCK)` rather
|
||||
// than two fixed-size arrays of length `BLOCK`. VLAs might be more cache-efficient.
|
||||
|
|
@ -272,8 +272,8 @@ fn partition_in_blocks<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize
|
|||
|
||||
if start_l == end_l {
|
||||
// Trace `block_l` elements from the left side.
|
||||
start_l = offsets_l.as_mut_ptr() as *mut u8;
|
||||
end_l = offsets_l.as_mut_ptr() as *mut u8;
|
||||
start_l = offsets_l.as_mut_ptr();
|
||||
end_l = offsets_l.as_mut_ptr();
|
||||
let mut elem = l;
|
||||
|
||||
for i in 0..block_l {
|
||||
|
|
@ -288,8 +288,8 @@ fn partition_in_blocks<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize
|
|||
|
||||
if start_r == end_r {
|
||||
// Trace `block_r` elements from the right side.
|
||||
start_r = offsets_r.as_mut_ptr() as *mut u8;
|
||||
end_r = offsets_r.as_mut_ptr() as *mut u8;
|
||||
start_r = offsets_r.as_mut_ptr();
|
||||
end_r = offsets_r.as_mut_ptr();
|
||||
let mut elem = r;
|
||||
|
||||
for i in 0..block_r {
|
||||
|
|
|
|||
|
|
@ -287,6 +287,31 @@ impl DefPath {
|
|||
s
|
||||
}
|
||||
|
||||
/// Return filename friendly string of the DefPah with the
|
||||
/// crate-prefix.
|
||||
pub fn to_string_friendly<F>(&self, crate_imported_name: F) -> String
|
||||
where F: FnOnce(CrateNum) -> Symbol
|
||||
{
|
||||
let crate_name_str = crate_imported_name(self.krate).as_str();
|
||||
let mut s = String::with_capacity(crate_name_str.len() + self.data.len() * 16);
|
||||
|
||||
write!(s, "::{}", crate_name_str).unwrap();
|
||||
|
||||
for component in &self.data {
|
||||
if component.disambiguator == 0 {
|
||||
write!(s, "::{}", component.data.as_interned_str()).unwrap();
|
||||
} else {
|
||||
write!(s,
|
||||
"{}[{}]",
|
||||
component.data.as_interned_str(),
|
||||
component.disambiguator)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
/// Return filename friendly string of the DefPah without
|
||||
/// the crate-prefix. This method is useful if you don't have
|
||||
/// a TyCtxt available.
|
||||
|
|
|
|||
|
|
@ -55,23 +55,22 @@
|
|||
//! ported to this system, and which relies on string concatenation at the
|
||||
//! time of error detection.
|
||||
|
||||
use infer;
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
use super::region_constraints::GenericKind;
|
||||
use super::lexical_region_resolve::RegionResolutionError;
|
||||
use super::region_constraints::GenericKind;
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
use infer::{self, SuppressRegionErrors};
|
||||
|
||||
use std::{cmp, fmt};
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
|
||||
use hir;
|
||||
use hir::Node;
|
||||
use hir::def_id::DefId;
|
||||
use hir::Node;
|
||||
use middle::region;
|
||||
use traits::{ObligationCause, ObligationCauseCode};
|
||||
use ty::{self, subst::Subst, Region, Ty, TyCtxt, TypeFoldable, TyKind};
|
||||
use ty::error::TypeError;
|
||||
use session::config::BorrowckMode;
|
||||
use std::{cmp, fmt};
|
||||
use syntax::ast::DUMMY_NODE_ID;
|
||||
use syntax_pos::{Pos, Span};
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
|
||||
use traits::{ObligationCause, ObligationCauseCode};
|
||||
use ty::error::TypeError;
|
||||
use ty::{self, subst::Subst, Region, Ty, TyCtxt, TyKind, TypeFoldable};
|
||||
|
||||
mod note;
|
||||
|
||||
|
|
@ -153,8 +152,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// We shouldn't encounter an error message with ReClosureBound.
|
||||
ty::ReCanonical(..) |
|
||||
ty::ReClosureBound(..) => {
|
||||
ty::ReCanonical(..) | ty::ReClosureBound(..) => {
|
||||
bug!("encountered unexpected ReClosureBound: {:?}", region,);
|
||||
}
|
||||
};
|
||||
|
|
@ -176,9 +174,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
|
||||
match *region {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
self.msg_span_from_early_bound_and_free_regions(region)
|
||||
},
|
||||
}
|
||||
ty::ReStatic => ("the static lifetime".to_owned(), None),
|
||||
_ => bug!("{:?}", region),
|
||||
}
|
||||
|
|
@ -197,25 +195,28 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
Some(Node::Item(it)) => Self::item_scope_tag(&it),
|
||||
Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
|
||||
Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let (prefix, span) = match *region {
|
||||
ty::ReEarlyBound(ref br) => {
|
||||
let mut sp = cm.def_span(self.hir.span(node));
|
||||
if let Some(param) = self.hir.get_generics(scope).and_then(|generics| {
|
||||
generics.get_named(&br.name)
|
||||
}) {
|
||||
if let Some(param) = self.hir
|
||||
.get_generics(scope)
|
||||
.and_then(|generics| generics.get_named(&br.name))
|
||||
{
|
||||
sp = param.span;
|
||||
}
|
||||
(format!("the lifetime {} as defined on", br.name), sp)
|
||||
}
|
||||
ty::ReFree(ty::FreeRegion {
|
||||
bound_region: ty::BoundRegion::BrNamed(_, ref name), ..
|
||||
bound_region: ty::BoundRegion::BrNamed(_, ref name),
|
||||
..
|
||||
}) => {
|
||||
let mut sp = cm.def_span(self.hir.span(node));
|
||||
if let Some(param) = self.hir.get_generics(scope).and_then(|generics| {
|
||||
generics.get_named(&name)
|
||||
}) {
|
||||
if let Some(param) = self.hir
|
||||
.get_generics(scope)
|
||||
.and_then(|generics| generics.get_named(&name))
|
||||
{
|
||||
sp = param.span;
|
||||
}
|
||||
(format!("the lifetime {} as defined on", name), sp)
|
||||
|
|
@ -278,9 +279,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
|
||||
match item.node {
|
||||
hir::ImplItemKind::Method(..) => "method body",
|
||||
hir::ImplItemKind::Const(..) |
|
||||
hir::ImplItemKind::Existential(..) |
|
||||
hir::ImplItemKind::Type(..) => "associated item",
|
||||
hir::ImplItemKind::Const(..)
|
||||
| hir::ImplItemKind::Existential(..)
|
||||
| hir::ImplItemKind::Type(..) => "associated item",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -298,20 +299,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
&self,
|
||||
region_scope_tree: ®ion::ScopeTree,
|
||||
errors: &Vec<RegionResolutionError<'tcx>>,
|
||||
will_later_be_reported_by_nll: bool,
|
||||
suppress: SuppressRegionErrors,
|
||||
) {
|
||||
debug!("report_region_errors(): {} errors to start", errors.len());
|
||||
debug!(
|
||||
"report_region_errors(): {} errors to start, suppress = {:?}",
|
||||
errors.len(),
|
||||
suppress
|
||||
);
|
||||
|
||||
// If the errors will later be reported by NLL, choose wether to display them or not based
|
||||
// on the borrowck mode
|
||||
if will_later_be_reported_by_nll {
|
||||
match self.tcx.borrowck_mode() {
|
||||
// If we're on AST or Migrate mode, report AST region errors
|
||||
BorrowckMode::Ast | BorrowckMode::Migrate => {},
|
||||
// If we're on MIR or Compare mode, don't report AST region errors as they should
|
||||
// be reported by NLL
|
||||
BorrowckMode::Compare | BorrowckMode::Mir => return,
|
||||
}
|
||||
if suppress.suppressed() {
|
||||
return;
|
||||
}
|
||||
|
||||
// try to pre-process the errors, which will group some of them
|
||||
|
|
@ -482,17 +479,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
} else {
|
||||
err.span_label(arm_span, msg);
|
||||
}
|
||||
},
|
||||
hir::MatchSource::TryDesugar => { // Issue #51632
|
||||
}
|
||||
hir::MatchSource::TryDesugar => {
|
||||
// Issue #51632
|
||||
if let Ok(try_snippet) = self.tcx.sess.source_map().span_to_snippet(arm_span) {
|
||||
err.span_suggestion_with_applicability(
|
||||
arm_span,
|
||||
"try wrapping with a success variant",
|
||||
format!("Ok({})", try_snippet),
|
||||
Applicability::MachineApplicable
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
let msg = "match arm with an incompatible type";
|
||||
if self.tcx.sess.source_map().is_multiline(arm_span) {
|
||||
|
|
@ -641,16 +639,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
fn strip_generic_default_params(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
substs: &ty::subst::Substs<'tcx>
|
||||
substs: &ty::subst::Substs<'tcx>,
|
||||
) -> &'tcx ty::subst::Substs<'tcx> {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let mut num_supplied_defaults = 0;
|
||||
let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => None,
|
||||
ty::GenericParamDefKind::Type { has_default, .. } => {
|
||||
Some((param.def_id, has_default))
|
||||
}
|
||||
}).peekable();
|
||||
let mut type_params = generics
|
||||
.params
|
||||
.iter()
|
||||
.rev()
|
||||
.filter_map(|param| match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => None,
|
||||
ty::GenericParamDefKind::Type { has_default, .. } => {
|
||||
Some((param.def_id, has_default))
|
||||
}
|
||||
})
|
||||
.peekable();
|
||||
let has_default = {
|
||||
let has_default = type_params.peek().map(|(_, has_default)| has_default);
|
||||
*has_default.unwrap_or(&false)
|
||||
|
|
@ -684,10 +687,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
| (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Infer(ty::InferTy::IntVar(_)))
|
||||
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
|
||||
| (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Float(_))
|
||||
| (
|
||||
&ty::Infer(ty::InferTy::FloatVar(_)),
|
||||
&ty::Infer(ty::InferTy::FloatVar(_)),
|
||||
) => true,
|
||||
| (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Infer(ty::InferTy::FloatVar(_))) => {
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -703,11 +705,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
"&{}{}{}",
|
||||
r,
|
||||
if r == "" { "" } else { " " },
|
||||
if mutbl == hir::MutMutable {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
}
|
||||
if mutbl == hir::MutMutable { "mut " } else { "" }
|
||||
));
|
||||
s.push_normal(ty.to_string());
|
||||
}
|
||||
|
|
@ -738,9 +736,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let common_len = cmp::min(len1, len2);
|
||||
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
|
||||
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
|
||||
let common_default_params =
|
||||
remainder1.iter().rev().zip(remainder2.iter().rev())
|
||||
.filter(|(a, b)| a == b).count();
|
||||
let common_default_params = remainder1
|
||||
.iter()
|
||||
.rev()
|
||||
.zip(remainder2.iter().rev())
|
||||
.filter(|(a, b)| a == b)
|
||||
.count();
|
||||
let len = sub1.len() - common_default_params;
|
||||
|
||||
// Only draw `<...>` if there're lifetime/type arguments.
|
||||
|
|
@ -866,8 +867,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// When encountering &T != &mut T, highlight only the borrow
|
||||
(&ty::Ref(r1, ref_ty1, mutbl1),
|
||||
&ty::Ref(r2, ref_ty2, mutbl2)) if equals(&ref_ty1, &ref_ty2) => {
|
||||
(&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2))
|
||||
if equals(&ref_ty1, &ref_ty2) =>
|
||||
{
|
||||
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
|
||||
push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0);
|
||||
push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1);
|
||||
|
|
@ -1068,11 +1070,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
bound_kind: GenericKind<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
) {
|
||||
self.construct_generic_bound_failure(region_scope_tree,
|
||||
span,
|
||||
origin,
|
||||
bound_kind,
|
||||
sub)
|
||||
self.construct_generic_bound_failure(region_scope_tree, span, origin, bound_kind, sub)
|
||||
.emit()
|
||||
}
|
||||
|
||||
|
|
@ -1083,8 +1081,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
origin: Option<SubregionOrigin<'tcx>>,
|
||||
bound_kind: GenericKind<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
) -> DiagnosticBuilder<'a>
|
||||
{
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
// Attempt to obtain the span of the parameter so we can
|
||||
// suggest adding an explicit lifetime bound to it.
|
||||
let type_param_span = match (self.in_progress_tables, bound_kind) {
|
||||
|
|
@ -1161,8 +1158,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let tail = if has_lifetimes { " + " } else { "" };
|
||||
let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
|
||||
err.span_suggestion_short_with_applicability(
|
||||
sp, consider, suggestion,
|
||||
Applicability::MaybeIncorrect // Issue #41966
|
||||
sp,
|
||||
consider,
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect, // Issue #41966
|
||||
);
|
||||
} else {
|
||||
err.help(consider);
|
||||
|
|
@ -1358,12 +1357,10 @@ impl<'tcx> ObligationCause<'tcx> {
|
|||
match self.code {
|
||||
CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
|
||||
MatchExpressionArm { source, .. } => Error0308(match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
"`if let` arms have incompatible types"
|
||||
},
|
||||
hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types",
|
||||
hir::MatchSource::TryDesugar => {
|
||||
"try expression alternatives have incompatible types"
|
||||
},
|
||||
}
|
||||
_ => "match arms have incompatible types",
|
||||
}),
|
||||
IfExpression => Error0308("if and else have incompatible types"),
|
||||
|
|
|
|||
|
|
@ -10,23 +10,26 @@
|
|||
|
||||
//! The code to do lexical region resolution.
|
||||
|
||||
use infer::SubregionOrigin;
|
||||
use infer::RegionVariableOrigin;
|
||||
use infer::region_constraints::Constraint;
|
||||
use infer::region_constraints::GenericKind;
|
||||
use infer::region_constraints::RegionConstraintData;
|
||||
use infer::region_constraints::VarInfos;
|
||||
use infer::region_constraints::VerifyBound;
|
||||
use infer::RegionVariableOrigin;
|
||||
use infer::SubregionOrigin;
|
||||
use middle::free_region::RegionRelations;
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::graph::implementation::{Graph, Direction, NodeIndex, INCOMING, OUTGOING};
|
||||
use rustc_data_structures::graph::implementation::{
|
||||
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
|
||||
};
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use std::fmt;
|
||||
use std::u32;
|
||||
use ty::{self, TyCtxt};
|
||||
use ty::{Region, RegionVid};
|
||||
use ty::fold::TypeFoldable;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
|
||||
use ty::{ReLateBound, ReScope, ReSkolemized, ReVar};
|
||||
use ty::{Region, RegionVid};
|
||||
|
||||
mod graphviz;
|
||||
|
||||
|
|
@ -108,11 +111,15 @@ struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
|||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
|
||||
self.region_rels.tcx
|
||||
}
|
||||
|
||||
fn infer_variable_values(
|
||||
&mut self,
|
||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
) -> LexicalRegionResolutions<'tcx> {
|
||||
let mut var_data = self.construct_var_data(self.region_rels.tcx);
|
||||
let mut var_data = self.construct_var_data(self.tcx());
|
||||
|
||||
// Dorky hack to cause `dump_constraints` to only get called
|
||||
// if debug mode is enabled:
|
||||
|
|
@ -239,9 +246,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
|
||||
debug!(
|
||||
"Expanding value of {:?} from {:?} to {:?}",
|
||||
b_vid,
|
||||
cur_region,
|
||||
lub
|
||||
b_vid, cur_region, lub
|
||||
);
|
||||
|
||||
*b_data = VarValue::Value(lub);
|
||||
|
|
@ -254,18 +259,17 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
|
||||
let tcx = self.region_rels.tcx;
|
||||
let tcx = self.tcx();
|
||||
match (a, b) {
|
||||
(&ty::ReCanonical(..), _) |
|
||||
(_, &ty::ReCanonical(..)) |
|
||||
(&ty::ReClosureBound(..), _) |
|
||||
(_, &ty::ReClosureBound(..)) |
|
||||
(&ReLateBound(..), _) |
|
||||
(_, &ReLateBound(..)) |
|
||||
(&ReErased, _) |
|
||||
(_, &ReErased) => {
|
||||
(&ty::ReCanonical(..), _)
|
||||
| (_, &ty::ReCanonical(..))
|
||||
| (&ty::ReClosureBound(..), _)
|
||||
| (_, &ty::ReClosureBound(..))
|
||||
| (&ReLateBound(..), _)
|
||||
| (_, &ReLateBound(..))
|
||||
| (&ReErased, _)
|
||||
| (_, &ReErased) => {
|
||||
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
|
||||
}
|
||||
|
||||
|
|
@ -287,20 +291,20 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
(&ReEarlyBound(_), &ReScope(s_id)) |
|
||||
(&ReScope(s_id), &ReEarlyBound(_)) |
|
||||
(&ReFree(_), &ReScope(s_id)) |
|
||||
(&ReScope(s_id), &ReFree(_)) => {
|
||||
(&ReEarlyBound(_), &ReScope(s_id))
|
||||
| (&ReScope(s_id), &ReEarlyBound(_))
|
||||
| (&ReFree(_), &ReScope(s_id))
|
||||
| (&ReScope(s_id), &ReFree(_)) => {
|
||||
// A "free" region can be interpreted as "some region
|
||||
// at least as big as fr.scope". So, we can
|
||||
// reasonably compare free regions and scopes:
|
||||
let fr_scope = match (a, b) {
|
||||
(&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
|
||||
.region_scope_tree
|
||||
.early_free_scope(self.region_rels.tcx, br),
|
||||
.early_free_scope(self.tcx(), br),
|
||||
(&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
|
||||
.region_scope_tree
|
||||
.free_scope(self.region_rels.tcx, fr),
|
||||
.free_scope(self.tcx(), fr),
|
||||
_ => bug!(),
|
||||
};
|
||||
let r_id = self.region_rels
|
||||
|
|
@ -332,10 +336,10 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
tcx.mk_region(ReScope(lub))
|
||||
}
|
||||
|
||||
(&ReEarlyBound(_), &ReEarlyBound(_)) |
|
||||
(&ReFree(_), &ReEarlyBound(_)) |
|
||||
(&ReEarlyBound(_), &ReFree(_)) |
|
||||
(&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
|
||||
(&ReEarlyBound(_), &ReEarlyBound(_))
|
||||
| (&ReFree(_), &ReEarlyBound(_))
|
||||
| (&ReEarlyBound(_), &ReFree(_))
|
||||
| (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
|
||||
|
||||
// For these types, we cannot define any additional
|
||||
// relationship:
|
||||
|
|
@ -358,8 +362,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
for (constraint, origin) in &self.data.constraints {
|
||||
debug!(
|
||||
"collect_errors: constraint={:?} origin={:?}",
|
||||
constraint,
|
||||
origin
|
||||
constraint, origin
|
||||
);
|
||||
match *constraint {
|
||||
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
|
||||
|
|
@ -374,9 +377,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
debug!(
|
||||
"collect_errors: region error at {:?}: \
|
||||
cannot verify that {:?} <= {:?}",
|
||||
origin,
|
||||
sub,
|
||||
sup
|
||||
origin, sub, sup
|
||||
);
|
||||
|
||||
errors.push(RegionResolutionError::ConcreteFailure(
|
||||
|
|
@ -402,10 +403,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
debug!(
|
||||
"collect_errors: region error at {:?}: \
|
||||
cannot verify that {:?}={:?} <= {:?}",
|
||||
origin,
|
||||
a_vid,
|
||||
a_region,
|
||||
b_region
|
||||
origin, a_vid, a_region, b_region
|
||||
);
|
||||
*a_data = VarValue::ErrorValue;
|
||||
}
|
||||
|
|
@ -415,7 +413,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
|
||||
for verify in &self.data.verifys {
|
||||
debug!("collect_errors: verify={:?}", verify);
|
||||
let sub = var_data.normalize(verify.region);
|
||||
let sub = var_data.normalize(self.tcx(), verify.region);
|
||||
|
||||
// This was an inference variable which didn't get
|
||||
// constrained, therefore it can be assume to hold.
|
||||
|
|
@ -423,16 +421,15 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if self.bound_is_met(&verify.bound, var_data, sub) {
|
||||
let verify_kind_ty = verify.kind.to_ty(self.tcx());
|
||||
if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"collect_errors: region error at {:?}: \
|
||||
cannot verify that {:?} <= {:?}",
|
||||
verify.origin,
|
||||
verify.region,
|
||||
verify.bound
|
||||
verify.origin, verify.region, verify.bound
|
||||
);
|
||||
|
||||
errors.push(RegionResolutionError::GenericBoundFailure(
|
||||
|
|
@ -580,10 +577,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
debug!(
|
||||
"region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
|
||||
sup: {:?}",
|
||||
origin,
|
||||
node_idx,
|
||||
lower_bound.region,
|
||||
upper_bound.region
|
||||
origin, node_idx, lower_bound.region, upper_bound.region
|
||||
);
|
||||
errors.push(RegionResolutionError::SubSupConflict(
|
||||
origin,
|
||||
|
|
@ -645,8 +639,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
|
||||
debug!(
|
||||
"collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
|
||||
orig_node_idx,
|
||||
node_idx
|
||||
orig_node_idx, node_idx
|
||||
);
|
||||
|
||||
process_edges(&self.data, &mut state, graph, node_idx, dir);
|
||||
|
|
@ -721,20 +714,26 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
&self,
|
||||
bound: &VerifyBound<'tcx>,
|
||||
var_values: &LexicalRegionResolutions<'tcx>,
|
||||
generic_ty: Ty<'tcx>,
|
||||
min: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
match bound {
|
||||
VerifyBound::AnyRegion(rs) => rs.iter()
|
||||
.map(|&r| var_values.normalize(r))
|
||||
.any(|r| self.region_rels.is_subregion_of(min, r)),
|
||||
VerifyBound::IfEq(k, b) => {
|
||||
(var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
|
||||
&& self.bound_is_met(b, var_values, generic_ty, min)
|
||||
}
|
||||
|
||||
VerifyBound::AllRegions(rs) => rs.iter()
|
||||
.map(|&r| var_values.normalize(r))
|
||||
.all(|r| self.region_rels.is_subregion_of(min, r)),
|
||||
VerifyBound::OutlivedBy(r) =>
|
||||
self.region_rels.is_subregion_of(
|
||||
min,
|
||||
var_values.normalize(self.tcx(), r),
|
||||
),
|
||||
|
||||
VerifyBound::AnyBound(bs) => bs.iter().any(|b| self.bound_is_met(b, var_values, min)),
|
||||
VerifyBound::AnyBound(bs) => bs.iter()
|
||||
.any(|b| self.bound_is_met(b, var_values, generic_ty, min)),
|
||||
|
||||
VerifyBound::AllBounds(bs) => bs.iter().all(|b| self.bound_is_met(b, var_values, min)),
|
||||
VerifyBound::AllBounds(bs) => bs.iter()
|
||||
.all(|b| self.bound_is_met(b, var_values, generic_ty, min)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -745,13 +744,15 @@ impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'tcx> LexicalRegionResolutions<'tcx> {
|
||||
fn normalize(&self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
ty::ReVar(rid) => self.resolve_var(rid),
|
||||
fn normalize<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
tcx.fold_regions(&value, &mut false, |r, _db| match r {
|
||||
ty::ReVar(rid) => self.resolve_var(*rid),
|
||||
_ => r,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use middle::free_region::RegionRelations;
|
|||
use middle::lang_items;
|
||||
use middle::region;
|
||||
use rustc_data_structures::unify as ut;
|
||||
use session::config::BorrowckMode;
|
||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
|
@ -80,6 +81,38 @@ pub type Bound<T> = Option<T>;
|
|||
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
||||
pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
|
||||
|
||||
/// A flag that is used to suppress region errors. This is normally
|
||||
/// false, but sometimes -- when we are doing region checks that the
|
||||
/// NLL borrow checker will also do -- it might be set to true.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct SuppressRegionErrors {
|
||||
suppressed: bool
|
||||
}
|
||||
|
||||
impl SuppressRegionErrors {
|
||||
pub fn suppressed(self) -> bool {
|
||||
self.suppressed
|
||||
}
|
||||
|
||||
/// Indicates that the MIR borrowck will repeat these region
|
||||
/// checks, so we should ignore errors if NLL is (unconditionally)
|
||||
/// enabled.
|
||||
pub fn when_nll_is_enabled(tcx: TyCtxt<'_, '_, '_>) -> Self {
|
||||
match tcx.borrowck_mode() {
|
||||
// If we're on AST or Migrate mode, report AST region errors
|
||||
BorrowckMode::Ast | BorrowckMode::Migrate => SuppressRegionErrors {
|
||||
suppressed: false
|
||||
},
|
||||
|
||||
// If we're on MIR or Compare mode, don't report AST region errors as they should
|
||||
// be reported by NLL
|
||||
BorrowckMode::Compare | BorrowckMode::Mir => SuppressRegionErrors {
|
||||
suppressed: true
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
||||
|
|
@ -408,7 +441,7 @@ pub enum FixupError {
|
|||
pub struct RegionObligation<'tcx> {
|
||||
pub sub_region: ty::Region<'tcx>,
|
||||
pub sup_type: Ty<'tcx>,
|
||||
pub cause: ObligationCause<'tcx>,
|
||||
pub origin: SubregionOrigin<'tcx>,
|
||||
}
|
||||
|
||||
impl fmt::Display for FixupError {
|
||||
|
|
@ -1039,34 +1072,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
region_context: DefId,
|
||||
region_map: ®ion::ScopeTree,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) {
|
||||
self.resolve_regions_and_report_errors_inner(
|
||||
region_context,
|
||||
region_map,
|
||||
outlives_env,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
/// Like `resolve_regions_and_report_errors`, but skips error
|
||||
/// reporting if NLL is enabled. This is used for fn bodies where
|
||||
/// the same error may later be reported by the NLL-based
|
||||
/// inference.
|
||||
pub fn resolve_regions_and_report_errors_unless_nll(
|
||||
&self,
|
||||
region_context: DefId,
|
||||
region_map: ®ion::ScopeTree,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) {
|
||||
self.resolve_regions_and_report_errors_inner(region_context, region_map, outlives_env, true)
|
||||
}
|
||||
|
||||
fn resolve_regions_and_report_errors_inner(
|
||||
&self,
|
||||
region_context: DefId,
|
||||
region_map: ®ion::ScopeTree,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
will_later_be_reported_by_nll: bool,
|
||||
suppress: SuppressRegionErrors,
|
||||
) {
|
||||
assert!(
|
||||
self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
|
||||
|
|
@ -1098,7 +1104,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// this infcx was in use. This is totally hokey but
|
||||
// otherwise we have a hard time separating legit region
|
||||
// errors from silly ones.
|
||||
self.report_region_errors(region_map, &errors, will_later_be_reported_by_nll);
|
||||
self.report_region_errors(region_map, &errors, suppress);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use infer::{GenericKind, InferCtxt};
|
||||
use infer::outlives::free_region_map::FreeRegionMap;
|
||||
use traits::query::outlives_bounds::{self, OutlivesBound};
|
||||
use ty::{self, Ty};
|
||||
|
||||
use infer::{GenericKind, InferCtxt};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use traits::query::outlives_bounds::{self, OutlivesBound};
|
||||
use ty::{self, Ty};
|
||||
|
||||
/// The `OutlivesEnvironment` collects information about what outlives
|
||||
/// what in a given type-checking setting. For example, if we have a
|
||||
|
|
@ -39,15 +39,51 @@ use syntax_pos::Span;
|
|||
pub struct OutlivesEnvironment<'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
free_region_map: FreeRegionMap<'tcx>,
|
||||
region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
|
||||
|
||||
// Contains, for each body B that we are checking (that is, the fn
|
||||
// item, but also any nested closures), the set of implied region
|
||||
// bounds that are in scope in that particular body.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ```
|
||||
// fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
|
||||
// bar(x, y, |y: &'b T| { .. } // body B1)
|
||||
// } // body B0
|
||||
// ```
|
||||
//
|
||||
// Here, for body B0, the list would be `[T: 'a]`, because we
|
||||
// infer that `T` must outlive `'a` from the implied bounds on the
|
||||
// fn declaration.
|
||||
//
|
||||
// For the body B1, the list would be `[T: 'a, T: 'b]`, because we
|
||||
// also can see that -- within the closure body! -- `T` must
|
||||
// outlive `'b`. This is not necessarily true outside the closure
|
||||
// body, since the closure may never be called.
|
||||
//
|
||||
// We collect this map as we descend the tree. We then use the
|
||||
// results when proving outlives obligations like `T: 'x` later
|
||||
// (e.g., if `T: 'x` must be proven within the body B1, then we
|
||||
// know it is true if either `'a: 'x` or `'b: 'x`).
|
||||
region_bound_pairs_map: FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>>,
|
||||
|
||||
// Used to compute `region_bound_pairs_map`: contains the set of
|
||||
// in-scope region-bound pairs thus far.
|
||||
region_bound_pairs_accum: RegionBoundPairs<'tcx>,
|
||||
}
|
||||
|
||||
/// "Region-bound pairs" tracks outlives relations that are known to
|
||||
/// be true, either because of explicit where clauses like `T: 'a` or
|
||||
/// because of implied bounds.
|
||||
pub type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
|
||||
|
||||
impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
||||
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
let mut env = OutlivesEnvironment {
|
||||
param_env,
|
||||
free_region_map: FreeRegionMap::new(),
|
||||
region_bound_pairs: vec![],
|
||||
region_bound_pairs_map: FxHashMap::default(),
|
||||
region_bound_pairs_accum: vec![],
|
||||
};
|
||||
|
||||
env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env));
|
||||
|
|
@ -61,8 +97,8 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
|||
}
|
||||
|
||||
/// Borrows current value of the `region_bound_pairs`.
|
||||
pub fn region_bound_pairs(&self) -> &[(ty::Region<'tcx>, GenericKind<'tcx>)] {
|
||||
&self.region_bound_pairs
|
||||
pub fn region_bound_pairs_map(&self) -> &FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>> {
|
||||
&self.region_bound_pairs_map
|
||||
}
|
||||
|
||||
/// Returns ownership of the `free_region_map`.
|
||||
|
|
@ -108,12 +144,12 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
|||
/// similar leaks around givens that seem equally suspicious, to
|
||||
/// be honest. --nmatsakis
|
||||
pub fn push_snapshot_pre_closure(&self) -> usize {
|
||||
self.region_bound_pairs.len()
|
||||
self.region_bound_pairs_accum.len()
|
||||
}
|
||||
|
||||
/// See `push_snapshot_pre_closure`.
|
||||
pub fn pop_snapshot_post_closure(&mut self, len: usize) {
|
||||
self.region_bound_pairs.truncate(len);
|
||||
self.region_bound_pairs_accum.truncate(len);
|
||||
}
|
||||
|
||||
/// This method adds "implied bounds" into the outlives environment.
|
||||
|
|
@ -149,6 +185,15 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Save the current set of region-bound pairs under the given `body_id`.
|
||||
pub fn save_implied_bounds(&mut self, body_id: ast::NodeId) {
|
||||
let old = self.region_bound_pairs_map.insert(
|
||||
body_id,
|
||||
self.region_bound_pairs_accum.clone(),
|
||||
);
|
||||
assert!(old.is_none());
|
||||
}
|
||||
|
||||
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
|
||||
///
|
||||
/// The `infcx` parameter is optional; if the implied bounds may
|
||||
|
|
@ -167,16 +212,18 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
|||
for outlives_bound in outlives_bounds {
|
||||
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
|
||||
match outlives_bound {
|
||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) |
|
||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
|
||||
infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
|
||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b))
|
||||
| OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
|
||||
infcx
|
||||
.expect("no infcx provided but region vars found")
|
||||
.add_given(r_a, vid_b);
|
||||
}
|
||||
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
||||
self.region_bound_pairs
|
||||
self.region_bound_pairs_accum
|
||||
.push((r_a, GenericKind::Param(param_b)));
|
||||
}
|
||||
OutlivesBound::RegionSubProjection(r_a, projection_b) => {
|
||||
self.region_bound_pairs
|
||||
self.region_bound_pairs_accum
|
||||
.push((r_a, GenericKind::Projection(projection_b)));
|
||||
}
|
||||
OutlivesBound::RegionSubRegion(r_a, r_b) => {
|
||||
|
|
|
|||
|
|
@ -13,3 +13,4 @@
|
|||
pub mod env;
|
||||
pub mod free_region_map;
|
||||
pub mod obligations;
|
||||
pub mod verify;
|
||||
|
|
|
|||
|
|
@ -69,13 +69,14 @@
|
|||
//! might later infer `?U` to something like `&'b u32`, which would
|
||||
//! imply that `'b: 'a`.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::outlives::env::RegionBoundPairs;
|
||||
use infer::outlives::verify::VerifyBoundCx;
|
||||
use infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax::ast;
|
||||
use traits;
|
||||
use traits::ObligationCause;
|
||||
use ty::outlives::Component;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Registers that the given region obligation must be resolved
|
||||
|
|
@ -98,6 +99,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
.push((body_id, obligation));
|
||||
}
|
||||
|
||||
pub fn register_region_obligation_with_cause(
|
||||
&self,
|
||||
sup_type: Ty<'tcx>,
|
||||
sub_region: Region<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
) {
|
||||
let origin = SubregionOrigin::from_obligation_cause(cause, || {
|
||||
infer::RelateParamBound(cause.span, sup_type)
|
||||
});
|
||||
|
||||
self.register_region_obligation(
|
||||
cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type,
|
||||
sub_region,
|
||||
origin,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Trait queries just want to pass back type obligations "as is"
|
||||
pub fn take_registered_region_obligations(&self) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> {
|
||||
::std::mem::replace(&mut *self.region_obligations.borrow_mut(), vec![])
|
||||
|
|
@ -138,10 +159,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
/// processed.
|
||||
pub fn process_registered_region_obligations(
|
||||
&self,
|
||||
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs_map: &FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
) {
|
||||
assert!(
|
||||
!self.in_snapshot.get(),
|
||||
|
|
@ -150,41 +170,39 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
debug!("process_registered_region_obligations()");
|
||||
|
||||
// pull out the region obligations with the given `body_id` (leaving the rest)
|
||||
let mut my_region_obligations = Vec::with_capacity(self.region_obligations.borrow().len());
|
||||
{
|
||||
let mut r_o = self.region_obligations.borrow_mut();
|
||||
my_region_obligations.extend(
|
||||
r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id)
|
||||
.map(|(_, obligation)| obligation)
|
||||
);
|
||||
}
|
||||
let my_region_obligations = self.take_registered_region_obligations();
|
||||
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
self,
|
||||
self.tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
);
|
||||
|
||||
for RegionObligation {
|
||||
sup_type,
|
||||
sub_region,
|
||||
cause,
|
||||
} in my_region_obligations
|
||||
for (
|
||||
body_id,
|
||||
RegionObligation {
|
||||
sup_type,
|
||||
sub_region,
|
||||
origin,
|
||||
},
|
||||
) in my_region_obligations
|
||||
{
|
||||
debug!(
|
||||
"process_registered_region_obligations: sup_type={:?} sub_region={:?} cause={:?}",
|
||||
sup_type, sub_region, cause
|
||||
"process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}",
|
||||
sup_type, sub_region, origin
|
||||
);
|
||||
|
||||
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
|
||||
infer::RelateParamBound(cause.span, sup_type)
|
||||
});
|
||||
|
||||
let sup_type = self.resolve_type_vars_if_possible(&sup_type);
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region);
|
||||
|
||||
if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) {
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
self,
|
||||
self.tcx,
|
||||
®ion_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
);
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region);
|
||||
} else {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
origin.span(),
|
||||
&format!("no region-bound-pairs for {:?}", body_id),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +210,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
/// registered in advance.
|
||||
pub fn type_must_outlive(
|
||||
&self,
|
||||
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
|
|
@ -225,9 +243,7 @@ where
|
|||
// of these fields.
|
||||
delegate: D,
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
verify_bound: VerifyBoundCx<'cx, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
pub trait TypeOutlivesDelegate<'tcx> {
|
||||
|
|
@ -254,16 +270,19 @@ where
|
|||
pub fn new(
|
||||
delegate: D,
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Self {
|
||||
Self {
|
||||
delegate,
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
verify_bound: VerifyBoundCx::new(
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -302,7 +321,8 @@ where
|
|||
let origin = origin.clone();
|
||||
match component {
|
||||
Component::Region(region1) => {
|
||||
self.delegate.push_sub_region_constraint(origin, region, region1);
|
||||
self.delegate
|
||||
.push_sub_region_constraint(origin, region, region1);
|
||||
}
|
||||
Component::Param(param_ty) => {
|
||||
self.param_ty_must_outlive(origin, region, param_ty);
|
||||
|
|
@ -337,8 +357,8 @@ where
|
|||
region, param_ty, origin
|
||||
);
|
||||
|
||||
let verify_bound = self.param_bound(param_ty);
|
||||
let generic = GenericKind::Param(param_ty);
|
||||
let verify_bound = self.verify_bound.generic_bound(generic);
|
||||
self.delegate
|
||||
.push_verify(origin, generic, region, verify_bound);
|
||||
}
|
||||
|
|
@ -368,19 +388,22 @@ where
|
|||
// rule might not apply (but another rule might). For now, we err
|
||||
// on the side of adding too few edges into the graph.
|
||||
|
||||
// Compute the bounds we can derive from the environment or trait
|
||||
// definition. We know that the projection outlives all the
|
||||
// regions in this list.
|
||||
let env_bounds = self.projection_declared_bounds(projection_ty);
|
||||
// Compute the bounds we can derive from the environment. This
|
||||
// is an "approximate" match -- in some cases, these bounds
|
||||
// may not apply.
|
||||
let approx_env_bounds = self.verify_bound
|
||||
.projection_approx_declared_bounds_from_env(projection_ty);
|
||||
debug!(
|
||||
"projection_must_outlive: approx_env_bounds={:?}",
|
||||
approx_env_bounds
|
||||
);
|
||||
|
||||
debug!("projection_must_outlive: env_bounds={:?}", env_bounds);
|
||||
|
||||
// If we know that the projection outlives 'static, then we're
|
||||
// done here.
|
||||
if env_bounds.contains(&&ty::ReStatic) {
|
||||
debug!("projection_must_outlive: 'static as declared bound");
|
||||
return;
|
||||
}
|
||||
// Compute the bounds we can derive from the trait definition.
|
||||
// These are guaranteed to apply, no matter the inference
|
||||
// results.
|
||||
let trait_bounds: Vec<_> = self.verify_bound
|
||||
.projection_declared_bounds_from_trait(projection_ty)
|
||||
.collect();
|
||||
|
||||
// If declared bounds list is empty, the only applicable rule is
|
||||
// OutlivesProjectionComponent. If there are inference variables,
|
||||
|
|
@ -397,7 +420,7 @@ where
|
|||
// inference variables, we use a verify constraint instead of adding
|
||||
// edges, which winds up enforcing the same condition.
|
||||
let needs_infer = projection_ty.needs_infer();
|
||||
if env_bounds.is_empty() && needs_infer {
|
||||
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
|
||||
debug!("projection_must_outlive: no declared bounds");
|
||||
|
||||
for component_ty in projection_ty.substs.types() {
|
||||
|
|
@ -405,36 +428,38 @@ where
|
|||
}
|
||||
|
||||
for r in projection_ty.substs.regions() {
|
||||
self.delegate.push_sub_region_constraint(origin.clone(), region, r);
|
||||
self.delegate
|
||||
.push_sub_region_constraint(origin.clone(), region, r);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we find that there is a unique declared bound `'b`, and this bound
|
||||
// appears in the trait reference, then the best action is to require that `'b:'r`,
|
||||
// so do that. This is best no matter what rule we use:
|
||||
// If we found a unique bound `'b` from the trait, and we
|
||||
// found nothing else from the environment, then the best
|
||||
// action is to require that `'b: 'r`, so do that.
|
||||
//
|
||||
// - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to
|
||||
// the requirement that `'b:'r`
|
||||
// - OutlivesProjectionComponent: this would require `'b:'r` in addition to
|
||||
// other conditions
|
||||
if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
|
||||
let unique_bound = env_bounds[0];
|
||||
// This is best no matter what rule we use:
|
||||
//
|
||||
// - OutlivesProjectionEnv: these would translate to the requirement that `'b:'r`
|
||||
// - OutlivesProjectionTraitDef: these would translate to the requirement that `'b:'r`
|
||||
// - OutlivesProjectionComponent: this would require `'b:'r`
|
||||
// in addition to other conditions
|
||||
if !trait_bounds.is_empty()
|
||||
&& trait_bounds[1..]
|
||||
.iter()
|
||||
.chain(approx_env_bounds.iter().map(|b| &b.1))
|
||||
.all(|b| *b == trait_bounds[0])
|
||||
{
|
||||
let unique_bound = trait_bounds[0];
|
||||
debug!(
|
||||
"projection_must_outlive: unique declared bound = {:?}",
|
||||
"projection_must_outlive: unique trait bound = {:?}",
|
||||
unique_bound
|
||||
);
|
||||
if projection_ty
|
||||
.substs
|
||||
.regions()
|
||||
.any(|r| env_bounds.contains(&r))
|
||||
{
|
||||
debug!("projection_must_outlive: unique declared bound appears in trait ref");
|
||||
self.delegate
|
||||
.push_sub_region_constraint(origin.clone(), region, unique_bound);
|
||||
return;
|
||||
}
|
||||
debug!("projection_must_outlive: unique declared bound appears in trait ref");
|
||||
self.delegate
|
||||
.push_sub_region_constraint(origin.clone(), region, unique_bound);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to verifying after the fact that there exists a
|
||||
|
|
@ -442,216 +467,11 @@ where
|
|||
// projection outlive; in some cases, this may add insufficient
|
||||
// edges into the inference graph, leading to inference failures
|
||||
// even though a satisfactory solution exists.
|
||||
let verify_bound = self.projection_bound(env_bounds, projection_ty);
|
||||
let generic = GenericKind::Projection(projection_ty);
|
||||
let verify_bound = self.verify_bound.generic_bound(generic);
|
||||
self.delegate
|
||||
.push_verify(origin, generic.clone(), region, verify_bound);
|
||||
}
|
||||
|
||||
fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
match ty.sty {
|
||||
ty::Param(p) => self.param_bound(p),
|
||||
ty::Projection(data) => {
|
||||
let declared_bounds = self.projection_declared_bounds(data);
|
||||
self.projection_bound(declared_bounds, data)
|
||||
}
|
||||
_ => self.recursive_type_bound(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
|
||||
debug!("param_bound(param_ty={:?})", param_ty);
|
||||
|
||||
let mut param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty));
|
||||
|
||||
// Add in the default bound of fn body that applies to all in
|
||||
// scope type parameters:
|
||||
param_bounds.extend(self.implicit_region_bound);
|
||||
|
||||
VerifyBound::AnyRegion(param_bounds)
|
||||
}
|
||||
|
||||
fn projection_declared_bounds(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
// First assemble bounds from where clauses and traits.
|
||||
|
||||
let mut declared_bounds =
|
||||
self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty));
|
||||
|
||||
declared_bounds
|
||||
.extend_from_slice(&self.declared_projection_bounds_from_trait(projection_ty));
|
||||
|
||||
declared_bounds
|
||||
}
|
||||
|
||||
fn projection_bound(
|
||||
&self,
|
||||
declared_bounds: Vec<ty::Region<'tcx>>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> VerifyBound<'tcx> {
|
||||
debug!(
|
||||
"projection_bound(declared_bounds={:?}, projection_ty={:?})",
|
||||
declared_bounds, projection_ty
|
||||
);
|
||||
|
||||
// see the extensive comment in projection_must_outlive
|
||||
let ty = self
|
||||
.tcx
|
||||
.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
||||
let recursive_bound = self.recursive_type_bound(ty);
|
||||
|
||||
VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
|
||||
}
|
||||
|
||||
fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
let mut bounds = ty.walk_shallow().map(|subty| self.type_bound(subty)).collect::<Vec<_>>();
|
||||
|
||||
let mut regions = ty.regions();
|
||||
regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
|
||||
bounds.push(VerifyBound::AllRegions(regions));
|
||||
|
||||
// remove bounds that must hold, since they are not interesting
|
||||
bounds.retain(|b| !b.must_hold());
|
||||
|
||||
if bounds.len() == 1 {
|
||||
bounds.pop().unwrap()
|
||||
} else {
|
||||
VerifyBound::AllBounds(bounds)
|
||||
}
|
||||
}
|
||||
|
||||
fn declared_generic_bounds_from_env(
|
||||
&self,
|
||||
generic: GenericKind<'tcx>,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// To start, collect bounds from user environment. Note that
|
||||
// parameter environments are already elaborated, so we don't
|
||||
// have to worry about that. Comparing using `==` is a bit
|
||||
// dubious for projections, but it will work for simple cases
|
||||
// like `T` and `T::Item`. It may not work as well for things
|
||||
// like `<T as Foo<'a>>::Item`.
|
||||
let generic_ty = generic.to_ty(tcx);
|
||||
let c_b = self.param_env.caller_bounds;
|
||||
let mut param_bounds = self.collect_outlives_from_predicate_list(generic_ty, c_b);
|
||||
|
||||
// Next, collect regions we scraped from the well-formedness
|
||||
// constraints in the fn signature. To do that, we walk the list
|
||||
// of known relations from the fn ctxt.
|
||||
//
|
||||
// This is crucial because otherwise code like this fails:
|
||||
//
|
||||
// fn foo<'a, A>(x: &'a A) { x.bar() }
|
||||
//
|
||||
// The problem is that the type of `x` is `&'a A`. To be
|
||||
// well-formed, then, A must be lower-generic by `'a`, but we
|
||||
// don't know that this holds from first principles.
|
||||
for &(r, p) in self.region_bound_pairs {
|
||||
debug!("generic={:?} p={:?}", generic, p);
|
||||
if generic == p {
|
||||
param_bounds.push(r);
|
||||
}
|
||||
}
|
||||
|
||||
param_bounds
|
||||
}
|
||||
|
||||
/// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
|
||||
/// declared in the trait definition. For example, if the trait were
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// then this function would return `'x`. This is subject to the
|
||||
/// limitations around higher-ranked bounds described in
|
||||
/// `region_bounds_declared_on_associated_item`.
|
||||
fn declared_projection_bounds_from_trait(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
debug!("projection_bounds(projection_ty={:?})", projection_ty);
|
||||
let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id);
|
||||
for r in &mut bounds {
|
||||
*r = r.subst(self.tcx, projection_ty.substs);
|
||||
}
|
||||
bounds
|
||||
}
|
||||
|
||||
/// Given the def-id of an associated item, returns any region
|
||||
/// bounds attached to that associated item from the trait definition.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If we were given the def-id of `Foo::Bar`, we would return
|
||||
/// `'a`. You could then apply the substitutions from the
|
||||
/// projection to convert this into your namespace. This also
|
||||
/// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on
|
||||
/// the trait. In fact, it works by searching for just such a
|
||||
/// where-clause.
|
||||
///
|
||||
/// It will not, however, work for higher-ranked bounds like:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a, 'b>
|
||||
/// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x
|
||||
/// {
|
||||
/// type Bar;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This is for simplicity, and because we are not really smart
|
||||
/// enough to cope with such bounds anywhere.
|
||||
fn region_bounds_declared_on_associated_item(
|
||||
&self,
|
||||
assoc_item_def_id: DefId,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let assoc_item = tcx.associated_item(assoc_item_def_id);
|
||||
let trait_def_id = assoc_item.container.assert_trait();
|
||||
let trait_predicates = tcx.predicates_of(trait_def_id);
|
||||
let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id);
|
||||
let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
|
||||
self.collect_outlives_from_predicate_list(
|
||||
identity_proj,
|
||||
traits::elaborate_predicates(tcx, trait_predicates.predicates),
|
||||
)
|
||||
}
|
||||
|
||||
/// Searches through a predicate list for a predicate `T: 'a`.
|
||||
///
|
||||
/// Careful: does not elaborate predicates, and just uses `==`
|
||||
/// when comparing `ty` for equality, so `ty` must be something
|
||||
/// that does not involve inference variables and where you
|
||||
/// otherwise want a precise match.
|
||||
fn collect_outlives_from_predicate_list<I, P>(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
predicates: I,
|
||||
) -> Vec<ty::Region<'tcx>>
|
||||
where
|
||||
I: IntoIterator<Item = P>,
|
||||
P: AsRef<ty::Predicate<'tcx>>,
|
||||
{
|
||||
predicates
|
||||
.into_iter()
|
||||
.filter_map(|p| p.as_ref().to_opt_type_outlives())
|
||||
.filter_map(|p| p.no_late_bound_regions())
|
||||
.filter(|p| p.0 == ty)
|
||||
.map(|p| p.1)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
|
@ -674,4 +494,3 @@ impl<'cx, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'gcx, '
|
|||
self.verify_generic_bound(origin, kind, a, bound)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
329
src/librustc/infer/outlives/verify.rs
Normal file
329
src/librustc/infer/outlives/verify.rs
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
// Copyright 2012-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.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::outlives::env::RegionBoundPairs;
|
||||
use infer::{GenericKind, VerifyBound};
|
||||
use traits;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use util::captures::Captures;
|
||||
|
||||
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
|
||||
/// obligation into a series of `'a: 'b` constraints and "verifys", as
|
||||
/// described on the module comment. The final constraints are emitted
|
||||
/// via a "delegate" of type `D` -- this is usually the `infcx`, which
|
||||
/// accrues them into the `region_obligations` code, but for NLL we
|
||||
/// use something else.
|
||||
pub struct VerifyBoundCx<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
|
||||
pub fn new(
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Self {
|
||||
Self {
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a "verify bound" that encodes what we know about
|
||||
/// `generic` and the regions it outlives.
|
||||
pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
|
||||
match generic {
|
||||
GenericKind::Param(param_ty) => self.param_bound(param_ty),
|
||||
GenericKind::Projection(projection_ty) => self.projection_bound(projection_ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
match ty.sty {
|
||||
ty::Param(p) => self.param_bound(p),
|
||||
ty::Projection(data) => self.projection_bound(data),
|
||||
_ => self.recursive_type_bound(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
|
||||
debug!("param_bound(param_ty={:?})", param_ty);
|
||||
|
||||
// Start with anything like `T: 'a` we can scrape from the
|
||||
// environment
|
||||
let param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty))
|
||||
.into_iter()
|
||||
.map(|outlives| outlives.1);
|
||||
|
||||
// Add in the default bound of fn body that applies to all in
|
||||
// scope type parameters:
|
||||
let param_bounds = param_bounds.chain(self.implicit_region_bound);
|
||||
|
||||
VerifyBound::AnyBound(param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect())
|
||||
}
|
||||
|
||||
/// Given a projection like `T::Item`, searches the environment
|
||||
/// for where-clauses like `T::Item: 'a`. Returns the set of
|
||||
/// regions `'a` that it finds.
|
||||
///
|
||||
/// This is an "approximate" check -- it may not find all
|
||||
/// applicable bounds, and not all the bounds it returns can be
|
||||
/// relied upon. In particular, this check ignores region
|
||||
/// identity. So, for example, if we have `<T as
|
||||
/// Trait<'0>>::Item` where `'0` is a region variable, and the
|
||||
/// user has `<T as Trait<'a>>::Item: 'b` in the environment, then
|
||||
/// the clause from the environment only applies if `'0 = 'a`,
|
||||
/// which we don't know yet. But we would still include `'b` in
|
||||
/// this list.
|
||||
pub fn projection_approx_declared_bounds_from_env(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
|
||||
let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
|
||||
let erased_projection_ty = self.tcx.erase_regions(&projection_ty);
|
||||
self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
|
||||
if let ty::Projection(..) = ty.sty {
|
||||
let erased_ty = self.tcx.erase_regions(&ty);
|
||||
erased_ty == erased_projection_ty
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Searches the where clauses in scope for regions that
|
||||
/// `projection_ty` is known to outlive. Currently requires an
|
||||
/// exact match.
|
||||
pub fn projection_declared_bounds_from_trait(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
|
||||
self.declared_projection_bounds_from_trait(projection_ty)
|
||||
}
|
||||
|
||||
pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> {
|
||||
debug!("projection_bound(projection_ty={:?})", projection_ty);
|
||||
|
||||
let projection_ty_as_ty =
|
||||
self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
||||
|
||||
// Search the env for where clauses like `P: 'a`.
|
||||
let env_bounds = self.projection_approx_declared_bounds_from_env(projection_ty)
|
||||
.into_iter()
|
||||
.map(|ty::OutlivesPredicate(ty, r)| {
|
||||
let vb = VerifyBound::OutlivedBy(r);
|
||||
if ty == projection_ty_as_ty {
|
||||
// Micro-optimize if this is an exact match (this
|
||||
// occurs often when there are no region variables
|
||||
// involved).
|
||||
vb
|
||||
} else {
|
||||
VerifyBound::IfEq(ty, Box::new(vb))
|
||||
}
|
||||
});
|
||||
|
||||
// Extend with bounds that we can find from the trait.
|
||||
let trait_bounds = self.projection_declared_bounds_from_trait(projection_ty)
|
||||
.into_iter()
|
||||
.map(|r| VerifyBound::OutlivedBy(r));
|
||||
|
||||
// see the extensive comment in projection_must_outlive
|
||||
let ty = self.tcx
|
||||
.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
||||
let recursive_bound = self.recursive_type_bound(ty);
|
||||
|
||||
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
|
||||
}
|
||||
|
||||
fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
let mut bounds = ty.walk_shallow()
|
||||
.map(|subty| self.type_bound(subty))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut regions = ty.regions();
|
||||
regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
|
||||
bounds.push(VerifyBound::AllBounds(
|
||||
regions
|
||||
.into_iter()
|
||||
.map(|r| VerifyBound::OutlivedBy(r))
|
||||
.collect(),
|
||||
));
|
||||
|
||||
// remove bounds that must hold, since they are not interesting
|
||||
bounds.retain(|b| !b.must_hold());
|
||||
|
||||
if bounds.len() == 1 {
|
||||
bounds.pop().unwrap()
|
||||
} else {
|
||||
VerifyBound::AllBounds(bounds)
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches the environment for where-clauses like `G: 'a` where
|
||||
/// `G` is either some type parameter `T` or a projection like
|
||||
/// `T::Item`. Returns a vector of the `'a` bounds it can find.
|
||||
///
|
||||
/// This is a conservative check -- it may not find all applicable
|
||||
/// bounds, but all the bounds it returns can be relied upon.
|
||||
fn declared_generic_bounds_from_env(
|
||||
&self,
|
||||
generic: GenericKind<'tcx>,
|
||||
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
|
||||
let generic_ty = generic.to_ty(self.tcx);
|
||||
self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty)
|
||||
}
|
||||
|
||||
fn declared_generic_bounds_from_env_with_compare_fn(
|
||||
&self,
|
||||
compare_ty: impl Fn(Ty<'tcx>) -> bool,
|
||||
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// To start, collect bounds from user environment. Note that
|
||||
// parameter environments are already elaborated, so we don't
|
||||
// have to worry about that. Comparing using `==` is a bit
|
||||
// dubious for projections, but it will work for simple cases
|
||||
// like `T` and `T::Item`. It may not work as well for things
|
||||
// like `<T as Foo<'a>>::Item`.
|
||||
let c_b = self.param_env.caller_bounds;
|
||||
let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b);
|
||||
|
||||
// Next, collect regions we scraped from the well-formedness
|
||||
// constraints in the fn signature. To do that, we walk the list
|
||||
// of known relations from the fn ctxt.
|
||||
//
|
||||
// This is crucial because otherwise code like this fails:
|
||||
//
|
||||
// fn foo<'a, A>(x: &'a A) { x.bar() }
|
||||
//
|
||||
// The problem is that the type of `x` is `&'a A`. To be
|
||||
// well-formed, then, A must be lower-generic by `'a`, but we
|
||||
// don't know that this holds from first principles.
|
||||
let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| {
|
||||
debug!(
|
||||
"declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}",
|
||||
(r, p)
|
||||
);
|
||||
let p_ty = p.to_ty(tcx);
|
||||
if compare_ty(p_ty) {
|
||||
Some(ty::OutlivesPredicate(p_ty, r))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
param_bounds
|
||||
.chain(from_region_bound_pairs)
|
||||
.inspect(|bound| {
|
||||
debug!(
|
||||
"declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
|
||||
bound
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
|
||||
/// declared in the trait definition. For example, if the trait were
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// then this function would return `'x`. This is subject to the
|
||||
/// limitations around higher-ranked bounds described in
|
||||
/// `region_bounds_declared_on_associated_item`.
|
||||
fn declared_projection_bounds_from_trait(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
|
||||
debug!("projection_bounds(projection_ty={:?})", projection_ty);
|
||||
let tcx = self.tcx;
|
||||
self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
|
||||
.map(move |r| r.subst(tcx, projection_ty.substs))
|
||||
}
|
||||
|
||||
/// Given the def-id of an associated item, returns any region
|
||||
/// bounds attached to that associated item from the trait definition.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If we were given the def-id of `Foo::Bar`, we would return
|
||||
/// `'a`. You could then apply the substitutions from the
|
||||
/// projection to convert this into your namespace. This also
|
||||
/// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on
|
||||
/// the trait. In fact, it works by searching for just such a
|
||||
/// where-clause.
|
||||
///
|
||||
/// It will not, however, work for higher-ranked bounds like:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a, 'b>
|
||||
/// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x
|
||||
/// {
|
||||
/// type Bar;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This is for simplicity, and because we are not really smart
|
||||
/// enough to cope with such bounds anywhere.
|
||||
fn region_bounds_declared_on_associated_item(
|
||||
&self,
|
||||
assoc_item_def_id: DefId,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
|
||||
let tcx = self.tcx;
|
||||
let assoc_item = tcx.associated_item(assoc_item_def_id);
|
||||
let trait_def_id = assoc_item.container.assert_trait();
|
||||
let trait_predicates = tcx.predicates_of(trait_def_id).predicates
|
||||
.into_iter()
|
||||
.map(|(p, _)| p)
|
||||
.collect();
|
||||
let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id);
|
||||
let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
|
||||
self.collect_outlives_from_predicate_list(
|
||||
move |ty| ty == identity_proj,
|
||||
traits::elaborate_predicates(tcx, trait_predicates),
|
||||
).map(|b| b.1)
|
||||
}
|
||||
|
||||
/// Searches through a predicate list for a predicate `T: 'a`.
|
||||
///
|
||||
/// Careful: does not elaborate predicates, and just uses `==`
|
||||
/// when comparing `ty` for equality, so `ty` must be something
|
||||
/// that does not involve inference variables and where you
|
||||
/// otherwise want a precise match.
|
||||
fn collect_outlives_from_predicate_list(
|
||||
&self,
|
||||
compare_ty: impl Fn(Ty<'tcx>) -> bool,
|
||||
predicates: impl IntoIterator<Item = impl AsRef<ty::Predicate<'tcx>>>,
|
||||
) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
|
||||
predicates
|
||||
.into_iter()
|
||||
.filter_map(|p| p.as_ref().to_opt_type_outlives())
|
||||
.filter_map(|p| p.no_late_bound_regions())
|
||||
.filter(move |p| compare_ty(p.0))
|
||||
}
|
||||
}
|
||||
|
|
@ -155,29 +155,94 @@ pub enum GenericKind<'tcx> {
|
|||
Projection(ty::ProjectionTy<'tcx>),
|
||||
}
|
||||
|
||||
/// When we introduce a verification step, we wish to test that a
|
||||
/// particular region (let's call it `'min`) meets some bound.
|
||||
/// The bound is described the by the following grammar:
|
||||
EnumTypeFoldableImpl! {
|
||||
impl<'tcx> TypeFoldable<'tcx> for GenericKind<'tcx> {
|
||||
(GenericKind::Param)(a),
|
||||
(GenericKind::Projection)(a),
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the things that some `GenericKind` value G is known to
|
||||
/// outlive. Each variant of `VerifyBound` can be thought of as a
|
||||
/// function:
|
||||
///
|
||||
/// fn(min: Region) -> bool { .. }
|
||||
///
|
||||
/// where `true` means that the region `min` meets that `G: min`.
|
||||
/// (False means nothing.)
|
||||
///
|
||||
/// So, for example, if we have the type `T` and we have in scope that
|
||||
/// `T: 'a` and `T: 'b`, then the verify bound might be:
|
||||
///
|
||||
/// fn(min: Region) -> bool {
|
||||
/// ('a: min) || ('b: min)
|
||||
/// }
|
||||
///
|
||||
/// This is described with a `AnyRegion('a, 'b)` node.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum VerifyBound<'tcx> {
|
||||
/// B = exists {R} --> some 'r in {R} must outlive 'min
|
||||
/// Given a kind K and a bound B, expands to a function like the
|
||||
/// following, where `G` is the generic for which this verify
|
||||
/// bound was created:
|
||||
///
|
||||
/// Put another way, the subject value is known to outlive all
|
||||
/// regions in {R}, so if any of those outlives 'min, then the
|
||||
/// bound is met.
|
||||
AnyRegion(Vec<Region<'tcx>>),
|
||||
|
||||
/// B = forall {R} --> all 'r in {R} must outlive 'min
|
||||
/// fn(min) -> bool {
|
||||
/// if G == K {
|
||||
/// B(min)
|
||||
/// } else {
|
||||
/// false
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Put another way, the subject value is known to outlive some
|
||||
/// region in {R}, so if all of those outlives 'min, then the bound
|
||||
/// is met.
|
||||
AllRegions(Vec<Region<'tcx>>),
|
||||
/// In other words, if the generic `G` that we are checking is
|
||||
/// equal to `K`, then check the associated verify bound
|
||||
/// (otherwise, false).
|
||||
///
|
||||
/// This is used when we have something in the environment that
|
||||
/// may or may not be relevant, depending on the region inference
|
||||
/// results. For example, we may have `where <T as
|
||||
/// Trait<'a>>::Item: 'b` in our where clauses. If we are
|
||||
/// generating the verify-bound for `<T as Trait<'0>>::Item`, then
|
||||
/// this where-clause is only relevant if `'0` winds up inferred
|
||||
/// to `'a`.
|
||||
///
|
||||
/// So we would compile to a verify-bound like
|
||||
///
|
||||
/// IfEq(<T as Trait<'a>>::Item, AnyRegion('a))
|
||||
///
|
||||
/// meaning, if the subject G is equal to `<T as Trait<'a>>::Item`
|
||||
/// (after inference), and `'a: min`, then `G: min`.
|
||||
IfEq(Ty<'tcx>, Box<VerifyBound<'tcx>>),
|
||||
|
||||
/// B = exists {B} --> 'min must meet some bound b in {B}
|
||||
/// Given a region `R`, expands to the function:
|
||||
///
|
||||
/// fn(min) -> bool {
|
||||
/// R: min
|
||||
/// }
|
||||
///
|
||||
/// This is used when we can establish that `G: R` -- therefore,
|
||||
/// if `R: min`, then by transitivity `G: min`.
|
||||
OutlivedBy(Region<'tcx>),
|
||||
|
||||
/// Given a set of bounds `B`, expands to the function:
|
||||
///
|
||||
/// fn(min) -> bool {
|
||||
/// exists (b in B) { b(min) }
|
||||
/// }
|
||||
///
|
||||
/// In other words, if we meet some bound in `B`, that suffices.
|
||||
/// This is used when all the bounds in `B` are known to apply to
|
||||
/// G.
|
||||
AnyBound(Vec<VerifyBound<'tcx>>),
|
||||
|
||||
/// B = forall {B} --> 'min must meet all bounds b in {B}
|
||||
/// Given a set of bounds `B`, expands to the function:
|
||||
///
|
||||
/// fn(min) -> bool {
|
||||
/// forall (b in B) { b(min) }
|
||||
/// }
|
||||
///
|
||||
/// In other words, if we meet *all* bounds in `B`, that suffices.
|
||||
/// This is used when *some* bound in `B` is known to suffice, but
|
||||
/// we don't know which.
|
||||
AllBounds(Vec<VerifyBound<'tcx>>),
|
||||
}
|
||||
|
||||
|
|
@ -882,33 +947,23 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
|
||||
fn for_each_region(&self, f: &mut dyn FnMut(ty::Region<'tcx>)) {
|
||||
match self {
|
||||
&VerifyBound::AnyRegion(ref rs) | &VerifyBound::AllRegions(ref rs) => for &r in rs {
|
||||
f(r);
|
||||
},
|
||||
|
||||
&VerifyBound::AnyBound(ref bs) | &VerifyBound::AllBounds(ref bs) => for b in bs {
|
||||
b.for_each_region(f);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn must_hold(&self) -> bool {
|
||||
match self {
|
||||
&VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic),
|
||||
&VerifyBound::AllRegions(ref bs) => bs.is_empty(),
|
||||
&VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()),
|
||||
&VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()),
|
||||
VerifyBound::IfEq(..) => false,
|
||||
VerifyBound::OutlivedBy(ty::ReStatic) => true,
|
||||
VerifyBound::OutlivedBy(_) => false,
|
||||
VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
|
||||
VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cannot_hold(&self) -> bool {
|
||||
match self {
|
||||
&VerifyBound::AnyRegion(ref bs) => bs.is_empty(),
|
||||
&VerifyBound::AllRegions(ref bs) => bs.contains(&&ty::ReEmpty),
|
||||
&VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()),
|
||||
&VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()),
|
||||
VerifyBound::IfEq(_, b) => b.cannot_hold(),
|
||||
VerifyBound::OutlivedBy(ty::ReEmpty) => true,
|
||||
VerifyBound::OutlivedBy(_) => false,
|
||||
VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
|
||||
VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,34 +13,39 @@ use super::*;
|
|||
#[derive(Debug)]
|
||||
pub(super) struct TaintSet<'tcx> {
|
||||
directions: TaintDirections,
|
||||
regions: FxHashSet<ty::Region<'tcx>>
|
||||
regions: FxHashSet<ty::Region<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TaintSet<'tcx> {
|
||||
pub(super) fn new(directions: TaintDirections,
|
||||
initial_region: ty::Region<'tcx>)
|
||||
-> Self {
|
||||
pub(super) fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
|
||||
let mut regions = FxHashSet();
|
||||
regions.insert(initial_region);
|
||||
TaintSet { directions: directions, regions: regions }
|
||||
TaintSet {
|
||||
directions: directions,
|
||||
regions: regions,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn fixed_point(&mut self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
undo_log: &[UndoLogEntry<'tcx>],
|
||||
verifys: &[Verify<'tcx>]) {
|
||||
pub(super) fn fixed_point(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
undo_log: &[UndoLogEntry<'tcx>],
|
||||
verifys: &[Verify<'tcx>],
|
||||
) {
|
||||
let mut prev_len = 0;
|
||||
while prev_len < self.len() {
|
||||
debug!("tainted: prev_len = {:?} new_len = {:?}",
|
||||
prev_len, self.len());
|
||||
debug!(
|
||||
"tainted: prev_len = {:?} new_len = {:?}",
|
||||
prev_len,
|
||||
self.len()
|
||||
);
|
||||
|
||||
prev_len = self.len();
|
||||
|
||||
for undo_entry in undo_log {
|
||||
match undo_entry {
|
||||
&AddConstraint(Constraint::VarSubVar(a, b)) => {
|
||||
self.add_edge(tcx.mk_region(ReVar(a)),
|
||||
tcx.mk_region(ReVar(b)));
|
||||
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddConstraint(Constraint::RegSubVar(a, b)) => {
|
||||
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||
|
|
@ -55,15 +60,13 @@ impl<'tcx> TaintSet<'tcx> {
|
|||
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddVerify(i) => {
|
||||
verifys[i].bound.for_each_region(&mut |b| {
|
||||
self.add_edge(verifys[i].region, b);
|
||||
});
|
||||
span_bug!(
|
||||
verifys[i].origin.span(),
|
||||
"we never add verifications while doing higher-ranked things",
|
||||
)
|
||||
}
|
||||
&Purged |
|
||||
&AddCombination(..) |
|
||||
&AddVar(..) |
|
||||
&OpenSnapshot |
|
||||
&CommitedSnapshot => {}
|
||||
&Purged | &AddCombination(..) | &AddVar(..) | &OpenSnapshot
|
||||
| &CommitedSnapshot => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -77,9 +80,7 @@ impl<'tcx> TaintSet<'tcx> {
|
|||
self.regions.len()
|
||||
}
|
||||
|
||||
fn add_edge(&mut self,
|
||||
source: ty::Region<'tcx>,
|
||||
target: ty::Region<'tcx>) {
|
||||
fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
|
||||
if self.directions.incoming {
|
||||
if self.regions.contains(&target) {
|
||||
self.regions.insert(source);
|
||||
|
|
@ -93,4 +94,3 @@ impl<'tcx> TaintSet<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -338,6 +338,12 @@ declare_lint! {
|
|||
cannot be referred to by absolute paths"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub EXPLICIT_OUTLIVES_REQUIREMENTS,
|
||||
Allow,
|
||||
"outlives requirements can be inferred"
|
||||
}
|
||||
|
||||
/// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`.
|
||||
pub mod parser {
|
||||
declare_lint! {
|
||||
|
|
|
|||
|
|
@ -1631,7 +1631,7 @@ impl<'tcx> Statement<'tcx> {
|
|||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum StatementKind<'tcx> {
|
||||
/// Write the RHS Rvalue to the LHS Place.
|
||||
Assign(Place<'tcx>, Rvalue<'tcx>),
|
||||
Assign(Place<'tcx>, Box<Rvalue<'tcx>>),
|
||||
|
||||
/// This represents all the reading that a pattern match may do
|
||||
/// (e.g. inspecting constants and discriminant values), and the
|
||||
|
|
@ -1654,8 +1654,8 @@ pub enum StatementKind<'tcx> {
|
|||
/// Execute a piece of inline Assembly.
|
||||
InlineAsm {
|
||||
asm: Box<InlineAsm>,
|
||||
outputs: Vec<Place<'tcx>>,
|
||||
inputs: Vec<Operand<'tcx>>,
|
||||
outputs: Box<[Place<'tcx>]>,
|
||||
inputs: Box<[Operand<'tcx>]>,
|
||||
},
|
||||
|
||||
/// Assert the given places to be valid inhabitants of their type. These statements are
|
||||
|
|
|
|||
|
|
@ -1385,6 +1385,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"run the self profiler"),
|
||||
profile_json: bool = (false, parse_bool, [UNTRACKED],
|
||||
"output a json file with profiler results"),
|
||||
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
|
||||
"emits a section containing stack size metadata"),
|
||||
}
|
||||
|
||||
pub fn default_lib_output() -> CrateType {
|
||||
|
|
|
|||
|
|
@ -16,10 +16,9 @@ use super::*;
|
|||
use std::collections::hash_map::Entry;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
||||
use infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use infer::{InferCtxt, RegionObligation};
|
||||
use infer::InferCtxt;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
||||
use ty::fold::TypeFolder;
|
||||
use ty::{Region, RegionVid};
|
||||
|
|
@ -227,20 +226,18 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
|
||||
_ => None
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let body_ids: FxHashSet<_> = infcx
|
||||
let body_id_map: FxHashMap<_, _> = infcx
|
||||
.region_obligations
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|&(id, _)| id)
|
||||
.map(|&(id, _)| (id, vec![]))
|
||||
.collect();
|
||||
|
||||
for id in body_ids {
|
||||
infcx.process_registered_region_obligations(&[], None, full_env.clone(), id);
|
||||
}
|
||||
infcx.process_registered_region_obligations(&body_id_map, None, full_env.clone());
|
||||
|
||||
let region_data = infcx
|
||||
.borrow_region_constraints()
|
||||
|
|
@ -359,8 +356,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
&Err(SelectionError::Unimplemented) => {
|
||||
if self.is_of_param(pred.skip_binder().trait_ref.substs) {
|
||||
already_visited.remove(&pred);
|
||||
self.add_user_pred(&mut user_computed_preds,
|
||||
ty::Predicate::Trait(pred.clone()));
|
||||
self.add_user_pred(
|
||||
&mut user_computed_preds,
|
||||
ty::Predicate::Trait(pred.clone()),
|
||||
);
|
||||
predicates.push_back(pred);
|
||||
} else {
|
||||
debug!(
|
||||
|
|
@ -418,8 +417,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
// under which a type implements an auto trait. A trait predicate involving
|
||||
// a HRTB means that the type needs to work with any choice of lifetime,
|
||||
// not just one specific lifetime (e.g. 'static).
|
||||
fn add_user_pred<'c>(&self, user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>,
|
||||
new_pred: ty::Predicate<'c>) {
|
||||
fn add_user_pred<'c>(
|
||||
&self,
|
||||
user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>,
|
||||
new_pred: ty::Predicate<'c>,
|
||||
) {
|
||||
let mut should_add_new = true;
|
||||
user_computed_preds.retain(|&old_pred| {
|
||||
match (&new_pred, old_pred) {
|
||||
|
|
@ -431,20 +433,19 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
if !new_substs.types().eq(old_substs.types()) {
|
||||
// We can't compare lifetimes if the types are different,
|
||||
// so skip checking old_pred
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
for (new_region, old_region) in new_substs
|
||||
.regions()
|
||||
.zip(old_substs.regions()) {
|
||||
|
||||
for (new_region, old_region) in
|
||||
new_substs.regions().zip(old_substs.regions())
|
||||
{
|
||||
match (new_region, old_region) {
|
||||
// If both predicates have an 'ReLateBound' (a HRTB) in the
|
||||
// same spot, we do nothing
|
||||
(
|
||||
ty::RegionKind::ReLateBound(_, _),
|
||||
ty::RegionKind::ReLateBound(_, _)
|
||||
) => {},
|
||||
ty::RegionKind::ReLateBound(_, _),
|
||||
) => {}
|
||||
|
||||
(ty::RegionKind::ReLateBound(_, _), _) => {
|
||||
// The new predicate has a HRTB in a spot where the old
|
||||
|
|
@ -458,7 +459,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
// so we return 'false' to remove the old predicate from
|
||||
// user_computed_preds
|
||||
return false;
|
||||
},
|
||||
}
|
||||
(_, ty::RegionKind::ReLateBound(_, _)) => {
|
||||
// This is the opposite situation as the previous arm - the
|
||||
// old predicate has a HRTB lifetime in a place where the
|
||||
|
|
@ -471,10 +472,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return true
|
||||
return true;
|
||||
});
|
||||
|
||||
if should_add_new {
|
||||
|
|
@ -513,28 +514,20 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
match constraint {
|
||||
&Constraint::VarSubVar(r1, r2) => {
|
||||
{
|
||||
let deps1 = vid_map
|
||||
.entry(RegionTarget::RegionVid(r1))
|
||||
.or_default();
|
||||
let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
|
||||
deps1.larger.insert(RegionTarget::RegionVid(r2));
|
||||
}
|
||||
|
||||
let deps2 = vid_map
|
||||
.entry(RegionTarget::RegionVid(r2))
|
||||
.or_default();
|
||||
let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
|
||||
deps2.smaller.insert(RegionTarget::RegionVid(r1));
|
||||
}
|
||||
&Constraint::RegSubVar(region, vid) => {
|
||||
{
|
||||
let deps1 = vid_map
|
||||
.entry(RegionTarget::Region(region))
|
||||
.or_default();
|
||||
let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default();
|
||||
deps1.larger.insert(RegionTarget::RegionVid(vid));
|
||||
}
|
||||
|
||||
let deps2 = vid_map
|
||||
.entry(RegionTarget::RegionVid(vid))
|
||||
.or_default();
|
||||
let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
|
||||
deps2.smaller.insert(RegionTarget::Region(region));
|
||||
}
|
||||
&Constraint::VarSubReg(vid, region) => {
|
||||
|
|
@ -542,15 +535,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
}
|
||||
&Constraint::RegSubReg(r1, r2) => {
|
||||
{
|
||||
let deps1 = vid_map
|
||||
.entry(RegionTarget::Region(r1))
|
||||
.or_default();
|
||||
let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default();
|
||||
deps1.larger.insert(RegionTarget::Region(r2));
|
||||
}
|
||||
|
||||
let deps2 = vid_map
|
||||
.entry(RegionTarget::Region(r2))
|
||||
.or_default();
|
||||
let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default();
|
||||
deps2.smaller.insert(RegionTarget::Region(r1));
|
||||
}
|
||||
}
|
||||
|
|
@ -683,7 +672,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
&ty::Predicate::RegionOutlives(ref binder) => {
|
||||
if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() {
|
||||
if select
|
||||
.infcx()
|
||||
.region_outlives_predicate(&dummy_cause, binder)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -693,23 +686,17 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(),
|
||||
) {
|
||||
(None, Some(t_a)) => {
|
||||
select.infcx().register_region_obligation(
|
||||
ast::DUMMY_NODE_ID,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: select.infcx().tcx.types.re_static,
|
||||
cause: dummy_cause.clone(),
|
||||
},
|
||||
select.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
select.infcx().tcx.types.re_static,
|
||||
&dummy_cause,
|
||||
);
|
||||
}
|
||||
(Some(ty::OutlivesPredicate(t_a, r_b)), _) => {
|
||||
select.infcx().register_region_obligation(
|
||||
ast::DUMMY_NODE_ID,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_b,
|
||||
cause: dummy_cause.clone(),
|
||||
},
|
||||
select.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
r_b,
|
||||
&dummy_cause,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -96,10 +96,10 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, '
|
|||
|
||||
let header = ty::ImplHeader {
|
||||
impl_def_id,
|
||||
self_ty: tcx.type_of(impl_def_id),
|
||||
trait_ref: tcx.impl_trait_ref(impl_def_id),
|
||||
predicates: tcx.predicates_of(impl_def_id).predicates
|
||||
}.subst(tcx, impl_substs);
|
||||
self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs),
|
||||
trait_ref: tcx.impl_trait_ref(impl_def_id).subst(tcx, impl_substs),
|
||||
predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
|
||||
};
|
||||
|
||||
let Normalized { value: mut header, obligations } =
|
||||
traits::normalize(selcx, param_env, ObligationCause::dummy(), &header);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use infer::{RegionObligation, InferCtxt};
|
||||
use infer::InferCtxt;
|
||||
use mir::interpret::GlobalId;
|
||||
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
|
||||
use ty::error::ExpectedFound;
|
||||
|
|
@ -372,13 +372,11 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
|||
Some(t_a) => {
|
||||
let r_static = self.selcx.tcx().types.re_static;
|
||||
if self.register_region_obligations {
|
||||
self.selcx.infcx().register_region_obligation(
|
||||
obligation.cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_static,
|
||||
cause: obligation.cause.clone(),
|
||||
});
|
||||
self.selcx.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
r_static,
|
||||
&obligation.cause,
|
||||
);
|
||||
}
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
|
|
@ -387,13 +385,11 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
|||
// If there aren't, register the obligation.
|
||||
Some(ty::OutlivesPredicate(t_a, r_b)) => {
|
||||
if self.register_region_obligations {
|
||||
self.selcx.infcx().register_region_obligation(
|
||||
obligation.cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_b,
|
||||
cause: obligation.cause.clone()
|
||||
});
|
||||
self.selcx.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
r_b,
|
||||
&obligation.cause,
|
||||
);
|
||||
}
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ pub use self::ObligationCauseCode::*;
|
|||
use chalk_engine;
|
||||
use hir;
|
||||
use hir::def_id::DefId;
|
||||
use infer::SuppressRegionErrors;
|
||||
use infer::outlives::env::OutlivesEnvironment;
|
||||
use middle::region;
|
||||
use mir::interpret::ConstEvalErr;
|
||||
|
|
@ -715,7 +716,12 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
// cares about declarations like `'a: 'b`.
|
||||
let outlives_env = OutlivesEnvironment::new(elaborated_env);
|
||||
|
||||
infcx.resolve_regions_and_report_errors(region_context, ®ion_scope_tree, &outlives_env);
|
||||
infcx.resolve_regions_and_report_errors(
|
||||
region_context,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
);
|
||||
|
||||
let predicates = match infcx.fully_resolve(&predicates) {
|
||||
Ok(predicates) => predicates,
|
||||
|
|
@ -810,11 +816,10 @@ fn substitute_normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
|
|||
key: (DefId, &'tcx Substs<'tcx>))
|
||||
-> bool
|
||||
{
|
||||
use ty::subst::Subst;
|
||||
debug!("substitute_normalize_and_test_predicates(key={:?})",
|
||||
key);
|
||||
|
||||
let predicates = tcx.predicates_of(key.0).predicates.subst(tcx, key.1);
|
||||
let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
|
||||
let result = normalize_and_test_predicates(tcx, predicates);
|
||||
|
||||
debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}",
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
predicates
|
||||
.predicates
|
||||
.into_iter()
|
||||
.map(|predicate| predicate.subst_supertrait(self, &trait_ref))
|
||||
.map(|(predicate, _)| predicate.subst_supertrait(self, &trait_ref))
|
||||
.any(|predicate| {
|
||||
match predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
|
|
@ -311,7 +311,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
if self.predicates_of(method.def_id).predicates.into_iter()
|
||||
// A trait object can't claim to live more than the concrete type,
|
||||
// so outlives predicates will always hold.
|
||||
.filter(|p| p.to_opt_type_outlives().is_none())
|
||||
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
|
||||
.collect::<Vec<_>>()
|
||||
// Do a shallow visit so that `contains_illegal_self_type_reference`
|
||||
// may apply it's custom visiting.
|
||||
|
|
|
|||
|
|
@ -3401,7 +3401,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
// that order.
|
||||
let predicates = tcx.predicates_of(def_id);
|
||||
assert_eq!(predicates.parent, None);
|
||||
let mut predicates: Vec<_> = predicates.predicates.iter().flat_map(|predicate| {
|
||||
let mut predicates: Vec<_> = predicates.predicates.iter().flat_map(|(predicate, _)| {
|
||||
let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth,
|
||||
&predicate.subst(tcx, substs));
|
||||
predicate.obligations.into_iter().chain(
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option<String> {
|
|||
let mut pretty_predicates = Vec::with_capacity(
|
||||
predicates.len() + types_without_default_bounds.len());
|
||||
|
||||
for p in predicates {
|
||||
for (p, _) in predicates {
|
||||
if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
|
||||
if Some(poly_trait_ref.def_id()) == sized_trait {
|
||||
types_without_default_bounds.remove(poly_trait_ref.self_ty());
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
|
|||
let mut predicates: Vec<_> =
|
||||
predicates.predicates
|
||||
.iter()
|
||||
.map(|p| p.subst_supertrait(tcx, &data.to_poly_trait_ref()))
|
||||
.map(|(p, _)| p.subst_supertrait(tcx, &data.to_poly_trait_ref()))
|
||||
.collect();
|
||||
|
||||
debug!("super_predicates: data={:?} predicates={:?}",
|
||||
|
|
@ -311,7 +311,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> {
|
|||
self.stack.extend(
|
||||
predicates.predicates
|
||||
.iter()
|
||||
.filter_map(|p| p.to_opt_poly_trait_ref())
|
||||
.filter_map(|(p, _)| p.to_opt_poly_trait_ref())
|
||||
.map(|t| t.def_id())
|
||||
.filter(|&super_def_id| visited.insert(super_def_id)));
|
||||
Some(def_id)
|
||||
|
|
|
|||
|
|
@ -109,8 +109,9 @@ pub fn encode_predicates<'tcx, E, C>(encoder: &mut E,
|
|||
{
|
||||
predicates.parent.encode(encoder)?;
|
||||
predicates.predicates.len().encode(encoder)?;
|
||||
for predicate in &predicates.predicates {
|
||||
encode_with_shorthand(encoder, predicate, &cache)?
|
||||
for (predicate, span) in &predicates.predicates {
|
||||
encode_with_shorthand(encoder, predicate, &cache)?;
|
||||
span.encode(encoder)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -178,7 +179,7 @@ pub fn decode_predicates<'a, 'tcx, D>(decoder: &mut D)
|
|||
parent: Decodable::decode(decoder)?,
|
||||
predicates: (0..decoder.read_usize()?).map(|_| {
|
||||
// Handle shorthands first, if we have an usize > 0x80.
|
||||
if decoder.positioned_at_shorthand() {
|
||||
let predicate = if decoder.positioned_at_shorthand() {
|
||||
let pos = decoder.read_usize()?;
|
||||
assert!(pos >= SHORTHAND_OFFSET);
|
||||
let shorthand = pos - SHORTHAND_OFFSET;
|
||||
|
|
@ -186,7 +187,8 @@ pub fn decode_predicates<'a, 'tcx, D>(decoder: &mut D)
|
|||
decoder.with_position(shorthand, ty::Predicate::decode)
|
||||
} else {
|
||||
ty::Predicate::decode(decoder)
|
||||
}
|
||||
}?;
|
||||
Ok((predicate, Decodable::decode(decoder)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
|||
}
|
||||
}
|
||||
|
||||
if sized && fields.iter().any(|f| f.abi.is_uninhabited()) {
|
||||
if sized && fields.iter().any(|f| f.abi == Abi::Uninhabited) {
|
||||
abi = Abi::Uninhabited;
|
||||
}
|
||||
|
||||
|
|
@ -724,7 +724,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
|||
// See issue #49298 for more details on the need to leave space
|
||||
// for non-ZST uninhabited data (mostly partial initialization).
|
||||
let absent = |fields: &[TyLayout]| {
|
||||
let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
|
||||
let uninhabited = fields.iter().any(|f| f.abi == Abi::Uninhabited);
|
||||
let is_zst = fields.iter().all(|f| f.is_zst());
|
||||
uninhabited && is_zst
|
||||
};
|
||||
|
|
@ -872,7 +872,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
|||
_ => Abi::Aggregate { sized: true },
|
||||
};
|
||||
|
||||
if st.iter().all(|v| v.abi.is_uninhabited()) {
|
||||
if st.iter().all(|v| v.abi == Abi::Uninhabited) {
|
||||
abi = Abi::Uninhabited;
|
||||
}
|
||||
|
||||
|
|
@ -900,7 +900,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
|||
let discr_type = def.repr.discr_type();
|
||||
let bits = Integer::from_attr(tcx, discr_type).size().bits();
|
||||
for (i, discr) in def.discriminants(tcx).enumerate() {
|
||||
if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
|
||||
if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) {
|
||||
continue;
|
||||
}
|
||||
let mut x = discr.val as i128;
|
||||
|
|
@ -1096,7 +1096,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
|||
}
|
||||
}
|
||||
|
||||
if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
|
||||
if layout_variants.iter().all(|v| v.abi == Abi::Uninhabited) {
|
||||
abi = Abi::Uninhabited;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -982,7 +982,7 @@ impl<'a, 'gcx, 'tcx> Generics {
|
|||
#[derive(Clone, Default)]
|
||||
pub struct GenericPredicates<'tcx> {
|
||||
pub parent: Option<DefId>,
|
||||
pub predicates: Vec<Predicate<'tcx>>,
|
||||
pub predicates: Vec<(Predicate<'tcx>, Span)>,
|
||||
}
|
||||
|
||||
impl<'tcx> serialize::UseSpecializedEncodable for GenericPredicates<'tcx> {}
|
||||
|
|
@ -998,7 +998,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
|
|||
pub fn instantiate_own(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>)
|
||||
-> InstantiatedPredicates<'tcx> {
|
||||
InstantiatedPredicates {
|
||||
predicates: self.predicates.subst(tcx, substs)
|
||||
predicates: self.predicates.iter().map(|(p, _)| p.subst(tcx, substs)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1008,7 +1008,9 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
|
|||
if let Some(def_id) = self.parent {
|
||||
tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs);
|
||||
}
|
||||
instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs)))
|
||||
instantiated.predicates.extend(
|
||||
self.predicates.iter().map(|(p, _)| p.subst(tcx, substs)),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn instantiate_identity(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
|
|
@ -1023,7 +1025,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
|
|||
if let Some(def_id) = self.parent {
|
||||
tcx.predicates_of(def_id).instantiate_identity_into(tcx, instantiated);
|
||||
}
|
||||
instantiated.predicates.extend(&self.predicates)
|
||||
instantiated.predicates.extend(self.predicates.iter().map(|&(p, _)| p))
|
||||
}
|
||||
|
||||
pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
|
@ -1032,7 +1034,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
|
|||
{
|
||||
assert_eq!(self.parent, None);
|
||||
InstantiatedPredicates {
|
||||
predicates: self.predicates.iter().map(|pred| {
|
||||
predicates: self.predicates.iter().map(|(pred, _)| {
|
||||
pred.subst_supertrait(tcx, poly_trait_ref)
|
||||
}).collect()
|
||||
}
|
||||
|
|
@ -2351,7 +2353,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||
substs: tcx.mk_substs_trait(ty, &[])
|
||||
}).to_predicate();
|
||||
let predicates = tcx.predicates_of(self.did).predicates;
|
||||
if predicates.into_iter().any(|p| p == sized_predicate) {
|
||||
if predicates.into_iter().any(|(p, _)| p == sized_predicate) {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ty]
|
||||
|
|
|
|||
|
|
@ -606,6 +606,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder<interpret::AllocId> for CacheDecoder<'a, '
|
|||
alloc_decoding_session.decode_alloc_id(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
|
||||
fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
|
||||
let tag: u8 = Decodable::decode(self)?;
|
||||
|
|
|
|||
|
|
@ -720,6 +720,16 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>().into_boxed_slice()
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.iter().any(|t| t.visit_with(visitor))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
self.map_bound_ref(|ty| ty.fold_with(folder))
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub fn codegen_inline_asm(
|
|||
ia: &hir::InlineAsm,
|
||||
outputs: Vec<PlaceRef<'ll, 'tcx>>,
|
||||
mut inputs: Vec<&'ll Value>
|
||||
) {
|
||||
) -> bool {
|
||||
let mut ext_constraints = vec![];
|
||||
let mut output_types = vec![];
|
||||
|
||||
|
|
@ -97,6 +97,10 @@ pub fn codegen_inline_asm(
|
|||
ia.alignstack,
|
||||
dialect
|
||||
);
|
||||
if r.is_none() {
|
||||
return false;
|
||||
}
|
||||
let r = r.unwrap();
|
||||
|
||||
// Again, based on how many outputs we have
|
||||
let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
|
||||
|
|
@ -117,6 +121,8 @@ pub fn codegen_inline_asm(
|
|||
llvm::LLVMSetMetadata(r, kind,
|
||||
llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn codegen_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ use std::str;
|
|||
use syntax::attr;
|
||||
|
||||
pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
|
||||
invalid_output_for_target, out_filename, check_file_is_writeable};
|
||||
invalid_output_for_target, out_filename, check_file_is_writeable,
|
||||
filename_for_metadata};
|
||||
|
||||
// The third parameter is for env vars, used on windows to set up the
|
||||
// path for MSVC to find its DLLs, and gcc to find its bundled
|
||||
|
|
@ -218,15 +219,6 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf {
|
||||
let out_filename = outputs.single_output_file.clone()
|
||||
.unwrap_or(outputs
|
||||
.out_directory
|
||||
.join(&format!("lib{}{}.rmeta", crate_name, sess.opts.cg.extra_filename)));
|
||||
check_file_is_writeable(&out_filename, sess);
|
||||
out_filename
|
||||
}
|
||||
|
||||
pub(crate) fn each_linked_rlib(sess: &Session,
|
||||
info: &CrateInfo,
|
||||
f: &mut dyn FnMut(CrateNum, &Path)) -> Result<(), String> {
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
|
|||
let features = CString::new(features).unwrap();
|
||||
let is_pie_binary = !find_features && is_pie_binary(sess);
|
||||
let trap_unreachable = sess.target.target.options.trap_unreachable;
|
||||
let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
|
||||
|
||||
let asm_comments = sess.asm_comments();
|
||||
|
||||
|
|
@ -213,6 +214,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
|
|||
trap_unreachable,
|
||||
singlethread,
|
||||
asm_comments,
|
||||
emit_stack_size_section,
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -737,7 +737,7 @@ impl Builder<'a, 'll, 'tcx> {
|
|||
pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
|
||||
inputs: &[&'ll Value], output: &'ll Type,
|
||||
volatile: bool, alignstack: bool,
|
||||
dia: AsmDialect) -> &'ll Value {
|
||||
dia: AsmDialect) -> Option<&'ll Value> {
|
||||
self.count_insn("inlineasm");
|
||||
|
||||
let volatile = if volatile { llvm::True }
|
||||
|
|
@ -753,9 +753,17 @@ impl Builder<'a, 'll, 'tcx> {
|
|||
debug!("Asm Output Type: {:?}", output);
|
||||
let fty = Type::func(&argtys[..], output);
|
||||
unsafe {
|
||||
let v = llvm::LLVMRustInlineAsm(
|
||||
fty, asm, cons, volatile, alignstack, dia);
|
||||
self.call(v, inputs, None)
|
||||
// Ask LLVM to verify that the constraints are well-formed.
|
||||
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons);
|
||||
debug!("Constraint verification result: {:?}", constraints_ok);
|
||||
if constraints_ok == llvm::True {
|
||||
let v = llvm::LLVMRustInlineAsm(
|
||||
fty, asm, cons, volatile, alignstack, dia);
|
||||
Some(self.call(v, inputs, None))
|
||||
} else {
|
||||
// LLVM has detected an issue with our constaints, bail out
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ pub fn create_function_debug_context(
|
|||
}
|
||||
None => {}
|
||||
};
|
||||
if cx.layout_of(sig.output()).abi.is_uninhabited() {
|
||||
if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited {
|
||||
flags = flags | DIFlags::FlagNoReturn;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
use llvm;
|
||||
use llvm::AttributePlace::Function;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::LayoutOf;
|
||||
use rustc::ty::layout::{self, LayoutOf};
|
||||
use rustc::session::config::Sanitizer;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
|
@ -137,7 +137,7 @@ pub fn declare_fn(
|
|||
let fty = FnType::new(cx, sig, &[]);
|
||||
let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx));
|
||||
|
||||
if cx.layout_of(sig.output()).abi.is_uninhabited() {
|
||||
if cx.layout_of(sig.output()).abi == layout::Abi::Uninhabited {
|
||||
llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,4 +47,26 @@ unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
|
|||
```
|
||||
"##,
|
||||
|
||||
E0668: r##"
|
||||
Malformed inline assembly rejected by LLVM.
|
||||
|
||||
LLVM checks the validity of the constraints and the assembly string passed to
|
||||
it. This error implies that LLVM seems something wrong with the inline
|
||||
assembly call.
|
||||
|
||||
In particular, it can happen if you forgot the closing bracket of a register
|
||||
constraint (see issue #51430):
|
||||
```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
|
||||
#![feature(asm)]
|
||||
|
||||
fn main() {
|
||||
let rax: u64;
|
||||
unsafe {
|
||||
asm!("" :"={rax"(rax));
|
||||
println!("Accumulator is: {}", rax);
|
||||
}
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1208,6 +1208,9 @@ extern "C" {
|
|||
AlignStack: Bool,
|
||||
Dialect: AsmDialect)
|
||||
-> &Value;
|
||||
pub fn LLVMRustInlineAsmVerify(Ty: &Type,
|
||||
Constraints: *const c_char)
|
||||
-> Bool;
|
||||
|
||||
pub fn LLVMRustDebugMetadataVersion() -> u32;
|
||||
pub fn LLVMRustVersionMajor() -> u32;
|
||||
|
|
@ -1460,7 +1463,8 @@ extern "C" {
|
|||
DataSections: bool,
|
||||
TrapUnreachable: bool,
|
||||
Singlethread: bool,
|
||||
AsmComments: bool)
|
||||
AsmComments: bool,
|
||||
EmitStackSizeSection: bool)
|
||||
-> Option<&'static mut TargetMachine>;
|
||||
pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
|
||||
pub fn LLVMRustAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>, M: &'a Module);
|
||||
|
|
|
|||
|
|
@ -482,54 +482,6 @@ impl FunctionCx<'a, 'll, 'tcx> {
|
|||
_ => FnType::new(bx.cx, sig, &extra_args)
|
||||
};
|
||||
|
||||
// emit a panic instead of instantiating an uninhabited type
|
||||
if (intrinsic == Some("init") || intrinsic == Some("uninit")) &&
|
||||
fn_ty.ret.layout.abi.is_uninhabited()
|
||||
{
|
||||
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
|
||||
let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
|
||||
let filename = C_str_slice(bx.cx, filename);
|
||||
let line = C_u32(bx.cx, loc.line as u32);
|
||||
let col = C_u32(bx.cx, loc.col.to_usize() as u32 + 1);
|
||||
let align = tcx.data_layout.aggregate_align
|
||||
.max(tcx.data_layout.i32_align)
|
||||
.max(tcx.data_layout.pointer_align);
|
||||
|
||||
let str = format!(
|
||||
"Attempted to instantiate uninhabited type {} using mem::{}",
|
||||
sig.output(),
|
||||
if intrinsic == Some("init") { "zeroed" } else { "uninitialized" }
|
||||
);
|
||||
let msg_str = Symbol::intern(&str).as_str();
|
||||
let msg_str = C_str_slice(bx.cx, msg_str);
|
||||
let msg_file_line_col = C_struct(bx.cx,
|
||||
&[msg_str, filename, line, col],
|
||||
false);
|
||||
let msg_file_line_col = consts::addr_of(bx.cx,
|
||||
msg_file_line_col,
|
||||
align,
|
||||
Some("panic_loc"));
|
||||
|
||||
// Obtain the panic entry point.
|
||||
let def_id =
|
||||
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
|
||||
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
||||
let fn_ty = FnType::of_instance(bx.cx, &instance);
|
||||
let llfn = callee::get_fn(bx.cx, instance);
|
||||
|
||||
// Codegen the actual panic invoke/call.
|
||||
do_call(
|
||||
self,
|
||||
bx,
|
||||
fn_ty,
|
||||
llfn,
|
||||
&[msg_file_line_col],
|
||||
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
|
||||
cleanup,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// The arguments we'll be passing. Plus one to account for outptr, if used.
|
||||
let arg_count = fn_ty.args.len() + fn_ty.ret.is_indirect() as usize;
|
||||
let mut llargs = Vec::with_capacity(arg_count);
|
||||
|
|
|
|||
|
|
@ -173,10 +173,7 @@ impl PlaceRef<'ll, 'tcx> {
|
|||
let cx = bx.cx;
|
||||
let field = self.layout.field(cx, ix);
|
||||
let offset = self.layout.fields.offset(ix);
|
||||
let effective_field_align = self.align
|
||||
.min(self.layout.align)
|
||||
.min(field.align)
|
||||
.restrict_for_offset(offset);
|
||||
let effective_field_align = self.align.restrict_for_offset(offset);
|
||||
|
||||
let simple = || {
|
||||
// Unions and newtypes only use an offset of 0.
|
||||
|
|
@ -278,7 +275,7 @@ impl PlaceRef<'ll, 'tcx> {
|
|||
/// Obtain the actual discriminant of a value.
|
||||
pub fn codegen_get_discr(self, bx: &Builder<'a, 'll, 'tcx>, cast_to: Ty<'tcx>) -> &'ll Value {
|
||||
let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx);
|
||||
if self.layout.abi.is_uninhabited() {
|
||||
if self.layout.abi == layout::Abi::Uninhabited {
|
||||
return C_undef(cast_to);
|
||||
}
|
||||
match self.layout.variants {
|
||||
|
|
@ -341,7 +338,7 @@ impl PlaceRef<'ll, 'tcx> {
|
|||
/// Set the discriminant for a new value of the given case of the given
|
||||
/// representation.
|
||||
pub fn codegen_set_discr(&self, bx: &Builder<'a, 'll, 'tcx>, variant_index: usize) {
|
||||
if self.layout.for_variant(bx.cx, variant_index).abi.is_uninhabited() {
|
||||
if self.layout.for_variant(bx.cx, variant_index).abi == layout::Abi::Uninhabited {
|
||||
return;
|
||||
}
|
||||
match self.layout.variants {
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
|
|||
mir::CastKind::Misc => {
|
||||
assert!(cast.is_llvm_immediate());
|
||||
let ll_t_out = cast.immediate_llvm_type(bx.cx);
|
||||
if operand.layout.abi.is_uninhabited() {
|
||||
if operand.layout.abi == layout::Abi::Uninhabited {
|
||||
return (bx, OperandRef {
|
||||
val: OperandValue::Immediate(C_undef(ll_t_out)),
|
||||
layout: cast,
|
||||
|
|
|
|||
|
|
@ -86,7 +86,11 @@ impl FunctionCx<'a, 'll, 'tcx> {
|
|||
self.codegen_operand(&bx, input).immediate()
|
||||
}).collect();
|
||||
|
||||
asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
|
||||
let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
|
||||
if !res {
|
||||
span_err!(bx.sess(), statement.source_info.span, E0668,
|
||||
"malformed inline assembly");
|
||||
}
|
||||
bx
|
||||
}
|
||||
mir::StatementKind::FakeRead(..) |
|
||||
|
|
|
|||
|
|
@ -97,6 +97,19 @@ pub fn find_crate_name(sess: Option<&Session>,
|
|||
"rust_out".to_string()
|
||||
}
|
||||
|
||||
pub fn filename_for_metadata(sess: &Session,
|
||||
crate_name: &str,
|
||||
outputs: &OutputFilenames) -> PathBuf {
|
||||
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
|
||||
|
||||
let out_filename = outputs.single_output_file.clone()
|
||||
.unwrap_or(outputs.out_directory.join(&format!("lib{}.rmeta", libname)));
|
||||
|
||||
check_file_is_writeable(&out_filename, sess);
|
||||
|
||||
out_filename
|
||||
}
|
||||
|
||||
pub fn filename_for_input(sess: &Session,
|
||||
crate_type: config::CrateType,
|
||||
crate_name: &str,
|
||||
|
|
|
|||
|
|
@ -535,6 +535,13 @@ impl<I: Idx, T> IndexVec<I, T> {
|
|||
self.raw.len()
|
||||
}
|
||||
|
||||
/// Gives the next index that will be assigned when `push` is
|
||||
/// called.
|
||||
#[inline]
|
||||
pub fn next_index(&self) -> I {
|
||||
I::new(self.len())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.raw.is_empty()
|
||||
|
|
|
|||
|
|
@ -980,6 +980,7 @@ pub fn enable_save_analysis(control: &mut CompileController) {
|
|||
state.expanded_crate.unwrap(),
|
||||
state.analysis.unwrap(),
|
||||
state.crate_name.unwrap(),
|
||||
state.input,
|
||||
None,
|
||||
DumpHandler::new(state.out_dir,
|
||||
state.crate_name.unwrap()))
|
||||
|
|
|
|||
|
|
@ -14,29 +14,29 @@ use std::path::PathBuf;
|
|||
use std::sync::mpsc;
|
||||
|
||||
use driver;
|
||||
use rustc_lint;
|
||||
use rustc_resolve::MakeGlobMap;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::traits::ObligationCause;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::query::OnDiskCache;
|
||||
use rustc::infer::{self, InferOk, InferResult};
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::session::{self, config};
|
||||
use rustc::session::config::{OutputFilenames, OutputTypes};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use syntax;
|
||||
use syntax::ast;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::source_map::{SourceMap, FilePathMapping, FileName};
|
||||
use errors;
|
||||
use errors::emitter::Emitter;
|
||||
use errors::{Level, DiagnosticBuilder};
|
||||
use errors::{DiagnosticBuilder, Level};
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::infer::{self, InferOk, InferResult, SuppressRegionErrors};
|
||||
use rustc::middle::region;
|
||||
use rustc::session::config::{OutputFilenames, OutputTypes};
|
||||
use rustc::session::{self, config};
|
||||
use rustc::traits::ObligationCause;
|
||||
use rustc::ty::query::OnDiskCache;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use rustc_lint;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc_resolve::MakeGlobMap;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax;
|
||||
use syntax::ast;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use syntax::source_map::{FileName, FilePathMapping, SourceMap};
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
|
|
@ -90,13 +90,15 @@ impl Emitter for ExpectErrorEmitter {
|
|||
|
||||
fn errors(msgs: &[&str]) -> (Box<dyn Emitter + sync::Send>, usize) {
|
||||
let v = msgs.iter().map(|m| m.to_string()).collect();
|
||||
(box ExpectErrorEmitter { messages: v } as Box<dyn Emitter + sync::Send>, msgs.len())
|
||||
(
|
||||
box ExpectErrorEmitter { messages: v } as Box<dyn Emitter + sync::Send>,
|
||||
msgs.len(),
|
||||
)
|
||||
}
|
||||
|
||||
fn test_env<F>(source_string: &str,
|
||||
args: (Box<dyn Emitter + sync::Send>, usize),
|
||||
body: F)
|
||||
where F: FnOnce(Env)
|
||||
fn test_env<F>(source_string: &str, args: (Box<dyn Emitter + sync::Send>, usize), body: F)
|
||||
where
|
||||
F: FnOnce(Env),
|
||||
{
|
||||
syntax::with_globals(|| {
|
||||
let mut options = config::Options::default();
|
||||
|
|
@ -113,34 +115,41 @@ fn test_env_with_pool<F>(
|
|||
options: config::Options,
|
||||
source_string: &str,
|
||||
(emitter, expected_err_count): (Box<dyn Emitter + sync::Send>, usize),
|
||||
body: F
|
||||
)
|
||||
where F: FnOnce(Env)
|
||||
body: F,
|
||||
) where
|
||||
F: FnOnce(Env),
|
||||
{
|
||||
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
|
||||
let sess = session::build_session_(options,
|
||||
None,
|
||||
diagnostic_handler,
|
||||
Lrc::new(SourceMap::new(FilePathMapping::empty())));
|
||||
let sess = session::build_session_(
|
||||
options,
|
||||
None,
|
||||
diagnostic_handler,
|
||||
Lrc::new(SourceMap::new(FilePathMapping::empty())),
|
||||
);
|
||||
let cstore = CStore::new(::get_codegen_backend(&sess).metadata_loader());
|
||||
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
|
||||
let input = config::Input::Str {
|
||||
name: FileName::Anon,
|
||||
input: source_string.to_string(),
|
||||
};
|
||||
let krate = driver::phase_1_parse_input(&driver::CompileController::basic(),
|
||||
&sess,
|
||||
&input).unwrap();
|
||||
let driver::ExpansionResult { defs, resolutions, mut hir_forest, .. } = {
|
||||
driver::phase_2_configure_and_expand(&sess,
|
||||
&cstore,
|
||||
krate,
|
||||
None,
|
||||
"test",
|
||||
None,
|
||||
MakeGlobMap::No,
|
||||
|_| Ok(()))
|
||||
.expect("phase 2 aborted")
|
||||
let krate =
|
||||
driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input).unwrap();
|
||||
let driver::ExpansionResult {
|
||||
defs,
|
||||
resolutions,
|
||||
mut hir_forest,
|
||||
..
|
||||
} = {
|
||||
driver::phase_2_configure_and_expand(
|
||||
&sess,
|
||||
&cstore,
|
||||
krate,
|
||||
None,
|
||||
"test",
|
||||
None,
|
||||
MakeGlobMap::No,
|
||||
|_| Ok(()),
|
||||
).expect("phase 2 aborted")
|
||||
};
|
||||
|
||||
let arenas = ty::AllArenas::new();
|
||||
|
|
@ -155,32 +164,39 @@ fn test_env_with_pool<F>(
|
|||
extra: String::new(),
|
||||
outputs: OutputTypes::new(&[]),
|
||||
};
|
||||
TyCtxt::create_and_enter(&sess,
|
||||
&cstore,
|
||||
ty::query::Providers::default(),
|
||||
ty::query::Providers::default(),
|
||||
&arenas,
|
||||
resolutions,
|
||||
hir_map,
|
||||
OnDiskCache::new_empty(sess.source_map()),
|
||||
"test_crate",
|
||||
tx,
|
||||
&outputs,
|
||||
|tcx| {
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut region_scope_tree = region::ScopeTree::default();
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
body(Env {
|
||||
infcx: &infcx,
|
||||
region_scope_tree: &mut region_scope_tree,
|
||||
param_env: param_env,
|
||||
TyCtxt::create_and_enter(
|
||||
&sess,
|
||||
&cstore,
|
||||
ty::query::Providers::default(),
|
||||
ty::query::Providers::default(),
|
||||
&arenas,
|
||||
resolutions,
|
||||
hir_map,
|
||||
OnDiskCache::new_empty(sess.source_map()),
|
||||
"test_crate",
|
||||
tx,
|
||||
&outputs,
|
||||
|tcx| {
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut region_scope_tree = region::ScopeTree::default();
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
body(Env {
|
||||
infcx: &infcx,
|
||||
region_scope_tree: &mut region_scope_tree,
|
||||
param_env: param_env,
|
||||
});
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
|
||||
infcx.resolve_regions_and_report_errors(
|
||||
def_id,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
);
|
||||
assert_eq!(tcx.sess.err_count(), expected_err_count);
|
||||
});
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
|
||||
infcx.resolve_regions_and_report_errors(def_id, ®ion_scope_tree, &outlives_env);
|
||||
assert_eq!(tcx.sess.err_count(), expected_err_count);
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn d1() -> ty::DebruijnIndex {
|
||||
|
|
@ -196,9 +212,15 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
self.infcx.tcx
|
||||
}
|
||||
|
||||
pub fn create_region_hierarchy(&mut self, rh: &RH,
|
||||
parent: (region::Scope, region::ScopeDepth)) {
|
||||
let me = region::Scope { id: rh.id, data: region::ScopeData::Node };
|
||||
pub fn create_region_hierarchy(
|
||||
&mut self,
|
||||
rh: &RH,
|
||||
parent: (region::Scope, region::ScopeDepth),
|
||||
) {
|
||||
let me = region::Scope {
|
||||
id: rh.id,
|
||||
data: region::ScopeData::Node,
|
||||
};
|
||||
self.region_scope_tree.record_scope_parent(me, Some(parent));
|
||||
for child_rh in rh.sub {
|
||||
self.create_region_hierarchy(child_rh, (me, parent.1 + 1));
|
||||
|
|
@ -211,20 +233,25 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
|
||||
let dscope = region::Scope {
|
||||
id: hir::ItemLocalId(1),
|
||||
data: region::ScopeData::Destruction
|
||||
data: region::ScopeData::Destruction,
|
||||
};
|
||||
self.region_scope_tree.record_scope_parent(dscope, None);
|
||||
self.create_region_hierarchy(&RH {
|
||||
id: hir::ItemLocalId(1),
|
||||
sub: &[RH {
|
||||
id: hir::ItemLocalId(10),
|
||||
sub: &[],
|
||||
self.create_region_hierarchy(
|
||||
&RH {
|
||||
id: hir::ItemLocalId(1),
|
||||
sub: &[
|
||||
RH {
|
||||
id: hir::ItemLocalId(10),
|
||||
sub: &[],
|
||||
},
|
||||
RH {
|
||||
id: hir::ItemLocalId(11),
|
||||
sub: &[],
|
||||
},
|
||||
],
|
||||
},
|
||||
RH {
|
||||
id: hir::ItemLocalId(11),
|
||||
sub: &[],
|
||||
}],
|
||||
}, (dscope, 1));
|
||||
(dscope, 1),
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
|
||||
|
|
@ -236,11 +263,12 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
fn search_mod(this: &Env,
|
||||
m: &hir::Mod,
|
||||
idx: usize,
|
||||
names: &[String])
|
||||
-> Option<ast::NodeId> {
|
||||
fn search_mod(
|
||||
this: &Env,
|
||||
m: &hir::Mod,
|
||||
idx: usize,
|
||||
names: &[String],
|
||||
) -> Option<ast::NodeId> {
|
||||
assert!(idx < names.len());
|
||||
for item in &m.item_ids {
|
||||
let item = this.infcx.tcx.hir.expect_item(item.id);
|
||||
|
|
@ -257,22 +285,22 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
return match it.node {
|
||||
hir::ItemKind::Use(..) |
|
||||
hir::ItemKind::ExternCrate(..) |
|
||||
hir::ItemKind::Const(..) |
|
||||
hir::ItemKind::Static(..) |
|
||||
hir::ItemKind::Fn(..) |
|
||||
hir::ItemKind::ForeignMod(..) |
|
||||
hir::ItemKind::GlobalAsm(..) |
|
||||
hir::ItemKind::Existential(..) |
|
||||
hir::ItemKind::Ty(..) => None,
|
||||
hir::ItemKind::Use(..)
|
||||
| hir::ItemKind::ExternCrate(..)
|
||||
| hir::ItemKind::Const(..)
|
||||
| hir::ItemKind::Static(..)
|
||||
| hir::ItemKind::Fn(..)
|
||||
| hir::ItemKind::ForeignMod(..)
|
||||
| hir::ItemKind::GlobalAsm(..)
|
||||
| hir::ItemKind::Existential(..)
|
||||
| hir::ItemKind::Ty(..) => None,
|
||||
|
||||
hir::ItemKind::Enum(..) |
|
||||
hir::ItemKind::Struct(..) |
|
||||
hir::ItemKind::Union(..) |
|
||||
hir::ItemKind::Trait(..) |
|
||||
hir::ItemKind::TraitAlias(..) |
|
||||
hir::ItemKind::Impl(..) => None,
|
||||
hir::ItemKind::Enum(..)
|
||||
| hir::ItemKind::Struct(..)
|
||||
| hir::ItemKind::Union(..)
|
||||
| hir::ItemKind::Trait(..)
|
||||
| hir::ItemKind::TraitAlias(..)
|
||||
| hir::ItemKind::Impl(..) => None,
|
||||
|
||||
hir::ItemKind::Mod(ref m) => search_mod(this, m, idx, names),
|
||||
};
|
||||
|
|
@ -280,7 +308,10 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
||||
match self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(a, b) {
|
||||
match self.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.sub(a, b)
|
||||
{
|
||||
Ok(_) => true,
|
||||
Err(ref e) => panic!("Encountered error: {}", e),
|
||||
}
|
||||
|
|
@ -302,13 +333,15 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.infcx.tcx.mk_fn_ptr(ty::Binder::bind(self.infcx.tcx.mk_fn_sig(
|
||||
input_tys.iter().cloned(),
|
||||
output_ty,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::Rust
|
||||
)))
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_fn_ptr(ty::Binder::bind(self.infcx.tcx.mk_fn_sig(
|
||||
input_tys.iter().cloned(),
|
||||
output_ty,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::Rust,
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn t_nil(&self) -> Ty<'tcx> {
|
||||
|
|
@ -321,23 +354,30 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
|
||||
pub fn t_param(&self, index: u32) -> Ty<'tcx> {
|
||||
let name = format!("T{}", index);
|
||||
self.infcx.tcx.mk_ty_param(index, Symbol::intern(&name).as_interned_str())
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_ty_param(index, Symbol::intern(&name).as_interned_str())
|
||||
}
|
||||
|
||||
pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
|
||||
let name = Symbol::intern(name).as_interned_str();
|
||||
self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
|
||||
index,
|
||||
name,
|
||||
}))
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
|
||||
index,
|
||||
name,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn re_late_bound_with_debruijn(&self,
|
||||
id: u32,
|
||||
debruijn: ty::DebruijnIndex)
|
||||
-> ty::Region<'tcx> {
|
||||
self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
|
||||
pub fn re_late_bound_with_debruijn(
|
||||
&self,
|
||||
id: u32,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
) -> ty::Region<'tcx> {
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
|
||||
}
|
||||
|
||||
pub fn t_rptr(&self, r: ty::Region<'tcx>) -> Ty<'tcx> {
|
||||
|
|
@ -349,10 +389,11 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
|
||||
}
|
||||
|
||||
pub fn t_rptr_late_bound_with_debruijn(&self,
|
||||
id: u32,
|
||||
debruijn: ty::DebruijnIndex)
|
||||
-> Ty<'tcx> {
|
||||
pub fn t_rptr_late_bound_with_debruijn(
|
||||
&self,
|
||||
id: u32,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
) -> Ty<'tcx> {
|
||||
let r = self.re_late_bound_with_debruijn(id, debruijn);
|
||||
self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
|
||||
}
|
||||
|
|
@ -360,9 +401,11 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
|
||||
let r = ty::ReScope(region::Scope {
|
||||
id: hir::ItemLocalId(id),
|
||||
data: region::ScopeData::Node
|
||||
data: region::ScopeData::Node,
|
||||
});
|
||||
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
|
||||
}
|
||||
|
||||
pub fn re_free(&self, id: u32) -> ty::Region<'tcx> {
|
||||
|
|
@ -378,14 +421,19 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> {
|
||||
self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2)
|
||||
self.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.sub(t1, t2)
|
||||
}
|
||||
|
||||
/// Checks that `t1 <: t2` is true (this may register additional
|
||||
/// region checks).
|
||||
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
|
||||
match self.sub(t1, t2) {
|
||||
Ok(InferOk { obligations, value: () }) => {
|
||||
Ok(InferOk {
|
||||
obligations,
|
||||
value: (),
|
||||
}) => {
|
||||
// None of these tests should require nested obligations:
|
||||
assert!(obligations.is_empty());
|
||||
}
|
||||
|
|
@ -445,8 +493,10 @@ fn sub_free_bound_false() {
|
|||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
env.check_not_sub(
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -462,8 +512,10 @@ fn sub_bound_free_true() {
|
|||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
|
||||
env.check_sub(
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -476,10 +528,13 @@ fn sub_free_bound_false_infer() {
|
|||
//! does NOT hold for any instantiation of `_#1`.
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
|
||||
let t_infer1 = env.infcx
|
||||
.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
env.check_not_sub(
|
||||
env.t_fn(&[t_infer1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +542,6 @@ fn sub_free_bound_false_infer() {
|
|||
/// This requires adjusting the Debruijn index.
|
||||
#[test]
|
||||
fn subst_ty_renumber_bound() {
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
// Situation:
|
||||
// Theta = [A -> &'a foo]
|
||||
|
|
@ -509,11 +563,10 @@ fn subst_ty_renumber_bound() {
|
|||
env.t_fn(&[t_ptr_bound2], env.t_nil())
|
||||
};
|
||||
|
||||
debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source,
|
||||
substs,
|
||||
t_substituted,
|
||||
t_expected);
|
||||
debug!(
|
||||
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source, substs, t_substituted, t_expected
|
||||
);
|
||||
|
||||
assert_eq!(t_substituted, t_expected);
|
||||
})
|
||||
|
|
@ -546,11 +599,10 @@ fn subst_ty_renumber_some_bounds() {
|
|||
env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
|
||||
};
|
||||
|
||||
debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source,
|
||||
substs,
|
||||
t_substituted,
|
||||
t_expected);
|
||||
debug!(
|
||||
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source, substs, t_substituted, t_expected
|
||||
);
|
||||
|
||||
assert_eq!(t_substituted, t_expected);
|
||||
})
|
||||
|
|
@ -559,7 +611,6 @@ fn subst_ty_renumber_some_bounds() {
|
|||
/// Test that we correctly compute whether a type has escaping regions or not.
|
||||
#[test]
|
||||
fn escaping() {
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
// Situation:
|
||||
// Theta = [A -> &'a foo]
|
||||
|
|
@ -608,11 +659,10 @@ fn subst_region_renumber_region() {
|
|||
env.t_fn(&[t_rptr_bound2], env.t_nil())
|
||||
};
|
||||
|
||||
debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source,
|
||||
substs,
|
||||
t_substituted,
|
||||
t_expected);
|
||||
debug!(
|
||||
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source, substs, t_substituted, t_expected
|
||||
);
|
||||
|
||||
assert_eq!(t_substituted, t_expected);
|
||||
})
|
||||
|
|
@ -627,9 +677,13 @@ fn walk_ty() {
|
|||
let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty]);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty]);
|
||||
let walked: Vec<_> = tup2_ty.walk().collect();
|
||||
assert_eq!(walked,
|
||||
[tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty,
|
||||
usize_ty, int_ty, usize_ty, usize_ty]);
|
||||
assert_eq!(
|
||||
walked,
|
||||
[
|
||||
tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty, usize_ty,
|
||||
int_ty, usize_ty, usize_ty
|
||||
]
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -644,14 +698,16 @@ fn walk_ty_skip_subtree() {
|
|||
|
||||
// types we expect to see (in order), plus a boolean saying
|
||||
// whether to skip the subtree.
|
||||
let mut expected = vec![(tup2_ty, false),
|
||||
(tup1_ty, false),
|
||||
(int_ty, false),
|
||||
(usize_ty, false),
|
||||
(int_ty, false),
|
||||
(usize_ty, false),
|
||||
(tup1_ty, true), // skip the isize/usize/isize/usize
|
||||
(usize_ty, false)];
|
||||
let mut expected = vec![
|
||||
(tup2_ty, false),
|
||||
(tup1_ty, false),
|
||||
(int_ty, false),
|
||||
(usize_ty, false),
|
||||
(int_ty, false),
|
||||
(usize_ty, false),
|
||||
(tup1_ty, true), // skip the isize/usize/isize/usize
|
||||
(usize_ty, false),
|
||||
];
|
||||
expected.reverse();
|
||||
|
||||
let mut walker = tup2_ty.walk();
|
||||
|
|
|
|||
|
|
@ -1736,8 +1736,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
|
|||
if cx.tcx.features().trivial_bounds {
|
||||
let def_id = cx.tcx.hir.local_def_id(item.id);
|
||||
let predicates = cx.tcx.predicates_of(def_id);
|
||||
for predicate in &predicates.predicates {
|
||||
let predicate_kind_name = match *predicate {
|
||||
for &(predicate, span) in &predicates.predicates {
|
||||
let predicate_kind_name = match predicate {
|
||||
Trait(..) => "Trait",
|
||||
TypeOutlives(..) |
|
||||
RegionOutlives(..) => "Lifetime",
|
||||
|
|
@ -1755,7 +1755,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
|
|||
if predicate.is_global() {
|
||||
cx.span_lint(
|
||||
TRIVIAL_BOUNDS,
|
||||
item.span,
|
||||
span,
|
||||
&format!("{} bound {} does not depend on any type \
|
||||
or lifetime parameters", predicate_kind_name, predicate),
|
||||
);
|
||||
|
|
@ -1999,3 +1999,233 @@ impl EarlyLintPass for KeywordIdents {
|
|||
lint.emit()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct ExplicitOutlivesRequirements;
|
||||
|
||||
impl LintPass for ExplicitOutlivesRequirements {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array![EXPLICIT_OUTLIVES_REQUIREMENTS]
|
||||
}
|
||||
}
|
||||
|
||||
impl ExplicitOutlivesRequirements {
|
||||
fn collect_outlives_bound_spans(
|
||||
&self,
|
||||
cx: &LateContext,
|
||||
item_def_id: DefId,
|
||||
param_name: &str,
|
||||
bounds: &hir::GenericBounds,
|
||||
infer_static: bool
|
||||
) -> Vec<(usize, Span)> {
|
||||
// For lack of a more elegant strategy for comparing the `ty::Predicate`s
|
||||
// returned by this query with the params/bounds grabbed from the HIR—and
|
||||
// with some regrets—we're going to covert the param/lifetime names to
|
||||
// strings
|
||||
let inferred_outlives = cx.tcx.inferred_outlives_of(item_def_id);
|
||||
|
||||
let ty_lt_names = inferred_outlives.iter().filter_map(|pred| {
|
||||
let binder = match pred {
|
||||
ty::Predicate::TypeOutlives(binder) => binder,
|
||||
_ => { return None; }
|
||||
};
|
||||
let ty_outlives_pred = binder.skip_binder();
|
||||
let ty_name = match ty_outlives_pred.0.sty {
|
||||
ty::Param(param) => param.name.to_string(),
|
||||
_ => { return None; }
|
||||
};
|
||||
let lt_name = match ty_outlives_pred.1 {
|
||||
ty::RegionKind::ReEarlyBound(region) => {
|
||||
region.name.to_string()
|
||||
},
|
||||
_ => { return None; }
|
||||
};
|
||||
Some((ty_name, lt_name))
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let mut bound_spans = Vec::new();
|
||||
for (i, bound) in bounds.iter().enumerate() {
|
||||
if let hir::GenericBound::Outlives(lifetime) = bound {
|
||||
let is_static = match lifetime.name {
|
||||
hir::LifetimeName::Static => true,
|
||||
_ => false
|
||||
};
|
||||
if is_static && !infer_static {
|
||||
// infer-outlives for 'static is still feature-gated (tracking issue #44493)
|
||||
continue;
|
||||
}
|
||||
|
||||
let lt_name = &lifetime.name.ident().to_string();
|
||||
if ty_lt_names.contains(&(param_name.to_owned(), lt_name.to_owned())) {
|
||||
bound_spans.push((i, bound.span()));
|
||||
}
|
||||
}
|
||||
}
|
||||
bound_spans
|
||||
}
|
||||
|
||||
fn consolidate_outlives_bound_spans(
|
||||
&self,
|
||||
lo: Span,
|
||||
bounds: &hir::GenericBounds,
|
||||
bound_spans: Vec<(usize, Span)>
|
||||
) -> Vec<Span> {
|
||||
if bounds.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
if bound_spans.len() == bounds.len() {
|
||||
let (_, last_bound_span) = bound_spans[bound_spans.len()-1];
|
||||
// If all bounds are inferable, we want to delete the colon, so
|
||||
// start from just after the parameter (span passed as argument)
|
||||
vec![lo.to(last_bound_span)]
|
||||
} else {
|
||||
let mut merged = Vec::new();
|
||||
let mut last_merged_i = None;
|
||||
|
||||
let mut from_start = true;
|
||||
for (i, bound_span) in bound_spans {
|
||||
match last_merged_i {
|
||||
// If the first bound is inferable, our span should also eat the trailing `+`
|
||||
None if i == 0 => {
|
||||
merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
|
||||
last_merged_i = Some(0);
|
||||
},
|
||||
// If consecutive bounds are inferable, merge their spans
|
||||
Some(h) if i == h+1 => {
|
||||
if let Some(tail) = merged.last_mut() {
|
||||
// Also eat the trailing `+` if the first
|
||||
// more-than-one bound is inferable
|
||||
let to_span = if from_start && i < bounds.len() {
|
||||
bounds[i+1].span().shrink_to_lo()
|
||||
} else {
|
||||
bound_span
|
||||
};
|
||||
*tail = tail.to(to_span);
|
||||
last_merged_i = Some(i);
|
||||
} else {
|
||||
bug!("another bound-span visited earlier");
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// When we find a non-inferable bound, subsequent inferable bounds
|
||||
// won't be consecutive from the start (and we'll eat the leading
|
||||
// `+` rather than the trailing one)
|
||||
from_start = false;
|
||||
merged.push(bounds[i-1].span().shrink_to_hi().to(bound_span));
|
||||
last_merged_i = Some(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
merged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
|
||||
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
|
||||
let infer_static = cx.tcx.features().infer_static_outlives_requirements;
|
||||
let def_id = cx.tcx.hir.local_def_id(item.id);
|
||||
if let hir::ItemKind::Struct(_, ref generics) = item.node {
|
||||
let mut bound_count = 0;
|
||||
let mut lint_spans = Vec::new();
|
||||
|
||||
for param in &generics.params {
|
||||
let param_name = match param.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => { continue; },
|
||||
hir::GenericParamKind::Type { .. } => {
|
||||
match param.name {
|
||||
hir::ParamName::Fresh(_) => { continue; },
|
||||
hir::ParamName::Plain(name) => name.to_string()
|
||||
}
|
||||
}
|
||||
};
|
||||
let bound_spans = self.collect_outlives_bound_spans(
|
||||
cx, def_id, ¶m_name, ¶m.bounds, infer_static
|
||||
);
|
||||
bound_count += bound_spans.len();
|
||||
lint_spans.extend(
|
||||
self.consolidate_outlives_bound_spans(
|
||||
param.span.shrink_to_hi(), ¶m.bounds, bound_spans
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let mut where_lint_spans = Vec::new();
|
||||
let mut dropped_predicate_count = 0;
|
||||
let num_predicates = generics.where_clause.predicates.len();
|
||||
for (i, where_predicate) in generics.where_clause.predicates.iter().enumerate() {
|
||||
if let hir::WherePredicate::BoundPredicate(predicate) = where_predicate {
|
||||
let param_name = match predicate.bounded_ty.node {
|
||||
hir::TyKind::Path(ref qpath) => {
|
||||
if let hir::QPath::Resolved(None, ty_param_path) = qpath {
|
||||
ty_param_path.segments[0].ident.to_string()
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
},
|
||||
_ => { continue; }
|
||||
};
|
||||
let bound_spans = self.collect_outlives_bound_spans(
|
||||
cx, def_id, ¶m_name, &predicate.bounds, infer_static
|
||||
);
|
||||
bound_count += bound_spans.len();
|
||||
|
||||
let drop_predicate = bound_spans.len() == predicate.bounds.len();
|
||||
if drop_predicate {
|
||||
dropped_predicate_count += 1;
|
||||
}
|
||||
|
||||
// If all the bounds on a predicate were inferable and there are
|
||||
// further predicates, we want to eat the trailing comma
|
||||
if drop_predicate && i + 1 < num_predicates {
|
||||
let next_predicate_span = generics.where_clause.predicates[i+1].span();
|
||||
where_lint_spans.push(
|
||||
predicate.span.to(next_predicate_span.shrink_to_lo())
|
||||
);
|
||||
} else {
|
||||
where_lint_spans.extend(
|
||||
self.consolidate_outlives_bound_spans(
|
||||
predicate.span.shrink_to_lo(),
|
||||
&predicate.bounds,
|
||||
bound_spans
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all predicates are inferable, drop the entire clause
|
||||
// (including the `where`)
|
||||
if num_predicates > 0 && dropped_predicate_count == num_predicates {
|
||||
let full_where_span = generics.span.shrink_to_hi()
|
||||
.to(generics.where_clause.span()
|
||||
.expect("span of (nonempty) where clause should exist"));
|
||||
lint_spans.push(
|
||||
full_where_span
|
||||
);
|
||||
} else {
|
||||
lint_spans.extend(where_lint_spans);
|
||||
}
|
||||
|
||||
if !lint_spans.is_empty() {
|
||||
let mut err = cx.struct_span_lint(
|
||||
EXPLICIT_OUTLIVES_REQUIREMENTS,
|
||||
lint_spans.clone(),
|
||||
"outlives requirements can be inferred"
|
||||
);
|
||||
err.multipart_suggestion_with_applicability(
|
||||
if bound_count == 1 {
|
||||
"remove this bound"
|
||||
} else {
|
||||
"remove these bounds"
|
||||
},
|
||||
lint_spans.into_iter().map(|span| (span, "".to_owned())).collect::<Vec<_>>(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ use rustc::lint::builtin::{
|
|||
BARE_TRAIT_OBJECTS,
|
||||
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
EXPLICIT_OUTLIVES_REQUIREMENTS,
|
||||
parser::QUESTION_MARK_MACRO_SEP
|
||||
};
|
||||
use rustc::session;
|
||||
|
|
@ -157,6 +158,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
TypeLimits: TypeLimits::new(),
|
||||
MissingDoc: MissingDoc::new(),
|
||||
MissingDebugImplementations: MissingDebugImplementations::new(),
|
||||
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
|
||||
]], ['tcx]);
|
||||
|
||||
store.register_late_pass(sess, false, box BuiltinCombinedLateLintPass::new());
|
||||
|
|
@ -199,7 +201,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
BARE_TRAIT_OBJECTS,
|
||||
UNUSED_EXTERN_CRATES,
|
||||
ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
|
||||
ELIDED_LIFETIMES_IN_PATHS
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
EXPLICIT_OUTLIVES_REQUIREMENTS
|
||||
|
||||
// FIXME(#52665, #47816) not always applicable and not all
|
||||
// macros are ready for this yet.
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ impl<'a> CrateLoader<'a> {
|
|||
|
||||
let cmeta = cstore::CrateMetadata {
|
||||
name: crate_root.name,
|
||||
imported_name: ident,
|
||||
extern_crate: Lock::new(None),
|
||||
def_path_table: Lrc::new(def_path_table),
|
||||
trait_impls,
|
||||
|
|
|
|||
|
|
@ -53,8 +53,13 @@ pub struct ImportedSourceFile {
|
|||
}
|
||||
|
||||
pub struct CrateMetadata {
|
||||
/// Original name of the crate.
|
||||
pub name: Symbol,
|
||||
|
||||
/// Name of the crate as imported. I.e. if imported with
|
||||
/// `extern crate foo as bar;` this will be `bar`.
|
||||
pub imported_name: Symbol,
|
||||
|
||||
/// Information about the extern crate that caused this crate to
|
||||
/// be loaded. If this is `None`, then the crate was injected
|
||||
/// (e.g., by the allocator)
|
||||
|
|
|
|||
|
|
@ -441,8 +441,7 @@ impl cstore::CStore {
|
|||
let data = self.get_crate_data(id.krate);
|
||||
if let Some(ref proc_macros) = data.proc_macros {
|
||||
return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
|
||||
} else if data.name == "proc_macro" &&
|
||||
self.get_crate_data(id.krate).item_name(id.index) == "quote" {
|
||||
} else if data.name == "proc_macro" && data.item_name(id.index) == "quote" {
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax_ext::proc_macro_impl::BangProcMacro;
|
||||
|
||||
|
|
@ -454,8 +453,9 @@ impl cstore::CStore {
|
|||
return LoadedMacro::ProcMacro(Lrc::new(ext));
|
||||
}
|
||||
|
||||
let (name, def) = data.get_macro(id.index);
|
||||
let source_name = FileName::Macros(name.to_string());
|
||||
let def = data.get_macro(id.index);
|
||||
let macro_full_name = data.def_path(id.index).to_string_friendly(|_| data.imported_name);
|
||||
let source_name = FileName::Macros(macro_full_name);
|
||||
|
||||
let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body);
|
||||
let local_span = Span::new(source_file.start_pos, source_file.end_pos, NO_EXPANSION);
|
||||
|
|
|
|||
|
|
@ -1106,10 +1106,10 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_macro(&self, id: DefIndex) -> (InternedString, MacroDef) {
|
||||
pub fn get_macro(&self, id: DefIndex) -> MacroDef {
|
||||
let entry = self.entry(id);
|
||||
match entry.kind {
|
||||
EntryKind::MacroDef(macro_def) => (self.item_name(id), macro_def.decode(self)),
|
||||
EntryKind::MacroDef(macro_def) => macro_def.decode(self),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1319,7 +1319,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
);
|
||||
if let StatementKind::Assign(
|
||||
Place::Local(assigned_to),
|
||||
rvalue,
|
||||
box rvalue,
|
||||
) = &stmt.kind {
|
||||
debug!("annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
rvalue={:?}", assigned_to, rvalue);
|
||||
|
|
@ -1823,7 +1823,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
None => return OtherUse(self.mir.source_info(location).span),
|
||||
};
|
||||
|
||||
if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
|
||||
if let StatementKind::Assign(_, box Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
|
||||
if let AggregateKind::Closure(def_id, _) = **kind {
|
||||
debug!("find_closure_move_span: found closure {:?}", places);
|
||||
|
||||
|
|
@ -1886,7 +1886,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
|
||||
if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
|
||||
if let StatementKind::Assign(_, box Rvalue::Aggregate(ref kind, ref places))
|
||||
= stmt.kind {
|
||||
if let AggregateKind::Closure(def_id, _) = **kind {
|
||||
debug!("find_closure_borrow_span: found closure {:?}", places);
|
||||
|
||||
|
|
|
|||
|
|
@ -534,7 +534,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||
ref inputs,
|
||||
} => {
|
||||
let context = ContextKind::InlineAsm.new(location);
|
||||
for (o, output) in asm.outputs.iter().zip(outputs) {
|
||||
for (o, output) in asm.outputs.iter().zip(outputs.iter()) {
|
||||
if o.is_indirect {
|
||||
// FIXME(eddyb) indirect inline asm outputs should
|
||||
// be encoeded through MIR place derefs instead.
|
||||
|
|
@ -561,7 +561,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||
);
|
||||
}
|
||||
}
|
||||
for input in inputs {
|
||||
for input in inputs.iter() {
|
||||
self.consume_operand(context, (input, span), flow_state);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
|||
// flow could be used.
|
||||
if let Some(StatementKind::Assign(
|
||||
Place::Local(local),
|
||||
Rvalue::Use(Operand::Move(move_from)),
|
||||
box Rvalue::Use(Operand::Move(move_from)),
|
||||
)) = self.mir.basic_blocks()[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||
ref inputs,
|
||||
} => {
|
||||
let context = ContextKind::InlineAsm.new(location);
|
||||
for (o, output) in asm.outputs.iter().zip(outputs) {
|
||||
for (o, output) in asm.outputs.iter().zip(outputs.iter()) {
|
||||
if o.is_indirect {
|
||||
// FIXME(eddyb) indirect inline asm outputs should
|
||||
// be encoeded through MIR place derefs instead.
|
||||
|
|
@ -128,7 +128,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
for input in inputs {
|
||||
for input in inputs.iter() {
|
||||
self.consume_operand(context, input);
|
||||
}
|
||||
}
|
||||
|
|
@ -479,7 +479,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||
|
||||
/// Generate a new invalidates(L, B) fact
|
||||
fn generate_invalidates(&mut self, b: BorrowIndex, l: Location) {
|
||||
let lidx = self.location_table.mid_index(l);
|
||||
let lidx = self.location_table.start_index(l);
|
||||
self.all_facts.invalidates.push((lidx, b));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,15 +10,13 @@
|
|||
|
||||
use super::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::constraints::graph::NormalConstraintGraph;
|
||||
use borrow_check::nll::constraints::{
|
||||
ConstraintSccIndex, ConstraintSet, OutlivesConstraint,
|
||||
};
|
||||
use borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, OutlivesConstraint};
|
||||
use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex};
|
||||
use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use borrow_check::nll::type_check::Locations;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::canonical::QueryRegionConstraint;
|
||||
use rustc::infer::region_constraints::{GenericKind, VarInfos};
|
||||
use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
|
||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc::mir::{
|
||||
ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
|
||||
|
|
@ -29,7 +27,7 @@ use rustc::util::common;
|
|||
use rustc_data_structures::bit_set::BitSet;
|
||||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_errors::{DiagnosticBuilder, Diagnostic};
|
||||
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -71,6 +69,15 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// visible from this index.
|
||||
scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
|
||||
|
||||
/// Contains a "representative" from each SCC. This will be the
|
||||
/// minimal RegionVid belonging to that universe. It is used as a
|
||||
/// kind of hacky way to manage checking outlives relationships,
|
||||
/// since we can 'canonicalize' each region to the representative
|
||||
/// of its SCC and be sure that -- if they have the same repr --
|
||||
/// they *must* be equal (though not having the same repr does not
|
||||
/// mean they are unequal).
|
||||
scc_representatives: IndexVec<ConstraintSccIndex, ty::RegionVid>,
|
||||
|
||||
/// The final inferred values of the region variables; we compute
|
||||
/// one value per SCC. To get the value for any given *region*,
|
||||
/// you first find which scc it is a part of.
|
||||
|
|
@ -162,42 +169,7 @@ pub struct TypeTest<'tcx> {
|
|||
|
||||
/// A test which, if met by the region `'x`, proves that this type
|
||||
/// constraint is satisfied.
|
||||
pub test: RegionTest,
|
||||
}
|
||||
|
||||
/// A "test" that can be applied to some "subject region" `'x`. These are used to
|
||||
/// describe type constraints. Tests do not presently affect the
|
||||
/// region values that get inferred for each variable; they only
|
||||
/// examine the results *after* inference. This means they can
|
||||
/// conveniently include disjuction ("a or b must be true").
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RegionTest {
|
||||
/// The subject region `'x` must by outlived by *some* region in
|
||||
/// the given set of regions.
|
||||
///
|
||||
/// This test comes from e.g. a where clause like `T: 'a + 'b`,
|
||||
/// which implies that we know that `T: 'a` and that `T:
|
||||
/// 'b`. Therefore, if we are trying to prove that `T: 'x`, we can
|
||||
/// do so by showing that `'a: 'x` *or* `'b: 'x`.
|
||||
IsOutlivedByAnyRegionIn(Vec<RegionVid>),
|
||||
|
||||
/// The subject region `'x` must by outlived by *all* regions in
|
||||
/// the given set of regions.
|
||||
///
|
||||
/// This test comes from e.g. a projection type like `T = <u32 as
|
||||
/// Trait<'a, 'b>>::Foo`, which must outlive `'a` or `'b`, and
|
||||
/// maybe both. Therefore we can prove that `T: 'x` if we know
|
||||
/// that `'a: 'x` *and* `'b: 'x`.
|
||||
IsOutlivedByAllRegionsIn(Vec<RegionVid>),
|
||||
|
||||
/// Any of the given tests are true.
|
||||
///
|
||||
/// This arises from projections, for which there are multiple
|
||||
/// ways to prove an outlives relationship.
|
||||
Any(Vec<RegionTest>),
|
||||
|
||||
/// All of the given tests are true.
|
||||
All(Vec<RegionTest>),
|
||||
pub verify_bound: VerifyBound<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
|
@ -245,6 +217,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions);
|
||||
|
||||
let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
|
||||
|
||||
let mut result = Self {
|
||||
definitions,
|
||||
liveness_constraints,
|
||||
|
|
@ -252,6 +226,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
constraint_graph,
|
||||
constraint_sccs,
|
||||
scc_universes,
|
||||
scc_representatives,
|
||||
scc_values,
|
||||
type_tests,
|
||||
universal_regions,
|
||||
|
|
@ -288,6 +263,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
scc_universes
|
||||
}
|
||||
|
||||
/// For each SCC, we compute a unique `RegionVid` (in fact, the
|
||||
/// minimal one that belongs to the SCC). See
|
||||
/// `scc_representatives` field of `RegionInferenceContext` for
|
||||
/// more details.
|
||||
fn compute_scc_representatives(
|
||||
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
|
||||
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
|
||||
) -> IndexVec<ConstraintSccIndex, ty::RegionVid> {
|
||||
let num_sccs = constraints_scc.num_sccs();
|
||||
let next_region_vid = definitions.next_index();
|
||||
let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs);
|
||||
|
||||
for region_vid in definitions.indices() {
|
||||
let scc = constraints_scc.scc(region_vid);
|
||||
let prev_min = scc_representatives[scc];
|
||||
scc_representatives[scc] = region_vid.min(prev_min);
|
||||
}
|
||||
|
||||
scc_representatives
|
||||
}
|
||||
|
||||
/// Initializes the region variables for each universally
|
||||
/// quantified region (lifetime parameter). The first N variables
|
||||
/// always correspond to the regions appearing in the function
|
||||
|
|
@ -582,7 +578,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
for type_test in &self.type_tests {
|
||||
debug!("check_type_test: {:?}", type_test);
|
||||
|
||||
if self.eval_region_test(mir, type_test.lower_bound, &type_test.test) {
|
||||
let generic_ty = type_test.generic_kind.to_ty(tcx);
|
||||
if self.eval_verify_bound(
|
||||
tcx,
|
||||
mir,
|
||||
generic_ty,
|
||||
type_test.lower_bound,
|
||||
&type_test.verify_bound,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -689,7 +692,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
generic_kind,
|
||||
lower_bound,
|
||||
locations,
|
||||
test: _,
|
||||
verify_bound: _,
|
||||
} = type_test;
|
||||
|
||||
let generic_ty = generic_kind.to_ty(tcx);
|
||||
|
|
@ -716,7 +719,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// where `ur` is a local bound -- we are sometimes in a
|
||||
// position to prove things that our caller cannot. See
|
||||
// #53570 for an example.
|
||||
if self.eval_region_test(mir, ur, &type_test.test) {
|
||||
if self.eval_verify_bound(tcx, mir, generic_ty, ur, &type_test.verify_bound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -888,31 +891,99 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
/// Test if `test` is true when applied to `lower_bound` at
|
||||
/// `point`, and returns true or false.
|
||||
fn eval_region_test(&self, mir: &Mir<'tcx>, lower_bound: RegionVid, test: &RegionTest) -> bool {
|
||||
fn eval_verify_bound(
|
||||
&self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
generic_ty: Ty<'tcx>,
|
||||
lower_bound: RegionVid,
|
||||
verify_bound: &VerifyBound<'tcx>,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"eval_region_test(lower_bound={:?}, test={:?})",
|
||||
lower_bound, test
|
||||
"eval_verify_bound(lower_bound={:?}, verify_bound={:?})",
|
||||
lower_bound, verify_bound
|
||||
);
|
||||
|
||||
match test {
|
||||
RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
|
||||
.iter()
|
||||
.all(|&r| self.eval_outlives(mir, r, lower_bound)),
|
||||
match verify_bound {
|
||||
VerifyBound::IfEq(test_ty, verify_bound1) => {
|
||||
self.eval_if_eq(tcx, mir, generic_ty, lower_bound, test_ty, verify_bound1)
|
||||
}
|
||||
|
||||
RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
|
||||
.iter()
|
||||
.any(|&r| self.eval_outlives(mir, r, lower_bound)),
|
||||
VerifyBound::OutlivedBy(r) => {
|
||||
let r_vid = self.to_region_vid(r);
|
||||
self.eval_outlives(mir, r_vid, lower_bound)
|
||||
}
|
||||
|
||||
RegionTest::Any(tests) => tests
|
||||
.iter()
|
||||
.any(|test| self.eval_region_test(mir, lower_bound, test)),
|
||||
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
|
||||
self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
|
||||
}),
|
||||
|
||||
RegionTest::All(tests) => tests
|
||||
.iter()
|
||||
.all(|test| self.eval_region_test(mir, lower_bound, test)),
|
||||
VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
|
||||
self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_if_eq(
|
||||
&self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
generic_ty: Ty<'tcx>,
|
||||
lower_bound: RegionVid,
|
||||
test_ty: Ty<'tcx>,
|
||||
verify_bound: &VerifyBound<'tcx>,
|
||||
) -> bool {
|
||||
let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty);
|
||||
let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty);
|
||||
if generic_ty_normalized == test_ty_normalized {
|
||||
self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a conservative normalization procedure. It takes every
|
||||
/// free region in `value` and replaces it with the
|
||||
/// "representative" of its SCC (see `scc_representatives` field).
|
||||
/// We are guaranteed that if two values normalize to the same
|
||||
/// thing, then they are equal; this is a conservative check in
|
||||
/// that they could still be equal even if they normalize to
|
||||
/// different results. (For example, there might be two regions
|
||||
/// with the same value that are not in the same SCC).
|
||||
///
|
||||
/// NB. This is not an ideal approach and I would like to revisit
|
||||
/// it. However, it works pretty well in practice. In particular,
|
||||
/// this is needed to deal with projection outlives bounds like
|
||||
///
|
||||
/// <T as Foo<'0>>::Item: '1
|
||||
///
|
||||
/// In particular, this routine winds up being important when
|
||||
/// there are bounds like `where <T as Foo<'a>>::Item: 'b` in the
|
||||
/// environment. In this case, if we can show that `'0 == 'a`,
|
||||
/// and that `'b: '1`, then we know that the clause is
|
||||
/// satisfied. In such cases, particularly due to limitations of
|
||||
/// the trait solver =), we usually wind up with a where-clause like
|
||||
/// `T: Foo<'a>` in scope, which thus forces `'0 == 'a` to be added as
|
||||
/// a constraint, and thus ensures that they are in the same SCC.
|
||||
///
|
||||
/// So why can't we do a more correct routine? Well, we could
|
||||
/// *almost* use the `relate_tys` code, but the way it is
|
||||
/// currently setup it creates inference variables to deal with
|
||||
/// higher-ranked things and so forth, and right now the inference
|
||||
/// context is not permitted to make more inference variables. So
|
||||
/// we use this kind of hacky solution.
|
||||
fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
tcx.fold_regions(&value, &mut false, |r, _db| {
|
||||
let vid = self.to_region_vid(r);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
let repr = self.scc_representatives[scc];
|
||||
tcx.mk_region(ty::ReVar(repr))
|
||||
})
|
||||
}
|
||||
|
||||
// Evaluate whether `sup_region: sub_region @ point`.
|
||||
fn eval_outlives(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -8,13 +8,12 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint};
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::region_infer::{RegionTest, TypeTest};
|
||||
use borrow_check::nll::region_infer::TypeTest;
|
||||
use borrow_check::nll::type_check::Locations;
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use rustc::infer::canonical::QueryRegionConstraint;
|
||||
use rustc::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
|
||||
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
|
||||
use rustc::infer::{self, SubregionOrigin};
|
||||
|
|
@ -25,35 +24,30 @@ use syntax_pos::DUMMY_SP;
|
|||
crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
outlives_constraints: &'a mut ConstraintSet,
|
||||
type_tests: &'a mut Vec<TypeTest<'tcx>>,
|
||||
all_facts: &'a mut Option<AllFacts>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
||||
crate fn new(
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
outlives_constraints: &'a mut ConstraintSet,
|
||||
type_tests: &'a mut Vec<TypeTest<'tcx>>,
|
||||
all_facts: &'a mut Option<AllFacts>,
|
||||
) -> Self {
|
||||
Self {
|
||||
tcx,
|
||||
universal_regions,
|
||||
location_table,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
|
|
@ -61,7 +55,6 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
|||
category,
|
||||
outlives_constraints,
|
||||
type_tests,
|
||||
all_facts,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,23 +93,6 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
|||
let r1_vid = self.to_region_vid(r1);
|
||||
let r2_vid = self.to_region_vid(r2);
|
||||
self.add_outlives(r1_vid, r2_vid);
|
||||
|
||||
// In the new analysis, all outlives relations etc
|
||||
// "take effect" at the mid point of the statement
|
||||
// that requires them, so ignore the `at_location`.
|
||||
if let Some(all_facts) = &mut self.all_facts {
|
||||
if let Some(from_location) = self.locations.from_location() {
|
||||
all_facts.outlives.push((
|
||||
r1_vid,
|
||||
r2_vid,
|
||||
self.location_table.mid_index(from_location),
|
||||
));
|
||||
} else {
|
||||
for location in self.location_table.all_points() {
|
||||
all_facts.outlives.push((r1_vid, r2_vid, location));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnpackedKind::Type(t1) => {
|
||||
|
|
@ -139,43 +115,15 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
|||
&self,
|
||||
generic_kind: GenericKind<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
bound: VerifyBound<'tcx>,
|
||||
verify_bound: VerifyBound<'tcx>,
|
||||
) -> TypeTest<'tcx> {
|
||||
let lower_bound = self.to_region_vid(region);
|
||||
|
||||
let test = self.verify_bound_to_region_test(&bound);
|
||||
|
||||
TypeTest {
|
||||
generic_kind,
|
||||
lower_bound,
|
||||
locations: self.locations,
|
||||
test,
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> RegionTest {
|
||||
match verify_bound {
|
||||
VerifyBound::AnyRegion(regions) => RegionTest::IsOutlivedByAnyRegionIn(
|
||||
regions.iter().map(|r| self.to_region_vid(r)).collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AllRegions(regions) => RegionTest::IsOutlivedByAllRegionsIn(
|
||||
regions.iter().map(|r| self.to_region_vid(r)).collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AnyBound(bounds) => RegionTest::Any(
|
||||
bounds
|
||||
.iter()
|
||||
.map(|b| self.verify_bound_to_region_test(b))
|
||||
.collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AllBounds(bounds) => RegionTest::All(
|
||||
bounds
|
||||
.iter()
|
||||
.map(|b| self.verify_bound_to_region_test(b))
|
||||
.collect(),
|
||||
),
|
||||
verify_bound,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::type_check::constraint_conversion;
|
||||
use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
|
|
@ -69,19 +67,15 @@ crate struct CreateResult<'tcx> {
|
|||
crate fn create(
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
) -> CreateResult<'tcx> {
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
location_table,
|
||||
all_facts,
|
||||
universal_regions: universal_regions.clone(),
|
||||
region_bound_pairs: Vec::new(),
|
||||
relations: UniversalRegionRelations {
|
||||
|
|
@ -210,11 +204,9 @@ impl UniversalRegionRelations<'tcx> {
|
|||
struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> {
|
||||
infcx: &'this InferCtxt<'this, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
location_table: &'this LocationTable,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
|
||||
all_facts: &'this mut Option<AllFacts>,
|
||||
|
||||
// outputs:
|
||||
relations: UniversalRegionRelations<'tcx>,
|
||||
|
|
@ -281,7 +273,6 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
|
|||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx.tcx,
|
||||
&self.universal_regions,
|
||||
&self.location_table,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
|
|
@ -289,7 +280,6 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
|
|||
ConstraintCategory::Internal,
|
||||
&mut self.constraints.outlives_constraints,
|
||||
&mut self.constraints.type_tests,
|
||||
&mut self.all_facts,
|
||||
).convert_all(&data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
//! types, instead of all variables.
|
||||
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use borrow_check::nll::facts::{AllFacts, AllFactsExt};
|
||||
use rustc::mir::{Local, Mir};
|
||||
use rustc::ty::{RegionVid, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -61,12 +62,13 @@ impl NllLivenessMap {
|
|||
mir: &Mir<'tcx>,
|
||||
) -> Self {
|
||||
let mut to_local = IndexVec::default();
|
||||
let facts_enabled = AllFacts::enabled(tcx);
|
||||
let from_local: IndexVec<Local, Option<_>> = mir.local_decls
|
||||
.iter_enumerated()
|
||||
.map(|(local, local_decl)| {
|
||||
if tcx.all_free_regions_meet(&local_decl.ty, |r| {
|
||||
free_regions.contains(&r.to_region_vid())
|
||||
}) {
|
||||
}) && !facts_enabled {
|
||||
// If all the regions in the type are free regions
|
||||
// (or there are no regions), then we don't need
|
||||
// to track liveness for this variable.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::region_infer::values::RegionValueElements;
|
||||
use borrow_check::nll::constraints::ConstraintSet;
|
||||
use borrow_check::nll::NllLivenessMap;
|
||||
|
|
@ -40,6 +41,7 @@ pub(super) fn generate<'gcx, 'tcx>(
|
|||
elements: &Rc<RegionValueElements>,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
) {
|
||||
debug!("liveness::generate");
|
||||
let free_regions = {
|
||||
|
|
@ -51,7 +53,7 @@ pub(super) fn generate<'gcx, 'tcx>(
|
|||
)
|
||||
};
|
||||
let liveness_map = NllLivenessMap::compute(typeck.tcx(), &free_regions, mir);
|
||||
trace::trace(typeck, mir, elements, flow_inits, move_data, &liveness_map);
|
||||
trace::trace(typeck, mir, elements, flow_inits, move_data, &liveness_map, location_table);
|
||||
}
|
||||
|
||||
/// Compute all regions that are (currently) known to outlive free
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::constraints::ConstraintCategory;
|
||||
use borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements};
|
||||
use borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap};
|
||||
|
|
@ -49,6 +50,7 @@ pub(super) fn trace(
|
|||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
liveness_map: &NllLivenessMap,
|
||||
location_table: &LocationTable,
|
||||
) {
|
||||
debug!("trace()");
|
||||
|
||||
|
|
@ -67,6 +69,7 @@ pub(super) fn trace(
|
|||
move_data,
|
||||
liveness_map,
|
||||
drop_data: FxHashMap::default(),
|
||||
location_table,
|
||||
};
|
||||
|
||||
LivenessResults::new(cx).compute_for_all_locals();
|
||||
|
|
@ -105,6 +108,9 @@ where
|
|||
|
||||
/// Map tracking which variables need liveness computation.
|
||||
liveness_map: &'me NllLivenessMap,
|
||||
|
||||
/// Maps between a MIR Location and a LocationIndex
|
||||
location_table: &'me LocationTable,
|
||||
}
|
||||
|
||||
struct DropData<'tcx> {
|
||||
|
|
@ -453,7 +459,13 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> {
|
|||
) {
|
||||
debug!("add_use_live_facts_for(value={:?})", value);
|
||||
|
||||
Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at)
|
||||
Self::make_all_regions_live(
|
||||
self.elements,
|
||||
&mut self.typeck,
|
||||
value,
|
||||
live_at,
|
||||
self.location_table,
|
||||
)
|
||||
}
|
||||
|
||||
/// Some variable with type `live_ty` is "drop live" at `location`
|
||||
|
|
@ -505,7 +517,13 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> {
|
|||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
for &kind in &drop_data.dropck_result.kinds {
|
||||
Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at);
|
||||
Self::make_all_regions_live(
|
||||
self.elements,
|
||||
&mut self.typeck,
|
||||
kind,
|
||||
live_at,
|
||||
self.location_table,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -514,6 +532,7 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> {
|
|||
typeck: &mut TypeChecker<'_, '_, 'tcx>,
|
||||
value: impl TypeFoldable<'tcx>,
|
||||
live_at: &HybridBitSet<PointIndex>,
|
||||
location_table: &LocationTable,
|
||||
) {
|
||||
debug!("make_all_regions_live(value={:?})", value);
|
||||
debug!(
|
||||
|
|
@ -532,8 +551,12 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> {
|
|||
.liveness_constraints
|
||||
.add_elements(live_region_vid, live_at);
|
||||
|
||||
if let Some(_) = borrowck_context.all_facts {
|
||||
bug!("polonius liveness facts not implemented yet")
|
||||
if let Some(facts) = borrowck_context.all_facts {
|
||||
for point in live_at.iter() {
|
||||
let loc = elements.to_location(point);
|
||||
facts.region_live_at.push((live_region_vid, location_table.start_index(loc)));
|
||||
facts.region_live_at.push((live_region_vid, location_table.mid_index(loc)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,37 +17,38 @@ use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, Outlives
|
|||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
|
||||
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
|
||||
use borrow_check::nll::renumber;
|
||||
use borrow_check::nll::type_check::free_region_relations::{
|
||||
CreateResult, UniversalRegionRelations,
|
||||
};
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use borrow_check::nll::renumber;
|
||||
use dataflow::move_paths::MoveData;
|
||||
use dataflow::FlowAtLocation;
|
||||
use dataflow::MaybeInitializedPlaces;
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::canonical::QueryRegionConstraint;
|
||||
use rustc::infer::region_constraints::GenericKind;
|
||||
use rustc::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::*;
|
||||
use rustc::traits::{ObligationCause, PredicateObligations};
|
||||
use rustc::traits::query::type_op;
|
||||
use rustc::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc::traits::query::{Fallible, NoSolution};
|
||||
use rustc::traits::{ObligationCause, PredicateObligations};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
||||
use rustc::ty::subst::Subst;
|
||||
use std::fmt;
|
||||
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
||||
use std::{fmt, iter};
|
||||
use std::rc::Rc;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use transform::{MirPass, MirSource};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use either::Either;
|
||||
|
||||
macro_rules! span_mirbug {
|
||||
($context:expr, $elem:expr, $($message:tt)*) => ({
|
||||
|
|
@ -135,41 +136,35 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
|||
} = free_region_relations::create(
|
||||
infcx,
|
||||
param_env,
|
||||
location_table,
|
||||
Some(implicit_region_bound),
|
||||
universal_regions,
|
||||
&mut constraints,
|
||||
all_facts,
|
||||
);
|
||||
|
||||
{
|
||||
let mut borrowck_context = BorrowCheckContext {
|
||||
universal_regions,
|
||||
location_table,
|
||||
borrow_set,
|
||||
all_facts,
|
||||
constraints: &mut constraints,
|
||||
};
|
||||
let mut borrowck_context = BorrowCheckContext {
|
||||
universal_regions,
|
||||
location_table,
|
||||
borrow_set,
|
||||
all_facts,
|
||||
constraints: &mut constraints,
|
||||
};
|
||||
|
||||
type_check_internal(
|
||||
infcx,
|
||||
mir_def_id,
|
||||
param_env,
|
||||
mir,
|
||||
®ion_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
Some(&mut borrowck_context),
|
||||
Some(&universal_region_relations),
|
||||
|cx| {
|
||||
cx.equate_inputs_and_outputs(
|
||||
mir,
|
||||
universal_regions,
|
||||
&normalized_inputs_and_output,
|
||||
);
|
||||
liveness::generate(cx, mir, elements, flow_inits, move_data);
|
||||
},
|
||||
);
|
||||
}
|
||||
type_check_internal(
|
||||
infcx,
|
||||
mir_def_id,
|
||||
param_env,
|
||||
mir,
|
||||
®ion_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
Some(&mut borrowck_context),
|
||||
Some(&universal_region_relations),
|
||||
|cx| {
|
||||
cx.equate_inputs_and_outputs(mir, universal_regions, &normalized_inputs_and_output);
|
||||
liveness::generate(cx, mir, elements, flow_inits, move_data, location_table);
|
||||
|
||||
cx.borrowck_context.as_mut().map(|bcx| translate_outlives_facts(bcx));
|
||||
},
|
||||
);
|
||||
|
||||
MirTypeckResults {
|
||||
constraints,
|
||||
|
|
@ -182,7 +177,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
|
|||
mir_def_id: DefId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &'a Mir<'tcx>,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||
|
|
@ -212,6 +207,27 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
|
|||
extra(&mut checker)
|
||||
}
|
||||
|
||||
fn translate_outlives_facts(cx: &mut BorrowCheckContext) {
|
||||
if let Some(facts) = cx.all_facts {
|
||||
let location_table = cx.location_table;
|
||||
facts.outlives.extend(
|
||||
cx.constraints.outlives_constraints.iter().flat_map(|constraint: &OutlivesConstraint| {
|
||||
if let Some(from_location) = constraint.locations.from_location() {
|
||||
Either::Left(iter::once((
|
||||
constraint.sup,
|
||||
constraint.sub,
|
||||
location_table.mid_index(from_location),
|
||||
)))
|
||||
} else {
|
||||
Either::Right(location_table.all_points().map(move |location| {
|
||||
(constraint.sup, constraint.sub, location)
|
||||
}))
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
|
||||
// We sometimes see MIR failures (notably predicate failures) due to
|
||||
// the fact that we check rvalue sized predicates here. So use `delay_span_bug`
|
||||
|
|
@ -377,14 +393,12 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
|
||||
debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty);
|
||||
|
||||
if let Err(terr) = self.cx
|
||||
.eq_types(
|
||||
constant.literal.ty,
|
||||
constant.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
)
|
||||
{
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
constant.literal.ty,
|
||||
constant.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
constant,
|
||||
|
|
@ -429,12 +443,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
let sty = self.sanitize_type(place, sty);
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
let ty = self.cx.normalize(ty, location);
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
ty,
|
||||
sty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
if let Err(terr) =
|
||||
self.cx
|
||||
.eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
place,
|
||||
|
|
@ -693,7 +705,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|||
last_span: Span,
|
||||
mir: &'a Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
|
|
@ -802,7 +814,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
mir: &'a Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||
|
|
@ -861,7 +873,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx.tcx,
|
||||
borrowck_context.universal_regions,
|
||||
borrowck_context.location_table,
|
||||
self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
|
|
@ -869,7 +880,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
category,
|
||||
&mut borrowck_context.constraints.outlives_constraints,
|
||||
&mut borrowck_context.constraints.type_tests,
|
||||
&mut borrowck_context.all_facts,
|
||||
).convert_all(&data);
|
||||
}
|
||||
}
|
||||
|
|
@ -955,66 +965,55 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
let tcx = infcx.tcx;
|
||||
let param_env = self.param_env;
|
||||
let parent_def_id = infcx.tcx.closure_base_def_id(self.mir_def_id);
|
||||
let opaque_type_map =
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
let opaque_type_map = self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
let (output_ty, opaque_type_map) =
|
||||
obligations.add(infcx.instantiate_opaque_types(
|
||||
parent_def_id,
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
&anon_ty,
|
||||
));
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
let (output_ty, opaque_type_map) =
|
||||
obligations.add(infcx.instantiate_opaque_types(
|
||||
parent_def_id,
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
&anon_ty,
|
||||
));
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: \
|
||||
instantiated output_ty={:?} \
|
||||
opaque_type_map={:#?} \
|
||||
revealed_ty={:?}",
|
||||
output_ty, opaque_type_map, revealed_ty
|
||||
);
|
||||
obligations.add(infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, revealed_ty)?);
|
||||
|
||||
for (&opaque_def_id, opaque_decl) in &opaque_type_map {
|
||||
let opaque_defn_ty = tcx.type_of(opaque_def_id);
|
||||
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
|
||||
let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: \
|
||||
instantiated output_ty={:?} \
|
||||
opaque_type_map={:#?} \
|
||||
revealed_ty={:?}",
|
||||
output_ty,
|
||||
opaque_type_map,
|
||||
revealed_ty
|
||||
);
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, revealed_ty)?,
|
||||
"eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}",
|
||||
opaque_decl.concrete_ty, opaque_defn_ty
|
||||
);
|
||||
obligations.add(infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?);
|
||||
}
|
||||
|
||||
for (&opaque_def_id, opaque_decl) in &opaque_type_map {
|
||||
let opaque_defn_ty = tcx.type_of(opaque_def_id);
|
||||
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
|
||||
let opaque_defn_ty = renumber::renumber_regions(
|
||||
infcx,
|
||||
&opaque_defn_ty,
|
||||
);
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}",
|
||||
opaque_decl.concrete_ty,
|
||||
opaque_defn_ty
|
||||
);
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
|
||||
);
|
||||
}
|
||||
debug!("eq_opaque_type_and_type: equated");
|
||||
|
||||
debug!("eq_opaque_type_and_type: equated");
|
||||
|
||||
Ok(InferOk {
|
||||
value: Some(opaque_type_map),
|
||||
obligations: obligations.into_vec(),
|
||||
})
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
)?;
|
||||
Ok(InferOk {
|
||||
value: Some(opaque_type_map),
|
||||
obligations: obligations.into_vec(),
|
||||
})
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let universal_region_relations = match self.universal_region_relations {
|
||||
Some(rel) => rel,
|
||||
|
|
@ -1035,7 +1034,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
infcx.constrain_opaque_type(
|
||||
opaque_def_id,
|
||||
&opaque_decl,
|
||||
universal_region_relations
|
||||
universal_region_relations,
|
||||
);
|
||||
Ok(InferOk {
|
||||
value: (),
|
||||
|
|
@ -1073,12 +1072,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
|
||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||
let rv_ty = rv.ty(mir, tcx);
|
||||
if let Err(terr) = self.sub_types_or_anon(
|
||||
rv_ty,
|
||||
place_ty,
|
||||
location.to_locations(),
|
||||
category,
|
||||
) {
|
||||
if let Err(terr) =
|
||||
self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
stmt,
|
||||
|
|
@ -1117,7 +1113,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
self.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::SizedBound,
|
||||
ConstraintCategory::SizedBound,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1148,15 +1144,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
StatementKind::AscribeUserType(ref place, variance, c_ty) => {
|
||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||
if let Err(terr) =
|
||||
self.relate_type_and_user_type(
|
||||
place_ty,
|
||||
variance,
|
||||
c_ty,
|
||||
Locations::All(stmt.source_info.span),
|
||||
ConstraintCategory::TypeAnnotation,
|
||||
)
|
||||
{
|
||||
if let Err(terr) = self.relate_type_and_user_type(
|
||||
place_ty,
|
||||
variance,
|
||||
c_ty,
|
||||
Locations::All(stmt.source_info.span),
|
||||
ConstraintCategory::TypeAnnotation,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
stmt,
|
||||
|
|
@ -1208,12 +1202,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
let rv_ty = value.ty(mir, tcx);
|
||||
|
||||
let locations = term_location.to_locations();
|
||||
if let Err(terr) = self.sub_types(
|
||||
rv_ty,
|
||||
place_ty,
|
||||
locations,
|
||||
ConstraintCategory::Assignment,
|
||||
) {
|
||||
if let Err(terr) =
|
||||
self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
|
|
@ -1327,8 +1318,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
ty,
|
||||
term_location.to_locations(),
|
||||
ConstraintCategory::Return,
|
||||
)
|
||||
{
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
|
|
@ -1366,12 +1356,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
|
||||
let locations = term_location.to_locations();
|
||||
|
||||
if let Err(terr) = self.sub_types_or_anon(
|
||||
sig.output(),
|
||||
dest_ty,
|
||||
locations,
|
||||
category,
|
||||
) {
|
||||
if let Err(terr) =
|
||||
self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
|
|
@ -1539,12 +1526,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_local(
|
||||
&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
local: Local,
|
||||
local_decl: &LocalDecl<'tcx>,
|
||||
) {
|
||||
fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
match mir.local_kind(local) {
|
||||
LocalKind::ReturnPointer | LocalKind::Arg => {
|
||||
// return values of normal functions are required to be
|
||||
|
|
@ -1713,13 +1695,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1739,13 +1721,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1768,13 +1750,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1957,14 +1939,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
category: ConstraintCategory::Boring,
|
||||
});
|
||||
|
||||
if let Some(all_facts) = all_facts {
|
||||
all_facts.outlives.push((
|
||||
ref_region.to_region_vid(),
|
||||
borrow_region.to_region_vid(),
|
||||
location_table.mid_index(location),
|
||||
));
|
||||
}
|
||||
|
||||
match mutbl {
|
||||
hir::Mutability::MutImmutable => {
|
||||
// Immutable reference. We don't need the base
|
||||
|
|
@ -2232,7 +2206,7 @@ impl MirPass for TypeckMir {
|
|||
def_id,
|
||||
param_env,
|
||||
mir,
|
||||
&[],
|
||||
&vec![],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
|
|
@ -2277,4 +2251,3 @@ impl<'tcx> ObligationAccumulator<'tcx> {
|
|||
self.obligations
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,15 +10,13 @@
|
|||
|
||||
use borrow_check::nll::constraints::{ConstraintCategory, OutlivesConstraint};
|
||||
use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use rustc::infer::canonical::{Canonical, CanonicalVarInfos};
|
||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
use rustc::traits::query::Fallible;
|
||||
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
|
||||
use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc::ty::subst::Kind;
|
||||
use rustc::ty::{self, CanonicalTy, CanonicalVar, RegionVid, Ty, TyCtxt};
|
||||
use rustc::ty::{self, CanonicalTy, CanonicalVar, Ty, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
|
||||
|
|
@ -33,11 +31,9 @@ pub(super) fn sub_types<'tcx>(
|
|||
) -> Fallible<()> {
|
||||
debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
infcx.tcx,
|
||||
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||
ty::Variance::Covariant,
|
||||
locations,
|
||||
category,
|
||||
borrowck_context,
|
||||
ty::List::empty(),
|
||||
).relate(&a, &b)?;
|
||||
Ok(())
|
||||
|
|
@ -54,11 +50,9 @@ pub(super) fn eq_types<'tcx>(
|
|||
) -> Fallible<()> {
|
||||
debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
infcx.tcx,
|
||||
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||
ty::Variance::Invariant,
|
||||
locations,
|
||||
category,
|
||||
borrowck_context,
|
||||
ty::List::empty(),
|
||||
).relate(&a, &b)?;
|
||||
Ok(())
|
||||
|
|
@ -91,18 +85,22 @@ pub(super) fn relate_type_and_user_type<'tcx>(
|
|||
let v1 = ty::Contravariant.xform(v);
|
||||
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
infcx.tcx,
|
||||
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||
v1,
|
||||
locations,
|
||||
category,
|
||||
borrowck_context,
|
||||
b_variables,
|
||||
).relate(&b_value, &a)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
tcx: TyCtxt<'me, 'gcx, 'tcx>,
|
||||
|
||||
/// Callback to use when we deduce an outlives relationship
|
||||
delegate: D,
|
||||
|
||||
/// How are we relating `a` and `b`?
|
||||
///
|
||||
|
|
@ -122,19 +120,10 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
|
|||
///
|
||||
/// This field stores the instantiations for late-bound regions in
|
||||
/// the `a` type.
|
||||
a_scopes: Vec<BoundRegionScope>,
|
||||
a_scopes: Vec<BoundRegionScope<'tcx>>,
|
||||
|
||||
/// Same as `a_scopes`, but for the `b` type.
|
||||
b_scopes: Vec<BoundRegionScope>,
|
||||
|
||||
/// Where (and why) is this relation taking place?
|
||||
locations: Locations,
|
||||
|
||||
category: ConstraintCategory,
|
||||
|
||||
/// This will be `Some` when we are running the type check as part
|
||||
/// of NLL, and `None` if we are running a "sanity check".
|
||||
borrowck_context: Option<&'cx mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
b_scopes: Vec<BoundRegionScope<'tcx>>,
|
||||
|
||||
/// As we execute, the type on the LHS *may* come from a canonical
|
||||
/// source. In that case, we will sometimes find a constraint like
|
||||
|
|
@ -150,37 +139,128 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
|
|||
canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
|
||||
}
|
||||
|
||||
trait TypeRelatingDelegate<'tcx> {
|
||||
/// Push a constraint `sup: sub` -- this constraint must be
|
||||
/// satisfied for the two types to be related. `sub` and `sup` may
|
||||
/// be regions from the type or new variables created through the
|
||||
/// delegate.
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
|
||||
|
||||
/// Creates a new region variable representing an instantiated
|
||||
/// higher-ranked region; this will be either existential or
|
||||
/// universal depending on the context. So e.g. if you have
|
||||
/// `for<'a> fn(..) <: for<'b> fn(..)`, then we will first
|
||||
/// instantiate `'b` with a universally quantitifed region and
|
||||
/// then `'a` with an existentially quantified region (the order
|
||||
/// is important so that the existential region `'a` can see the
|
||||
/// universal one).
|
||||
fn next_region_var(
|
||||
&mut self,
|
||||
universally_quantified: UniversallyQuantified,
|
||||
) -> ty::Region<'tcx>;
|
||||
|
||||
/// Creates a new existential region in the given universe. This
|
||||
/// is used when handling subtyping and type variables -- if we
|
||||
/// have that `?X <: Foo<'a>`, for example, we would instantiate
|
||||
/// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh
|
||||
/// existential variable created by this function. We would then
|
||||
/// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives
|
||||
/// relation stating that `'?0: 'a`).
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
|
||||
}
|
||||
|
||||
struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
|
||||
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
|
||||
borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
|
||||
/// Where (and why) is this relation taking place?
|
||||
locations: Locations,
|
||||
|
||||
/// What category do we assign the resulting `'a: 'b` relationships?
|
||||
category: ConstraintCategory,
|
||||
}
|
||||
|
||||
impl NllTypeRelatingDelegate<'me, 'bccx, 'gcx, 'tcx> {
|
||||
fn new(
|
||||
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
|
||||
borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Self {
|
||||
Self {
|
||||
infcx,
|
||||
borrowck_context,
|
||||
locations,
|
||||
category,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> {
|
||||
fn next_region_var(
|
||||
&mut self,
|
||||
universally_quantified: UniversallyQuantified,
|
||||
) -> ty::Region<'tcx> {
|
||||
let origin = if universally_quantified.0 {
|
||||
NLLRegionVariableOrigin::BoundRegion(self.infcx.create_subuniverse())
|
||||
} else {
|
||||
NLLRegionVariableOrigin::Existential
|
||||
};
|
||||
self.infcx.next_nll_region_var(origin)
|
||||
}
|
||||
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||
self.infcx
|
||||
.next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, universe)
|
||||
}
|
||||
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
|
||||
if let Some(borrowck_context) = &mut self.borrowck_context {
|
||||
let sub = borrowck_context.universal_regions.to_region_vid(sub);
|
||||
let sup = borrowck_context.universal_regions.to_region_vid(sup);
|
||||
borrowck_context
|
||||
.constraints
|
||||
.outlives_constraints
|
||||
.push(OutlivesConstraint {
|
||||
sup,
|
||||
sub,
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ScopesAndKind<'tcx> {
|
||||
scopes: Vec<BoundRegionScope>,
|
||||
scopes: Vec<BoundRegionScope<'tcx>>,
|
||||
kind: Kind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct BoundRegionScope {
|
||||
map: FxHashMap<ty::BoundRegion, RegionVid>,
|
||||
struct BoundRegionScope<'tcx> {
|
||||
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct UniversallyQuantified(bool);
|
||||
|
||||
impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
||||
impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn new(
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
tcx: TyCtxt<'me, 'gcx, 'tcx>,
|
||||
delegate: D,
|
||||
ambient_variance: ty::Variance,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
borrowck_context: Option<&'cx mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
canonical_var_infos: CanonicalVarInfos<'tcx>,
|
||||
) -> Self {
|
||||
let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len());
|
||||
Self {
|
||||
infcx,
|
||||
tcx,
|
||||
delegate,
|
||||
ambient_variance,
|
||||
borrowck_context,
|
||||
locations,
|
||||
canonical_var_values,
|
||||
category,
|
||||
a_scopes: vec![],
|
||||
b_scopes: vec![],
|
||||
}
|
||||
|
|
@ -204,10 +284,10 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
&mut self,
|
||||
value: &ty::Binder<impl TypeFoldable<'tcx>>,
|
||||
universally_quantified: UniversallyQuantified,
|
||||
) -> BoundRegionScope {
|
||||
) -> BoundRegionScope<'tcx> {
|
||||
let mut scope = BoundRegionScope::default();
|
||||
value.skip_binder().visit_with(&mut ScopeInstantiator {
|
||||
infcx: self.infcx,
|
||||
delegate: &mut self.delegate,
|
||||
target_index: ty::INNERMOST,
|
||||
universally_quantified,
|
||||
bound_region_scope: &mut scope,
|
||||
|
|
@ -227,8 +307,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
debruijn: ty::DebruijnIndex,
|
||||
br: &ty::BoundRegion,
|
||||
first_free_index: ty::DebruijnIndex,
|
||||
scopes: &[BoundRegionScope],
|
||||
) -> RegionVid {
|
||||
scopes: &[BoundRegionScope<'tcx>],
|
||||
) -> ty::Region<'tcx> {
|
||||
// The debruijn index is a "reverse index" into the
|
||||
// scopes listing. So when we have INNERMOST (0), we
|
||||
// want the *last* scope pushed, and so forth.
|
||||
|
|
@ -245,40 +325,23 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
/// with. Otherwise just return `r`.
|
||||
fn replace_bound_region(
|
||||
&self,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
r: ty::Region<'tcx>,
|
||||
first_free_index: ty::DebruijnIndex,
|
||||
scopes: &[BoundRegionScope],
|
||||
) -> RegionVid {
|
||||
match r {
|
||||
ty::ReLateBound(debruijn, br) => {
|
||||
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
|
||||
}
|
||||
|
||||
ty::ReVar(v) => *v,
|
||||
|
||||
_ => universal_regions.to_region_vid(r),
|
||||
scopes: &[BoundRegionScope<'tcx>],
|
||||
) -> ty::Region<'tcx> {
|
||||
if let ty::ReLateBound(debruijn, br) = r {
|
||||
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
|
||||
} else {
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
/// Push a new outlives requirement into our output set of
|
||||
/// constraints.
|
||||
fn push_outlives(&mut self, sup: RegionVid, sub: RegionVid) {
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
|
||||
debug!("push_outlives({:?}: {:?})", sup, sub);
|
||||
|
||||
if let Some(borrowck_context) = &mut self.borrowck_context {
|
||||
borrowck_context
|
||||
.constraints
|
||||
.outlives_constraints
|
||||
.push(OutlivesConstraint {
|
||||
sup,
|
||||
sub,
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
});
|
||||
|
||||
// FIXME all facts!
|
||||
}
|
||||
self.delegate.push_outlives(sup, sub);
|
||||
}
|
||||
|
||||
/// When we encounter a canonical variable `var` in the output,
|
||||
|
|
@ -316,12 +379,10 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
return result;
|
||||
}
|
||||
|
||||
fn generalize_value(
|
||||
&self,
|
||||
kind: Kind<'tcx>,
|
||||
) -> Kind<'tcx> {
|
||||
fn generalize_value(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> {
|
||||
TypeGeneralizer {
|
||||
type_rel: self,
|
||||
tcx: self.tcx,
|
||||
delegate: &mut self.delegate,
|
||||
first_free_index: ty::INNERMOST,
|
||||
ambient_variance: self.ambient_variance,
|
||||
|
||||
|
|
@ -333,11 +394,12 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
||||
for TypeRelating<'cx, 'bccx, 'gcx, 'tcx>
|
||||
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
|
||||
self.infcx.tcx
|
||||
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
|
|
@ -397,37 +459,30 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
if let Some(&mut BorrowCheckContext {
|
||||
universal_regions, ..
|
||||
}) = self.borrowck_context
|
||||
{
|
||||
if let ty::ReCanonical(var) = a {
|
||||
self.relate_var(*var, b.into())?;
|
||||
return Ok(a);
|
||||
}
|
||||
if let ty::ReCanonical(var) = a {
|
||||
self.relate_var(*var, b.into())?;
|
||||
return Ok(a);
|
||||
}
|
||||
|
||||
debug!(
|
||||
"regions(a={:?}, b={:?}, variance={:?})",
|
||||
a, b, self.ambient_variance
|
||||
);
|
||||
debug!(
|
||||
"regions(a={:?}, b={:?}, variance={:?})",
|
||||
a, b, self.ambient_variance
|
||||
);
|
||||
|
||||
let v_a =
|
||||
self.replace_bound_region(universal_regions, a, ty::INNERMOST, &self.a_scopes);
|
||||
let v_b =
|
||||
self.replace_bound_region(universal_regions, b, ty::INNERMOST, &self.b_scopes);
|
||||
let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
|
||||
let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
|
||||
|
||||
debug!("regions: v_a = {:?}", v_a);
|
||||
debug!("regions: v_b = {:?}", v_b);
|
||||
debug!("regions: v_a = {:?}", v_a);
|
||||
debug!("regions: v_b = {:?}", v_b);
|
||||
|
||||
if self.ambient_covariance() {
|
||||
// Covariance: a <= b. Hence, `b: a`.
|
||||
self.push_outlives(v_b, v_a);
|
||||
}
|
||||
if self.ambient_covariance() {
|
||||
// Covariance: a <= b. Hence, `b: a`.
|
||||
self.push_outlives(v_b, v_a);
|
||||
}
|
||||
|
||||
if self.ambient_contravariance() {
|
||||
// Contravariant: b <= a. Hence, `a: b`.
|
||||
self.push_outlives(v_a, v_b);
|
||||
}
|
||||
if self.ambient_contravariance() {
|
||||
// Contravariant: b <= a. Hence, `a: b`.
|
||||
self.push_outlives(v_a, v_b);
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
|
|
@ -527,10 +582,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
|
||||
// Reset ambient variance to contravariance. See the
|
||||
// covariant case above for an explanation.
|
||||
let variance = ::std::mem::replace(
|
||||
&mut self.ambient_variance,
|
||||
ty::Variance::Contravariant,
|
||||
);
|
||||
let variance =
|
||||
::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
|
||||
|
||||
self.relate(a.skip_binder(), b.skip_binder())?;
|
||||
|
||||
|
|
@ -551,15 +604,21 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
/// binder depth, and finds late-bound regions targeting the
|
||||
/// `for<..`>. For each of those, it creates an entry in
|
||||
/// `bound_region_scope`.
|
||||
struct ScopeInstantiator<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
struct ScopeInstantiator<'me, 'tcx: 'me, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx> + 'me,
|
||||
{
|
||||
delegate: &'me mut D,
|
||||
// The debruijn index of the scope we are instantiating.
|
||||
target_index: ty::DebruijnIndex,
|
||||
universally_quantified: UniversallyQuantified,
|
||||
bound_region_scope: &'cx mut BoundRegionScope,
|
||||
bound_region_scope: &'me mut BoundRegionScope<'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
|
||||
impl<'me, 'tcx, D> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
|
||||
self.target_index.shift_in(1);
|
||||
t.super_visit_with(self);
|
||||
|
|
@ -570,21 +629,18 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
|
|||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
|
||||
let ScopeInstantiator {
|
||||
infcx,
|
||||
universally_quantified,
|
||||
bound_region_scope,
|
||||
delegate,
|
||||
..
|
||||
} = *self;
|
||||
} = self;
|
||||
|
||||
match r {
|
||||
ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
|
||||
self.bound_region_scope.map.entry(*br).or_insert_with(|| {
|
||||
let origin = if universally_quantified.0 {
|
||||
NLLRegionVariableOrigin::BoundRegion(infcx.create_subuniverse())
|
||||
} else {
|
||||
NLLRegionVariableOrigin::Existential
|
||||
};
|
||||
infcx.next_nll_region_var(origin).to_region_vid()
|
||||
});
|
||||
bound_region_scope
|
||||
.map
|
||||
.entry(*br)
|
||||
.or_insert_with(|| delegate.next_region_var(*universally_quantified));
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
|
@ -613,8 +669,13 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
|
|||
/// scopes.
|
||||
///
|
||||
/// [blog post]: https://is.gd/0hKvIr
|
||||
struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
|
||||
type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
|
||||
struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx> + 'me,
|
||||
{
|
||||
tcx: TyCtxt<'me, 'gcx, 'tcx>,
|
||||
|
||||
delegate: &'me mut D,
|
||||
|
||||
/// After we generalize this type, we are going to relative it to
|
||||
/// some other type. What will be the variance at this point?
|
||||
|
|
@ -625,9 +686,12 @@ struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
|
|||
universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
|
||||
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
|
||||
self.type_rel.infcx.tcx
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
|
|
@ -710,9 +774,7 @@ impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
|
|||
// though, we may however need to check well-formedness or
|
||||
// risk a problem like #41677 again.
|
||||
|
||||
let replacement_region_vid = self.type_rel
|
||||
.infcx
|
||||
.next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, self.universe);
|
||||
let replacement_region_vid = self.delegate.generalize_existential(self.universe);
|
||||
|
||||
Ok(replacement_region_vid)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ impl<'tcx> CFG<'tcx> {
|
|||
rvalue: Rvalue<'tcx>) {
|
||||
self.push(block, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(place.clone(), rvalue)
|
||||
kind: StatementKind::Assign(place.clone(), box rvalue)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -143,11 +143,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let outputs = outputs
|
||||
.into_iter()
|
||||
.map(|output| unpack!(block = this.as_place(block, output)))
|
||||
.collect();
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
let inputs = inputs
|
||||
.into_iter()
|
||||
.map(|input| unpack!(block = this.as_local_operand(block, input)))
|
||||
.collect();
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
this.cfg.push(
|
||||
block,
|
||||
Statement {
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
|||
// re-consider the current implementations of the
|
||||
// propagate_call_return method.
|
||||
|
||||
if let mir::Rvalue::Ref(region, _, ref place) = *rhs {
|
||||
if let mir::Rvalue::Ref(region, _, ref place) = **rhs {
|
||||
if place.ignore_borrow(
|
||||
self.tcx,
|
||||
self.mir,
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
self.gather_init(output, InitKind::Deep);
|
||||
}
|
||||
}
|
||||
for input in inputs {
|
||||
for input in inputs.iter() {
|
||||
self.gather_operand(input);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -539,7 +539,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
|||
.emit();
|
||||
} else if has_guard && !cx.tcx.allow_bind_by_move_patterns_with_guards() {
|
||||
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
|
||||
"cannot bind by-move into a pattern guard");
|
||||
"cannot bind by-move into a pattern guard");
|
||||
err.span_label(p.span, "moves value into pattern guard");
|
||||
if cx.tcx.sess.opts.unstable_features.is_nightly_build() && cx.tcx.use_mir_borrowck() {
|
||||
err.help("add #![feature(bind_by_move_pattern_guards)] to the \
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
|||
rval: OpTy<'tcx>,
|
||||
) -> EvalResult<'tcx, (u128, usize)> {
|
||||
trace!("read_discriminant_value {:#?}", rval.layout);
|
||||
if rval.layout.abi.is_uninhabited() {
|
||||
if rval.layout.abi == layout::Abi::Uninhabited {
|
||||
return err!(Unreachable);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let ret_statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::Local(RETURN_PLACE),
|
||||
Rvalue::Use(Operand::Copy(rcvr))
|
||||
box Rvalue::Use(Operand::Copy(rcvr))
|
||||
)
|
||||
);
|
||||
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
||||
|
|
@ -458,7 +458,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
ref_loc.clone(),
|
||||
Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, src)
|
||||
box Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, src)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -485,7 +485,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let compute_cond = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
cond.clone(),
|
||||
Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
|
||||
box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -521,13 +521,13 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::Local(beg),
|
||||
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||
box Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||
)
|
||||
),
|
||||
self.make_statement(
|
||||
StatementKind::Assign(
|
||||
end.clone(),
|
||||
Rvalue::Use(Operand::Constant(self.make_usize(len)))
|
||||
box Rvalue::Use(Operand::Constant(self.make_usize(len)))
|
||||
)
|
||||
)
|
||||
];
|
||||
|
|
@ -555,7 +555,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::Local(beg),
|
||||
Rvalue::BinaryOp(
|
||||
box Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Copy(Place::Local(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
|
|
@ -578,7 +578,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let init = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::Local(beg),
|
||||
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||
box Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||
)
|
||||
);
|
||||
self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
|
||||
|
|
@ -605,7 +605,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::Local(beg),
|
||||
Rvalue::BinaryOp(
|
||||
box Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Copy(Place::Local(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
|
|
@ -715,7 +715,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Place::Local(ref_rcvr),
|
||||
Rvalue::Ref(tcx.types.re_erased, borrow_kind, rcvr_l)
|
||||
box Rvalue::Ref(tcx.types.re_erased, borrow_kind, rcvr_l)
|
||||
)
|
||||
});
|
||||
Operand::Move(Place::Local(ref_rcvr))
|
||||
|
|
@ -851,7 +851,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
|||
source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Place::Local(RETURN_PLACE),
|
||||
Rvalue::Aggregate(
|
||||
box Rvalue::Aggregate(
|
||||
box AggregateKind::Adt(adt_def, variant_no, substs, None, None),
|
||||
(1..sig.inputs().len()+1).map(|i| {
|
||||
Operand::Move(Place::Local(Local::new(i)))
|
||||
|
|
|
|||
|
|
@ -320,12 +320,12 @@ impl MirPass for AddValidation {
|
|||
for i in (0..block_data.statements.len()).rev() {
|
||||
match block_data.statements[i].kind {
|
||||
// When the borrow of this ref expires, we need to recover validation.
|
||||
StatementKind::Assign(_, Rvalue::Ref(_, _, _)) => {
|
||||
StatementKind::Assign(_, box Rvalue::Ref(_, _, _)) => {
|
||||
// Due to a lack of NLL; we can't capture anything directly here.
|
||||
// Instead, we have to re-match and clone there.
|
||||
let (dest_place, re, src_place) = match block_data.statements[i].kind {
|
||||
StatementKind::Assign(ref dest_place,
|
||||
Rvalue::Ref(re, _, ref src_place)) => {
|
||||
box Rvalue::Ref(re, _, ref src_place)) => {
|
||||
(dest_place.clone(), re, src_place.clone())
|
||||
},
|
||||
_ => bug!("We already matched this."),
|
||||
|
|
@ -354,17 +354,17 @@ impl MirPass for AddValidation {
|
|||
block_data.statements.insert(i, release_stmt);
|
||||
}
|
||||
// Casts can change what validation does (e.g. unsizing)
|
||||
StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Copy(_), _)) |
|
||||
StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Move(_), _))
|
||||
StatementKind::Assign(_, box Rvalue::Cast(kind, Operand::Copy(_), _)) |
|
||||
StatementKind::Assign(_, box Rvalue::Cast(kind, Operand::Move(_), _))
|
||||
if kind != CastKind::Misc =>
|
||||
{
|
||||
// Due to a lack of NLL; we can't capture anything directly here.
|
||||
// Instead, we have to re-match and clone there.
|
||||
let (dest_place, src_place) = match block_data.statements[i].kind {
|
||||
StatementKind::Assign(ref dest_place,
|
||||
Rvalue::Cast(_, Operand::Copy(ref src_place), _)) |
|
||||
box Rvalue::Cast(_, Operand::Copy(ref src_place), _)) |
|
||||
StatementKind::Assign(ref dest_place,
|
||||
Rvalue::Cast(_, Operand::Move(ref src_place), _)) =>
|
||||
box Rvalue::Cast(_, Operand::Move(ref src_place), _)) =>
|
||||
{
|
||||
(dest_place.clone(), src_place.clone())
|
||||
},
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ impl MirPass for CopyPropagation {
|
|||
|
||||
// That use of the source must be an assignment.
|
||||
match statement.kind {
|
||||
StatementKind::Assign(Place::Local(local), Rvalue::Use(ref operand)) if
|
||||
StatementKind::Assign(Place::Local(local), box Rvalue::Use(ref operand)) if
|
||||
local == dest_local => {
|
||||
let maybe_action = match *operand {
|
||||
Operand::Copy(ref src_place) |
|
||||
|
|
@ -155,11 +155,11 @@ fn eliminate_self_assignments<'tcx>(
|
|||
match stmt.kind {
|
||||
StatementKind::Assign(
|
||||
Place::Local(local),
|
||||
Rvalue::Use(Operand::Copy(Place::Local(src_local))),
|
||||
box Rvalue::Use(Operand::Copy(Place::Local(src_local))),
|
||||
) |
|
||||
StatementKind::Assign(
|
||||
Place::Local(local),
|
||||
Rvalue::Use(Operand::Move(Place::Local(src_local))),
|
||||
box Rvalue::Use(Operand::Move(Place::Local(src_local))),
|
||||
) if local == dest_local && dest_local == src_local => {}
|
||||
_ => {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ impl MirPass for Deaggregator {
|
|||
bb.expand_statements(|stmt| {
|
||||
// FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
|
||||
if let StatementKind::Assign(_, ref rhs) = stmt.kind {
|
||||
if let Rvalue::Aggregate(ref kind, _) = *rhs {
|
||||
if let Rvalue::Aggregate(ref kind, _) = **rhs {
|
||||
// FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
|
||||
if let AggregateKind::Array(_) = **kind {
|
||||
return None;
|
||||
|
|
@ -41,8 +41,12 @@ impl MirPass for Deaggregator {
|
|||
let stmt = stmt.replace_nop();
|
||||
let source_info = stmt.source_info;
|
||||
let (mut lhs, kind, operands) = match stmt.kind {
|
||||
StatementKind::Assign(lhs, Rvalue::Aggregate(kind, operands))
|
||||
=> (lhs, kind, operands),
|
||||
StatementKind::Assign(lhs, box rvalue) => {
|
||||
match rvalue {
|
||||
Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
|
||||
_ => bug!()
|
||||
}
|
||||
}
|
||||
_ => bug!()
|
||||
};
|
||||
|
||||
|
|
@ -82,7 +86,7 @@ impl MirPass for Deaggregator {
|
|||
};
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(lhs_field, Rvalue::Use(op)),
|
||||
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
|
||||
}
|
||||
}).chain(set_discriminant))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
|
||||
|
||||
let assign = Statement {
|
||||
kind: StatementKind::Assign(location.clone(), Rvalue::Use(value.clone())),
|
||||
kind: StatementKind::Assign(location.clone(), box Rvalue::Use(value.clone())),
|
||||
source_info: terminator.source_info
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
|||
});
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(state, Rvalue::Use(val)),
|
||||
kind: StatementKind::Assign(state, box Rvalue::Use(val)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -246,7 +246,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
|||
data.statements.push(Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(Place::Local(RETURN_PLACE),
|
||||
self.make_state(state_idx, v)),
|
||||
box self.make_state(state_idx, v)),
|
||||
});
|
||||
let state = if let Some(resume) = resume { // Yield
|
||||
let state = 3 + self.suspension_points.len() as u32;
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
|||
|
||||
let stmt = Statement {
|
||||
source_info: callsite.location,
|
||||
kind: StatementKind::Assign(tmp.clone(), dest)
|
||||
kind: StatementKind::Assign(tmp.clone(), box dest)
|
||||
};
|
||||
caller_mir[callsite.bb]
|
||||
.statements.push(stmt);
|
||||
|
|
@ -594,7 +594,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
|||
|
||||
let stmt = Statement {
|
||||
source_info: callsite.location,
|
||||
kind: StatementKind::Assign(Place::Local(arg_tmp), arg),
|
||||
kind: StatementKind::Assign(Place::Local(arg_tmp), box arg),
|
||||
};
|
||||
caller_mir[callsite.bb].statements.push(stmt);
|
||||
arg_tmp
|
||||
|
|
|
|||
|
|
@ -79,11 +79,14 @@ impl Lower128Bit {
|
|||
let bin_statement = block.statements.pop().unwrap();
|
||||
let source_info = bin_statement.source_info;
|
||||
let (place, lhs, mut rhs) = match bin_statement.kind {
|
||||
StatementKind::Assign(place, Rvalue::BinaryOp(_, lhs, rhs))
|
||||
| StatementKind::Assign(place, Rvalue::CheckedBinaryOp(_, lhs, rhs)) => {
|
||||
(place, lhs, rhs)
|
||||
StatementKind::Assign(place, box rvalue) => {
|
||||
match rvalue {
|
||||
Rvalue::BinaryOp(_, lhs, rhs)
|
||||
| Rvalue::CheckedBinaryOp(_, lhs, rhs) => (place, lhs, rhs),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
_ => bug!("Statement doesn't match pattern any more?"),
|
||||
_ => bug!()
|
||||
};
|
||||
|
||||
if let Some(local) = cast_local {
|
||||
|
|
@ -95,7 +98,7 @@ impl Lower128Bit {
|
|||
source_info: source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Place::Local(local),
|
||||
Rvalue::Cast(
|
||||
box Rvalue::Cast(
|
||||
CastKind::Misc,
|
||||
rhs,
|
||||
rhs_override_ty.unwrap())),
|
||||
|
|
@ -154,13 +157,13 @@ fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCt
|
|||
where D: HasLocalDecls<'tcx>
|
||||
{
|
||||
match statement.kind {
|
||||
StatementKind::Assign(_, Rvalue::BinaryOp(bin_op, ref lhs, _)) => {
|
||||
StatementKind::Assign(_, box Rvalue::BinaryOp(bin_op, ref lhs, _)) => {
|
||||
let ty = lhs.ty(local_decls, tcx);
|
||||
if let Some(is_signed) = sign_of_128bit(ty) {
|
||||
return item_for_op(bin_op, is_signed);
|
||||
}
|
||||
},
|
||||
StatementKind::Assign(_, Rvalue::CheckedBinaryOp(bin_op, ref lhs, _)) => {
|
||||
StatementKind::Assign(_, box Rvalue::CheckedBinaryOp(bin_op, ref lhs, _)) => {
|
||||
let ty = lhs.ty(local_decls, tcx);
|
||||
if let Some(is_signed) = sign_of_128bit(ty) {
|
||||
return item_for_checked_op(bin_op, is_signed);
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
span,
|
||||
scope: OUTERMOST_SOURCE_SCOPE
|
||||
},
|
||||
kind: StatementKind::Assign(Place::Local(dest), rvalue)
|
||||
kind: StatementKind::Assign(Place::Local(dest), box rvalue)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
// First, take the Rvalue or Call out of the source MIR,
|
||||
// or duplicate it, depending on keep_original.
|
||||
if loc.statement_index < no_stmts {
|
||||
let (mut rvalue, source_info) = {
|
||||
let (rvalue, source_info) = {
|
||||
let statement = &mut self.source[loc.block].statements[loc.statement_index];
|
||||
let rhs = match statement.kind {
|
||||
StatementKind::Assign(_, ref mut rhs) => rhs,
|
||||
|
|
@ -230,11 +230,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
(if self.keep_original {
|
||||
rhs.clone()
|
||||
} else {
|
||||
let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
|
||||
let unit = box Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
|
||||
mem::replace(rhs, unit)
|
||||
}, statement.source_info)
|
||||
};
|
||||
|
||||
let mut rvalue = *rvalue;
|
||||
self.visit_rvalue(&mut rvalue, loc);
|
||||
self.assign(new_temp, rvalue, source_info.span);
|
||||
} else {
|
||||
|
|
@ -301,7 +302,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
Candidate::Ref(loc) => {
|
||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
StatementKind::Assign(_, Rvalue::Ref(_, _, ref mut place)) => {
|
||||
StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
|
||||
// Find the underlying local for this (necessarily interior) borrow.
|
||||
// HACK(eddyb) using a recursive function because of mutable borrows.
|
||||
fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>)
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
match *candidate {
|
||||
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
|
||||
match self.mir[bb].statements[stmt_idx].kind {
|
||||
StatementKind::Assign(_, Rvalue::Ref(_, _, Place::Local(index))) => {
|
||||
StatementKind::Assign(_, box Rvalue::Ref(_, _, Place::Local(index))) => {
|
||||
promoted_temps.insert(index);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub fn is_min_const_fn(
|
|||
let mut current = def_id;
|
||||
loop {
|
||||
let predicates = tcx.predicates_of(current);
|
||||
for predicate in &predicates.predicates {
|
||||
for (predicate, _) in &predicates.predicates {
|
||||
match predicate {
|
||||
| Predicate::RegionOutlives(_)
|
||||
| Predicate::TypeOutlives(_)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ impl RemoveNoopLandingPads {
|
|||
// instructions, but this should all run after borrowck).
|
||||
}
|
||||
|
||||
StatementKind::Assign(Place::Local(_), Rvalue::Use(_)) => {
|
||||
StatementKind::Assign(Place::Local(_), box Rvalue::Use(_)) => {
|
||||
// Writing to a local (e.g. a drop flag) does not
|
||||
// turn a landing pad to a non-nop
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
};
|
||||
|
||||
if place == peek_arg_place {
|
||||
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = *rvalue {
|
||||
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue {
|
||||
// Okay, our search is over.
|
||||
match move_data.rev_lookup.find(peeking_at_place) {
|
||||
LookupResult::Exact(peek_mpi) => {
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
|
|||
for candidate in &visitor.candidates {
|
||||
let statement = &mir[candidate.block].statements[candidate.statement_index];
|
||||
if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
|
||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
|
||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval {
|
||||
let items : Vec<_> = items.iter().map(|item| {
|
||||
if let Operand::Move(Place::Local(local)) = item {
|
||||
let local_use = &visitor.locals_use[*local];
|
||||
|
|
@ -268,7 +268,7 @@ impl RestoreSubsliceArrayMoveOut {
|
|||
let statement = &block.statements[location.statement_index];
|
||||
if let StatementKind::Assign(
|
||||
Place::Local(_),
|
||||
Rvalue::Use(Operand::Move(Place::Projection(box PlaceProjection{
|
||||
box Rvalue::Use(Operand::Move(Place::Projection(box PlaceProjection{
|
||||
ref base, elem: ProjectionElem::ConstantIndex{
|
||||
offset, min_length: _, from_end: false}})))) = statement.kind {
|
||||
return Some((offset, base))
|
||||
|
|
|
|||
|
|
@ -977,7 +977,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
|
||||
Statement {
|
||||
source_info: self.source_info,
|
||||
kind: StatementKind::Assign(lhs.clone(), rhs)
|
||||
kind: StatementKind::Assign(lhs.clone(), box rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
}
|
||||
|
||||
pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
|
||||
self.add_statement(loc, StatementKind::Assign(place, rv));
|
||||
self.add_statement(loc, StatementKind::Assign(place, box rv));
|
||||
}
|
||||
|
||||
pub fn make_nop(&mut self, loc: Location) {
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
|||
|
||||
fn predicates(&mut self) -> &mut Self {
|
||||
let predicates = self.ev.tcx.predicates_of(self.item_def_id);
|
||||
for predicate in &predicates.predicates {
|
||||
for (predicate, _) in &predicates.predicates {
|
||||
predicate.visit_with(self);
|
||||
match predicate {
|
||||
&ty::Predicate::Trait(poly_predicate) => {
|
||||
|
|
@ -781,7 +781,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
|||
if self.check_trait_ref(*principal.skip_binder()) {
|
||||
return;
|
||||
}
|
||||
for poly_predicate in projections {
|
||||
for (poly_predicate, _) in projections {
|
||||
let tcx = self.tcx;
|
||||
if self.check_trait_ref(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
|
||||
return;
|
||||
|
|
@ -956,7 +956,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ty::Opaque(def_id, ..) => {
|
||||
for predicate in &self.tcx.predicates_of(def_id).predicates {
|
||||
for (predicate, _) in &self.tcx.predicates_of(def_id).predicates {
|
||||
let trait_ref = match *predicate {
|
||||
ty::Predicate::Trait(ref poly_trait_predicate) => {
|
||||
Some(poly_trait_predicate.skip_binder().trait_ref)
|
||||
|
|
@ -1387,7 +1387,7 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
|
|||
// for the inferred outlives rules; see
|
||||
// `src/test/ui/rfc-2093-infer-outlives/privacy.rs`.
|
||||
let predicates = self.tcx.explicit_predicates_of(self.item_def_id);
|
||||
for predicate in &predicates.predicates {
|
||||
for (predicate, _) in &predicates.predicates {
|
||||
predicate.visit_with(self);
|
||||
match predicate {
|
||||
&ty::Predicate::Trait(poly_predicate) => {
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ use rustc::lint;
|
|||
use rustc::hir::def::*;
|
||||
use rustc::hir::def::Namespace::*;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
|
||||
use rustc::ty;
|
||||
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
|
||||
use rustc::session::config::nightly_options;
|
||||
use rustc::ty;
|
||||
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
|
||||
|
||||
use rustc_metadata::creader::CrateLoader;
|
||||
|
|
@ -1381,6 +1382,9 @@ pub struct Resolver<'a, 'b: 'a> {
|
|||
/// The current self type if inside an impl (used for better errors).
|
||||
current_self_type: Option<Ty>,
|
||||
|
||||
/// The current self item if inside an ADT (used for better errors).
|
||||
current_self_item: Option<NodeId>,
|
||||
|
||||
/// The idents for the primitive types.
|
||||
primitive_type_table: PrimitiveTypeTable,
|
||||
|
||||
|
|
@ -1710,6 +1714,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
|
||||
current_trait_ref: None,
|
||||
current_self_type: None,
|
||||
current_self_item: None,
|
||||
|
||||
primitive_type_table: PrimitiveTypeTable::new(),
|
||||
|
||||
|
|
@ -2186,15 +2191,17 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
}
|
||||
|
||||
fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
|
||||
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
|
||||
let item_def_id = this.definitions.local_def_id(item.id);
|
||||
if this.session.features_untracked().self_in_typedefs {
|
||||
this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| {
|
||||
self.with_current_self_item(item, |this| {
|
||||
this.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
|
||||
let item_def_id = this.definitions.local_def_id(item.id);
|
||||
if this.session.features_untracked().self_in_typedefs {
|
||||
this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| {
|
||||
visit::walk_item(this, item);
|
||||
});
|
||||
} else {
|
||||
visit::walk_item(this, item);
|
||||
});
|
||||
} else {
|
||||
visit::walk_item(this, item);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -2435,6 +2442,15 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
result
|
||||
}
|
||||
|
||||
fn with_current_self_item<T, F>(&mut self, self_item: &Item, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver) -> T
|
||||
{
|
||||
let previous_value = replace(&mut self.current_self_item, Some(self_item.id));
|
||||
let result = f(self);
|
||||
self.current_self_item = previous_value;
|
||||
result
|
||||
}
|
||||
|
||||
/// This is called to resolve a trait reference from an `impl` (i.e. `impl Trait for Foo`)
|
||||
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver, Option<DefId>) -> T
|
||||
|
|
@ -3004,6 +3020,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
"traits and impls"
|
||||
};
|
||||
err.span_label(span, format!("`Self` is only available in {}", available_in));
|
||||
if this.current_self_item.is_some() && nightly_options::is_nightly_build() {
|
||||
err.help("add #![feature(self_in_typedefs)] to the crate attributes \
|
||||
to enable");
|
||||
}
|
||||
return (err, Vec::new());
|
||||
}
|
||||
if is_self_value(path, ns) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ crate-type = ["dylib"]
|
|||
log = "0.4"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_typeck = { path = "../librustc_typeck" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
|
|
|
|||
|
|
@ -25,10 +25,12 @@
|
|||
|
||||
use rustc::hir::def::Def as HirDef;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::session::config::Input;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
use std::path::Path;
|
||||
use std::env;
|
||||
|
||||
use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID};
|
||||
use syntax::parse::token;
|
||||
|
|
@ -49,8 +51,8 @@ use json_dumper::{Access, DumpOutput, JsonDumper};
|
|||
use span_utils::SpanUtils;
|
||||
use sig;
|
||||
|
||||
use rls_data::{CratePreludeData, Def, DefKind, GlobalCrateId, Import, ImportKind, Ref, RefKind,
|
||||
Relation, RelationKind, SpanData};
|
||||
use rls_data::{CompilationOptions, CratePreludeData, Def, DefKind, GlobalCrateId, Import,
|
||||
ImportKind, Ref, RefKind, Relation, RelationKind, SpanData};
|
||||
|
||||
macro_rules! down_cast_data {
|
||||
($id:ident, $kind:ident, $sp:expr) => {
|
||||
|
|
@ -169,6 +171,54 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
|||
self.dumper.crate_prelude(data);
|
||||
}
|
||||
|
||||
pub fn dump_compilation_options(&mut self, input: &Input, crate_name: &str) {
|
||||
// Apply possible `remap-path-prefix` remapping to the input source file
|
||||
// (and don't include remapping args anymore)
|
||||
let (program, arguments) = {
|
||||
let remap_arg_indices = {
|
||||
let mut indices = FxHashSet();
|
||||
// Args are guaranteed to be valid UTF-8 (checked early)
|
||||
for (i, e) in env::args().enumerate() {
|
||||
if e.starts_with("--remap-path-prefix=") {
|
||||
indices.insert(i);
|
||||
} else if e == "--remap-path-prefix" {
|
||||
indices.insert(i);
|
||||
indices.insert(i + 1);
|
||||
}
|
||||
}
|
||||
indices
|
||||
};
|
||||
|
||||
let mut args = env::args()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| !remap_arg_indices.contains(i))
|
||||
.map(|(_, arg)| {
|
||||
match input {
|
||||
Input::File(ref path) if path == Path::new(&arg) => {
|
||||
let mapped = &self.tcx.sess.local_crate_source_file;
|
||||
mapped
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.into()
|
||||
},
|
||||
_ => arg,
|
||||
}
|
||||
});
|
||||
|
||||
(args.next().unwrap(), args.collect())
|
||||
};
|
||||
|
||||
let data = CompilationOptions {
|
||||
directory: self.tcx.sess.working_dir.0.clone(),
|
||||
program,
|
||||
arguments,
|
||||
output: self.save_ctxt.compilation_output(crate_name),
|
||||
};
|
||||
|
||||
self.dumper.compilation_opts(data);
|
||||
}
|
||||
|
||||
// Return all non-empty prefixes of a path.
|
||||
// For each prefix, we return the span for the last segment in the prefix and
|
||||
// a str representation of the entire prefix.
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ use std::io::Write;
|
|||
|
||||
use rustc_serialize::json::as_json;
|
||||
|
||||
use rls_data::{self, Analysis, CratePreludeData, Def, DefKind, Import, MacroRef, Ref, RefKind,
|
||||
Relation, Impl};
|
||||
use rls_data::config::Config;
|
||||
use rls_data::{self, Analysis, CompilationOptions, CratePreludeData, Def, DefKind, Impl, Import,
|
||||
MacroRef, Ref, RefKind, Relation};
|
||||
use rls_span::{Column, Row};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -89,6 +89,10 @@ impl<'b, O: DumpOutput + 'b> JsonDumper<O> {
|
|||
self.result.prelude = Some(data)
|
||||
}
|
||||
|
||||
pub fn compilation_opts(&mut self, data: CompilationOptions) {
|
||||
self.result.compilation = Some(data);
|
||||
}
|
||||
|
||||
pub fn macro_use(&mut self, data: MacroRef) {
|
||||
if self.config.pub_only || self.config.reachable_only {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ extern crate rustc;
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_codegen_utils;
|
||||
extern crate rustc_serialize;
|
||||
extern crate rustc_target;
|
||||
extern crate rustc_typeck;
|
||||
|
|
@ -45,9 +46,10 @@ use rustc::hir::def::Def as HirDef;
|
|||
use rustc::hir::Node;
|
||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc::middle::cstore::ExternCrate;
|
||||
use rustc::session::config::CrateType;
|
||||
use rustc::session::config::{CrateType, Input, OutputType};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_typeck::hir_ty_to_ty;
|
||||
use rustc_codegen_utils::link::{filename_for_metadata, out_filename};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::default::Default;
|
||||
|
|
@ -110,6 +112,24 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns path to the compilation output (e.g. libfoo-12345678.rmeta)
|
||||
pub fn compilation_output(&self, crate_name: &str) -> PathBuf {
|
||||
let sess = &self.tcx.sess;
|
||||
// Save-analysis is emitted per whole session, not per each crate type
|
||||
let crate_type = sess.crate_types.borrow()[0];
|
||||
let outputs = &*self.tcx.output_filenames(LOCAL_CRATE);
|
||||
|
||||
if outputs.outputs.contains_key(&OutputType::Metadata) {
|
||||
filename_for_metadata(sess, crate_name, outputs)
|
||||
} else if outputs.outputs.should_codegen() {
|
||||
out_filename(sess, crate_type, outputs, crate_name)
|
||||
} else {
|
||||
// Otherwise it's only a DepInfo, in which case we return early and
|
||||
// not even reach the analysis stage.
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
// List external crates used by the current crate.
|
||||
pub fn get_external_crates(&self) -> Vec<ExternalCrateData> {
|
||||
let mut result = Vec::with_capacity(self.tcx.crates().len());
|
||||
|
|
@ -126,7 +146,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
result.push(ExternalCrateData {
|
||||
// FIXME: change file_name field to PathBuf in rls-data
|
||||
// https://github.com/nrc/rls-data/issues/7
|
||||
file_name: self.span_utils.make_path_string(&lo_loc.file.name),
|
||||
file_name: self.span_utils.make_filename_string(&lo_loc.file),
|
||||
num: n.as_u32(),
|
||||
id: GlobalCrateId {
|
||||
name: self.tcx.crate_name(n).to_string(),
|
||||
|
|
@ -1015,6 +1035,7 @@ pub trait SaveHandler {
|
|||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
krate: &ast::Crate,
|
||||
cratename: &str,
|
||||
input: &'l Input,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1080,12 +1101,14 @@ impl<'a> SaveHandler for DumpHandler<'a> {
|
|||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
krate: &ast::Crate,
|
||||
cratename: &str,
|
||||
input: &'l Input,
|
||||
) {
|
||||
let output = &mut self.output_file(&save_ctxt);
|
||||
let mut dumper = JsonDumper::new(output, save_ctxt.config.clone());
|
||||
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
|
||||
|
||||
visitor.dump_crate_info(cratename, krate);
|
||||
visitor.dump_compilation_options(input, cratename);
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
}
|
||||
}
|
||||
|
|
@ -1101,6 +1124,7 @@ impl<'b> SaveHandler for CallbackHandler<'b> {
|
|||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
krate: &ast::Crate,
|
||||
cratename: &str,
|
||||
input: &'l Input,
|
||||
) {
|
||||
// We're using the JsonDumper here because it has the format of the
|
||||
// save-analysis results that we will pass to the callback. IOW, we are
|
||||
|
|
@ -1111,6 +1135,7 @@ impl<'b> SaveHandler for CallbackHandler<'b> {
|
|||
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
|
||||
|
||||
visitor.dump_crate_info(cratename, krate);
|
||||
visitor.dump_compilation_options(input, cratename);
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
}
|
||||
}
|
||||
|
|
@ -1120,6 +1145,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
|
|||
krate: &ast::Crate,
|
||||
analysis: &'l ty::CrateAnalysis,
|
||||
cratename: &str,
|
||||
input: &'l Input,
|
||||
config: Option<Config>,
|
||||
mut handler: H,
|
||||
) {
|
||||
|
|
@ -1137,7 +1163,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
|
|||
impl_counter: Cell::new(0),
|
||||
};
|
||||
|
||||
handler.save(save_ctxt, krate, cratename)
|
||||
handler.save(save_ctxt, krate, cratename, input)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue